#!/bin/csh -f

####################################################################################
## Copyright (c) 2014, University of British Columbia (UBC)  All rights reserved. ##
##                                                                                ##
## Redistribution  and  use  in  source   and  binary  forms,   with  or  without ##
## modification,  are permitted  provided that  the following conditions are met: ##
##   * Redistributions   of  source   code  must  retain   the   above  copyright ##
##     notice,  this   list   of   conditions   and   the  following  disclaimer. ##
##   * Redistributions  in  binary  form  must  reproduce  the  above   copyright ##
##     notice, this  list  of  conditions  and the  following  disclaimer in  the ##
##     documentation and/or  other  materials  provided  with  the  distribution. ##
##   * Neither the name of the University of British Columbia (UBC) nor the names ##
##     of   its   contributors  may  be  used  to  endorse  or   promote products ##
##     derived from  this  software without  specific  prior  written permission. ##
##                                                                                ##
## THIS  SOFTWARE IS  PROVIDED  BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ##
## AND  ANY EXPRESS  OR IMPLIED WARRANTIES,  INCLUDING,  BUT NOT LIMITED TO,  THE ##
## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ##
## DISCLAIMED.  IN NO  EVENT SHALL University of British Columbia (UBC) BE LIABLE ##
## FOR ANY DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL ##
## DAMAGES  (INCLUDING,  BUT NOT LIMITED TO,  PROCUREMENT OF  SUBSTITUTE GOODS OR ##
## SERVICES;  LOSS OF USE,  DATA,  OR PROFITS;  OR BUSINESS INTERRUPTION) HOWEVER ##
## CAUSED AND ON ANY THEORY OF LIABILITY,  WHETHER IN CONTRACT, STRICT LIABILITY, ##
## OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ##
## OF  THIS SOFTWARE,  EVEN  IF  ADVISED  OF  THE  POSSIBILITY  OF  SUCH  DAMAGE. ##
####################################################################################

####################################################################################
##                        Wide Pipelined reduction function                       ##
##                                                                                ##
##    Author: Ameer M. Abdelhadi (ameer@ece.ubc.ca, ameer.abdelhadi@gmail.com)    ##
##     SRAM-based BCAM; The University of British Columbia (UBC), April 2014      ##
####################################################################################

####################################################################################
## USAGE:                                                                         ##
## ./reduction <in data width> <internal logic block width> <reg in?> <reg out?>\ ##
##       <maximum combinatorial depth>  <reduction function> <top module suffex>  ##
##     - data width is positive integers                                          ##
##     - internal logic block width is the width of the basic logic block used to ##
##       construct the wide reduction                                             ##
##     - register inputs/outputs is a binary (0/1) indicating if inputs/outputs   ##
##       should be registerd for pipelining                                       ##
##     - maximum combinatorial mux depth is acheived by pipelining                ##
##     - Top module name and file will be "reduction_<top module suffex>"         ##
## EXAMPLES:                                                                      ##
## ./reduction 1024 6 1 1 1 OR or                                                 ##
##     - Will generate Verilog files for a 1K wide reduction OR                   ##
##     - Registered inputs and outputs; maximum 6 inputs width combinatorial OR   ##
##     - Top level will be reduction_or and will be located in reduction_or.v     ##
## The following files and directories will be created:                           ##
## - reduction_<suffex>.v: reduction function top module file                     ##
####################################################################################

################################## ARGUMENTS CHECK #################################

