/// LSU EE 4755 -- Fall 2016 -- Digital Design / HDL /// /// Elaboration, Parameters, and Generate Constructs // Time-stamp: <30 September 2016, 18:30:47 CDT, koppel@cyc.ece.lsu.edu> // Under construction. /// References // :SV12: IEEE 1800-2012 -- The SystemVerilog Standard // http://standards.ieee.org/getieee/1800/download/1800-2012.pdf // // :BV3: Brown & Vranesic, Fundamentals of Digital Logic with Verilog, 3rd Ed. // The text used in LSU EE 4720, 4730, and 4740. ////////////////////////////////////////////////////////////////////////////// /// Elaboration // :Def: Elaboration [of a module] // The process of locating instantiated modules, applying parameter // values, and running generate expressions. It is roughly analogous // to preprocessig in C. // :Def: Design Hierarchy // Details about the design elaborated from some top-level modules // constructed and used by a Verilog tool, such as simulator, synthesis // program, etc. // // Cadence Incisive uses program ncelab for elaboration. (It is // automatically called by other tools.) // :Example: // // Module sat_add is instantiated three times by elab_demo, at two // different sizes. // // After elaborating elab_demo, the design hierarchy will have four // modules: elab_demo, two sat_add's at 5 bits, and one at 9 bits. module sat_add #( int width = 8 ) ( output wire [width:1] sum, input wire [width:1] a, b ); localparam logic [width:1] val_max = -1; // Or ( 1 << width ) - 1 wire [width:1] raw_sum; wire carry_out; assign { carry_out, raw_sum } = a + b; assign sum = carry_out ? val_max : raw_sum; endmodule module elab_demo ( output wire [4:0] s1, s3, output wire [8:0] s2, output wire [8:0] d, input wire [4:0] a, b, input wire [8:0] c ); sat_add #(5) a1( s1, a, b); sat_add #(5) a2( s3, a, -b); sat_add #(9) a3( s2, {4'b0,a} , c); assign d = s2 - s1; endmodule ////////////////////////////////////////////////////////////////////////////// /// Generate Constructs // :SV: Chapter 27 /// :Def: Generate Construct // Verilog statements that are executed during elaboration and // which essentially write new Verilog code. // /// Important Concepts // // Generate statements execute before simulation or synthesis. // // Expressions in generate statements can only refer to generate-time // constants (expressions that can be computed in terms of parameters, // literals, and genvars.) /// The Generate Constructs // // - Loop Generate Constructs // for ( genvar IDENT = INIT; TEST; INCR ) // // - Conditional Generate Constructs // if / else // case / endcase module gen_good #( int option = 0 ) ( output wire [7:0] ab,abc, input wire [7:0] a, b, c ); for ( genvar i=0; i<8; i += 2 ) begin assign ab[i] = a[i]; assign ab[i+1] = b[i+1]; end for ( genvar i=0; i<8; i++ ) begin:myblock wire aab; and a1(aab,a[i],b[i]); if ( option == 0 ) or o1(abc[i],aab,c[i]); else xor o1(abc[i],aab,c[i]); end endmodule module gen_bad ( output wire [7:0] ab,abc, input wire option, input wire [7:0] a, b, c ); for ( genvar i=0; i<8; i += 2 ) begin assign ab[i] = a[i]; assign ab[i+1] = b[i+1]; end for ( genvar i=0; i<8; i++ ) begin:myblock wire aab; and a1(aab,a[i],b[i]); if ( option == 0 ) /// Bad, because option not constant. or o1(abc[i],aab,c[i]); else xor o1(abc[i],aab,c[i]); end for ( genvar i=0; i<8; i++ ) begin:myotherblock wire aab, ior, eor; and a1(aab,a[i],b[i]); // if ( option == 0 ) /// Bad, because option not constant. or o1(ior,aab,c[i]); // else xor o1(eor,aab,c[i]); assign abc[i] = option == 0 ? ior : eor; end endmodule // :Example: // // Use of generate statements to construct a ripple adder. module bfa_structural ( output wire sum, cout, input wire a, b, cin ); assign sum = a ^ b ^ cin; assign cout = a & b | a & cin | b & cin; endmodule /// Four-Bit Ripple Adder // // Instantiate four bfa's to make a 4-bit adder. // module ripple_4 ( output [3:0] sum, output cout, input [3:0] a, input [3:0] b, input cin); wire c0, c1, c2; bfa_structural bfa0(sum[0],c0,a[0],b[0],cin); bfa_structural bfa1(sum[1],c1,a[1],b[1],c0); bfa_structural bfa2(sum[2],c2,a[2],b[2],c1); bfa_structural bfa3(sum[3],cout,a[3],b[3],c2); endmodule module ripple_4 ( output [3:0] sum, output cout, input [3:0] a, b, input cin); wire carry[3:-1]; assign carry[-1] = cin; assign cout = carry[3]; // Runs at elaboration time. // Runs at elaboration time. // Runs at elaboration time. // Runs at elaboration time. for ( genvar i = 0; i<4; i++ ) bfa_structural bfa(sum[i], carry[i], a[i], b[i], carry[i-1]); endmodule module ripple_n #( int width = 16 ) ( output [width-1:0] sum, output cout, input [width-1:0] a, input [width-1:0] b, input cin); wire carry[width-1:-1]; assign carry[-1] = cin; assign cout = carry[width-1]; for ( genvar i = 0; i<width; i++ ) begin bfa_structural bfa(sum[i], carry[i], a[i], b[i], carry[i-1]); end endmodule /// Elaboration of Tree Structure module pop_1 (output logic [4:0] p, input [15:0] v ); always_comb begin p = 0; for ( int i=0; i<16; i++ ) p += v[i]; end endmodule module pop_n #( int bits = 16 ) ( output [4:0] p, input [bits-1:0] v ); if ( bits == 1 ) begin assign p = v[0]; end else begin wire [4:0] p1, p2; pop_n #(bits/2) pi1(p1,v[bits/2-1:0]); pop_n #(bits-bits/2) pi2(p2,v[bits-1:bits/2]); assign p = p1 + p2; end endmodule