#!/bin/sh --# perl, to stop looping eval 'exec /usr/local/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 the number of x bits # -y the number of y bits # -z the number of output bits # -k number of columns to keep # -m 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 the number of x bits\n"); print(" -y the number of y bits\n"); print(" -z the number of output bits\n"); print(" -k number of columns to keep\n"); print(" -m 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); }