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

 /// Assignment  http://www.ece.lsu.edu/koppel/v/2014/hw01.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/hw01
  //     to a directory ~/hw01 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/


`default_nettype none


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


// 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];

   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.
//
//   [ ]  Complete module shift_right2, the testbench should not report errors.
//   [ ]  Perform the shift using 4 shift_right_fixed modules.


// 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, modify the next one.

   // (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.

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

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.
         //
         for ( int mut=0; mut<2; mut++ ) begin

            automatic logic [width-1: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