/// LSU EE 3755 -- Spring 2002 -- Computer Organization // /// Verilog Notes 3 -- Delay /// Contents /// Delays /// Ripple Adder and Delays /// The Event Queue and Verilog Simulation /// Lexicographic Conventions // // :Sample: A short example of Verilog, much less than a whole module. // :Example: A long example of Verilog code, usually a module. // /foo/: A defining reference, indicating that this is where foo is defined. // [bar]: Information that EE 3755 students are not yet responsible for // but is included here anyway. /// References // :P: Palnitkar, "Verilog HDL" // :Q: Qualis, "Verilog HDL Quick Reference Card Revision 1.0" // :H: Hyde, "Handbook on Verilog HDL" // :LRM: IEEE, Verilog Language Reference Manual (Hawaii Section Numbering) // :PH: Patterson & Hennessy, "Computer Organization & Design" //////////////////////////////////////////////////////////////////////////////// /// Delays // :P: 6.2, 6.2.2, 6.2.3 // :H: Not covered for continuous assignments. // :LRM: 6.1 // A /delay/ is a specification of elapsed time, the amount of // time the simulator is supposed to wait. // The simulator keeps track of simulated time, measured in cycles. // This is unlike conventional languages. // The default delay is zero. // // If delays are not specified things happen instantly. // // The default delay for a gate is zero. // // The default delay for an assign is zero. // // The default delay for an assign with a really complex expression is zero. // // The default delay for a module containing a zillion gates is zero. // // Zero is NOT the same as one. // // Delays can be specified in a variety of ways. // // The following will be covered in class: // // Delays in wires and assigns (this set). // Delays in behavioral statements (later this semester). // // See "delays" module, below, for further description. // :Example: // // A module that just passes the signal through, like wire. Suppose // at t=5 input a changes from 0 to 1, when does x change? module no_delays(x,a); input a; output x; assign x = a; wire w = x; endmodule // Ans: x changes at 5 + 0 = 5. // :Example: // // A module that just passes the signal through unchanged, though it // passes through two inverters. Suppose at t=5 input a changes from // 0 to 1, when does x change? module no_delays2(x,a); input a; output x; wire b; not n1(b,a); not n2(x,b); endmodule // Ans: x changes at 5. // :Example: // // Illustration and explanation of delays in assigns and wires. module delays(x,a); input a; output x; // Delay (For nets.) // wire #7 w = a; // // w gets value of a 7 cycles after each change in a (a must hold // steady for at least 7 cycles). // Delay (For continuous assignments.) // assign #3 x = w; // // x gets value of "w" 3 cycles after each change in "w" (w must // hold steady for at least 3 cycles). endmodule //////////////////////////////////////////////////////////////////////////////// /// Ripple Adder and Delays // :Example: // // The binary full adder presented earlier. There are no delays here. module bfa_implicit(sum,cout,a,b,cin); input a,b,cin; output sum,cout; assign sum = ~a & ~b & cin | ~a & b & ~cin | a & ~b & ~cin | a & b & cin; assign cout = a & b | b & cin | a & cin; endmodule // :Example: // // The same BFA with delays. // Suppose "a" changes at t=5 and "b" changes at t=20. // When do sum and cout change? module bfa_implicit_d(sum,cout,a,b,cin); input a,b,cin; output sum,cout; assign #3 sum = ~a & ~b & cin | ~a & b & ~cin | a & ~b & ~cin | a & b & cin; assign #2 cout = a & b | b & cin | a & cin; endmodule // Ans: sum: t=8 and t=23; cout t=7 and t=22. /// More information // // If a changes at t=5 and b changes at t=6 the situation is // different because there are two changes in "sum" within the // 3-cycle delay. // :Example: // // A 4-bit ripple adder constructed using the undelayed BFA. // If a changes at t=5 when does sum change? module ripple_4(sum,cout,a,b); input [3:0] a, b; output [3:0] sum; output cout; wire c0, c1, c2; bfa_implicit bfa0(sum[0],c0,a[0],b[0],1'b0); bfa_implicit bfa1(sum[1],c1,a[1],b[1],c0); bfa_implicit bfa2(sum[2],c2,a[2],b[2],c1); bfa_implicit bfa3(sum[3],cout,a[3],b[3],c2); endmodule // Ans: I'm sure everyone got it. // :Example: // // A 4-bit ripple adder constructed using the BFA with delays. // Suppose at t=0 a=0 and b=4'b1111 // If a changes to 1 at t=100 when does sum stop changing? module ripple_4_d(sum,cout,a,b); input [3:0] a, b; output [3:0] sum; output cout; wire c0, c1, c2; bfa_implicit_d bfa0(sum[0],c0,a[0],b[0],1'b0); bfa_implicit_d bfa1(sum[1],c1,a[1],b[1],c0); bfa_implicit_d bfa2(sum[2],c2,a[2],b[2],c1); bfa_implicit_d bfa3(sum[3],cout,a[3],b[3],c2); endmodule // Ans t=109 (Not checked) // :Example: // // A 4-bit adder using operators and no delays. This would be // a better way of coding a 4-bit adder in Verilog, but it's // not a good way to demonstrate the low speed of a ripple adder // to a computer organization class. module another_adder(sum,cout,a,b); input [3:0] a, b; output [3:0] sum; output cout; wire [4:0] sum_with_carry = a + b; assign sum = sum_with_carry[3:0]; assign cout = sum_with_carry[4]; endmodule // :Example: // // This is not really an example and students are not expected // to understand it. This is a testbench for the adder, it // instantiates the adders, generates inputs for them, and checks // for the correct output. module demoadd(); wire [4:0] sum1, sum2, sum3; reg [4:0] shadow_sum; reg [3:0] a, b; integer i; ripple_4 adder1(sum1[3:0],sum1[4],a,b); ripple_4_d adder2(sum2[3:0],sum2[4],a,b); another_adder adder3(sum3[3:0],sum3[4],a,b); task check_sum; input [4:0] s; input [79:0] name; if( s != shadow_sum ) begin $display("Wrong sum in %s: %d + %d = %d != %d\n", name, a, b, shadow_sum, s); $stop; end endtask initial begin for(i=0; i<=255; i=i+1) begin a = i[3:0]; b = i[7:4]; shadow_sum = a + b; #10; check_sum(sum1,"Ripple"); check_sum(sum2,"Ripple_d"); check_sum(sum3,"Operator"); end $display("Tests completed."); end endmodule //////////////////////////////////////////////////////////////////////////////// /// The Event Queue and Verilog Simulation /// The Verilog Simulator Event Queue // // Simulator maintains a "to-do list" called an /event queue/. // // An entry in the event queue specifies something that the simulator // needs to do. These include: // // (A) Changing the value of a wire [or reg]. // // (B) Evaluating an expression appearing in an assign statement. // // (C) Determining the output of a gate. // // (The letters above are used in the example below.) // // Each entry has a /timestamp/ which indicates when the action // specified by the entry is supposed to be done. // // Entries are sorted by timestamp. // // [Entries with the same timestamp are divided in to five layers.] /// How Verilog Simulators Run // // Wires [and registers] are initialized to x. // // Initial entries are put in the event queue. (Covered later in the // semester.) // // WHILE there the event queue is non-empty: // // Remove any entry with the smallest time stamp. // // Set the time to that time stamp. // // If the entry changes the value of a wire [or reg]: // // Put entries in the event queue for all gates and expressions // [and event controls] affected by the wire [or reg]. // // Else If the entry is for an expression in an assign statement: // // Evaluate the expression. Put an entry in the event queue // to modify the wire that's assigned. The entry's time stamp // is the current time plus the delay (plus zero if no delay). // [Delete other entries in the event queue corresponding to the // same assign.] // // Else If the entry is for a gate: // // Determine the output of the gate. Put an entry in the event // queue to modify the wire connected to the gate's output. The // entry's time stamp is the current time plus the delay (plus // zero if no delay). [Delete other entries in the event queue // corresponding to the same gate instance.] // // Else If ... (Covered with procedural code.) // // End simulation (when while loop is done). // :Example: // // Module illustrating timing and event queue. The testbench (shown // further below) sets a and b equal to 0 at t=0. module timing(x,y,a,b); input a, b; output x,y; wire d, e; not #2 n1(d,a); not #3 n2(e,d); assign x = b ^ d ^ e; xor a1(y,b,d,e); endmodule /// Event Queue for Example // // The comments below show the contents of the event queue as the // module above is simulated with the testbench way below. Some // events generated by the testbench have not been shown. // Event Queue After Testbench Starts, t = 0 // // Entry 2 timestamp = 8; Resume testbench procedural code. // Entry 1 timestamp = 0; A: Set a <- 0 // Entry 0 timestamp = 0; A: Set b <- 0 // Entry 0 removed. // Change b from x to 0. // Add affected items: // Event Queue at t = 0 // // Entry 2 timestamp = 8; Resume testbench procedural code. // Entry 4 timestamp = 0; B: Evaluate: xor a1(y,b,d,e); // Entry 3 timestamp = 0; B: Evaluate: assign x = b ^ d ^ e; // Entry 1 timestamp = 0; A: Set a <- 0 // Entry 1 removed. // Change a from x to 0. // Add affected items. // Event Queue at t = 0 // // Entry 2 timestamp = 8; Resume testbench procedural code. // Entry 5 timestamp = 0; C: Evaluate: not #2 n1(d,a); // Entry 4 timestamp = 0; C: Evaluate: xor a1(y,b,d,e); // Entry 3 timestamp = 0; B: Evaluate: assign x = b ^ d ^ e; // Entry 3 removed. // Compute b ^ d ^ e, result wire x does not change (was undefined, still is) // Event Queue at t = 0 // // Entry 2 timestamp = 8; Resume testbench procedural code. // Entry 5 timestamp = 0; C: Evaluate: not #2 n1(d,a); // Entry 4 timestamp = 0; C: Evaluate: xor a1(y,b,d,e); // Entry 4 removed // Compute xor a1(y,b,d,e). Output y does not change (was x, still is). // Event Queue at t = 0 // // Entry 2 timestamp = 8; Resume testbench procedural code. // Entry 5 timestamp = 0; C: Evaluate: not #2 n1(d,a); // Entry 5 removed. // Compute n1(d,a). d is to change from x to 1. // Insert change to d in event queue for 2 cycles later. // Event Queue at t = 0 // // Entry 2 timestamp = 8; Resume testbench procedural code. // Entry 6 timestamp = 2; Set d <- 1 // Remove entry 6. // Change time to t = 2. // Set d to 1. // Add items affected by d. // Event Queue at t = 2 // // Entry 2 timestamp = 8; Resume testbench procedural code. // Entry 9 timestamp = 2; assign x = b ^ d ^ e; // Entry 8 timestamp = 2; xor a1(y,b,d,e); // Entry 7 timestamp = 2; not #3 n2(e,d); // Remove entry 7. // Compute n2(e,d). e is to change from x to 0 // Insert change to e in event queue for 3 cycles later. // Event Queue at t = 2 // // Entry 2 timestamp = 8; Resume testbench procedural code. // Entry 10 timestamp = 5; Set e <- 0 // Entry 9 timestamp = 2; assign x = b ^ d ^ e; // Entry 8 timestamp = 2; xor a1(y,b,d,e); // Remove entry 8. // Compute xor(y,b,d,e) // No change in y. (Was x, still is.) // Event Queue at t = 2 // // Entry 2 timestamp = 8; Resume testbench procedural code. // Entry 10 timestamp = 5; Set e <- 0 // Entry 9 timestamp = 2; assign x = b ^ d ^ e; // Remove entry 9 // Compute b ^ d ^ e // No change in x. // Event Queue at t = 2 // // Entry 2 timestamp = 8; Resume testbench procedural code. // Entry 10 timestamp = 5; Set e <- 0 // Remove entry 10. // Change time to t = 5 // Set e to 0 // Add affected items. // Event Queue at t = 5 // // Entry 2 timestamp = 8; Resume testbench procedural code. // Entry 12 timestamp = 5; assign x = b ^ d ^ e; // Entry 11 timestamp = 5; xor a1(y,b,d,e); // Remove entry 11. // Evaluate xor(y,b,d,e) y to change from x to 1. // Add change to queue. // Event Queue at t = 5 // // Entry 2 timestamp = 8; Resume testbench procedural code. // Entry 13 timestamp = 5; Set x <- 1 // Entry 12 timestamp = 5; assign x = b ^ d ^ e; // Remove entry 12. // Evaluate b ^ d ^ e. wire x to change from x to 1. // Add change to queue. // Event Queue at t = 5 // // Entry 2 timestamp = 8; Resume testbench procedural code. // Entry 14 timestamp = 5; Set y <- 1 // Entry 13 timestamp = 5; Set x <- 1 // Remove entry 13. // Set x to 1. // Add affected items. (The affected item is in the testbench which isn't shown.) // Event Queue at t = 5 // // Entry 2 timestamp = 8; Resume testbench procedural code. // Entry 15 timestamp = 5; Some procedural stuff.[always @( a or b or x or y )] // Entry 14 timestamp = 5; Set y <- 1 // Remove entry 14 // Set y to 1. // Add affected items. (The affected item is already there, the always thing.) // Event Queue at t = 5 // // Entry 2 timestamp = 8; Resume testbench procedural code. // Entry 15 timestamp = 5; Some procedural stuff.[always @( a or b or x or y )] // Remove entry 15 // The procedural code prints a message. // Event Queue at t = 5 // // Entry 2 timestamp = 8; Resume testbench procedural code. // Remove entry 2 (finally). // Change time to t = 8 // Continue running the procedural code until... something else // is put in the event queue. More details will be provided when procedural // code covered. // :Example: // // The testbench for the code above. This module uses procedural // code which has not been covered yet. It can be ignored for now. module demo_timing(); reg a, b; wire x, y; timing everyones_timing_module_instance(x,y,a,b); integer i; always @( a or b or x or y ) $display(" a,b = %d, %d x,y= %d, %d",a,b,x,y); initial begin for(i=0; i<4; i=i+1) begin {a,b} = i[1:0]; #8; end end endmodule