// Verilog Synthesis Notes and code for LSU EE 4702 Spring 2000 `define EDGE2 // Notes on Synthesis of Procedural Code: The Three Forms // Material below based on LeonardoSpectrum HDL Synthesis manual and // Ciletti Chapters 8, 9, and 10. The discussion in Ciletti is of // synthesis programs in general so some details differ. `ifdef DONTDEFINEME //////////////////////////////////////////////////////////////////////////////// // Leonardo (1999.1f) will synthesize procedural code only if it is // in one of three forms: // // Form 1: Combinational / Level Triggered // Form 2: Edge Triggered // Form 3: Implicit State Machine // // This applies to each process (code starting with "always"). A // module can have any number of processes and each can be in any of // these forms. (However a register can only be written in a single // process.) // // Summary of Forms // // Form 1: Combinational / Level Triggered // // Describes combinational logic. // Describes level-triggered registers. // Unlimited number of level-trigger conditions. // // Form 2: Edge Triggered // // Describes registers clocked on the edge of a single signal. // Registers can also be written with constants at asynchronous trigger. // // Form 3: Implicit State Machine // // Describes a state machine synchronized to a clock. // // // Caution // // Code which is not in one of these forms may: // // Cause synthesis to stop with a helpful error message. // // Cause the synthesis program to issue a warning message but // continue to synthesize. The synthesized description will // function differently than the Verilog code read by the // synthesizer. This is why one must simulate the synthesized // code. // // Be processed by the synthesizer without even a warning. The // synthesized description will function differently than the // Verilog code read by the synthesizer. Just think of the // "back in my day" stories you can tell your grandchildren // if they become EEs! //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Detailed Descriptions //------------------------------------------------------------------------------ // Form 1: Combinational / Level Triggered // // Describes combinational logic. // Describes level-triggered registers. // Unlimited number of level-trigger conditions. // // Basic Form // // always @( a1 or a2 or /* ... */ an ) begin // <non-timing-statements>; // end // // The non-timing-statements include some but not all Verilog // statements. A complete list is not given here. // // Not allowed: // Edge trigger in first event control: @( a1 or posedge a2 ... ) // Event controls (other than first): @( foo or bar ). // Looping constructs with an infinite or non-constant number of iterations. // // Inference of Registers (Synthesis of assignment statements.) // // Unconditional assignment to register generates wire: // x1 = a1 | a2; // x1 synthesized as a wire, not a register. // Conditional assignment to register generates level-triggered register. // if( a3 ) x2 = a1 | a2; // x2 synthesized as a register. // If there are multiple conditional assignments to a register and // at least one of them will execute, register synthesized as wire. // Example: always @( a1 or a2 or /* ... */ an ) begin // No event controls. Not allowed: @( a1 ) // Only signals in event control, a1 .. an, can appear in expressions. x1 = a1 | a2; // Okay. x1 synthesized as wire. x2 = b1 | a1; // WARNING: b1 not in event control. syn != sim. if( a3 ) x3 = a1 & a2; // x3 synthesized as level-triggered register. if( a1 | a2 ) x4 = a1 | a2; // x4 synthesized as level-trig. register. if( a4 ) x5 = a3; // Because this or assignment below will execute ... if( !a4 ) x5 = a2; // ...x5 synthesized as wire. end //------------------------------------------------------------------------------ // Form 2: Edge Triggered // Describes registers clocked on the edge of a single signal which // can also be written with a constant at an asynchronous trigger. // Basic Form always @( posedge s1 or posedge s2 or posedge s3 or /* ... */ posedge sn ) if( s1 ) begin <constant-assignments>; end else if ( s2 ) begin <constant-assignments>; end else if ( s3 ) begin /* ... */ end else begin <non-timing-statements>; end // The form above must be adhered to, in particular: // // All terms in the event expression must be either posedge or negedge // of a signal. No signal can appear more than once. // // The condition in each of the if statements shown above must be // one of the signals in the event expression. If the event // expressions is "posedge foo" then the condition must be ( foo ), // if the event expression is "negedge foo" the condition must be ( // !foo ). All of the signals except one must appear in one of the // if conditions. The signal that's not used is called the clock. // // Procedural statements can only be added where <constant-assignments> // and <non-timing-statements> appear. // // Assignments in <constant-assignments> can only assign constants // or constant expressions. x1 = 0 is okay but x1 = a1 is not. If // this rule is violated there will be a warning and the synthesized // hardware will behave differently than the simulated hardware. // One minor exception: signals in the event expression can be // tested, except the one in the condition immediately preceding the // code. (Whose value is known anyway.) // // Assignments in <non-timing-statements> can assign any valid // expression. That is, a signal can be used in an expression // whether or not it appears in the event expression. Timing // controls cannot be used in <non-timing-statements>, nor can loops // with a non-constant number of iterations. // // Inference of Registers (Synthesis of assignment statements.) // // Registers synthesized for all assignments. // // Unconditional assignment in <non-timing-statements>: // Edge-triggered (on clock). // x1 = a1 | a2; // x1 loaded with a1 | a2 on edge of clock. // // Conditional assignment in <non-timing-statements>: // Edge-triggered (on clock) with enable signal. // if( a3 ) x2 = a1 | a2; // x2 loaded with a1 | a2 on edge of clock if a3. // // Assignments in <constant-assignments> // Asynchronous set or reset triggered on signal in if condition. // x1 = 0; // Load x1 with zero when sx true or false. // // Note: The same register CAN be written in <constant-assignments> and // <non-timing-statements>, see "a" below: On a positive edge of // the clock (which may be sn) "a" will be loaded with "c". Whenever // "s1" is 1 a will be set to zero, when "s1" and "s2" are 0 "a" // will be set to one. // // Example: always @( posedge s1 or negedge s2 or posedge s3 or /* ... */ posedge sn ) if( s1 ) begin // Can only assign constants here. a = 0; // Asynchronous reset when s1 true. b = c; // WRONG: c not a constant. end else if ( !s2 ) begin // Note condition in if. // Can only assign constants here. a = 1; // Asynchronous set when s2 false and s1 false. b = 0; // Asynchronous reset when s2 false and s1 false. end else if ( s3 ) begin // ... end else begin // Note that there is no condition after the else. // Edge triggered assignments here. a = c; // Assign a to c on a positive edge of the clk. if( c ) x1 = a3; // Edge triggered assignment to x1 if c true. end //------------------------------------------------------------------------------ // Form 3: Implicit State Machine (To be covered 14 April 2000 or later.) // // Describes a state machine synchronized to clock. // // Basic Form // // always <clk-or-non-timing-statements>; // <clk-or-non-timing-statements> can include one kind of timing // statement: @( posedge clk ). (negedge can be used, clk can // be any signal.). // // The timing statement must appear at least once on every cycle through // a non-constant or infinite loop. (See examples.) // // Okay, timing control appears once: always @( posedge clk ) a = a + 1; always begin @( posedge clk ); a = a + 1; end always begin if( a1 ) @(posedge clk ) a = a + 1; else @(posedge clk ); // Okay, timing control appears twice: always @( posedge clk ) begin @(posedge clk) a = a + 1; end always begin @( posedge clk ); @(posedge clk) a = a + 1; end // NOT okay, timing control may appear zero times (if a1 false). always begin if( a1 ) @(posedge clk ) a = a + 1; // Inference of Registers (Synthesis of assignment statements.) // // Registers synthesized for all assignments, edge triggered on clk. // // State register inferred, state corresponds to position in procedural // code. `endif //////////////////////////////////////////////////////////////////////////////// // Code Examples: `ifdef EDGE1 // Plain old edge triggered flip flop. module edge_triggered(q, d, clk); input d, clk; output q; wire d, clk; reg q; // Synthesis program will use an edge-triggered flip-flop to // hold q. always @( posedge clk ) q = d; endmodule // edge_triggered `endif `ifdef EDGE2 module misc_edge_trig(x1, x2, x3, a, b, c, clk); input a, b, c, clk; output x1, x2, x3; wire a, b, c, clk; reg x1, x2, x3; // Synthesis program uses edge triggered flip-flops for x1, x2, and x3. // The clocking of x2 and x3 use the positive edge of clk and are // also enabled: by a & c for x2, and a & b for x3. always @( posedge clk ) begin x1 = a; if( a & c ) x2 = a | b; if( a & b ) x3 = c; end // Below: Rejected by synthesizer because of concurrent assignment to x1. // always @( c ) if( c ) x1 = 0; endmodule `endif `ifdef EDGE3 module misc_edge_trig(x1, x2, x3, a, b, c, clk); input a, b, c, clk; output x1, x2, x3; wire a, b, c, clk; reg x1, x2, x3; // Synthesis program will chose an edge triggered flip-flop // for x1 with an asynchronous reset input. On a positive edge // of clk a will be clocked into x1, whenever c is high x1 is // set to zero. Signal clk is used as an edge trigger because // its value is not tested (unlike c). always @( posedge clk or posedge c ) begin if( c ) x1 = 0; else x1 = a; end // Edge triggered flip-flops used for x2 and x3; x3 uses a // clock enable. always @( posedge clk ) begin x2 = a | b; if( a & b ) x3 = c; end endmodule `endif // ifdef EDGE3 // Example of a multifunction counter. `ifdef COUNTER module counter(cnt,op,d,clk); input op, d, clk; output cnt; reg [7:0] cnt; wire [1:0] op; wire [7:0] d; wire clk; parameter op_incr = 0; parameter op_decr = 1; parameter op_load = 2; parameter op_hold = 3; // Leonardo will synthesize an edge triggered register for cnt. always @( posedge clk ) case ( op ) op_incr: cnt = cnt + 1; op_decr: cnt = cnt - 1; op_load: cnt = d; endcase // case( op ) endmodule // counter `endif // Basic level-triggered flip-flop. `ifdef LEVEL1 module level_triggered(q1, q2, d, enable); input d, enable; output q1, q2; wire d, enable; reg q1, q2; // A level-triggered flip-flop is chosen for q1. always @( enable or d ) if( enable ) q1 = d; // WARNING: The Leonardo synthesized code will function differently // than the simulated code. In the synthesized code q2 is // connected directly to d whereas the Verilog code says q2 should // only be assigned when enable changes. always @( enable ) q2 = d; endmodule `endif `ifdef LEVEL2 module test(qlevelm,qlevelc,qclk,enable,d,x); input enable, d, x; output qlevelm, qlevelc, qclk; reg qlevelm, qlevelc, qclk; wire enable, d, x; // Level triggered chosen for qlevelm. always @( enable or d or x ) if( enable ) qlevelm = d ^ x; // This WILL NOT synthesize a level-triggered flip-flop. Do // not use code like this. always @( enable or d or x ) qlevelc = enable ? d ^ x : qlevelc; // Edge triggered flip-flop chosen for qclk. always @( posedge enable ) qclk = d ^ x; endmodule // test `endif // ifdef LATCH