////////////////////////////////////////////////////////////////////////////////
//
 /// LSU EE 4755 Fall 2014 Homework 1 -- SOLUTION
//

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


`default_nettype none


//////////////////////////////////////////////////////////////////////////////
///  Problem 1
//
 /// Logical Right Shift Module 1
//
//   The module below performs a logical right shift of a 16-bit
//   quantity.
//
//   [x]  Fix the module, the testbench should not report errors.
//   [x]  Don't substantially change the way the code works.
//   [x]  Don't try to make the code synthesizable.
//   [x]  Don't use shift (<<) or concatenation operators ({}) ..
//        .. assign shifted bit-by-bit as the code already does.


// cadence translate_off

module shift_right1
   ( output logic [15:0] shifted,
     input wire [15:0] unshifted,
     input wire [3:0] amt );

   /// Problem 1 solution goes in this module.

   localparam int width = 16;

   always @* begin

      automatic int limit = width - amt;

      for ( int i=0; i<limit; i++ ) shifted[i] = unshifted[i+amt];

      /// SOLUTION
      //  Just zero the "vacated" bits.
      //
      for ( int i=limit; i<width; i++ ) shifted[i] = 0;

   end

endmodule

// cadence translate_on


//////////////////////////////////////////////////////////////////////////////
///  Problem 2
//
 /// Logical Right Shift Module 2
//
//   The module below performs a logical right shift of a 16-bit
//   quantity.
//
//   [x]  Complete module shift_right2, the testbench should not report errors.


// Perform Two Possible Shifts:  by 0 bits or by fsamt bits.
//
module shift_right_fixed
   ( output wire [15:0] shifted,
     input wire [15:0] unshifted,
     input wire shift );

   // Problem 2: DON'T modify this module.

   // (Fixed) Shift Amount
   //
   parameter int fsamt = 3;

   // If shift is true shift by fsamt, otherwise don't shift.
   //
   assign    shifted =  shift  ?  unshifted >> fsamt  :  unshifted;

endmodule

module shift_right2
  ( output wire [15:0] shifted,
    input wire [15:0] unshifted,
    input wire [3:0] amt );

   /// Problem 2 solution goes in this module.

   /// SOLUTION
   //
   //  Declare wires to interconnect the modules.
   //
   uwire [15:0]  s8, s4, s2;

   shift_right_fixed #(8) sm8
     ( .shifted(s8), .unshifted(unshifted), .shift(amt[3]) );

   /// SOLUTION
   //
   //  Instantiate three more modules and connect them.
   //  Note: You don't have to use named ports.

   shift_right_fixed #(4) sm4 (s4, s8, amt[2]);
   shift_right_fixed #(2) sm2 (s2, s4, amt[1]);
   shift_right_fixed #(1) sm1 (shifted, s2, amt[0]);

endmodule


//////////////////////////////////////////////////////////////////////////////
/// Testbench Code
//
//  The code below instantiates shift_right1 and shift_right2,
//  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
//  considered a correct solution. (The idea is to put in tests 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();

   uwire logic [15:0] sout1, sout2;
   logic [15:0] sin;
   logic [3:0] amt;

   shift_right1 my_sr1(sout1, sin, amt);
   shift_right2 my_sr2(sout2, sin, amt);

   // Width of shifters' input and output.
   // The parameter is used only by this testbench.
   //
   localparam int width = 16;
   //
   // To keep things simple the shifter modules themselves are written
   // with a hardcoded width of 16 bits. That's bad style since
   // changing the width would be tedious and error prone. The
   // hardcoded widths are used in this first homework assignment only
   // to keep things simple. (The shifter modules could have used a
   // parameter to specify the width or a user-defined type.)

   // Provide names for the modules for use in error messages.
   //
   localparam string name[2] = '{"Prob 1", "Prob 2"};

   initial begin

      // Count of errors for each module.
      //
      automatic int err_count[2] = '{0,0};
      //
      // Note: The automatic qualifier is needed so that the initialization
      // could appear on the same line as the declaration.

      // Number of test inputs (stimuli).
      //
      automatic int test_count = 0;

      // Provide one test pattern per shift amount.
      //
      for ( int i=0; i<width; i++ ) begin

         int shadow_sout;
         test_count++;

         sin = $random;
         amt = i;

         shadow_sout = sin >> amt;

         #1;

         // Check the output of each Module Under Test.
         //
         foreach ( name[ mut ] ) begin

            automatic logic [15:0] sout = mut == 0 ? sout1 : sout2;

            if ( shadow_sout !== sout ) begin
               err_count[mut]++;
               if ( err_count[mut] < 5 )
                 $display
                   ("MUT %s wrong result for %h >> %d:  %h != %h (correct)\n",
                    name[mut], sin, amt, sout, shadow_sout);
            end

         end

      end

      $display("Ran %d tests, %d, %d errors found.\n",
               test_count, err_count[0], err_count[1]);

   end

endmodule

// cadence translate_on