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


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

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

 /// Goal
 //
 //  Refresh your memory of Verilog.
 //  Design of an efficient right shift module.
 //  Provide an overview of Verilog simulation and synthesis.
 //  Different approaches to expressing a design:
 //    machine synthesizability v. human readability.


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

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

 /// :SV12: SystemVerilog -- IEEE Std 1800-2017
 //  https://ieeexplore.ieee.org/document/8299595/
 //
 //  The current Verilog language standard.
 //  The primary Verilog reference for this course.
 //  It can be obtained legally for free, don't pay for it.

 /// :BV3:  Brown & Vranesic, Fundamentals of Digital Logic with Verilog, 3rd Ed.
 //
 //  The text used in LSU EE 274x
 //  Includes material on logic design and elementary Verilog.
 //  Use Brown & Vranesic for reviewing logic design and basic Verilog.



//////////////////////////////////////////////////////////////////////////////
/// Logical Right Shifter -- Functional Description
//

 /// Logical Right Shifter Informal Description
//
// This should be something everyone has seen before.
//
// There are two inputs, amt (amount) and din (data in)
// There is one output: dout (data out)
// The value at dout is set to the value at din right-shifted by amt bits.
// Zeros are placed in vacated positions.
//

// 

// :Example: Behavior of right shift.
//
// Input - amt  : 2
// Input - din  : 00111000  <--  Shifted ..
// Output- dout : 00001110  <--  .. by two bits.
//
// Input - amt  : 1          
// Input - din  : 01101001  <--  Shifted ..
// Output- dout : 00110100  <--  .. by one bit.
//
// Input - amt  : 3
// Input - din  : 01101001  <--  Shifted
// Output- dout : 00001101  <--  .. by three bits.


 /// Terminology
//
//   w - Number of bits in din and dout.


//////////////////////////////////////////////////////////////////////////////
/// Things to Review and Think About
//
 /// What should the shifter hardware look like?
//
//    Those who want to exercise rusty logic design skills might want
//    to try to design a shifter before scrolling down.
//
//    Exercising and developing our digital design skills will
//    be an important part of this course.
//
//
 /// How can we describe the shifter in Verilog?
//
//    There are many ways to do so.
//
//    Our goal here will be clarity and a low-cost design.
//
//
 /// What is the relationship between the Verilog description of the
 /// shifter and the hardware that will be synthesized?
//
//    The examples below start with hardware diagrams, and from those
//    will be derived Verilog descriptions.
//
//    The expectation is that these Verilog descriptions will
//    synthesize into the hardware shown in the diagrams. 
//
//    Maybe they will, maybe they won't. An important part of this
//    course is understanding what sort of hardware will be
//    synthesized from a given Verilog description.
//
//    It is important that this is understood so that we can
//    estimate the cost and performance of our design ideas.



//////////////////////////////////////////////////////////////////////////////
/// Logical Right Shifter -- Hardware Designs
//

 /// Two Designs Shown Here
 //
 //  Both designs are combinational, meaning that they do not use
 //  storage elements. (Sequential designs do use storage elements,
 //  we'll cover them later in the semester.)
 //
 //  The combinational designs are:
 //
 //  - Single Multiplexor (Brute Force Method)
 //    Conceptually simple but costly.
 //
 //  - Logarithmic Shifter
 //    Efficient.
 //    Illustrates an important design approach.

//
 /// Single Multiplexor (Brute Force) Logical Right Shifter
//
//     Use a multiplexor with w inputs, each input is w bits wide.
//     Cost is about 3w² before optimization.
//
//     Illustration below is for w = 16.

// 

// With Sample Values and Explanation of Notation
// 

//
 ///   The Logarithmic Shifter
//
//    Uses lg(w) multiplexors, each with two w-bit inputs.
//    Cost is about 3 w lg(w).
//    Delay is 2 lg(w).
//
//    Illustration below is for w = 16, so that there are four 2-input
//    multiplexors.

