////////////////////////////////////////////////////////////////////////////////
//
/// LSU EE 4755 Fall 2017 Homework 1
//
 /// SOLUTION


`default_nettype none

//////////////////////////////////////////////////////////////////////////////
///  Problem 1
//
 /// Modify mux4 so that it implements a 4-input mux as described in handout.
//
//     [✔] Make sure that the testbench does not report errors.
//     [✔] Code must instantiate three mux2 modules as shown in hw01.pdf.
//     [✔] Make sure that parameters set correctly in instantiation.

module mux4
  #( int w = 6 )
   ( output uwire [w-1:0] x,
     input uwire [1:0] s,
     input uwire [w-1:0] a[3:0] );

   /// SOLUTION
   //
   //  Notice that wires and modules are named based upon the select
   //  bits for which they connect to the output.
   //
   uwire [w-1:0] x0x, x1x;

   mux2 #(w) m0x(x0x, s[0], a[0], a[1]);
   mux2 #(w) m1x(x1x, s[0], a[2], a[3]);

   mux2 #(w) mxx(x, s[1], x0x, x1x);


endmodule

module mux2
  #( int w = 16 )
   ( output uwire [w-1:0] x,
     input uwire s,
     input uwire [w-1:0] a, b );

   assign  x = s == 0 ? a : b;

endmodule


//////////////////////////////////////////////////////////////////////////////
///  Problem 2
//
 /// Modify mux8 so that it implements an 8-input mux as described in handout.
//
//     [✔] Make sure that the testbench does not report errors.
//     [✔] Code must instantiate two mux4 and one mux2 modules.
//     [✔] Make sure that parameters set correctly in instantiation.


module mux8
  #( int w = 5 )
   ( output uwire [w-1:0] x,
     input uwire [2:0] s,
     input uwire [w-1:0] a[7:0] );

   /// SOLUTION

   uwire [w-1:0] x0xx, x1xx;

   mux4 #(w) m0xx(x0xx, s[1:0], a[3:0]);
   mux4 #(w) m1xx(x1xx, s[1:0], a[7:4]);

   mux2 #(w) m(x, s[2], x0xx, x1xx);


endmodule


//////////////////////////////////////////////////////////////////////////////
/// Testbench Code
//
//  The code below instantiates some of the modules above,
//  provides test inputs, and verifies the outputs.
//
//  The testbench may be modified to facilitate your solution. Of
//  course, the removal of tests which your module fails is not a
//  method of fixing a broken module. (One might modify the testbench
//  so that the first tests it performs are those which make it easier
//  to determine what the problem is, for example, test inputs that
//  are all 0's or all 1's.)



// cadence translate_off


module testbench();

   localparam int w = 10;
   localparam int n_in_max = 8;
   localparam int n_mut = 3;

   uwire [w-1:0] x[n_mut];
   logic [2:0]  s;
   logic [w-1:0] a[n_in_max-1:0];

   mux2 #(w) mm2(x[0], s[0], a[0], a[1]);
   mux4 #(w) mm4(x[1], s[1:0], a[3:0]);
   mux8 #(w) mm8(x[2], s[2:0], a[7:0]);

   initial begin

      automatic int n_test = 0;
      automatic int n_err = 0;

      for ( int i=0; i < n_in_max; i++ ) begin
         n_test++;
         s = i;
         for ( int j=0; j<n_in_max; j++ ) a[j] = $random;
         #1;
         for ( int m=0; m<n_mut; m++ ) begin

            automatic int n_in = 2 << m;
            automatic int sm = i & ( n_in - 1 );

            if ( x[m] !== a[sm] ) begin
               n_err++;
               $write("Error in %0d-input mux for s=%0d, 0x%0x != 0x%0x (correct)\n",
                      n_in, sm, x[m], a[sm]);
            end
         end
      end
      $write("Done with %0d tests, %0d errors found.\n",n_test,n_err);
   end

endmodule

// cadence translate_on