# require exactly 7 arguments
if (${#argv} != 7) then
    printf '\x1b[%i;3%im' 1 1
    printf 'Error: Exactly 7 argument are required\n'
    printf '\x1b[0m'
    goto errorMessage
endif

# data width
# check argument correctness (positive integer number)
if ( (`echo ${argv[1]} | egrep -c '^[0-9]+$'` != 1) ) then
  printf '\x1b[%i;3%im' 1 1
  printf "Error (${argv[1]}): input data width must be a possitive integer\n"
  printf '\x1b[0m'
  goto errorMessage
endif
@ DW = ${argv[1]}

# internal logic block width
# check argument correctness (positive integer number)
if ((`echo ${argv[2]} | egrep -c '^[0-9]+$'` != 1) || (${argv[2]} < 2) ) then
  printf '\x1b[%i;3%im' 1 1
  printf "Error (${argv[2]}): internal logic block width must be larger than 1\n"
  printf '\x1b[0m'
  goto errorMessage
endif
@ IW = ${argv[2]}

# register inputs? (binary)
# check argument correctness (binary 0/1)
if ( (${argv[3]} != "0") & (${argv[3]} != "1") )then
  printf '\x1b[%i;3%im' 1 1
  printf "Error (${argv[3]}): Register inputs? should be a binary 0/1\n"
  printf '\x1b[0m'
  goto errorMessage
endif
@ RI = ${argv[3]}

# # register outputs? (binary)
# check argument correctness (binary 0/1)
if ( (${argv[4]} != "0") & (${argv[4]} != "1") )then
  printf '\x1b[%i;3%im' 1 1
  printf "Error (${argv[4]}): Register outputs? should be a binary 0/1\n"
  printf '\x1b[0m'
  goto errorMessage
endif
@ RO = ${argv[4]}

# maximum combinatorial depth
# check argument correctness (positive integer number)
if ((`echo ${argv[5]} | egrep -c '^[0-9]+$'` != 1) || (${argv[5]} < 1) ) then
  printf '\x1b[%i;3%im' 1 1
  printf "Error (${argv[5]}): reduction function maximum combinatorial depth must be a possitive integer\n"
  printf '\x1b[0m'
  goto errorMessage
endif
@ CD = ${argv[5]}

# reduction functiob
# check argument correctness ("AND", "OR", "XOR")

switch (${argv[6]})
  case AND:
    set RF = '&'
    breaksw
  case OR:
    set RF = '|'
    breaksw
  case XOR:
    set RF = '^'
    breaksw
  default:
    printf '\x1b[%i;3%im' 1 1
    printf 'Error (%s): reduction function should be "AND", "OR", or "XOR" \n' ${argv[6]}
    printf '\x1b[0m'
    goto errorMessage
endsw

# top module suffex
set MS = ${argv[7]}

################################## ARGUMENTS CHECK #################################


# reserved keywords
set REG = "always @(posedge clk, posedge rst)\n  if (rst) %s = %d'b0;\n  else     %s = %s;\n"

# upper(log2(data width))
@ i = 2
@ L2DW = 1
while ($i < $DW)
  @ i = $i * 2
  @ L2DW++
end

# upper(log2(internal logic block width))
@ i = 2
@ L2IW = 1
while ($i < $IW)
  @ i = $i * 2
  @ L2IW++
end

# wide pipelined reduction function top module file

printf "// reduction_$MS.v: wide pipelined reduction function; automatically generated\n" >! reduction_$MS.v
printf "// input data is a ${DW} bit vector\n" >> reduction_$MS.v
printf "// Ameer Abedlhadi; April 2014 - University of British Columbia\n\n" >> reduction_$MS.v
printf "module reduction_$MS(input clk, input rst, input [$DW-1:0] dat, output out);\n" >> reduction_$MS.v

if $RI then
  printf "\n// register inputs\n" >> reduction_$MS.v
  printf "reg [$DW-1:0] w0;\n" >> reduction_$MS.v
  printf "$REG" w0 $DW w0  dat >> reduction_$MS.v
else
  printf "wire [$DW-1:0] w0 = dat;\n" >> reduction_$MS.v
endif

## current width
@ cw = $DW

## current stage number
@ cs = 0

while ($cw > 1)

  ## padding width
  @ pw = ($IW - ($cw % $IW)) % $IW

  ## add padding width to current stage width
  @ cw = $cw + $pw

  ## next stage width = number of blocks in current stage
  @ nw = $cw / $IW

  ## next stage number
  @ ns = $cs + 1

  printf "\n//////////////\n// stage #$cs //\n//////////////\n\n" >> reduction_$MS.v
  set tmp = "w$cs"; if $pw set tmp = "{$pw'b0,w$cs}"; printf "wire [$cw-1:0] w${cs}p = $tmp; // padding input to stage $cs\n" >> reduction_$MS.v
  printf "wire [$nw-1:0] w${ns}i; // output of stage $cs (unregistered)\n" >> reduction_$MS.v
  #############
  ## number of muxes in current stage
  printf "\n// logic blocks for stage #$cs\n" >> reduction_$MS.v
  @ nwl = `echo -n $nw|wc -c`
  foreach i (`awk "BEGIN { for (i=0; i<$nw; i++) print i; exit }"`)
    printf "assign w${ns}i[%0${nwl}d] = $RF w${cs}p[$IW*%${nwl}d +: $IW];\n" $i $i >> reduction_$MS.v
  end

  ## pipelining
  if ( !($ns % $CD) & ($nw > 1) ) then
    printf "\n// register stage $cs\n" >> reduction_$MS.v
    printf "reg  [$nw-1:0] w${ns};\n" >> reduction_$MS.v
    printf "$REG" w$ns $nw w$ns w${ns}i  >> reduction_$MS.v
  else
    printf "wire [$nw-1:0] w$ns = w${ns}i; // data output of stage $cs\n" >> reduction_$MS.v
  endif

  ## stage width for next stage
  @ cw = $nw

  ## stage number for next stage
  @ cs = $ns

end

## register output
if $RO then
  printf "\n// register output\n" >> reduction_$MS.v
  printf "reg outR;\n" >> reduction_$MS.v
  printf "$REG" outR 1 outR w$cs >> reduction_$MS.v
  printf "assign out = outR; // assign output to last stage / registered\n" >> reduction_$MS.v
else
  printf "assign out = w$cs; // assign output to last stage\n" >> reduction_$MS.v
endif

printf "\nendmodule\n" >> reduction_$MS.v

goto scriptEnd

################################## ERROR MESSAGE ####################################

errorMessage:
printf '\x1b[%i;3%im' 1 1
cat << EOH
USAGE:
./reduction <in data width> <internal logic block width> <reg in?> <reg out?>\
      <maximum combinatorial depth>  <reduction function> <top module suffex>
    - data width is positive integers
    - internal logic block width is the width of the basic logic block used to
      construct the wide reduction
    - register inputs/outputs is a binary (0/1) indicating if inputs/outputs
      should be registerd for pipelining
    - maximum combinatorial mux depth is acheived by pipelining
    - Top module name and file will be "reduction_<top module suffex>"
EXAMPLES:
./reduction 1024 6 1 1 1 OR or
    - Will generate Verilog files for a 1K wide reduction OR
    - Registered inputs and outputs; maximum 6 inputs width combinatorial OR 
    - Top level will be reduction_or and will be located in reduction_or.v
The following files and directories will be created:
- reduction_<suffex>.v: reduction function top module file
EOH
printf '\x1b[0m'
scriptEnd:

