/// EE 4755 - Digital Design Using HDLs
//
//  Classroom demonstration code.

// Time-stamp: <22 August 2016, 12:07:57 CDT, koppel@cyc.ece.lsu.edu>


//////////////////////////////////////////////////////////////////////////////
/// Behavioral Multiplier


module mult_behavioral #( int wid = 16 )
   ( output logic[2*wid-1:0] prod, 
     input logic[wid-1:0] plier, cand );

   assign prod = plier * cand;

endmodule


//////////////////////////////////////////////////////////////////////////////
/// Simple Sequential Multiplier


module mult_seq #( int wid = 16 )
   ( output logic [2*wid-1:0] prod,
     input logic [wid-1:0] plier,
     input logic [wid-1:0] cand,
     input clk);

   localparam int wlog = $clog2(wid);

   logic [wlog-1:0] pos;
   logic [2*wid-1:0] accum;

   // cadence translate_off
   initial pos = 0;
   // cadence translate_on

   always @( posedge clk ) begin

      if ( pos == 0 ) begin

         prod = accum;
         accum = 0;

      end

      if ( cand[pos] == 1 ) accum += plier << pos;

      pos++;

   end

endmodule


//////////////////////////////////////////////////////////////////////////////
/// Testbench Code

// cadence translate_off

module testbench;

   localparam int wid = 16;
   localparam int num_tests = 1000;
   localparam int NUM_MULT = 2;
   localparam int err_limit = 7;
   localparam bit pipeline_test_exact = 1;

   logic clock;

   always #1 clock <= !clock;

   logic [wid-1:0] plier, cand;
   logic [2*wid-1:0] prod[NUM_MULT];

   mult_behavioral #(wid) mb1(prod[0], plier, cand);
   mult_seq        #(wid) ms3(prod[1], plier, cand, clock);

   string names[] = '{ "Behavioral", "Sequential" };

   int err_cnt[NUM_MULT];

   // Array of multiplier/multiplicand values to try out.
   // After these values are used a random number generator will be used.
   //
   int tests[$] = {1,1, 1,2,  1,32,  32, 1};

   initial begin

      clock = 0;

      for ( int i=0; i<num_tests; i++ ) begin

         // Set multiplier and multiplicand values.
         //
         plier = tests.size() ? tests.pop_front() : $random();
         cand = tests.size() ? tests.pop_front() : $random();

         #1000;

         // Make sure each module's output is correct.
         //
         for ( int mut=1; mut<NUM_MULT; mut++ ) begin

            if ( prod[0] !== prod[mut] ) begin

               err_cnt[mut]++;

               if ( err_cnt[mut] < err_limit )
                 $display("Error in %s test %4d:  %x != %x (correct)\n",
                          names[mut], i, prod[mut], prod[0]);
            end

         end

      end

      // Tests completed, report error count for each device.
      //
      for ( int mut=1; mut<NUM_MULT; mut++ ) begin

         $display("Mut %s, %d errors (%.1f%% of tests)\n",
                  names[mut], err_cnt[mut],
                  100.0 * err_cnt[mut]/real'(num_tests) );

      end

      $finish(2);

   end

endmodule

// cadence translate_on