Procedural timing control
The timing control is used to advance simulation time and it has two methods
- Delay timing control
- Event timing control
Delay timing control
The delay timing control allows to add up a delay between when the statement is encountered and when it is executed by the simulator. The delay is specified with the ‘#’ symbol.
Syntax:
A number, identifies or (min, typical, max) expression is used to specify delay timing control
#<number>
#<identifier>
#(<min_exp>: <typical_exp>, <max_exp>)
There are three types of delay timing control as follows
Delay timing control types |
Declaration |
Regular delay control |
The non-zero delay is specified at the LHS of the procedural statement. |
Intra-assignment delay control |
Delay is specified between the assignment operator and the RHS operand. |
Zero delay control |
The zero delay is specified at LHS of procedural statement |
Use Cases:
- Regular delay control delays the execution of the entire statement by a specified value.
Examples:
a. #5 data = i_value;
b. #(2:3:6) data = 20; - Intra-assignment delay control delays computed value assignment by a specified value. The RHS operand expression is evaluated at the current simulation time and assigned to LHS operand after a specified delay value.
Example: data = #5 i_value; - Zero delay control is used to control execution order when multiple procedural blocks try to update values of the same variable. Both always and initial blocks execution order is non-deterministic as they start evaluation at the same simulation time. The statement having zero control delay executes last, thus it avoids race conditions.
Example:
reg [2:0] data;
initial begin
data = 2;
end
initial begin
#0 data = 3;
end
Without zero delay control, the ‘data’ variable may have a value of either 2 or 3 due to race conditions. Having zero delay statement as specified in the above code guarantees outcome to be 3. However, it is not recommended to assign value to the variable at the same simulation time.
Event timing control
The event timing control method is used to trigger a statement or procedural block execution due to a change in the value of a net or register. It can be classified into four types
Event timing control types |
Declaration |
Regular event control |
An event control is specified using @ symbol |
Event OR control |
Multiple events are declared using the ‘or’ keyword or comma ‘,’ symbol. |
Named event control |
The event declared using
|
Level sensitive timing control |
The ‘wait’ keyword is used in the declaration |
a. Regular event control
The statement or procedural block is executed based on positive or negative edge transition in a signal value.
posedge – A posedge is used to execute statement/s whenever there is a transition from 0 or X or Z to 1.
negedge – A negedge is used to execute statement/s whenever there is a transition from 1 or X or Z to 0.
Examples:
Examples |
Description |
@(posedge clk) q = d; |
The q = d is executed whenever the clk signal does transition from 0/X/Z to 1. |
@(negedge clk) q = d; |
The q = d is executed whenever the clk signal does transition from 1/X/Z to 0. |
out = @(posedge clk) (a & b) |
The a & b is evaluated immediately but assigned to out at the positive edge of the clk. |
out = @(negedge clk) (a & b) |
The a & b is evaluated immediately but assigned to out at the negative edge of the clk. |
module tb;
reg clk;
reg [3:0] i1, i2;
reg [3:0] out1, out2, out3;
initial clk = 0;
always #5 clk = ~clk;
always @(clk) begin
@(posedge clk) out1 = i1;
@(negedge clk) out2 = i2;
out3 = @(posedge clk) (i1 & i2);
end
initial begin
$monitor("Time = %0t: i1 = %0d, i2 = %0d, out1 = %0d, out2 = %0d", $time, i1, i2, out1, out2);
repeat(4) begin
i1 = $random;
i2 = $random;
#10;
end
#20;
$finish;
end
endmodule
Output:
Time = 0: i1 = 4, i2 = 1, out1 = x, out2 = x
Time = 10: i1 = 9, i2 = 3, out1 = x, out2 = x
Time = 15: i1 = 9, i2 = 3, out1 = 9, out2 = x
Time = 20: i1 = 13, i2 = 13, out1 = 9, out2 = 13
Time = 30: i1 = 5, i2 = 2, out1 = 9, out2 = 13
Time = 35: i1 = 5, i2 = 2, out1 = 5, out2 = 13
Time = 40: i1 = 5, i2 = 2, out1 = 5, out2 = 2
Simulation complete via $finish(1) at time 60 NS + 0
./testbench.sv:25 $finish;
b. Event OR control
The statement or procedural block is executed based on positive or negative edge or level transition of more signals by mentioning into the sensitivity list using the ‘or’ keyword or comma ‘,’.
Examples |
Description |
always @(clk or rst_n) |
Level sensitive for clk and rst_n signals using or keyword. |
always @(posedge clk or negedge rst_n) |
Edge sensitive for clk and rst_n signals using or keyword. |
always @(clk, rst_n) |
Level sensitive for clk and rst_n signals using a comma. |
always @(posedge clk, negedge rst_n) |
Edge sensitive for clk and rst_n signals using a comma. |
module tb;
reg clk_1, clk_2, clk_3;
reg [3:0] i1, i2;
reg [3:0] out1, out2, out3;
initial begin
clk_1 = 0;
clk_2 = 0;
clk_3 = 0;
end
always #5 clk_1 = ~clk_1;
always #10 clk_2 = ~clk_2;
always #15 clk_3 = ~clk_3;
always @(posedge clk_1 or negedge clk_2) begin
out1 = i1;
out2 = (i1 & i2);
end
always @(negedge clk_1, posedge clk_3) begin
out3 = (i1 | i2);
end
initial begin
$monitor("Time = %0t: i1 = %0d, i2 = %0d, out1 = %0d, out2 = %0d", $time, i1, i2, out1, out2);
repeat(4) begin
i1 = $random;
i2 = $random;
#10;
end
#20;
$finish;
end
initial begin
$dumpfile("dump.vcd");
$dumpvars(1);
end
endmodule
Output:
Time = 0: i1 = 4, i2 = 1, out1 = x, out2 = x
Time = 5: i1 = 4, i2 = 1, out1 = 4, out2 = 0
Time = 10: i1 = 9, i2 = 3, out1 = 4, out2 = 0
Time = 15: i1 = 9, i2 = 3, out1 = 9, out2 = 1
Time = 20: i1 = 13, i2 = 13, out1 = 13, out2 = 13
Time = 30: i1 = 5, i2 = 2, out1 = 13, out2 = 13
Time = 35: i1 = 5, i2 = 2, out1 = 5, out2 = 0
Simulation complete via $finish(1) at time 60 NS + 0
./testbench.sv:35 $finish;
c. Named event control
In Verilog, the keyword ‘event’ is used to declare ‘named events’ that trigger an event using -> symbol and it is recognized by @ symbol.
The named events are also commonly knowns as Verilog events’.
The named event or Verilog events are used for synchronization between two or more processes.
Syntax:
To trigger an event: ->
Waiting for the event or recognize the event: @(
Note:
- The Verilog event does not hold any data.
- The @ symbol is used for edge-sensitive constructs.
module tb;
event e1;
initial begin
#10;
$display("Triggering an event e1");
->e1;
end
initial begin
@(e1) $display("Event e1 is triggered");
end
endmodule
Output:
Triggering an event e1
Event e1 is triggered
d. Level sensitive timing control
Along with the edge-sensitive construct (while waiting for an event trigger), Verilog adds up the ‘wait’ level-sensitive construct to wait for a specified condition to be true, and then only one or more statements will be executed. Thus, a set of statements will be blocked until the ‘wait’ condition is evaluated to be true.
Syntax:
wait(<expression or variable>)
module tb;
integer count;
initial begin
count = 0;
forever begin
count++;
#2;
end
end
initial begin
wait(count == 'd5);
$display("count has reached till %0d at time = %0t", count, $time);
$finish;
end
endmodule
Output:
count has reached till 5 at time = 8
Verilog Tutorials