Lecture 06 – Events Timing and Basic Testbenches

Ryan Robucci

1. References

  • (Cummings 2000) Some examples are borrowed: Cummings, Clifford E. "Nonblocking assignments in verilog synthesis, coding styles that kill!." SNUG (Synopsys Users Group) 2000 User Papers (2000). http://www.sunburst-design.com/papers/CummingsSNUG2000SJ_NBA.pdf
  • (IEEE Std 1364-2005) IEEE Standard for Verilog Hardware Description Language," in IEEE Std 1364-2005 (Revision of IEEE Std 1364-2001) , vol., no., pp.1-590, 7 April 2006 doi: 10.1109/IEEESTD.2006.99495 Abstract: The Verilog hardware description language (HDL) is defined in this standard. Verilog HDL is a formal notation intended for use in all phases of the creation of electronic systems. Because it is both machine-readable and human-readable, it supports the development, verification, synthesis, and testing of hardware designs; the communication of hardware design data; and the maintenance, modification, and procurement of hardware. The primary audiences for this standard are the implementers of tools supporting the language and advanced users of the language. URL: http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=1620780&isnumber=33945
  • Reference material for timing examples: (Cummings 1999) Cummings, Clifford E. "Correct Methods for Adding Delays to Verilog Behavioral Models !." HDLCON 1999. http://www.sunburst-design.com/papers/CummingsHDLCON1999_BehavioralDelays_Rev1_1.pdf

2. An Event Driven Language also used for Synthesis

  • We emphasize use of Verilog as a hardware description language for synthesis, but it is a general event-driven simulation language
  • Verilog is event driven, events are triggered to cause evaluation events to be queued which cause updates to be queued which may in turn serve as triggers for other events to be queued.
  • Events are entered into a priority queue for processing. Event elements in the priority queue are removed and processed according to two rules
    • earliest time first
    • then first come first serve stack behavior
  • Nondeterminism of concurrent statements: By default, individual assignment statements and blocks in a module are considered to be concurrent. This means that there evaluation may be queued in any order if triggered.
  • Certain coding guidelines constrain the use of the language to ensure deterministic behavior in simulation and are known to map to hardware with the same behavior
    • Most of these issues relate to concurrency

3. Verilog Language

  • Being a hardware description and modeling language, Verilog supports modeling of concurrency as well as time.
  • all of the following should be considered as equivalent since concurrent processes are described

    not I1(b_n,x);
    and I2(b_n,x);
    assign w = (a|b);
    assign y = (w|u);
    

    and I2(b_n,x);
    assign w = (a|b);
    assign y = (w|u);
    not I1(b_n,x);
    

    assign y = (w|u);
    and I2(b_n,x);
    assign w = (a|b);
    not I1(b_n,x);
    

  • In-class: discuss flow of value propagation and events: \(\boxed{{a,b,c,d}={1,1,1,1}} \rightarrow \boxed{{a,b,c,d}={1,1,1,0}}\)
  • Event-Driven: update events cause evaluation events, which case update events
    • selective, as-needed processing of expressions and code
      • massive simulation time savings for large circuits with few value changes (low activation)

4. Timing

  • Timing and delay are intrinsic aspects of physical circuits and are important concepts for hardware modeling
  • Delay in a logic path might be a parasitic effect, and must be analyzed to ensure the circuit can operate fast enough.

  • Delay in the logic path also helps prevent race conditions if the clk arival at the downpath register is slightly delayed

5. Timing (Example: Pulse Circuit)

  • Other times, delay is fundamental to how a circuit works.

    • In the circuit below delay is necessary for the circuit to generate a pulse.

Structural Example with delays indicated with #:

module  pulser(y, x);
  input   x;
  output  y; 
  wire    x_n;

  and     #5 (y,x,x_n)
  not     #3 (x_n,x);
endmodule

6. Concurrent Operation

  • Describing concurrency (usually to model parallelism) is another key feature of an HDL
  • The following code attempts to model a swap of y1 and y2, as in
    • y1 = old y2 , concurrently with
    • y2 = old y1

Concurrent Assignment (Cummings 2000):

