System Verilog events are powerful synchronization constructs that allow processes to communicate and coordinate effectively. Events play a crucial role in both design and verification, enabling precise control of the timing and sequencing of actions. This article provides an in-depth exploration of events, including triggering with -> and ->>, waiting for events using @ and wait, and leveraging the wait_order() method for ordered synchronization.
1. Understanding Events in SystemVerilog
An event in SystemVerilog is a handle used to signal and wait for specific occurrences in the simulation. Events do not hold any value or state, and they do not persist after they are triggered. They are primarily used for synchronization between processes.
An event is declared using the event keyword:
event my_event;
2. Event Triggering
Events can be triggered using the -> operator or the ->> operator. Both are used to notify processes waiting for the event, but they differ in how they schedule the waiting processes.
Triggering with ->
The -> operator immediately notifies all processes waiting for the event.
Example:
event my_event;
initial begin
#10; // Delay for 10 time units
->my_event; // Trigger the event
$display("Event triggered at time %0t", $time);
end
Here, any process waiting on my_event will be immediately notified when ->my_event is executed.
Triggering with ->>
The ->> operator queues the notification of waiting processes for execution in the next time step (i.e., it adds the notification to the event queue).
Example:
event my_event;
initial begin
#10; // Delay for 10 time units
->>my_event; // Schedule the event trigger for the next time step
$display("Event triggered at time %0t", $time);
end
Key difference:
- ->: Processes are notified immediately.
- ->>: Notifications are queued and processed in the next simulation time step.
The ->> operator is useful for ensuring deterministic behavior when multiple processes are waiting on the same event. This operator is used for triggering the non-blocking events.
3. Waiting for an Event Trigger
Processes can wait for an event to be triggered using the @ operator or the wait statement. Both serve similar purposes but have subtle differences.
Waiting with @ Operator
The @ operator suspends the execution of a process until the specified event is triggered.
Example:
module tb();
event my_event;
initial begin
fork
begin
#20; // Delay for 20 time units
->my_event; // Trigger the event
$display("triggering the event at time %0t",$time);
end
begin
@(my_event.triggered); // Wait for the event
$display("Event caught at time %0t", $time);
end
join
end
endmodule
Here:
- The first process triggers my_event after 20 time units.
- The second process waits using @(my_event.triggered) and resumes once the event is triggered.
Output:
triggering the event at time 20
Event caught at time 20
Waiting with wait Statement
The wait statement can also be used to pause execution until a condition involving an event is met. Unlike @, it supports complex conditions.
Example:
module tb();
event my_event;
initial begin
fork
begin
#20; // Delay for 20 time units
->my_event; // Trigger the event
$display("triggering the event at time %0t",$time);
end
begin
#20;
wait(my_event.triggered); // Wait for the event
$display("Event caught at time %0t", $time);
end
join
end
endmodule
Output:
triggering the event at time 20
Event caught at time 20
Key differences:
The key difference between @ operator and wait operator is that if event triggering and waiting for event trigger using @ operator happens at same time then it will miss the event triggering but if we use wait() operator it will simulate the process. Take above code as an example. If we replace wait operator with @ operator, it will not detect the event and output will come as follow:
Output:
triggering the event at time 20
Also the waiting process must execute the @ statement first before triggering process executes the event “->”. If the trigger executes first, then the waiting process remains blocked.
4. Merging and Synchronizing Events
SystemVerilog supports merging events using logical operators like or and and.
Example: Merging with or
module tb();
event event_a, event_b;
initial begin
fork
begin
#15; // Trigger event_a after 15 time units
->event_a;
end
begin
#30; // Trigger event_b after 30 time units
->event_b;
end
begin
@(event_a or event_b); // Wait for either event_a or event_b
$display("Event_a or Event_b triggered at time %0t", $time);
end
join
end
endmodule
Output:
Event_a or Event_b triggered at time 15
5. Using wait_order()
The wait_order() method is a specialized synchronization mechanism that ensures events are triggered in a specific order. It is used to verify that multiple events occur in the desired sequence.
Syntax:
wait_order(event1, event2, ..., eventN);
- The process blocks until all the specified events are triggered in the specified order.
- If the events occur out of order, a runtime error is generated.
Example: Using wait_order()
module tb();
event event1, event2, event3;
initial begin
fork
begin
#10; ->event1; // Trigger event1
#20; ->event2; // Trigger event2
#30; ->event3; // Trigger event3
end
begin
wait_order(event1, event2, event3); // Wait for events in order
$display("Events occurred in the correct order at time %0t", $time);
end
join
end
endmodule
If event1, event2, and event3 are triggered in the specified order, the process proceeds. If the order is violated, an error is raised.
Output:
Events occurred in the correct order at time 60
Conclusion
SystemVerilog events provide essential synchronization tools for hardware design and verification. By understanding how to trigger (-> and ->>), wait (@ and wait), and synchronize (wait_order) events, you can implement robust and well-coordinated processes in your testbench or design.
Mastering these concepts will not only enhance your SystemVerilog skills but also make your verification environment more efficient and predictable.