/// 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 /// :SV23: SystemVerilog -- IEEE Std 1800-2023 // https://ieeexplore.ieee.org/document/10458102 // // 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 an inviting 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 = select == 0 ? a[0] : a[1]; 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 /// :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 to interconnect mux2 instances. assign s[-1] = un; for ( genvar i=0; i<lgw; i++ ) muxw2 #(w) st( s[i], amt[i], s[i-1], s[i-1] >> ( 1 << i ) ); assign shifted = s[lgw-1]; endmodule module mux2 ( output uwire [15:0] x, input uwire select, input uwire [15:0] a0, a1 ); assign x = select ? a1 : a0; endmodule module muxw2 #( int w = 5 ) ( output uwire [w-1:0] x, input uwire select, input uwire [w-1: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 // // 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 /// Synthesis Results // Version: 23.12-s086_1, built Wed Jul 24 17:05:35 PDT 2024 // Synthesizing at effort level "high" // Module Name Area Delay Delay // Actual Target // shift_right_operator 23023 1.062 10.000 ns // shift_right_mux_s 23076 0.826 10.000 ns // shift_right_logarithmic 23176 0.801 10.000 ns // shift_right_operator_1 70214 0.464 0.100 ns // shift_right_mux_s_1 54577 0.476 0.100 ns // shift_right_logarithmic_1 52196 0.474 0.100 ns ////////////////////////////////////////////////////////////////////////////// /// 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; // Compute the shifted value ourselves. // shadow_sout = sin >> amt; // // The outputs of the two shifters (modules under test) will // be compared to shadow_sout. // Wait one time unit. #1; // Check the output of each shifter (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