module fbosc2 (y1, y2, clk, rst);
  output y1, y2;
  input clk, rst;
  reg y1, y2;

  always @(posedge clk or posedge rst)
    if (rst) y1 <= 0; // reset
    else y1 <= y2;

  always @(posedge clk or posedge rst)
    if (rst) y2 <= 1; // preset
    else y2 <= y1;
endmodule

This is a case where handing of concurrency, is critical as two interdependent updates are at once

7. Verilog Execution Model

  • A Verilog Simulation involves processing events from different queues that have different priorities
  • Most events in the queues can be describe as evaluation or update events
    • Evaluation events involve processing or execution. These events can enable other events to enter the active queue, often it enters value assignment events into the queue.
    • Update events involve making a value assignment to a variable. These in turn may implicitly enable evaluation events that are sensitive to the changed variable

8. The stratified event queue

The IEEE standard identifies 5 regions for events to live:

  • Active events: in queue ready for execution in current simulation time. The Nondeterminism property states that the order that they are removed is not specified. One effect is that concurrent statements and blocks are not guaranteed execution in any order. Furthermore, blocks of behavioral statements may be returned to the active queue at any point even if only partially completed. This allows interleaving of process execution but also unpredictable behavior for concurrent processes with miscoded communication paths between them.
  • Inactive events: to be processed at the end of the current simulation time after any active events in the queue. An explicit zero delay (#0) is a way to force an event to be transferred to the inactive event queue.
  • Nonblocking assign update events: to be processed at the end of the current simulation time after active and inactive events in the queue. They are processed in the order they are added to the queue.
  • Monitor events: to be processed if no active, inactive, or nonblocking assign update events are in the queue. These events do no create any other events. `$monitor` and `$strobe` system tasks generate monitor events.
  • Future events: active, inactive and nonblocking assign update events scheduled with a future time

9. IEEE Specification of Event Handling

(Quoted from IEEE Std 1364-2005 with colors added)

while (there are events){
  if (no  active events){
    if      (there are  inactive events){
           activate all inactive events;
    } else if(there are  nonblocking assign update events){
           activate all nonblocking assign update events;
    } else if(there are   monitor events){
           activate all monitor events;
    } else{
          advance T to the next event time;
          activate all inactive events for time T;
    }
  }

  E = any active event;
  if (E is an update event){
    update the modified object;
    add evaluation events for sensitive processes  to event queue;
  }else { /* shall be an evaluation event */
     evaluate the process;
     add update events  to the event queue;
  }
}

10. Bad Parallel Blocks

Bad Concurrent Assignment (Cummings 2000):

module fbosc1 (y1, y2, clk, rst);
  output y1, y2;
  input clk, rst;
  reg y1, y2;

  always @(posedge clk or posedge rst)
    if (rst) y1 = 0; // reset
    else y1 = y2;

  always @(posedge clk or posedge rst)
    if (rst) y2 = 1; // preset
    else y2 = y1;
endmodule

  • This code attempts to model a swap of y1 and y2
  • Timing of execution of parallel always blocks is not guaranteed in simulation — though synthesis will probably work since synthesis approaches each always blocks somewhat independently at first

11. Simulation of parallel blocks

12. Good Parallel Blocks

Will not only synthesize correctly, but also simulate correctly:

Good Concurrent Assignment (Cummings 2000):

module fbosc2 (y1, y2, clk, rst);
  output y1, y2;
  input clk, rst;
  reg y1, y2;

  always @(posedge clk or posedge rst)
    if (rst) y1 <= 0; // reset
    else y1 <= y2;

  always @(posedge clk or posedge rst)
    if (rst) y2 <= 1; // preset
    else y2 <= y1;
endmodule

13. Sim Example

module amb_parallel_swap();

  reg clk, rst;
  reg y1, y2;
  reg z1, z2;

 initial clk = 0;
 always #50 clk = ~clk;

 initial begin
  rst = 1;
  #10; 
  rst = 0;
 end


  initial begin
   #1000 $finish;
  end
 always @(posedge clk , posedge rst)
  if (rst) y1 = 0; // reset
  else y1 = y2;

always @(posedge clk , posedge rst)
  if (rst) y2 = 1; // preset
  else y2 = y1;
always @(posedge clk , posedge rst)
  if (rst) z1 <= 0; // reset
  else z1 <= z2;

always @(posedge clk , posedge rst)
  if (rst) z2 <= 1; // preset
  else z2 <= z1;
endmodule

14. Continuous Assignment

  • Continuous assignment statements enable (a.k.a. schedule or trigger) an evaluation event when any source element of the RHS expression changes. Upon any expression's resulting value change, an update event for the LHS is added to the active queue.

    assign {cout,b} = d+a;
    
    • Left-hand-side (LHS) expression: {cout,b}
    • Right-hand-side (RHS) expression: d+a
  • At the start of each simulation, an initial evaluation of continuous assignments occurs at time zero to propagate constant values. The various cascades of dependanceis cause other expresssions and procedural code in the HDL models to be evaluated at time zero as a result. In the the following, an initial evaluation and assignment will occur, but no other update to a will happen in the simulation.

    assign a=1;
    

15. Procedural continuous assignment

  • Consider this topic not covered until future notice
  • Involves keywords assign, force, deassign, release when specifically used inside procedural code

16. Switch (transistor) processing

  • Not covered until future notice: switch modeling keywords such as tran, tranif0, tranif1,rtran, rtranif0, rtranif1

17. Blocking and Nonblocking Procedural Assignment with Delays

  • Blocking assignments cause an immediate evaluation of the right hand side. If delay is provide, then the assignment to the left-hand-expression is scheduled for a future time unless the delay is 0 and in which case the assignment event is entered into the inactive queue. If no delay is specified the statement performs the assignment and returns immediately. Once the assignment is performed, any change will enable any events dependent on the value.

    a = #D b+c;
    

    delay D before blocking assignment

  • Nonblocking assignments schedule an evaluation and assignment using the values of the inputs at the time of the scheduling. The event is placed in the nonblocking assignment update event queue for the current time or, if a delay is provided, a future time.

    a <= #D b + c;
    

    assignment delay D

Delays are only for Simulation ; Delays are Ignored for Synthesis

Delays are only used when modeling for simulation. They should not be used to describe characteristics to a hardware synthesis tool. Typically, all # delays are stripped from code before synthesis.

18. Procedural Blocking and Procedural Assignment Delay

  • In the delay before evaluation form (statement delay or evaluation delay), the delay essentially β€œsleeps” the process until another time before the following code is evaluated.
    • so call statement delay because delay is essentially before entire statement

      #D a =  b + c;
      

      #D;
      a =  b + c;
      

      #D a <=  b + c;
      

      #D;
      a <=  b + c;
      

  • Assignment delay schedules an assignment for a future time, though the RHS expression evaluation is not delay and may use the variable values at the time of the scheduling rather than the future.
    • for delayed blocking assignments, no progression in procedural code until update event is handled (code does not pass control)
      • control is not passed out of the block (particularly, always block control triggers may be missed)
    • for delayed non-blocking assignments, the update is delayed yet execution control is passed immediately

Evaluation Delay (delay before evaluation)

#D a =  b + c;
  • delay>evaluate>assign>progress
    • future values of b,c used
    • passes control after assignment
#D a <= b + c;
  • delay>evaluate>progress>assign
    • future values of b,c used
    • passes control after evaluation

Assignment Delay (delay before assignment)

a = #D b + c;
  • evaluate>delay>assign>progress
    • current values of b,c used
    • control passed after blocking assignment
a <= #D b + c;
  • evaluate>delay>progress>assign
    • current values of b,c used
    • control passed after blocking assignment

Code example

 initial #0 $display($time,"  a  b  y  z");

initial begin
    $monitor($time,u8a,u8b,u8y,u8z);
    u8a=0; u8b=0;      
    #5;
    #5 u8a = 1;
    #5 u8b = 1;      
 end

 always@* begin
    $display($time,u8a,u8b,"       enter nonblocking");      
    u8y <= #20 u8a+u8b;   
    $display($time,u8a,u8b,"       leave nonblocking");      
 end

 always@* begin
    $display($time,u8a,u8b,"       enter blocking");      
    u8z = #20 u8a+u8b;
    $display($time,u8a,u8b,"       leave blocking");      
 end

 initial #100 $finish;   

Result

 Simulator is doing circuit initialization process.
                 0  0  0       enter nonblocking
                 0  0  0       leave nonblocking
                 0  0  0       enter blocking           ***
 Finished circuit initialization process.
                 0  a  b  y  z
                 0  0  0  x  x
                10  1  0       enter nonblocking
                10  1  0       leave nonblocking
                10  1  0  x  x
                15  1  1       enter nonblocking
                15  1  1       leave nonblocking
                15  1  1  x  x
                20  1  1       leave blocking           ***
                20  1  1  0  0
                30  1  1  1  0
                35  1  1  2  0
Stopped at time : 100 ns : File "…/delay_tests.v" Line 56

Delayed Blocking assignment prevented multiple calls.

19. Inertial and Transport Delay

  • Transport Delay maintains all transitions and delays them by a specified amount. Models a delay like an ideal transmission line.
    • Transport delay does not model pulse rejection described below.
  • Inertial Delay also delays transitions, but it only maintains transitions to new states that are held for as long as the specified delay. Approximates models charging and pulse rejection.
  • Inertial Delay Pulse Rejection: pulses of a duration less than the specified inertial delay are rejected.

20. Inertial Delay Using Continuous Assignment (wire and SystemVerilog reg/logic)

The following are all examples of inertial delay on a wire.

  • delay in the continuous assignment

Verilog/SystemVerilog

wire x_n;
assign #5 x_n = ~n; 
wire #5 x_n;
assign x_n = ~n; 
wire #5 x_n = ~n;

SystemVerilog

logic x_n;
assign #5 x_n = ~n; 

  • delay in the wire declaration

    wire #5 x;
    assign x = ~x;
    
    • delay in the declaration of a wire with implicit assignment

      wire #5 x_n = ~n;
      
    • ⚠️ invalid

      logic #5 x_n = ~n;
      
      reg #5 x_n = ~n;
      

  • Additive inertial delay: delay in declaration is added to any in the assignment
    • in this example, the inertial delay to `a` is from `x` is 3:

      wire #2 a;
      assign #1 a = x;
      
    • in this example, the inertial delay to `a` is `4` and for `b` is `3`:

      wire #3 a;
      wire #2 b;
      assign #1 {a,b} = {x,x};
      

21. Primitive Delay is Inertial Delay

Inertial delay may be provide to primitives using the simplist form of the delay operator.

wire y;
and #3 I1(y,a,b);

In this next example, the inertial delay to y is 4 since delay provide in the declaration is added.

wire #1 y;
and #3 I1(y,a,b);

22. Pulse Rejection is Based on the Result/Output (not input pulse-width)

The pulse rejection behavior is based on the result, not the inputs. The result of an expression to be assigned must maintain a new value for the specified time.

wire y;
assign #2 y = a&b;
wire y;
and #2 I1(y,a,b);

wire y;
assign #3 y = |{a,b,c};
wire y;
or #3 I1(y,a,b,c);

23. Rising and Falling Delay Can Be Different

Delays can be assigned distinctly to either rising vs falling output edges

wire y;
and #(3,2) I1(y,a,b); //#(rising delay,falling delay)
Transitions Edge Type
0 → 1, X→1 Z→1 Rising Edge
1 → 0, X→0, Z→0 Falling Edge

Other output edges (e.g. X→Z , 1→Z ) assume the minimum value between the of the rising and falling delays (2 in the example above)

Good Reference:http://verilog.renerta.com/source/vrg00011.htm

24. Inertial Delay for "reg"

For a reg, to model inertial delay it is recommend to create a delayed wire copy. Direct modeling of inertial delay is difficult otherwise.

Augmenting reg with Inertial Delay:

wire c;
reg c_nodelay
assign #5 c = c_nodelay;
always @(b,d)
  c_nodelay = ~b|d;
end   

25. Modeling of Delay for Sequential Logic

  • Study these examples one-by-one as practice to understand Verilog; and reference when trying to model delay (no need to memorize)
  • Note that always_ff or always_comb are not used since this a modeling exercise and not for synthesis

Good

parameter TC2Q;
reg q;
always @(posedge clk)
  q <= #TC2Q ~b;
  • Evaluate now, assign later
  • Models Clk-to-Q delay

Bad

  • ❌

    parameter TC2Q;
    reg q;
    always @(posedge clk)
      q = #TC2Q ~b;
    
    • Evaluate now, assign later
    • Bad: Nondeterminism of assignment at later time
  • ❌ (delay the clock)

    parameter TC2Q;
    reg q;
    always @(posedge clk) 
      #TC2Q q <= ~b;
    
    • Evaluate after delay then assign
    • Models a delay in the clock signal. Not recommended, better to create and use a delayed clock using other delay methods
  • ❌

    parameter TC2Q;
    reg q;
    always @(posedge clk) 
      #TC2Q q = ~b;
    
    • Evaluate after delay then assign
    • Bad: Nondeterminism of assignment at later time

26. Modeling of Transport Delay

  • transmission lines
    • transport delay models transmission line delay, for which the digital signal at a far destination is a delayed copy of the source end signal
  • combinational logic blocks
    • inertial delay captures the idea that the "switches" of digital logic must be held in a state for some time to affect the capacitors involve
      • useful for modeling switches driving capacitors
    • transport delay models a slowed propagation of change through a cascade of gates
      • does not represent that an input must be held, only that there is a delay between a change in an input and a resulting in an output
inertial delay transport delay
- modeling a gate driving a capacitor load at the output of a circuit - modeling delays through several combinational logic gates, e.g. combinatorial path delay

intertial_delay.svg

Good for Simulation Model

βœ”οΈ Trasport Delay for combinational logic

parameter D;
reg y;
always @(a,b)
  y <= #D a&b;
always @(y)
  y_delayed <= #D y;
  • Evaluate now, assign later
  • Can be use to model transport delay for combinatorial logic or a delayed signal such a from a transmission line
  • Note that non-blocking assignment is required to to prevent blocking of re-evaluation

Bad

parameter D;
reg y;
always @(a,b)
  y = #D a&b;
  • Evaluate now, assign later
  • Bad: Blocks reevaluation (ignores input update events)
parameter D;
reg y;
always @(a,b) 
  #D y <= a&b;
  • Evaluate later and assign
  • Bad: Blocks reevaluation
parameter D;
reg y;
always @(a,b)
  #D y = a&b;
  • Evaluate later and assign
  • Bad: Blocks reevaluation

27. Simulation Use of RHS non-blocking assignment delay

Useful / Example

  • RHS non-blocking delays may be conveniently used in testbenches to schedule several delayed assignments (not something I use)

Example 1:

initial begin
  a <= 0;
  a <= #10 255;
  a <= #20 22;
  a <= #30 10;
  b <= 'bx;
  b <= #1 1193;
  b <= #10 122;
  c <= #10 92;
  c <= #15 93;
end

Example 2: delays relative to rst signal change

initial begin
  a = 0;
  b = 0;
  c = 0;
  wait (rst==0);
  a <= #10 255;
  a <= #20 22;
  a <= #30 10;
  b <= #1 1193;
  b <= #10 122;
  c <= #10 92;
  c <= #15 93;
end

28. Procedural Timing Controls

  • Delay control: delay between encountering the expression and when it executes.
    • Introduced by simple #
  • Event control: delay until event

    • Explicit Events are named events that allow triggering from other procedures
      • A named event may be declared using the keyword event
      • The event control operator @ can be used to hold procedural code execution operator -> triggers the event
    • Implicit events are responses to changes in variables
      • The event control operator @ can be provided a sensitivity list with variables and on optional event selectivity using keywords posedge and negedge
    event triggerName;
    
    @(triggerName);
    
    -> triggerName;
    

29. Event Control Operator

  • The event control operator may be provided with variables
    • multiple variables using comma separation. (older syntax is to use or)

      @(a,b,c)
      

      πŸ’€ Old Syntax

      @(a or b or c)
      
  • Edge selective: negedge and posedge restrict sensitivity to the following transitions

    @(posedge clk or negedge en)
    
    • Negedge Bit Transitions:
      • 1β†’ 0
      • 1β†’ x or z
      • x or z β†’ 0
    • Posedge Bit Transitions:
      • 0 β†’ 1
      • x or z β†’1
      • 0 β†’ x or z
    • Multibit: When posedge and negedge modify a multi-bit operand , only the lsb is used to detect the edge.
1010 -> 0001    posedge



1011 -> 1110    negedge

30. Level-sensitive event control using wait

  • The wait statement suspends execution until a condition is true.
  • It can be considered as a level-sensitive control since it doesn't wait for a transition edge.
  • Comparison of wait to posedge:

    @(posedge clk) 
    

    even if clk is already true, wait for next rising edge

    wait (clk); 
    

    if clk is already true, produce without delay

  • Example to change data on the falling clock edge that follows a variable exceeding the value 10:

    wait(a>10);
    @ (negedge clk);
    data<=data+1;
    

31. Repeat Construct

Repeat keyword can be used to create repetition of statements or delay operations

Repeat "Loop"

repeat (3) begin
   count = count +1;
   $display ("Count" : count);
end

Repeat timing control

Any timing control may be modified so as to be repeated/multiplied, by using the keyword repeat

Dynamic Repeat (simulation run-time variable)

repeat (count) @ (event expression) /*empty statement*/;

If count is positive, repeat the timing control that number of time. If count is equal or less than 0, skip

Cycle Delay

Wait fot 10 clk rising edges before proceeding execution:

repeat (10) @ (posedge clk);
do_stuff

Delay an assignment by 5 clk edges

a <= repeat(5) @(posedge clk) data;

Delay Multiplicity

Delay an assignment by 5 inverter delays:

parameter INV_DELAY = 4.5;
a <= repeat(5) #INV_DELAY data;

32. initial and always

The initial construct is used to denote code to be executed once at the beginning of the simulation.

The always construct causes code to run repeatedly in an infinite loop. It is only useful with a delay or control construct, otherwise will create a zero delay infinite loop that can block time progression in simulation

This would run infinitely and stall the simulation time:

always x=a&b;

This prints endlessly in the beginning of the simulation:

always begin
  $display(“hello %0t);
end
0 : hello
0 : hello
0 : hello
0 : hello
0 : hello ...

33. Sequential and Parallel Blocks

  • Sequential procedural blocks are wrapped with begin...end
  • Parallel procedural blocks are wrapped with fork...join
    • Statement Delay control is relative to entering the block
    • Control passes out of the block when the last statement, which may be delayed in time, is completed
  • Here is a mix, waiting for two three events before performing assignment a=b:
begin
   x=y;
   fork
      @event ... ;
      @event ... ;
      @event ... ;
   join
   a = b;
end
  • Don't confuse the term sequential code to mean coding a procedural block for sequential hardware
    • sequential code refers to control flow of code which defines its functional interpretation, but it can describe the functionality of combinatorial hardware and/or sequential hardware
    • sequential hardware would refers to inferred hardware

34. Sim Using Test Bench

DUT:

module Nand_Latch_1 (q,qbar,preset,clear);
  output q, qbar;
  input preset,clear;
   nand #1 G1 (q,preset,bar);
   nand #1 G2 (qbar,clear,q);
endmodule

Testbench:

module Nand_Latch_1_TB; // Design Unit Testbench
  reg       preset, clear;
  wire       q, qbar;
  Nand_Latch_1 M1 (q, qbar, preset, clear);// Instantiate DUT
  initial // Create DUTB response monitor
  begin
    $monitor ($time, 
              "|preset = %b clear = %b q = %b 1 qbar = %b",
               preset, clear, q, qbar);
  end

  initial
  begin // Create DUTB stimulus generator
    #10    preset    =0;   clear =1;
    #10    preset    =1;   $stop;
    #10    clear     =0;
    #10    clear     =1;
    #10    preset    =0;
  end

  initial begin
    #60    $finish ; 
  end
endmodule

Results:

xcelium> run
                   0|preset = x clear = x q = x 1 qbar = x
                  10|preset = 0 clear = 1 q = x 1 qbar = x
                  11|preset = 0 clear = 1 q = 1 1 qbar = x
                  12|preset = 0 clear = 1 q = 1 1 qbar = 0
Simulation stopped via $stop(1) at time 20 NS + 0
./test_nand_tb.sv:25     #10    preset    =1;   $stop;
xcelium> run
                  20|preset = 1 clear = 1 q = 1 1 qbar = 0
                  21|preset = 1 clear = 1 q = x 1 qbar = 0
                  22|preset = 1 clear = 1 q = x 1 qbar = x
                  30|preset = 1 clear = 0 q = x 1 qbar = x
                  31|preset = 1 clear = 0 q = x 1 qbar = 1
                  40|preset = 1 clear = 1 q = x 1 qbar = 1
                  41|preset = 1 clear = 1 q = x 1 qbar = x
                  50|preset = 0 clear = 1 q = x 1 qbar = x
                  51|preset = 0 clear = 1 q = 1 1 qbar = x
                  52|preset = 0 clear = 1 q = 1 1 qbar = 0
Simulation complete via $finish(1) at time 60 NS + 0
./test_nand_tb.sv:31     #60    $finish ; // Stop watch

35. Time Unit and Resolution Directive

  • clocks can be set to realistic frequencies for timing simulation

    parameter PERIOD=4;
    
    initial clock = 1’b0;
    always #(PERIOD/2) clock = ~clock;
    
  • unit and precision for the time quantity is defined by a derective at the top of a Verilog file

    `timescale unit/resolution
    
  • time unit: what unit the delays should be interpreted as
  • precision: what the precision is used for each timing event

Examples:

  • example :

    `timescale 1ns/1ps
    

    Then `#17.0402` represents 17.040 ns

  • example

    `timescale 1.0ns/100ps
    ...
     #(10/3.0) clock = 1'b1;
    

    10/3.0 = 3.33…ns = 3333.3333….ps, but delay in simulation is rounded to 3300 ps because resolution is 100ps

  • errors can accumulate over time:

    `timescale 1.0ns/100ps
    ...
     #(10/3.0) clock = 1'b1;
     #(10/3.0) clock = 1'b0;
     #(10/3.0) clock = 1'b1;
    

36. Generating a clock in a testbench

50% duty cycle:

clock-50-50.svg

initial begin
  clk = 0;
end
always begin
  #5 clk = 0;
  #5 clk = 1;
end
initial begin
 clk = 0;
end

always begin
  #5 clk = ~clk;
end

The procedural construct forever can be used the create an infinite loop:

initial begin
  clk = 0;
  forever begin
    #5 clk = ~clk;
  end
end

37. Generating an irregular clock in a testbench

clock-spi.svg

initial begin
  clk = 0;
  forever begin
    repeat (16) begin
      #5 clk = ~clk;
    end
    #20;
  end
end

The procedural construct repeat can be used to create a limited loop

38. Testing all combinatorial inputs using a counter

Here, the first input, a, is changed every 5 time units, cycling every 10 Each subsequent input at half the rate of the previous

reg a,b,c,d;
initial begin
 a <= 0; b <= 0;
 c <= 0; d <= 0;
end

always begin
  #5 a <= ~a;
end
always begin
  #10 b <= ~b;
end
always begin
  #20 c <= ~c;
end
always begin
  #40 d <= ~d;
end

The same can be achieved using a counter:

wire a,b,c,d;
reg [3:0] count;
initial begin
  count = 0;
end

assign {a,b,c,d}=count;
always begin
  #5 count = count+1;
end

39. Application of Stimulus in Testbench

testbench_parts.svg

  • recommended: non-blocking updates to drive primary inputs of a DUT
    • assumes DUT is a synchronous circuit
    • emulates FFs driving inputs, providing deterministic simulation

      always @(posedge clk) begin
         a <= seqA;
         b <= seqB;
         c <= seqC;
      end
      
      • test bench that applies stimuli to design's primary inputs
        • ❌

          always @(posedge clk) begin 
           a = pattern_memory[i][0]; // non-determinism
           b = pattern_memory[i][1]; // non-determinism
           c = pattern_memory[i][2]; // non-determinism
           i=i+1;
          end
          
        • βœ”οΈ

          always @(posedge clk) begin 
           a <= pattern_memory[i][0]; // good
           b <= pattern_memory[i][1]; // good
           c <= pattern_memory[i][2]; // good
           i=i+1;
          end
          
  • Input Driver Stage Modeling in Testbench using non-blocking assignments to primary inputs :

driver.svg

DUT with primary inputs a,b,c:

DUT-primary-inputs.svg

example testbench

  • inline driver
module tb  ;
     ...
     logic [7:0] a,b,c,clk,u,v,v_q,w_q;
     ...
     my_module dut(.*);
     ...
     initial begin
        a='0;
        b='0;
        c='0;
     end
     always @ (posdge clk) begin : driver //DRIVER
        automatic logic [7:0] gen_a, gen_b, gen_c; //automatic implies no memory between invocations of block
        gen_a = a + 1;
        gen_b = gen_a + 1;
        gen_c = gen_b + 1;

        a<=gen_a;
        b<=gen_b;
        c<=gen_c;

     end
     ...
     ...

to freestyle input generation, use more timing controls based on clock

module DUT(w_q, v_q,a,b,c,clk,u,v);
   input logic [7:0] a,b,c;
   output logic [7:0] v_q,w_q;
   input logic        clk;
   output logic [7:0] u,v;
   always_comb begin
      u=a|b;
      v=u|c;
   end
   always_ff @ (posedge clk) begin
      v_q<=v;
      w_q<=v_q;
   end

endmodule // DUT



module tb;
   logic [7:0] w_q, v_q,a,b,c,u,v;
   logic       clk;

   DUT dut(.*);

   initial begin
      #0   $display("%5s ","time","%3s %3s %3s %3s %3s %3s %3s ","a","b","c","u","v","v_q","w_q");
      /**/ $monitor("%5t ",$time,"%3d %3d %3d %3d %3d %3d %3d " , a,  b,  c,  u,  v , v_q,  w_q);
   end

   initial begin: CLK
      clk = 0;
      #5;
      forever #5 clk = ~ clk;
   end

   initial begin
      a='0;
      b='0;
      c='0;
      @ (posedge clk);
      a<=2;
      b<=3;
      c<=4;
      repeat (2) @ (posedge clk); //2-cycle stall
      @ (posedge clk);
      $display("%5t-",$time,"%60s","d:(set a,b,c to 0):"); //consistently before monitor
      a<=0;             //set with rising edge concluding cycle in which w_q==7
      b<=0;
      c<=0;
      repeat (10) @ (posedge clk);
      //$display("%5t-",$time,"%60s","d:(set a,b,c to 255):");
      a<=255;
      b<=255;
      c<=255;
      repeat (10) @ (posedge clk);
      $finish;
   end // initial begin
endmodule
xcelium> run
 time   a   b   c   u   v v_q w_q 
    0   0   0   0   0   0   x   x 
   10   2   3   4   3   7   0   x 
   20   2   3   4   3   7   7   0 
   30   2   3   4   3   7   7   7 
   40-                                         d:(set a,b,c to 0):
   40   0   0   0   0   0   7   7 
   50   0   0   0   0   0   0   7 
   60   0   0   0   0   0   0   0 
  140 255 255 255 255 255   0   0 
  150 255 255 255 255 255 255   0 
  160 255 255 255 255 255 255 255 
Simulation complete via $finish(1) at time 240 NS + 0
./test.sv:60       $finish;

Timing Simulation (sub-cycle timing)

  • a timing simulation with circuit delays displays transitions with sub-cycle timing accuracy

tmp-534.svg

Zero-Delay Simulation, a.k.a. functional/behavioral

  • Sometimes called a behavioral / functional simulation since it is checking the digital functionality on a cycle-accurate basis.

tmp-5qwe34.svg

40. Use $display for debugging procedural code

$display statements are best used for observing sequential procedural code blocks, which have multiple statements processes for one instant of time

always_comb  begin // (dep. on a,b,c)
   automatic logic [7:0] _u; //for RTL code use automatic for internal combinatorial variables
                             //  (akin to VHDL variable)
   $display("a(0)=",a);
   $display("b(0)=",b);
   _u = a * 2;           //u is twice a
   $display("u(0)=",u);
   _u = _u>b ? b:_u;       //u is limited/clipped to threshold b
   $display("u(1)=",_u);
   v = _u + c;           //v is min(a*2,b) + c
   $display("v(0)=",v);
end

41. $final (System Verilog )

  • complementary to initial
  • like initial procedures, but instead are called at the end of a simulation instead of at the begining keyword use:

    final begin
       $display("Simulation Ended");
    end
    

42. Differentiate "Use of Loops for Simulation Testbenches" vs "Loops in RTL for Synthesis"

  • In the previous slides you were taught for , forever and repeat in the context of simulation behavioral code for a testbench
  • going forward you are expected to know such use
  • However you should NOT yet start using loops for synthesis.
  • Rules for using loops in synthesis will be taught in a later lecture

Author: Dr. Ryan Robucci

Created: 2025-02-27 Thu 10:13

Validate