Lecture 02 – Verilog Events, Timing, and Testbenches

Ryan Robucci

• Spacebar to advance through slides in order
• Shift-Spacebar to go back
• Arrow keys for navigation

• ESC/O-Key to see slide overview
• ? to see help

Printable Version

Table of Contents

References

An Event Driven Language also used for Synthesis

Verilog Language

Timing

Timing (Ex. Pulse Circuit)

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

Concurrent Operation

Describing Concurrency is another 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

Verilog Execution Model

The stratified event queue

The IEEE standard identifies 5 regions for events to live:

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;
  }
}

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

Simulation of parallel blocks

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

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

Continuous Assignment

Procedural continuous assignment

Switch (transistor) processing

Blocking and Nonblocking Procedural Assignment with Delays

Delays are for Simulation Only

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.

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.

#D a = b + c;  //delay before evaluation
#D a <= b + c; //delay before evaluation

Code after these statements in a begin…end block will not execute until after the delay, nor will the block pass control

Assignment delay schedules an assignment for a future time, though the RHS expression is evaluated using the values at the time of the scheduling.

a = #D b + c; delay before assignment, execution in begin…end block does not progress until assignment event is handled, nor will the block will pass control

a <= #D b + c; delay before assignment: RHS evaluation is followed by scheduling a future nonblocking assignment event, execution within a begin…end block progresses and control may be passed out of the block

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.

Inertial and Transport Delay

Inertial Delay on Wires

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

delay in the continuous assignment

wire x_n;
assign #5 x_n = ~n; 

delay in the implicit assignment

wire #5 x_n = ~n;

delay in the wire declaration (added to any assignment delay)

wire #5 x;
assign x = ~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};

Inertial Delay using Primitives

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);

Pulse Rejection is Based on the Result/Output

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);

Rising and Falling Delay

Separate delays may be provided for rising and falling output edges

wire y;
and #(3,2) I1(y,a,b); //#(rising delay,falling delay)

Rising Edges:
0 → 1, X→1 Z→1

Falling Edges:
1 → 0, X→0, Z→0

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

You can also specify Min:Typ:Max delays which are selected by the simulator:

assign #(1:2:3) y = a & b;
assign #(2:3:4,1:2:3) y = a & b;

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

Inertial Delay for reg

For a reg signal, 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   

Modeling of Delay for Sequential Logic

parameter TC2Q;
reg q;
always @(posedge clk)
  q <= #TC2Q ~b;
parameter TC2Q;
reg q;
always @(posedge clk)
  q = #TC2Q ~b;
parameter TC2Q;
reg q;
always @(posedge clk) 
  #TC2Q q <= ~b;
parameter TC2Q;
reg q;
always @(posedge clk) 
  #TC2Q q = ~b;

Modeling of Delay for Combinational Logic

parameter D;
reg y;
always @(a,b)
  y <= #D a&b;
always @(y)
  y_delayed <= #D y;
parameter D;
reg y;
always @(a,b)
  y = #D a&b;
parameter D;
reg y;
always @(a,b) 
  #D y <= a&b;
parameter D;
reg y;
always @(a,b)
  #D y = a&b;

Simulation Use of RHS non-blocking assignment delay

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

Procedural Timing Controls

event triggerName;
@(triggerName);
-> triggerName;

Event Control Operator

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

@(a,b,c)
@(a or b or c)

Negedge and posedge restrict sensitivity to the following
transitions

@(posedge clk or negedge en)

Negedge:
1→ 0
1→ x or z
x or z → 0

Posedge:
0 → 1
x or z →1
0 → x or z

When posedge and negedge modify a multi-bit operand , only the lsb is used to detect the edge.

Level-sensitive event control using wait

Repeat

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

repeat (count) @ (event expression)

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

Wait fot 10 clk rising edges before proceeding execution:

repeat (10) @ (posedge clk);

Delay an assignment by 5 clk edges

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

Delay an assignment by 5 inverter delays:

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

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:

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 ...

Sequential and Parallel Blocks

Sim Using Test Bench

DUT:

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

Testbench:

module test_Nand_Latch_1; // 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;    // Enter, to proceed 
    #10    clear     =0;
    #10    clear     =1;
    #10    preset    =0;
  end
  initial
    #60    $finish ; // Stop watch
  end
endmodule

Results:

  0 preset = x clear = x q = x qbar = x
 10 preset = 0 clear = 1 q = x qbar = x
 11 preset = 0 clear = 1 q = 1 qbar = x
 12 preset = 0 clear = 1 q = 1 qbar = 0
 20 preset = 1 clear = 1 q = 1 qbar = 0
 30 preset = 1 clear = 0 q = 1 qbar = 0
 31 preset = 1 clear = 0 q = 1 qbar = 1
 32 preset = 1 clear = 0 q = 0 qbar = 1
 40 preset = 1 clear = 1 q = 0 qbar = 1

Timescale Directive

`timescale 
<reference_time_unit>/<time_precision>

Generating a clock in a testbench

50% duty cycle:

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

Generating an irregular clock in a testbench

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

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 affect 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

Testing memory

wire data_out;
reg write;
reg [3:0] addr;
reg [7:0] memory_buffer [0:15]; // 16 entries 8 bit #'s 
reg [7:0] data_in; 
integer i; integer file; 
my_mem I0 (data_out,data_int,addr,write);
initial begin
    $readmemh("memory_hex_in.txt", memory_buff); //init memory_buff from file
    file = $fopen(“memory_hex_out.txt”);  //open a file for writing results
    #5 write = 0; addr =0;
    for (i=0; i<16; i++) begin //write to mem
        #5 write = 0; data_in= memory_buff[i]; addr= i;
        #5 write = 1;
    end
    #10 write = 0;
    
    //reading and writing to file
    for (i=0; i<16; i++) begin  
        #5 addr =i;
        $fstrobe(file,%2H”,data_out);
    end
    $fclose(file);
end

The procedural construct for can be used to create simulation loops.

Note on Use of Loops for Simulation vs Synthesis