1 # Generate unsigned nonrecoded Wallace multiplier Verilog, 
  2 # testing with Icarus Verilog testbench and Verilator C++ 
  3 # testbench.
  4 # John Bryan 
  5 # 2017
  6 # Perl v5.14.3
  7 # Usage: Script takes 3 arguments; 
  8 # 1.multiplicand length. 
  9 # 2.multiplier length.
 10 # 3.integer = # increasing operand sizes to be tested.
 11 # i.e., perl wallace.pl 6 6 8 
 12 use strict;
 13 use warnings;
 14 use diagnostics;
 15 use 5.006;
 16 use FileHandle;
 17 use List::MoreUtils qw(firstidx);
 18 use IPC::System::Simple qw(system);
 19 use Benchmark qw(:all);
 20 use PDL;
 21 use PDL::Graphics::PLplot;
 22 use Time::HiRes qw(gettimeofday tv_interval clock);
 23 local $| = 1;
 24 
 25 
 26 # subroutine prototypes 
 27 sub partial_products;
 28 sub wallace_tree;
 29 sub kogge_stone;
 30 sub generate_multiplier;
 31 sub generate_and_test;
 32 sub verilog_testbench;
 33 sub cpp_testbench;
 34 sub make;
 35 sub makefile;
 36 sub chart;
 37 
 38 
 39 &generate_and_test();
 40 exit(0);
 41 
 42 
 43 sub generate_multiplier() 
 44 {
 45     my ($i,$j)=(@_);
 46     my $pp=partial_products($i,$j);
 47     my @pp=@$pp;
 48     my $pph=wallace_tree(\@pp);
 49     my %pp=%$pph;
 50     my $pl=$i+$j-1;
 51     kogge_stone($pl,\%pp);
 52     return;
 53 }
 54 
 55 
 56 sub partial_products() 
 57 {
 58     my ($multiplicand_length,$multiplier_length)=(@_);
 59     my $ul =$multiplicand_length-1;
 60     my $zl =$multiplier_length-1;
 61     my $ul2 ="a" . "$ul";
 62     my $zl2 ="b" . "$zl";
 63     my @rmultiplicand;
 64     my @pp;
 65     my $i; my $k; my $fh;
 66     for ($i=0; $i < $multiplicand_length; $i++)
 67         { $rmultiplicand[$i]= 'a'.$i; }
 68     my @multiplicand=reverse(@rmultiplicand);
 69     my $multiplicand = @multiplicand;
 70     my @rmultiplier;
 71     for ($i=0; $i < $multiplier_length; $i++)
 72         { $rmultiplier[$i]= 'b'.$i; }
 73     my @multiplier=reverse(@rmultiplier);
 74     my $multiplier = @multiplier;
 75     my $product = $multiplicand + $multiplier;
 76     my $pl =$product - 1;
 77     for my $multiplier (@multiplier)
 78     {   for my $multiplicand (@multiplicand)
 79            {push @pp, $multiplier.$multiplicand;}
 80     }
 81     open $fh, ">", "wallace.vl";
 82     print $fh ("module wallace(a, b, product);\n");
 83     print $fh ("   // Unsigned nonrecoded Wallace multiplier.\n");
 84     print $fh ("   // John Bryan, 2017.\n");
 85     print $fh ("   input [$ul:0] a;\n   input [$zl:0] b;\n");
 86     print $fh ("   output [$pl:0] product;\n");
 87     my $icount=$zl;
 88     my $jcount=$ul;
 89     loop_g:
 90     for($k = 0; $k < scalar(@pp); $k++)
 91     {
 92         print $fh ("   assign ", $pp[$k], " = ","b[",$icount,"]", " & ",
 93                           "a[",$jcount,"];\n");
 94         if ($jcount==0)
 95         {   $icount--;
 96             $jcount=$ul; }
 97         else
 98         {   $jcount--; }
 99     } #loop_g
100     close $fh;
101     return (\@pp);
102 }
103 
104 
105 sub wallace_tree() 
106 {
107     my @pp=@{$_[0]};
108     my $i;
109     my $j;
110     my $k;
111     my(@other_array)=();
112     my %counts;
113     my %pp;
114     my %pp_copy;
115     my $key;
116     my $fh;
117     my $value;
118     my $final_flag;
119     my $flag;
120     my $tag;
121     my $string="";
122     my $c_string="";
123     my $cutoff_count;
124     my @sum_array=();
125     my @carry_array=();
126     my @sorted_pp_keys = ();
127     my @sca=();
128     my @carries=();
129     my $sca_count;
130     my $sum_array_index=0;
131     my $carry_array_index=0;
132     my $array_index=0;
133     my $carries_index=0;
134     my @array = ("aaaa" .. "zzzz");
135     @pp{@pp} = (1) x @pp;
136     my @two_nums;
137     while (  ($key, $value) = each(%pp) )
138     {
139          @two_nums=$key =~ /(\d+)/g;
140          $pp{$key}=$two_nums[0]+$two_nums[1];
141     }
142     @other_array=values %pp;       # weights of each pp
143     $counts{$_} ++ for @other_array;
144     $j=scalar(keys %counts)-1;
145     %pp_copy=%pp;
146     $sca_count=0;
147     $flag=1;
148     $tag=0;
149     loop_e:
150     while (($j>-1)&&($flag==1))
151     {
152        loop_d:
153        #loop_d for full adder
154        for ($i=0;$i<int($counts{$j}/3);$i++)
155        {
156            $cutoff_count=0;
157            $string=$array[$array_index];
158            $array_index++;
159            $c_string=$array[$array_index];
160            $array_index++;
161            loop_c:
162            while ( ($key, $value) = each(%pp_copy) )
163            {
164                conditional_b:
165                if (($value==$j) && ($cutoff_count < 3))
166                {
167                    $cutoff_count++;
168                    $pp{$string} = $pp{$key};
169                    $pp{$c_string} = $pp{$key};
170                    $sca[$sca_count] = $key;
171                    $sca_count++;
172                    delete($pp{$key});
173                    delete($pp_copy{$key});
174                    my $n = keys %pp;
175                    conditional_a:
176                    if ($cutoff_count==3)
177                    {
178                        $pp{$c_string} = int($pp{$c_string})+1;
179                        $sum_array[$sum_array_index]= "   assign $string" . ' = ' . "$sca[0]" .  ' ^ ' .
180                                                     "$sca[1]" . ' ^ ' . "$sca[2]" . ';';
181                        $carry_array[$carry_array_index]= "   assign $c_string" . ' = (' . "$sca[0]" .' & '.
182                                                          "$sca[1]" .') | ('.  "$sca[2]" .' & (' .
183                                                           "$sca[0]" .' ^ '. "$sca[1]" .'));';
184                        $sum_array_index++;
185                        $carry_array_index++;
186                        $sca_count=0;
187                    } #conditional_a  
188                } #conditional_b
189            } #loop_c
190            $tag=1;
191        } #loop_d
192        $counts{$j}=$counts{$j}-(3*($i));
193        loop_h:
194        #loop_h for half adder
195        for ($i=0;$i<int($counts{$j}/2);$i++)
196        {
197             $counts{$j}=$counts{$j}-2;
198             $cutoff_count=0;
199             $string=$array[$array_index];
200             $array_index++;
201             $c_string=$array[$array_index];
202             $array_index++;
203             loop_i:
204             while (  ($key, $value) = each(%pp_copy) )
205             {
206                 if (($value==$j) && ($cutoff_count < 2))
207                 {
208                    $cutoff_count++;
209                    $pp{$string} = $pp{$key};
210                    $pp{$c_string} = $pp{$key};
211                    $sca[$sca_count] = $key;
212                    $sca_count++;
213                    delete($pp{$key});
214                    delete($pp_copy{$key});
215                    if ($cutoff_count ==2 ) # half adder  
216                    {
217                        $pp{$c_string} = $pp{$c_string}+1;
218                        $sum_array[$sum_array_index]= "   assign $string" . ' = ' . "$sca[0]" .
219                                                       ' ^ ' . "$sca[1]" .  ';';
220                        $carry_array[$carry_array_index]= "   assign $c_string" . ' = ' . "$sca[0]" .
221                                                          ' & '. "$sca[1]" .';';
222                        $sum_array_index++;
223                        $carry_array_index++;
224                        $sca_count=0;
225                    }
226                }
227            } #loop_i
228            $tag=1;
229         } #loop_h
230         $j=$j-1;
231         conditional_c:
232         if (($tag==1) && ($j==-1))
233         {
234             @other_array=values %pp;
235             $_ = 0 for %counts;
236             $counts{$_} ++ for @other_array;
237             $j=scalar(keys %counts)-1;
238             %pp_copy=%pp;
239             $flag=0;
240             for my $i ( 0 .. (keys %counts) )
241             {
242                 if (defined $counts{$i})
243                 {   if ($counts{$i}>2)
244                     {   $flag=1; }
245                 }
246             }
247         } #conditional_c
248    } #loop_e
249    open $fh, ">>", "wallace.vl";
250    for ($k = 0; $k < $sum_array_index; $k++)
251    {   print $fh "$sum_array[$k]\n";
252        print $fh "$carry_array[$k]\n";
253    }
254    close $fh;
255    return (\%pp);
256 }
257 
258 
259 sub kogge_stone() 
260 {
261    my ($pl,$pp)=(@_);
262    my %pp=%$pp;
263    my @other_array;
264    my %counts;
265    my @sorted_counts=();
266    @other_array=values %pp;
267    $counts{$_}=0 for @other_array;
268    $counts{$_}++ for @other_array;
269    $sorted_counts[$_]=$counts{$_} for sort {$a <=> $b} keys %counts;
270    my @sorted_pp_keys = sort {$pp{$a} <=> $pp{$b}} keys %pp;
271    my $first_index= firstidx { $_ eq '2' } @sorted_counts;
272    my $adder_length=$pl+1-$first_index;
273    my @p0= ("p000" .. "p200");
274    my @p1= ("pa000" .. "pa200");
275    my @p2= ("pb000" .. "pb200");
276    my @p3= ("pc000" .. "pc200");
277    my @p4= ("pd000" .. "pd200");
278    my @p5= ("pe000" .. "pe200");
279    my @p6= ("pf000" .. "pf200");
280    my @p7= ("pg000" .. "pg200");
281    my @g0= ("g000" .. "g200");
282    my @g1= ("ga000" .. "ga200");
283    my @g2= ("gb000" .. "gb200");
284    my @g3= ("gc000" .. "gc200");
285    my @g4= ("gd000" .. "gd200");
286    my @g5= ("ge000" .. "ge200");
287    my @g6= ("gf000" .. "gf200");
288    my @g7= ("gg000" .. "gg200");
289    my $final_flag=0; my $i=0; my $k=0; my $gg=0; my $fh;
290    open $fh, ">>", "wallace.vl";
291    loop_k:
292    for my $k ( 0 .. $#sorted_counts )
293    {
294       if (($sorted_counts[$k]==1) && ($final_flag==0))
295       {
296           print $fh "   assign product[$k] = $sorted_pp_keys[$i];\n";
297           $i++;
298       }
299       conditional_d:
300       if (($sorted_counts[$k]==2) && ($final_flag==0))
301       {
302           print $fh "   assign $p0[$gg] = $sorted_pp_keys[$i] ^ $sorted_pp_keys[$i+1];\n";
303           print $fh "   assign product[$k] = $p0[$gg];\n";
304           print $fh "   assign $g0[$gg] = $sorted_pp_keys[$i] & $sorted_pp_keys[$i+1];\n";
305           if ($adder_length > 1)
306           {
307               print $fh "   buf($p1[$gg],$p0[$gg]);\n";
308               print $fh "   buf($g1[$gg],$g0[$gg]);\n";
309           }
310           if ($adder_length > 2)
311           {
312               print $fh "   buf($p2[$gg],$p1[$gg]);\n";
313               print $fh "   buf($g2[$gg],$g1[$gg]);\n";
314           }
315           if ($adder_length > 4)
316           {
317               print $fh "   buf($p3[$gg],$p2[$gg]);\n";
318               print $fh "   buf($g3[$gg],$g2[$gg]);\n";
319           }
320           if ($adder_length > 8)
321           {
322               print $fh "   buf($p4[$gg],$p3[$gg]);\n";
323               print $fh "   buf($g4[$gg],$g3[$gg]);\n";
324           }
325           if ($adder_length > 16)
326           {
327               print $fh "   buf($p5[$gg],$p4[$gg]);\n";
328               print $fh "   buf($g5[$gg],$g4[$gg]);\n";
329           }
330           if ($adder_length > 32)
331           {
332               print $fh "   buf($p6[$gg],$p5[$gg]);\n";
333               print $fh "   buf($g6[$gg],$g5[$gg]);\n";
334           }
335           if ($adder_length > 64)
336           {
337               print $fh "   buf($p7[$gg],$p6[$gg]);\n";
338               print $fh "   buf($g7[$gg],$g6[$gg]);\n";
339           }
340           $final_flag=1;
341           $gg=$gg+1;
342           $i=$i+2;
343           next;
344       } #conditional_d
345       conditional_e:
346       if ($final_flag==1)
347       {
348           conditional_f:
349           if ($k < $pl)
350           {
351              print $fh "   assign $p0[$gg] = $sorted_pp_keys[$i] ^ $sorted_pp_keys[$i+1];\n";
352              print $fh "   assign $g0[$gg] = $sorted_pp_keys[$i] & $sorted_pp_keys[$i+1];\n";
353              if ($adder_length==2)
354              { print $fh "   assign product[$k] = $p0[$gg];\n"; }
355              if ($adder_length==3)
356              { print $fh "   assign product[$k] = $p0[$gg] ^ $g1[$gg-1];\n"; }
357              if ((6> $adder_length) && ($adder_length > 3))
358              { print $fh "   assign product[$k] = $p0[$gg] ^ $g2[$gg-1];\n"; }
359              if ((9> $adder_length) && ($adder_length > 5))
360              { print $fh "   assign product[$k] = $p0[$gg] ^ $g3[$gg-1];\n"; }
361              if ((18> $adder_length) && ($adder_length > 8))
362              { print $fh "   assign product[$k] = $p0[$gg] ^ $g4[$gg-1];\n"; }
363              if ((34> $adder_length) && ($adder_length > 17))
364              { print $fh "   assign product[$k] = $p0[$gg] ^ $g5[$gg-1];\n"; }
365              if ((66> $adder_length) && ($adder_length > 33))
366              { print $fh "   assign product[$k] = $p0[$gg] ^ $g6[$gg-1];\n"; }
367              if ((130> $adder_length) && ($adder_length > 65))
368              { print $fh "   assign product[$k] = $p0[$gg] ^ $g7[$gg-1];\n"; }
369              if ($adder_length > 1)
370              { if ($gg>0)
371                  { print $fh "   assign $p1[$gg] = $p0[$gg] & $p0[$gg-1];\n";
372                    print $fh "   assign $g1[$gg] = $g0[$gg] | ($p0[$gg] & $g0[$gg-1]);\n"; }
373                  else
374                  { print $fh "   buf($p1[$gg],$p0[$gg]);\n";
375                    print $fh "   buf($g1[$gg],$g0[$gg]);\n"; }
376              }
377              if ($adder_length > 2)
378              { if ($gg>1)
379                 { print $fh "   assign $p2[$gg] = $p1[$gg] & $p1[$gg-2];\n";
380                   print $fh "   assign $g2[$gg] = $g1[$gg] | ($p1[$gg] & $g1[$gg-2]);\n"; }
381                 else
382                 { print $fh "   buf($p2[$gg],$p1[$gg]);\n";
383                   print $fh "   buf($g2[$gg],$g1[$gg]);\n"; }
384              }
385              if ($adder_length > 4)
386              { if ($gg>3)
387                 { print $fh "   assign $p3[$gg] = $p2[$gg] & $p2[$gg-4];\n";
388                   print $fh "   assign $g3[$gg] = $g2[$gg] | ($p2[$gg] & $g2[$gg-4]);\n"; }
389                 else
390                 { print $fh "   buf($p3[$gg],$p2[$gg]);\n";
391                   print $fh "   buf($g3[$gg],$g2[$gg]);\n"; }
392              }
393              if ($adder_length > 8)
394              { if ($gg>7)
395                 { print $fh "   assign $p4[$gg] = $p3[$gg] & $p3[$gg-8];\n";
396                   print $fh "   assign $g4[$gg] = $g3[$gg] | ($p3[$gg] & $g3[$gg-8]);\n"; }
397                 else
398                 { print $fh "   buf($p4[$gg],$p3[$gg]);\n";
399                   print $fh "   buf($g4[$gg],$g3[$gg]);\n"; }
400              }
401              if ($adder_length > 16)
402              { if ($gg>15)
403                 { print $fh "   assign $p5[$gg] = $p4[$gg] & $p4[$gg-16];\n";
404                   print $fh "   assign $g5[$gg] = $g4[$gg] | ($p4[$gg] & $g4[$gg-16]);\n"; }
405                 else
406                 { print $fh "   buf($p5[$gg],$p4[$gg]);\n";
407                   print $fh "   buf($g5[$gg],$g4[$gg]);\n"; }
408              }
409              if ($adder_length > 32)
410              { if ($gg>31)
411                 { print $fh "   assign $p6[$gg] = $p5[$gg] & $p5[$gg-32];\n";
412                   print $fh "   assign $g6[$gg] = $g5[$gg] | ($p5[$gg] & $g5[$gg-32]);\n"; }
413                 else
414                 { print $fh "   buf($p6[$gg],$p5[$gg]);\n";
415                   print $fh "   buf($g6[$gg],$g5[$gg]);\n"; }
416              }
417              if ($adder_length > 64)
418              { if ($gg>63)
419                 { print $fh "   assign $p7[$gg] = $p6[$gg] & $p6[$gg-64];\n";
420                   print $fh "   assign $g7[$gg] = $g6[$gg] | ($p6[$gg] & $g6[$gg-64]);\n"; }
421                 else
422                 { print $fh "   buf($p7[$gg],$p6[$gg]);\n";
423                   print $fh "   buf($g7[$gg],$g6[$gg]);\n"; }
424              }
425           }
426           else
427           {
428               if ($k==$pl)
429               {
430                   if ($sorted_counts[$k]==2)
431                       {print $fh "   assign $p0[$gg] = $sorted_pp_keys[$i] ^ $sorted_pp_keys[$i+1];\n";}
432                   else
433                       {print $fh "   assign $p0[$gg] = $sorted_pp_keys[$i];\n";}
434                   if ($adder_length==2)
435                   {
436                      print $fh "   assign product[$k] = $p0[$gg] ^ $g0[$gg-1];\n";
437                   }
438                   if ($adder_length==3)
439                   {
440                      print $fh "   assign product[$k] = $p0[$gg] ^ $g1[$gg-1];\n";
441                   }
442                   if (($adder_length==4) || ($adder_length == 5))
443                   {
444                      print $fh "   assign product[$k] = $p0[$gg] ^ $g2[$gg-1];\n";
445                   }
446                   if ((10> $adder_length) && ($adder_length > 5))
447                   {
448                      print $fh "   assign product[$k] = $p0[$gg] ^ $g3[$gg-1];\n";
449                   }
450                   if ((18> $adder_length) && ($adder_length > 9))
451                   {
452                      print $fh "   assign product[$k] = $p0[$gg] ^ $g4[$gg-1];\n";
453                   }
454                   if ((34> $adder_length) && ($adder_length > 17))
455                   {
456                      print $fh "   assign product[$k] = $p0[$gg] ^ $g5[$gg-1];\n";
457                   }
458                   if ((66> $adder_length) && ($adder_length > 33))
459                   {
460                      print $fh "   assign product[$k] = $p0[$gg] ^ $g6[$gg-1];\n";
461                   }
462                   if ((130> $adder_length) && ($adder_length > 65))
463                   {
464                      print $fh "   assign product[$k] = $p0[$gg] ^ $g7[$gg-1];\n";
465                   }
466               }
467           } #conditional_f
468           $i=$i+2;
469           $gg=$gg+1;
470       } #conditional_e
471    } #loop_k
472    if ($pl>$#sorted_counts)
473                {
474                   if ($adder_length==2)
475                   {
476                      print $fh "   assign product[$pl] = $g0[$gg-1];\n";
477                   }
478                   if ($adder_length==3)
479                   {
480                      print $fh "   assign product[$pl] =  $g1[$gg-1];\n";
481                   }
482                   if (($adder_length==4) || ($adder_length == 5))
483                   {
484                      print $fh "   assign product[$pl] = $g2[$gg-1];\n";
485                   }
486                   if (($adder_length>=6) && ($adder_length<=9))
487                   {
488                      print $fh "   assign product[$pl] = $g3[$gg-1];\n";
489                   }
490                   if (($adder_length>=10) && ($adder_length<=17))
491                   {
492                      print $fh "   assign product[$pl] = $g4[$gg-1];\n";
493                   }
494                   if (($adder_length>=18) && ($adder_length<=33))
495                   {
496                      print $fh "   assign product[$pl] = $g5[$gg-1];\n";
497                   }
498                   if (($adder_length>=34) && ($adder_length<=65))
499                   {
500                      print $fh "   assign product[$pl] = $g6[$gg-1];\n";
501                   }
502               }
503    print $fh "endmodule";
504    close $fh;
505    return;
506 }
507 
508 
509 sub verilog_testbench()
510 {
511     my ($mdl,$mrl)=(@_);
512     my $ul =$mdl-1;
513     my $zl =$mrl-1;
514     my $pl =$ul+$zl+1;
515     my $plplus1=$pl+1;
516     my $fh;
517     open  $fh, ">", "tb_wallace.vl";
518     print $fh "`timescale 1ns/1ns\n";
519     print $fh "module tb_wallace;\n";
520     print $fh "    // Unsigned multiplier Verilog testbench\n";
521     print $fh "    // John Bryan, 2017\n";
522     print $fh "    reg  [$ul:0] a;\n";
523     print $fh "    reg  [$zl:0] b;\n";
524     print $fh "    wire [$pl:0] product;\n";
525     print $fh "    reg  [$pl:0] check;\n";
526     my $mdlul = 2**$mdl;
527     my $mrlul = 2**$mrl;
528     my $total_tested = $mdlul*$mrlul;
529     my $mdlp1 = $mdl+1;
530     my $mrlp1 = $mrl+1;
531     print $fh "    reg  [$mdl:0]  i,mdlul;\n";
532     print $fh "    reg  [$mrl:0]  j,mrlul;\n\n";
533     print $fh "    wallace wall0(a,b,product);\n\n";
534     print $fh "    initial\n";
535     print $fh "    begin\n";
536     print $fh "        a=$mdl\'d0;\n";
537     print $fh "        b=$mrl\'d0;\n";
538     print $fh "        mrlul=$mrlp1\'d$mrlul;\n";
539     print $fh "        mdlul=$mdlp1\'d$mdlul;\n";
540     print $fh "        for (i=0;i<mdlul;i=i+1)\n";
541     print $fh "        begin\n";
542     print $fh "            for (j=0;j<mrlul;j=j+1)\n";
543     print $fh "            begin\n";
544     print $fh "                check=a*b;\n";
545     print $fh "                #1;\n";
546     print $fh "                if (product != check)\n";
547     print $fh "                begin\n";
548     print $fh "                    \$display(\"time=%0t\", \$time);\n";
549     print $fh "                    \$display(\"a =%0d, b=%0d\", a, b);\n";
550     print $fh "                    \$display(\"product=%0d, check=%0d\", product, check);\n";
551     print $fh "                    \$finish;\n";
552     print $fh "                end\n";
553     print $fh "                b=b+1'b1;\n";
554     print $fh "           end\n";
555     print $fh "           a=a+1'b1;\n";
556     print $fh "        end\n";
557     print $fh "        \$display(\"   All $total_tested were correct using Verilog tb.\");\n";
558     print $fh "        \$finish;\n";
559     print $fh "    end\n\n";
560     print $fh " endmodule\n";
561     close $fh;
562     return;
563 }
564 
565 
566 
567 sub cpp_testbench() 
568 {
569     my ($mdl,$mrl)=(@_);
570     my $ul =$mdl - 1;
571     my $zl =$mrl - 1;
572     my $pl =$ul+$zl+1;
573     my $plplus1 =$pl+1;
574     my $fh;
575     my $mdul=0;
576     my $mrul=0;
577     my $mdll;
578     my $mrll;
579     open  $fh, ">", "sim_main.cpp";
580     print $fh "// C++ multiplier testbench\n";
581     print $fh "\#include <stdlib.h>\n";
582     print $fh "\#include <iostream>\n";
583     print $fh "\#include <ctime>\n";
584     print $fh "\#include \"Vwallace.h\"\n";
585     print $fh "\#include \"verilated.h\"\n";
586     print $fh "using namespace std;\n\n";
587     print $fh "int main(int argc, char **argv, char **env)\n";
588     print $fh "{\n";
589     print $fh "    Verilated::commandArgs(argc,argv);\n";
590     print $fh "    Vwallace *top=new Vwallace;\n";
591     $mdul = 2**$mdl;
592     $mrul = 2**$mrl;
593     my $total_tested = $mdul*$mrul;
594     print $fh "    const unsigned int mdlul=$mdul;\n";
595     print $fh "    const unsigned int mrlul=$mrul;\n";
596     print $fh "    unsigned int check;\n";
597     print $fh "    unsigned int i,j;\n";
598     print $fh "    unsigned int flag=0;\n";
599     print $fh "    for (i=0;i<mdlul;i++)\n";
600     print $fh "    {\n";
601     print $fh "        top->a=i;\n";
602     print $fh "        for (j=0;j<mrlul;j++)\n";
603     print $fh "        {\n";
604     print $fh "            top->b=j;\n";
605     print $fh "            check=top->a*top->b;\n";
606     print $fh "            top->eval();\n";
607     print $fh "            if (top->product!=check)\n";
608     print $fh "            {\n";
609     print $fh "                printf(\"\\na=%d, b=%d\\n\", top->a,top->b);\n";
610     print $fh "                printf(\"product=%d, check=%d\\n\",top->product,check);\n";
611     print $fh "                flag=1;\n";
612     print $fh "                break;\n";
613     print $fh "            }\n";
614     print $fh "        }\n";
615     print $fh "    }\n";
616    print $fh "    if (flag==0)\n";
617     print $fh "        {printf(\"   All $total_tested were correct using C++ tb.\\n\\n\");}\n";
618 
619     print $fh "    delete top;\n";
620     print $fh "    exit(0);\n";
621     print $fh "}\n";
622     close $fh;
623     return;
624 }
625 
626 
627 sub makefile()
628 {
629     my $fh;
630     open  $fh, ">", "Makefile";
631     print $fh "TARGET=wallace\n\n";
632     print $fh "clean:\n";
633     print $fh "\t\@rm -rf obj_dir *~\n";
634     print $fh "all:\n";
635     print $fh "\t\@verilator -cc \$(TARGET).vl --exe sim_main.cpp -Wno-lint\n";
636     print $fh "build:\n";
637     print $fh "\t\@make -w -s -C obj_dir -f V\$(TARGET).mk V\$(TARGET) > /dev/null 2>&1\n";
638     print $fh "test:\n";
639     print $fh "\t\@./obj_dir/V\$(TARGET) -s\n";
640     close $fh;
641     return;
642 }
643 
644 
645 sub make()
646 {
647     system("make clean");
648     system("make all");
649     system("make build");
650     system("make test");
651     return;
652 }
653 
654 
655 sub chart()
656 {
657     my ($x_ref,$y_ref,$v_ref)=(@_);
658     my @x=@$x_ref;
659     my @y=@$y_ref;
660     my @v=@$v_ref;
661     my $pl = PDL::Graphics::PLplot->new(DEV=>'svg', FILE=>'chart.svg');
662     my $x  = pdl(@x);
663     my $y  = pdl(@y);
664     my $v  = pdl(@v);
665     $pl->xyplot($x, $v, COLOR => 'BROWN', PLOTTYPE => 'LINEPOINTS');
666     $pl->xyplot($x, $y, COLOR => 'BLUE', PLOTTYPE => 'LINEPOINTS');
667     $pl->xyplot(pdl(13,14), pdl(90,90),COLOR=>'BROWN');
668     $pl->xyplot(pdl(13,14), pdl(80,80),COLOR=>'BLUE');
669     $pl->text("Icarus", COLOR=>'BROWN',TEXTPOSITION => [14.5,90,15.5,0,0]);
670     $pl->text("Verilator", COLOR=>'BLUE',TEXTPOSITION => [14.5,80,15.5,0,0]);
671     $pl->text('Performance vs Product Size',COLOR=>'BLACK',TEXTPOSITION=>['t',1.5,0.5,0.5]);
672     $pl->text('Time (seconds)',COLOR=>'BLACK',TEXTPOSITION=>['l',3,.5,.5]);
673     $pl->text('Product bit size',COLOR=>'BLACK',TEXTPOSITION=>['b',3,.5,.5]);
674     $pl->close;
675     return;
676 }
677 
678 
679 sub generate_and_test
680 {
681     my ($i,$j,$increment)=@ARGV;
682     my $hl=$i+$j+$increment+1;
683     my $ll=$i+$j;
684     my $count=$ll;
685     my $left; my $pl; my $k;
686     my $t0; my $t1; my $td; my $m;
687     my @x; my @y; my @v;
688     u_for:
689     for (;($i+$j)<$hl;$i++)
690     {
691         $left=$hl-$count;
692         print "\n   $left test(s) to go . . .\n";
693         $pl=$i+$j;
694         print "   Testing product length of $pl . . .\n";
695         &generate_multiplier($i,$j);
696         &verilog_testbench($i,$j);
697         $t0=[gettimeofday];
698         system ("iverilog wallace.vl tb_wallace.vl");
699         system ("vvp a.out");
700         $t1=[gettimeofday];
701         $td=tv_interval $t0,$t1;
702         push @v, $td;
703         &cpp_testbench($i,$j);
704         &makefile;
705         $t0=[gettimeofday];
706         &make;
707         $t1=[gettimeofday];
708         $td=tv_interval $t0,$t1;
709         push @y, $td;
710         my $x=$i+$j;
711         push @x, $x;
712         $count++;
713         $left=$hl-$count;
714         $j=$j+1;
715         if (($i+$j)<$hl)
716         {
717             print "\n   $left test(s) to go . . .\n";
718             $pl=$i+$j;
719             print "   Testing product length of $pl . . .\n";
720             &generate_multiplier($i,$j);
721             &verilog_testbench($i,$j);
722             $t0=[gettimeofday];
723             system ("iverilog wallace.vl tb_wallace.vl");
724             system ("vvp a.out");
725             $t1=[gettimeofday];
726             $td=tv_interval $t0,$t1;
727             push @v, $td;
728             &cpp_testbench($i,$j);
729             &makefile;
730             $t0=[gettimeofday];
731             &make;
732             $t1=[gettimeofday];
733             $td=tv_interval $t0,$t1;
734             push @y, $td;
735             my $x=$i+$j;
736             push @x, $x;
737             $count++;
738             $left=$hl-$count;
739         }
740     } #u_for
741     &chart(\@x,\@y,\@v);
742     return;
743 } #sub generate_and_test