| eval 'exec /usr/bin/perl $0 ${1+"${@}"}' |
| if 0; |
| |
| # Perl script to generate truncated array multiplier (Constant Correction) |
| # Last update: 08/23/02 |
| |
| use Getopt::Std; |
| |
| # options are |
| # -x <bits> the number of x bits |
| # -y <bits> the number of y bits |
| # -z <bits> the number of output bits |
| # -k <int> number of columns to keep |
| # -m <string> module name |
| |
| getopts('x:y:z:k:m:'); |
| |
| $XBITS=$opt_x; |
| $YBITS=$opt_y; |
| $ZBITS=$opt_z; |
| $K=$opt_k; |
| $MODULE=$opt_m; |
| |
| if($XBITS<=0 || $YBITS<=0 || $ZBITS<=0 || $K<0){ |
| print("Input parameters:\n"); |
| print(" -x <bits> the number of x bits\n"); |
| print(" -y <bits> the number of y bits\n"); |
| print(" -z <bits> the number of output bits\n"); |
| print(" -k <int> number of columns to keep\n"); |
| print(" -m <string> module name (optional)\n"); |
| exit(1); |
| } |
| |
| if($ZBITS+$K>$XBITS+$YBITS) { |
| print("Error: z+k must be smaller than or equal to x+y\n\n"); |
| exit(1); |
| } |
| |
| $pp_label=1; |
| $ha_label=1; |
| $fa_label=1; |
| $cpa_label=1; |
| |
| $instcnt=1; |
| |
| # Calculation of the correction constant |
| # -------------------------------------- |
| $err_red = 0; |
| for($q = $ZBITS+$K+1; $q <= $XBITS+$YBITS; $q++) { |
| $err_red += ($XBITS+$YBITS+1-$q)/&pow2($q); # reduction error |
| # printf("%s %s %s %s\n",$q,&pow2($q),$err_red,$XBITS+$YBITS+1-$q); |
| } |
| $err_rnd = 1/pow2($ZBITS)*(1 - 1/&pow2($K)); # rounding error |
| $err_tot = 0.25*$err_red + 0.5*$err_rnd; |
| printf("\n// Correction constant value: %s (",$err_tot); |
| |
| # Rounding of that constant |
| $err_tot_rnd = $err_tot * &pow2($ZBITS+$K); |
| $err_tot_rnd = &round_near($err_tot_rnd); |
| $err_tot_rnd = $err_tot_rnd / &pow2($ZBITS+$K); |
| |
| # Conversion into binary format |
| @carray; |
| $rem = $err_tot_rnd; |
| for($j=1;$j<=$ZBITS+$K;$j++){ |
| $mod = $rem * &pow2($j); |
| if($mod>=1){ |
| $rem = $rem - 1/&pow2($j); |
| @carray[$XBITS+$YBITS-$j] = 1; |
| } |
| else{ |
| @carray[$XBITS+$YBITS-$j] = 0; |
| } |
| } |
| |
| # Display the value of the constant correction |
| for($j=$XBITS+$YBITS-1;$j>=$XBITS+$YBITS-$ZBITS-$K;$j--){ |
| printf("%s",@carray[$j]); |
| } |
| printf(")\n\n"); |
| |
| # Calculation of the number of bits required for the constant correction |
| # ---------------------------------------------------------------------- |
| $nbitscon=0; |
| for($j=$XBITS+$YBITS-$ZBITS-$K;$j<$XBITS+$YBITS;$j++){ |
| $nbitscon += @carray[$j]*&pow2($j-($XBITS+$YBITS-$ZBITS-$K)); |
| } |
| |
| # calculation of which partial products have to be generated |
| # ---------------------------------------------------------- |
| if($XBITS<$ZBITS+$K){ |
| $x_pp_size=$XBITS; |
| $h_pp_size=$K+$ZBITS-$XBITS; |
| } |
| else{ |
| $x_pp_size=$ZBITS+$K; |
| $h_pp_size=0; |
| } |
| if($YBITS<=$ZBITS+$K){ |
| $y_pp_size=$YBITS; |
| } |
| else{ |
| $y_pp_size=$ZBITS+$K-1; |
| } |
| |
| # Calculation of the number of bits available for correction |
| # (number of HA located on the diagonal and on the second line) |
| # ------------------------------------------------------------- |
| $nha=0; |
| $nhadiag=0; |
| for($y=$YBITS-$y_pp_size; $y < $YBITS ; $y++) { |
| for($x=$XBITS-2; $x >= $XBITS-$x_pp_size; $x--) { |
| if($x+$y>=$XBITS+$YBITS-$ZBITS-$K){ |
| if($y==$YBITS-$y_pp_size+1){ |
| $nha++; |
| } |
| } |
| if($x+$y==$XBITS+$YBITS-$ZBITS-$K && $y>$YBITS-$y_pp_size+1){ |
| $nhadiag++; |
| } |
| } |
| } |
| |
| # Check if the constant correction can be done |
| # -------------------------------------------- |
| $sum_max=$nhadiag; |
| for($i=0;$i<$nha;$i++){ |
| $sum_max += &pow2($i); |
| } |
| $sum_req=$nbitscon; |
| if($sum_req>$sum_max || ($XBITS+$YBITS==$ZBITS+$K && @carray[$XBITS+$YBITS-$ZBITS-$K]==1)){ |
| $optimize=0; |
| } |
| else{ |
| $optimize=1; |
| } |
| |
| # Write the header of the verilog file (variables definition) |
| # ----------------------------------------------------------- |
| if(length($MODULE)==0){ |
| printf("module CCTarray%s_%s_%s_%s (Z2, X, Y);\n", $XBITS, $YBITS, $ZBITS, $K); |
| } |
| else{ |
| printf("module $MODULE (Z2, X, Y);\n", $XBITS, $YBITS, $ZBITS, $K); |
| } |
| printf("\t\n"); |
| printf("\tinput [%s:0] Y;\n",$YBITS-1); |
| printf("\tinput [%s:0] X;\n",$XBITS-1); |
| printf("\toutput [%s:0] Z2;\n",$ZBITS-1); |
| printf("\n\n"); |
| for($y=0; $y < $YBITS ; $y++) { |
| printf("\twire [%s:0] P%s;\n", $XBITS-1, $y); |
| printf("\twire [%s:0] carry%s;\n", $XBITS-1, $y+1); |
| printf("\twire [%s:0] sum%s;\n", $XBITS-1, $y+1); |
| } |
| printf("\twire [%s:0] carry%s;\n",$ZBITS+$K-2,$YBITS+1); |
| printf("\twire [%s:0] Z;\n",$ZBITS+$K-1); |
| print "\n\n"; |
| |
| # Generate the partial products |
| # ----------------------------- |
| print "\t// generate the partial products.\n"; |
| for($y=$YBITS-$y_pp_size; $y < $YBITS ; $y++) { |
| for($x=$XBITS-1; $x >= $XBITS-$x_pp_size; $x--) { |
| if($x+$y>=$XBITS+$YBITS-$ZBITS-$K){ |
| if($y>$YBITS-$y_pp_size && $x==$XBITS-1) { |
| printf ("\tand pp%s(sum%s[%s], X[%s], Y[%s]);\n", $pp_label, $y, $x, $x, $y); |
| $pp_label++; |
| } |
| else { |
| printf ("\tand pp%s(P%s[%s], X[%s], Y[%s]);\n", $pp_label, $y, $x, $x, $y); |
| $pp_label++; |
| } |
| } |
| } |
| } |
| print "\n"; |
| |
| # $optimize=0; |
| if($optimize==0 || $XBITS+$YBITS==$ZBITS){ |
| goto NO_OPTIMIZE; |
| } |
| |
| # Array Reduction |
| # --------------- |
| $nbitsvarused=0; |
| $nbitsconused=0; |
| print "\t// Array Reduction\n"; |
| for($y=$YBITS-$y_pp_size; $y < $YBITS ; $y++) { |
| for($x=$XBITS-2; $x >= $XBITS-$x_pp_size; $x--) { |
| if($x+$y>=$XBITS+$YBITS-$ZBITS-$K){ |
| if($y==$YBITS-$y_pp_size+1){ |
| if($nbitsconused+&pow2($x-($XBITS+$YBITS-$ZBITS-$K-$y))<=$nbitscon){ |
| if($K>=2 && $x==0){ |
| printf("\tassign carry%s[%s] = P%s[%s] & P%s[%s];\n",$y,$x,$y,$x,$y-1,$x+1); |
| $nbitsconused++; |
| } |
| else{ |
| printf("\tspecialized_half_adder SHA%s(carry%s[%s],sum%s[%s],P%s[%s],P%s[%s]);\n",$sha_label,$y,$x,$y,$x,$y,$x,$y-1,$x+1); |
| $sha_label++; |
| $nbitsconused += &pow2($x-($XBITS+$YBITS-$ZBITS-$K-$y)); |
| } |
| } |
| else{ |
| if($K>=2 && $x==0){ |
| printf("\tassign carry%s[%s] = P%s[%s] | P%s[%s];\n",$y,$x,$y,$x,$y-1,$x+1); |
| } |
| else{ |
| printf("\thalf_adder HA%s(carry%s[%s],sum%s[%s],P%s[%s],P%s[%s]);\n",$ha_label,$y,$x,$y,$x,$y,$x,$y-1,$x+1); |
| $ha_label++; |
| } |
| } |
| } |
| if($y>$YBITS-$y_pp_size+1){ |
| if($x+$y==$XBITS+$YBITS-$ZBITS-$K){ |
| if($nbitsconused<$nbitscon){ |
| if($x==0 && $y<$YBITS-$h_pp_size+$K){ |
| printf("\tassign carry%s[%s] = P%s[%s] | sum%s[%s];\n",$y,$x,$y,$x,$y-1,$x+1); |
| $nbitsconused++; |
| } |
| else{ |
| printf("\tspecialized_half_adder SHA%s(carry%s[%s],sum%s[%s],P%s[%s],sum%s[%s]);\n",$sha_label,$y,$x,$y,$x,$y,$x,$y-1,$x+1); |
| $sha_label++; |
| $nbitsconused++; |
| } |
| } |
| else{ |
| if($x==0 && $y<$YBITS-$h_pp_size+$K){ |
| printf("\tassign carry%s[%s] = P%s[%s] & sum%s[%s];\n",$y,$x,$y,$x,$y-1,$x+1); |
| } |
| else{ |
| printf("\thalf_adder HA%s(carry%s[%s],sum%s[%s],P%s[%s],sum%s[%s]);\n",$ha_label,$y,$x,$y,$x,$y,$x,$y-1,$x+1); |
| $ha_label++; |
| } |
| } |
| } |
| else{ |
| if($x==0 && $y<$YBITS-$h_pp_size+$K){ |
| printf("\treduced_full_adder RFA%s(carry%s[%s],P%s[%s],sum%s[%s],carry%s[%s]);\n",$rfa_label,$y,$x,$y,$x,$y-1,$x+1,$y-1,$x); |
| $rfa_label++; |
| } |
| else{ |
| printf("\tfull_adder FA%s(carry%s[%s],sum%s[%s],P%s[%s],sum%s[%s],carry%s[%s]);\n",$fa_label,$y,$x,$y,$x,$y,$x,$y-1,$x+1,$y-1,$x); |
| $fa_label++; |
| } |
| } |
| } |
| } |
| } |
| } |
| print "\n"; |
| # Generate lower order product |
| print "\t// Generate lower product bits YBITS \n"; |
| $Zpin=0; |
| if($ZBITS>$XBITS){ |
| for($y=$YBITS+$XBITS-$ZBITS; $y < $YBITS ; $y++){ |
| if($y==0){ |
| printf("\tbuf b1(Z2[0], P0[0]);\n"); |
| $Zpin++; |
| } |
| else{ |
| printf ("\tassign Z2[%s] = sum%s[0];\n",$Zpin,$y); |
| $Zpin++; |
| } |
| } |
| } |
| print "\n"; |
| # Generate higher order product |
| print "\t// Final Carry Propagate Addition\n"; |
| print "\t// Generate higher product bits\n"; |
| if($ZBITS>$XBITS){ |
| $nhop=$XBITS; |
| } |
| else{ |
| $nhop=$ZBITS; |
| } |
| if($ZBITS+$K>$XBITS){ |
| $xstart=0; |
| } |
| else{ |
| $xstart=$XBITS-$ZBITS-$K;; |
| } |
| for($x=$xstart; $x < $XBITS ; $x++) { |
| if($x==$xstart) { |
| if($x==$XBITS-$nhop){ |
| if($ZBITS+$K>$XBITS){ |
| printf("\thalf_adder CPA%s(carry%s[%s],Z2[%s],carry%s[%s],sum%s[%s]);\n",$cpa_label,$YBITS,$x,$Zpin,$YBITS-1,$x,$YBITS-1,$x+1); |
| $cpa_label++; |
| } |
| else{ |
| printf("\tassign carry%s[%s] = 0;\n",$YBITS,$x); |
| printf("\tassign Z2[%s] = sum%s[%s];\n",$Zpin,$YBITS-1,$x+1); |
| } |
| $Zpin++; |
| } |
| else{ |
| if($ZBITS+$K>$XBITS){ |
| printf("\tassign carry%s[%s] = carry%s[%s] & sum%s[%s];\n",$YBITS,$x,$YBITS-1,$x,$YBITS-1,$x+1); |
| } |
| else{ |
| printf("\tassign carry%s[%s] = 0;\n",$YBITS,$x); |
| } |
| } |
| } |
| else{ |
| if($x==$XBITS-2) { |
| printf("\tfull_adder CPA%s(Z2[%s],Z2[%s],carry%s[%s],carry%s[%s],sum%s[%s]);\n",$cpa_label,$Zpin+1,$Zpin,$YBITS-1,$x,$YBITS,$x-1,$YBITS-1,$x+1); |
| } |
| else{ |
| if($x>=$XBITS-$nhop && $x<$XBITS-2) { |
| printf("\tfull_adder CPA%s(carry%s[%s],Z2[%s],carry%s[%s],carry%s[%s],sum%s[%s]);\n",$cpa_label,$YBITS,$x,$Zpin,$YBITS-1,$x,$YBITS,$x-1,$YBITS-1,$x+1); |
| $cpa_label++; |
| $Zpin++; |
| } |
| if($x<$XBITS-$nhop && $x>$xstart && $x<$XBITS-2){ |
| printf("\treduced_full_adder CPA%s(carry%s[%s],carry%s[%s],carry%s[%s],sum%s[%s]);\n",$cpa_label,$YBITS,$x,$YBITS-1,$x,$YBITS,$x-1,$YBITS-1,$x+1); |
| $cpa_label++; |
| } |
| } |
| } |
| } |
| goto END; |
| |
| NO_OPTIMIZE: printf("// FAILED TO OPTIMIZE THE CORRECTION!\n"); |
| # Array Reduction |
| # --------------- |
| print "\t// Array Reduction\n"; |
| for($y=$YBITS-$y_pp_size; $y < $YBITS ; $y++) { |
| for($x=$XBITS-2; $x >= $XBITS-$x_pp_size; $x--) { |
| if($x+$y>=$XBITS+$YBITS-$ZBITS-$K){ |
| if($y==$YBITS-$y_pp_size+1){ |
| printf("\thalf_adder HA%s(carry%s[%s],sum%s[%s],P%s[%s],P%s[%s]);\n",$ha_label,$y,$x,$y,$x,$y,$x,$y-1,$x+1); |
| $ha_label++; |
| } |
| if($y>$YBITS-$y_pp_size+1){ |
| if($x+$y==$XBITS+$YBITS-$ZBITS-$K){ |
| printf("\thalf_adder HA%s(carry%s[%s],sum%s[%s],P%s[%s],sum%s[%s]);\n",$ha_label,$y,$x,$y,$x,$y,$x,$y-1,$x+1); |
| $ha_label++; |
| } |
| else{ |
| printf("\tfull_adder FA%s(carry%s[%s],sum%s[%s],P%s[%s],sum%s[%s],carry%s[%s]);\n",$fa_label,$y,$x,$y,$x,$y,$x,$y-1,$x+1,$y-1,$x); |
| $fa_label++; |
| } |
| } |
| } |
| } |
| } |
| |
| |
| print "\n"; |
| if($XBITS+$YBITS>$ZBITS){ |
| # Generate lower order product |
| print "\t// Generate lower product bits YBITS \n"; |
| $Zpin=0; |
| if($ZBITS+$K>$XBITS){ |
| for($y=$YBITS-$ZBITS-$K+$XBITS; $y < $YBITS ; $y++){ |
| if($y==0){ |
| printf("\tbuf b1(Z[0], P0[0]);\n"); |
| $Zpin++; |
| } |
| else{ |
| printf ("\tassign Z[%s] = sum%s[0];\n",$Zpin,$y); |
| $Zpin++; |
| } |
| } |
| } |
| print "\n"; |
| # Generate higher order product |
| print "\t// Final Carry Propagate Addition\n"; |
| print "\t// Generate higher product bits\n"; |
| if($ZBITS+$K>$XBITS){ |
| $nhop=$XBITS; |
| } |
| else{ |
| $nhop=$ZBITS+$K; |
| } |
| for($x=$XBITS-$nhop; $x < $XBITS ; $x++) { |
| if($x==$XBITS-$nhop) { |
| if($ZBITS+$K>$XBITS){ |
| printf("\thalf_adder CPA%s(carry%s[%s],Z[%s],carry%s[%s],sum%s[%s]);\n",$cpa_label,$YBITS,$x,$Zpin,$YBITS-1,$x,$YBITS-1,$x+1); |
| } |
| else{ |
| printf("\tassign carry%s[%s] = 0;\n",$YBITS,$x); |
| printf("\tassign Z[%s] = sum%s[%s];\n",$Zpin,$YBITS-1,$x+1); |
| } |
| $cpa_label++; |
| $Zpin++; |
| } |
| if($x==$XBITS-2) { |
| printf("\tfull_adder CPA%s(Z[%s],Z[%s],carry%s[%s],carry%s[%s],sum%s[%s]);\n",$cpa_label,$Zpin+1,$Zpin,$YBITS-1,$x,$YBITS,$x-1,$YBITS-1,$x+1); |
| $cpa_label++; |
| $Zpin++; |
| } |
| if($x>$XBITS-$nhop && $x<$XBITS-2) { |
| printf("\tfull_adder CPA%s(carry%s[%s],Z[%s],carry%s[%s],carry%s[%s],sum%s[%s]);\n",$cpa_label,$YBITS,$x,$Zpin,$YBITS-1,$x,$YBITS,$x-1,$YBITS-1,$x+1); |
| $cpa_label++; |
| $Zpin++; |
| } |
| } |
| |
| |
| print "\n"; |
| # Add the constant to the sum previously calculated |
| print "\t// Add the constant\n"; |
| for($x=0;$x<$ZBITS+$K;$x++){ |
| if($x==0) { |
| if(@carray[$XBITS+$YBITS-$ZBITS-$K+$x]==0){ |
| if($K==0){ |
| printf("\tassign Z2[%s] = Z[%s];\n",$x,$x); |
| } |
| printf("\tassign carry%s[%s] = 0;\n",$YBITS+1,$x); |
| } |
| else{ |
| if($K==0){ |
| printf("\tassign Z2[%s] = !Z[%s];\n",$x,$x); |
| } |
| printf("\tassign carry%s[%s] = Z[%s];\n",$YBITS+1,$x,$x); |
| } |
| } |
| if($x==$ZBITS+$K-1) { |
| if(@carray[$XBITS+$YBITS-$ZBITS-$K+$x]==0){ |
| printf("\tassign Z2[%s] = Z[%s] ^ carry%s[%s];\n",$x-$K,$x,$YBITS+1,$x-1); |
| } |
| else{ |
| printf("\tassign Z2[%s] = !Z[%s] ^ carry%s[%s];\n",$x-$K,$x,$YBITS+1,$x-1); |
| } |
| $cpa_label++; |
| } |
| if($x>0 && $x<$ZBITS+$K-1) { |
| if($x>=$K){ |
| if(@carray[$XBITS+$YBITS-$ZBITS-$K+$x]==0){ |
| printf("\thalf_adder CPA%s(carry%s[%s],Z2[%s],Z[%s],carry%s[%s]);\n",$cpa_label,$YBITS+1,$x,$x-$K,$x,$YBITS+1,$x-1); |
| } |
| else{ |
| printf("\tspecialized_half_adder CPA%s(carry%s[%s],Z2[%s],Z[%s],carry%s[%s]);\n",$cpa_label,$YBITS+1,$x,$x-$K,$x,$YBITS+1,$x-1); |
| } |
| } |
| else{ |
| if(@carray[$XBITS+$YBITS-$ZBITS-$K+$x]==0){ |
| printf("\tand CPA%s(carry%s[%s],Z[%s],carry%s[%s]);\n",$cpa_label,$YBITS+1,$x,$x,$YBITS+1,$x-1); |
| } |
| else{ |
| printf("\tor CPA%s(carry%s[%s],Z[%s],carry%s[%s]);\n",$cpa_label,$YBITS+1,$x,$x,$YBITS+1,$x-1); |
| } |
| } |
| $cpa_label++; |
| } |
| } |
| } |
| else{ # if $XBITS+$YBITS=$ZBITS |
| # Generate lower order product |
| print "\t// Generate lower product bits YBITS \n"; |
| $Zpin=0; |
| if($ZBITS>$XBITS){ |
| for($y=$YBITS-$ZBITS+$XBITS; $y < $YBITS ; $y++){ |
| if($y==0){ |
| printf("\tbuf b1(Z2[0], P0[0]);\n"); |
| $Zpin++; |
| } |
| else{ |
| printf ("\tassign Z2[%s] = sum%s[0];\n",$Zpin,$y); |
| $Zpin++; |
| } |
| } |
| } |
| print "\n"; |
| # Generate higher order product |
| print "\t// Final Carry Propagate Addition\n"; |
| print "\t// Generate higher product bits\n"; |
| if($ZBITS>$XBITS){ |
| $nhop=$XBITS; |
| } |
| else{ |
| $nhop=$ZBITS; |
| } |
| if($XBITS-$ZBITS-$K>0){ |
| $xstart=$XBITS-$ZBITS-$K; |
| } |
| else{ |
| $xstart=0; |
| } |
| for($x=$xstart; $x < $XBITS ; $x++) { |
| if($x==$xstart) { |
| if($x==$XBITS-$nhop){ |
| printf("\thalf_adder CPA%s(carry%s[%s],Z2[%s],carry%s[%s],sum%s[%s]);\n",$cpa_label,$YBITS,$x,$Zpin,$YBITS-1,$x,$YBITS-1,$x+1); |
| $cpa_label++; |
| $Zpin++; |
| } |
| else{ |
| printf("\tassign carry%s[%s] = carry%s[%s] & sum%s[%s];\n",$YBITS,$x,$YBITS-1,$x,$YBITS-1,$x+1); |
| } |
| } |
| else{ |
| if($x==$XBITS-2) { |
| printf("\tfull_adder CPA%s(Z2[%s],Z2[%s],carry%s[%s],carry%s[%s],sum%s[%s]);\n",$cpa_label,$Zpin+1,$Zpin,$YBITS-1,$x,$YBITS,$x-1,$YBITS-1,$x+1); |
| $cpa_label++; |
| $Zpin++; |
| } |
| else{ |
| if($x>=$XBITS-$nhop && $x<$XBITS-2) { |
| printf("\tfull_adder CPA%s(carry%s[%s],Z2[%s],carry%s[%s],carry%s[%s],sum%s[%s]);\n",$cpa_label,$YBITS,$x,$Zpin,$YBITS-1,$x,$YBITS,$x-1,$YBITS-1,$x+1); |
| $cpa_label++; |
| $Zpin++; |
| } |
| if($x<$XBITS-$nhop && $x>$xstart && $x<$XBITS-2){ |
| printf("\treduced_full_adder CPA%s(carry%s[%s],carry%s[%s],carry%s[%s],sum%s[%s]);\n",$cpa_label,$YBITS,$x,$YBITS-1,$x,$YBITS,$x-1,$YBITS-1,$x+1); |
| $cpa_label++; |
| } |
| } |
| } |
| } |
| } |
| |
| END: print "endmodule"; |
| |
| sub pow2 { |
| ($p) = @_; |
| $res = 1; |
| for($i=1;$i<=$p;$i++){ |
| $res = $res * 2; |
| } |
| return($res); |
| } |
| |
| sub round_near { |
| ($num) = @_; |
| $rnd = 0; |
| while($num>$rnd+0.5){ |
| $rnd = $rnd + 1; |
| } |
| return($rnd); |
| } |
| |
| |
| |