```/// 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, Verilog simulation, and synthesis.
//  Exposure to some SystemVerilog features.
//  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 2740.
//  Includes material on logic design and elementary 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.
//
//
//  What is the relationship between the Verilog description of the
//  shifter and the hardware that will be synthesized?
//
//    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. Later in the semester we'll cover sequential
//  designs.
//
//  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 6 w 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, >>.
//
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: Unnecessarily Complicated Behavioral Shifter Description
//
// This description is correct but unnecessarily complicated and so
// should not be used. It is also not synthesizable for reasons to be
// covered later. (If you must know: it's because the number of
// iterations in the loops depends upon a non-constant value, the
// module amt input.)
//
module shift_right_behavioral
( output logic [15:0] shifted,
input uwire [15:0] unshifted,
input uwire [3:0] amt );

localparam int width = 16;

always_comb begin

// Correct, but more complicated than it needs to be. Also,
// cannot be synthesized for reasons that we'll cover later.
//
for ( int i=0; i<width-amt; i++ ) shifted[i] = unshifted[i+amt];
for ( int i=width-amt; i<width; i++ ) shifted[i] = 0;

end

endmodule

// :Example: Unnecessarily Complicated Behavioral Shifter Description
//
// This description is correct but unnecessarily complicated and so
// should not be used.
//
module shift_right_mux_b
( output logic [15:0] shifted,
input uwire [15:0] unshifted,
input uwire [3:0] amt );

always_comb begin

// Correct, but susceptible to accidental changes. Loose bits sink chips.
//
case ( amt )
0: shifted = unshifted;
1: shifted = { 1'b0, unshifted[15:1] };
2: shifted = { 2'b0, unshifted[15:2] };
3: shifted = { 3'b0, unshifted[15:3] };
4: shifted = { 4'b0, unshifted[15:4] };
5: shifted = { 5'b0, unshifted[15:5] };
6: shifted = { 6'b0, unshifted[15:6] };
7: shifted = { 7'b0, unshifted[15:7] };
8: shifted = { 8'b0, unshifted[15:8] };
9: shifted = { 9'b0, unshifted[15:9] };
10: shifted = { 10'b0, unshifted[15:10] };
11: shifted = { 11'b0, unshifted[15:11] };
12: shifted = { 12'b0, unshifted[15:12] };
13: shifted = { 13'b0, unshifted[15:13] };
14: shifted = { 14'b0, unshifted[15:14] };
15: shifted = { 15'b0, unshifted[15:15] };
endcase

end

endmodule

// :Example: Unnecessarily Complicated Structural Shifter Description
//
// This description is correct but unnecessarily complicated and so
// should not be used.
//
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.
//
mux16 m( shifted, amt,
unshifted,
{ 1'b0, unshifted[15:1] },
{ 2'b0, unshifted[15:2] },
{ 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] } );

endmodule

module mux16
( output logic [15:0] x,
input uwire [3:0] select,
input uwire [15:0] a0, a1, a2, a3, a4, a5, a6, a7,
input uwire [15:0] a8, a9, a10, a11, a12, a13, a14, a15 );

// Correct, but susceptible to accidental changes.
//
always_comb
case ( select )
0: x = a0;
1: x = a1;
2: x = a2;
3: x = a3;
4: x = a4;
5: x = a5;
6: x = a6;
7: x = a7;
8: x = a8;
9: x = a9;
10: x = a10;
11: x = a11;
12: x = a12;
13: x = a13;
14: x = a14;
15: x = a15;
endcase

endmodule

// :Example: Structural Description Of 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

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

/// Module declaration

/// Variable v. Net

/// Continuous assignment.

/// always, initial

/// Module Instantiation

// Simulation

// Testbenches

// Synthesis

// Synthesis optimization goals.

// Scripting

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

/// Synthesis Software
//
//
//

/// Elaboration [of a Top-Level Module]
//
//  The process of generating and gathering all the HDL needed for
//  the top-level module.
//
//  .. 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

// elaborate shift_right_operator
// gui_show
// set_db syn_global_effort high
//   Effort levels: none | low | medium | high | express
// vcd design: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.
//

module testbench();

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

shift_right_mux_s my_sr1(sout1, sin, amt);
shift_right_logarithmic 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 int tests_per_sa = 100;
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

test_count++;

sin = \$random;
amt = i / tests_per_sa;

#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",
end

end

end

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

end

endmodule

// Local paths to Chipware code
//
//  Simulation Model
//
//  Synthesis Model