// 



//////////////////////////////////////////////////////////////////////////////
/// Logical Right Shifter Verilog Descriptions

// Appearing below are several different ways of writing a logical
// right shift module in Verilog. All of them are correct but when
// coding style is taken into account some are better than others.
//
// Coding style is important because the cost of designing a system
// includes the time it takes engineers to read HDL descriptions
// and to find bugs in the descriptions.


 /// :Example: Simple Behavioral Shifter Description
//
// This description is good for an ordinary shifter. We are relying on
// the synthesis program to do a good job with the logical right shift
// operator, >>. Because left and right shifts are frequently used in
// describing hardware there is a good chance the synthesis program
// will do a good job (to keep customers happy).
// 
module shift_right_operator
  ( output uwire [15:0] shifted,
    input uwire [15:0] unshifted,
    input uwire [3:0] amt );

   // Note: Reasonable code.  We expect synthesis prog to DTRT here.
   //
   assign shifted = unshifted >> amt;

endmodule




 /// :Example: Single Multiplexor (Brute Force) Shifter Description
//
// This description is correct but is unnecessarily lengthy and so
// designs like this should be avoided. There is a greater chance of a
// typo or other error slipping in to lengthy designs.
//
module shift_right_mux_s
   ( output uwire [15:0] shifted,
     input uwire [15:0] unshifted,
     input uwire [3:0] amt );

   // Correct, but susceptible to accidental changes.
   //
   mux16r m( shifted, amt,
            { unshifted,
              { 1'b0, unshifted[15:1] },  // Shifted by 1 bit.
              { 2'b0, unshifted[15:2] },  // Shifted by 2 bits.
              { 3'b0, unshifted[15:3] },  // ...
              { 4'b0, unshifted[15:4] },
              { 5'b0, unshifted[15:5] },
              { 6'b0, unshifted[15:6] },
              { 7'b0, unshifted[15:7] },
              { 8'b0, unshifted[15:8] },
              { 9'b0, unshifted[15:9] },
              { 10'b0, unshifted[15:10] },
              { 11'b0, unshifted[15:11] },
              { 12'b0, unshifted[15:12] },
              { 13'b0, unshifted[15:13] },
              { 14'b0, unshifted[15:14] },
              { 15'b0, unshifted[15:15] }} );
   //
   /// WARNING: Don't write code like this (with 15 lines following a pattern) ..
   ///  .. because it's a good place for BUGS TO HIDE and it's tedious to write.

endmodule


 /// Behavioral Description of 16-Input Multiplexor
//
module mux16a
  ( output logic [15:0] x,
    input uwire [3:0] select,
    input uwire [15:0] a [0:15] );

   assign x = a[select];

endmodule

 /// Structural Description of 16-Input Multiplexor
//
module mux16r
  ( output logic [15:0] x,
    input uwire [3:0] select,
    input uwire [15:0] a [0:15] );

   uwire [15:0] xlo, xhi;
   mux8r mhi( xhi, select[2:0], a[8:15] );
   mux8r mlo( xlo, select[2:0], a[0:7] );
   mux2r  m( x, select[3],  { xlo, xhi } );

endmodule

module mux8r
  ( output logic [15:0] x,
    input uwire [2:0] select,
    input uwire [15:0] a [0:7] );

   uwire [15:0] xlo, xhi;
   mux4r mhi( xhi, select[1:0], a[4:7] );
   mux4r mlo( xlo, select[1:0], a[0:3] );
   mux2r  m( x, select[2], { xlo, xhi } );

endmodule

module mux4r
  ( output logic [15:0] x,
    input uwire [1:0] select,
    input uwire [15:0] a [0:3] );

   uwire [15:0] xlo, xhi;
   mux2r mhi( xhi, select[0], a[2:3] );
   mux2r mlo( xlo, select[0], a[0:1] );
   mux2r  m( x, select[1], { xlo, xhi } );

endmodule

module mux2r
  ( output logic [15:0] x,
    input uwire select,
    input uwire [15:0] a [0:1] );

   assign x = a[select];

endmodule



 /// :Example: Logarithmic Shifter
//
// A logarithmic shifter is far less costly than one constructed
// using a single multiplexor. It consists of lg w
// multiplexors, one for each bit in the shift amount. The mux
// connected to bit i of amt shifts by either 0 or by 2^i bits.
//

// 

//
module shift_right_logarithmic
  ( output uwire [15:0] shifted,
    input uwire [15:0] un,
    input uwire [3:0] amt );

   uwire [15:0] s1, s2, s3;

   // Shift by either 0 or 1 bits.
   //
   mux2 st0( s1, amt[0], un, {1'b0, un[15:1]} );

   // Shift by either 0 or 2 bits.
   //
   mux2 st1( s2, amt[1], s1, {2'b0, s1[15:2]} );

   // Shift by either 0 or 4 bits.
   //
   mux2 st2( s3, amt[2], s2, {4'b0, s2[15:4]} );

   // Shift by either 0 or 8 bits.
   //
   mux2 st3( shifted, amt[3], s3, {8'b0, s3[15:8]} );

endmodule

module mux2
  ( output uwire [15:0] x,
    input uwire select,
    input uwire [15:0] a0, a1 );

   assign x = select ? a1 : a0;

endmodule


 /// :Example: w-bit Logarithmic Right Shifter
//
// The module below implements a logical right shifter of any size,
// the default size is 16. The module uses a generate loop to instantiate
// lg w mux2 modules. That's something will cover later in the course.
//
module shift_right_logarithmic_w
  #( int w = 16, lgw = $clog2(w) )
   ( output uwire [w-1:0] shifted,
     input uwire [w-1:0] un,
     input uwire [lgw-1:0] amt );

   uwire [w-1:0] s[lgw:-1];  // Array of wires for connections to mux2 mods.

   assign s[-1] = un;
   assign shifted = s[lgw-1];

   for ( genvar i=0; i<lgw; i++ )
     mux2 st( s[i],  amt[i],  s[i-1],  s[i-1] >> ( 1 << i )  );

endmodule


//////////////////////////////////////////////////////////////////////////////
/// Review Concepts
//

 /// Module declaration

 /// Variable v. Net

 /// Continuous assignment.

 /// always, initial

 /// Module Instantiation

// Simulation

// Testbenches

// Synthesis

// Synthesis optimization goals.

// Scripting



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

 /// Synthesis Software
//
//   Cadence Genus
//
//

 /// 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_right_operator) ..
 //  .. 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

 /// Commands for Genus

// read_hdl shifter.v
// elaborate shift_right_operator
// gui_show
// set_db syn_global_effort high
//   Effort levels: none | low | medium | high | express
// vcd designs:shift_right_operator
// create_clock -name clk -period 1
//   Units are nanoseconds
// set_input_delay -clock clk 0.0 [all_inputs]
// set_output_delay -clock clk 0.0 [all_outputs]
// syn_gen
// syn_map
// syn_opt
// report area
// report timing


//////////////////////////////////////////////////////////////////////////////
/// Testbench Code
//
//  The code below instantiates shift_right1 and shift_right_operator,
//  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_right_mux_s my_s_mux(sout1, sin, amt);
   shift_right_logarithmic my_s_log(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_mux", "shift_log"};

   localparam int tests_per_sa = 20;
   localparam int 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

// Local paths to Chipware code
//
//  Simulation Model
//  /apps/linux/cadence/GENUS211/share/synth/lib/chipware/sim/verilog/CW/CW_shifter.v
//
//  Synthesis Model
//  /apps/linux/cadence/GENUS211/share/synth/lib/chipware/syn/CW/CW_shifter.v