/// EE 4755 - Digital Design Using HDLs
//
 ///  Introductory Review

// Time-stamp: <31 August 2015, 11:41:51 CDT, koppel@sky.ece.lsu.edu>


//////////////////////////////////////////////////////////////////////////////
/// This Note/Demo Set

 /// Prerequisite
 //
 //  Some familiarity with Verilog.
 //  Familiarity with digital design.

 /// Goal
 //
 //  Refresh your memory of Verilog, Verilog simulation, and synthesis.
 //  Exposure to some SystemVerilog features.


//////////////////////////////////////////////////////////////////////////////
/// References
//

 /// Web page with references for this class:  
 //  http://www.ece.lsu.edu/v/ref.html

 /// SystemVerilog -- IEEE Std 1800-2012
 //
 //  The current Verilog language standard.
 //  The primary Verilog reference for this course.

 


//////////////////////////////////////////////////////////////////////////////
/// Concepts
//

 /// Module declaration

 /// Variable v. Net

 /// Continuous assignment.

 /// always, initial

 /// Module Instantiation

// Simulation

// Testbenches

// Synthesis

// Synthesis optimization goals.

// Scripting



//////////////////////////////////////////////////////////////////////////////
/// Synthesis
//

 /// Synthesis Software
//
//   Cadence Encounter(R) RTL Compiler
//
//

 /// Elaboration [of a Top-Level Module]
 //
 //  The process of generating and gathering all the HDL needed for
 //  the top-level module.
 //
 //  Start with some top-level module (shift_right2) ..
 //  .. gather instantiated modules ..
 //  .. and perform elaboration on them.
 //
 //  For those who know what "generate statements" are:
 //   Generate statements are executed during elaboration.


 /// Synthesis Target
 //
 //  The kind of thing you want to make. For example,
 //
 //  ASIC
 //  FPGA.

 /// Inference
 //
 //  Figuring out what hardware to use for a given piece of Verilog.


 /// Mapping [of one piece of hardware to another]
 //
 //  The replacing one piece of hardware (Verilog module or primitive)
 //  with another.


 /// Generic Target

 /// Mapped (To Technology) Target

 /// Area and Timing

 /// Design Constraints

 /// Scripting


// read_hdl shifter.v
// elaborate shift_right2
// gui_show
// synthesize -to_generic -effort high
// synthesize -to_mapped -effort high
// report area
// report timing
// define_clock -name clk -period 100
// external_delay -clock clk -output 0 [find /designs/*/ports_out/ -port *]
// external_delay -clock clk -input 0 [find /designs/*/ports_in/ -port *]
// synthesize -to_mapped -effort high
// report timing
// report area



`default_nettype none


// Perform Two Possible Shifts:  by 0 bits or by fsamt bits.
//
module shift_right_fixed_amt
  #( int fsamt = 4 )   // Fixed shift amount.
   ( output wire [15:0] shifted,
     input wire [15:0] unshifted,
     input wire shift );

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

   //  Module interconnections.
   //
   uwire [15:0]  s8, s4, s2;

   shift_right_fixed_amt #(8) sm8 ( s8,      unshifted, amt[3] );
   shift_right_fixed_amt #(4) sm4 ( s4,      s8,        amt[2] );
   shift_right_fixed_amt #(2) sm2 ( s2,      s4,        amt[1] );
   shift_right_fixed_amt #(1) sm1 ( shifted, s2,        amt[0] );

endmodule


module shift_right3
  #( int wid = 16,
     int awid = $clog2(wid) )
   ( output wire [wid:1] shifted,
     input wire [wid:1] unshifted,
     input wire [awid-1:0] amt );

   //  Module interconnections.
   //
   uwire [15:0]  s8, s4, s2;

   wire [wid:1] inter_mod[awid:0];

   assign       inter_mod[awid] = unshifted;
   assign       shifted = inter_mod[0];

   for ( genvar i=awid-1; i>=0; i-- )
     shift_right_fixed_amt #( 1<<i ) sm ( inter_mod[i], inter_mod[i+1], amt[i] );
   
endmodule


// cadence translate_off

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

   localparam int width = 16;
   
   // Old-School Verilog
   //  always @( unshifted or amt ) begin lala; end
   // Verilog 2000
   //  always @* begin

   always_comb begin

      automatic int limit = width - amt;

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

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

   end

endmodule

// cadence translate_on




//////////////////////////////////////////////////////////////////////////////
/// Testbench Code
//
//  The code below instantiates shift_right1 and shift_right2,
//  provides test inputs and verifies the outputs.
//

// 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_right3 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
   // 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] = '{"shift_right1", "shift_right2"};

   localparam tests_per_sa = 100;
   localparam num_tests = width * tests_per_sa;
   
   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<num_tests; i++ ) begin

         int shadow_sout;
         test_count++;

         sin = $random;
         amt = i / tests_per_sa;

         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 0x%h >> %d:  0x%h != 0x%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