////////////////////////////////////////////////////////////////////////////////
//
/// LSU EE 4755 Fall 2014 Homework 2
//

 /// Assignment  http://www.ece.lsu.edu/koppel/v/2014/hw02.pdf

 /// Instructions:
  //
  // (1) Find the undergraduate workstation laboratory, room 126 EE
  //     Building.
  //
  // (2) Locate your account.  If you did not get an account please
  //     E-mail: koppel@ece.lsu.edu
  //
  // (3) Log in to a Linux workstation.
  //     The account should start up with a WIMP interface (windows, icons,
  //     mouse, pull-down menus)  ( :-) ) but one or two things need
  //     to be done from a command-line shell.  If you need to brush up
  //     on Unix commands follow http://www.ece.lsu.edu/koppel/v/4ltrwrd/.
  //
  // (4) If you haven't already, follow the account setup instructions here:
  //     http://www.ece.lsu.edu/koppel/v/proc.html
  //
  // (5) Copy this assignment, local path name
  //     /home/faculty/koppel/pub/ee4755/hw/2014f/hw02
  //     to a directory ~/hw02 in your class account. (~ is your home
  //     directory.) Use this file for your solution.
  //
  // (6) Find the problems in this file and solve them.
  //
  //     Your entire solution should be in this file.
  //
  //     Do not change module names.
  //
  // (7) Your solution will automatically be copied from your account by
  //     the TA-bot.


 /// Additional Resources
  //
  // Verilog Documentation
  //    The Verilog Standard
  //      http://standards.ieee.org/getieee/1800/download/1800-2012.pdf
  //    Introductory Treatment (Warning: Does not include SystemVerilog)
  //      Brown & Vranesic, Fundamentals of Digital Logic with Verilog, 3rd Ed.
  //
  // Account Setup and Emacs (Text Editor) Instructions
  //      http://www.ece.lsu.edu/koppel/v/proc.html
  //      To learn Emacs look for Emacs tutorial.
  //
  // Unix Help
  //      http://www.ece.lsu.edu/koppel/v/4ltrwrd/


//////////////////////////////////////////////////////////////////////////////
/// Behavioral Multipliers


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


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

   always @* begin

      prod = 0;

      for ( int i=0; i<wid; i++ ) if ( plier[i] ) prod = prod + ( cand << i );

   end

endmodule


//////////////////////////////////////////////////////////////////////////////
/// Problem 2: Linear Multiplier

 /// Simple Adder, Don't Modify
module good_adder#(int w=16)(output [w:1] s, input [w:1] a,b);
   assign s = a + b;
endmodule


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

   /// Problem 2 Solution Goes Here.
   //  This module should be a structural version of mult_behav_2,
   //   using generate statements to instantiate good_adder.


endmodule

//////////////////////////////////////////////////////////////////////////////
/// Problem 3: Tree Multiplier


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

   localparam int widp2 = 1 << $clog2(wid);

   /// Problem 3 Solution goes here.

   

endmodule


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

// cadence translate_off

module testbench;

   localparam int wid = 64;
   localparam int num_tests = 1000;
   localparam int NUM_MULT = 4;
   localparam int err_limit = 4;

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

   mult_behav_1 #(wid) mb1(prod[0], plier, cand);
   mult_behav_2 #(wid) mb2(prod[1], plier, cand);
   mult_linear  #(wid) ms1(prod[2], plier, cand);
   mult_tree    #(wid) ms2(prod[3], plier, cand);

   string names[] = '{"Behav_1","Behav_2","Linear", "Tree"};
   int err_cnt[NUM_MULT];
   int tests[$] = {1,1, 1,2,  1,32,  32, 1};

   initial begin

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

         plier = tests.size() ? tests.pop_front() : $random();
         cand = tests.size() ? tests.pop_front() : $random();

         #1;

         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:  %d != %d (correct)\n",
                          names[mut], i, prod[mut], prod[0]);
            end

         end

      end

      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


   end

endmodule

// cadence translate_on