UVM Event
The event mechanism provides synchronization between processes. The UVM event provides additional flexibility over the System Verilog event like maintaining the number of event waiters and setting callbacks.
uvm_event class declaration:
virtual class uvm_event_base extends uvm_object
class uvm_event#(type T=uvm_object) extends uvm_event_base;
uvm_event class hierarchy
For UVM 1.2, the uvm_event_base class is an abstract wrapper class over the System Verilog event construct and the uvm_event class is an extension of the uvm_event_base class.
For UVM1.1d, an abstract uvm_event_base class does not exist. The uvm_event class is directly derived from the uvm_object class.
The events provide synchronization between processes by triggering an event from one process and waiting for that event in another process to be triggered. The UVM event can also pass data when it is triggered that makes it different from the SV event.
uvm_event_base class methods
Type |
Methods |
Description |
function |
new |
Creates a new object for the event |
task |
wait_on |
Waits for the event to be activated for the first time until the event is reset. This task returns immediately if the event has already been triggered. |
task |
wait_off |
For an already triggered event, this task waits for an event to be turned ‘off’ via a call to reset function. |
task |
wait_trigger |
Waits for the event to be triggered |
task |
wait_ptrigger |
Waits for a persistent trigger of the event. The trigger views as persistent within a given time slice to avoid a race condition. |
function |
is_on |
Returns 1 if an event has triggered. |
function |
is_off |
Returns 1 if an event has not been triggered. |
function |
get_trigger_time |
To get time at which event was last triggered. The time reruns 0 if an event has been reset or not triggered. |
function |
reset |
Resets event to its off state. No callbacks are called during reset. |
function |
get_num_waiters |
Returns the number of processes waiting on that event. |
function |
cancel |
Decrement the number of waiters at the event. |
uvm_event class methods
Type |
Methods |
Description |
function |
new |
Creates a new object for the event |
function |
trigger |
Triggers the event for resuming all waiting processes. It also has an optional data argument to provide trigger-specific information. |
function |
get_trigger_data |
Gets the data information provided by the last trigger function call if any. |
task |
wait_trigger_data |
This method calls uvm_event_base::wait_trigger followed by get_trigger_data. |
task |
wait_ptrigger_data |
This method calls uvm_event_base::wait_ptrigger followed by get_trigger_data. |
function |
add_callback |
Registers a callback cb object with the event. It may include pre-trigger and post_trigger functionality. |
function |
delete_callback |
Unregisters the given callback cb from the event. |
UVM Event Examples
I. Event is triggered and waiting for the event to be triggered via the wait_trigger method
For example, there are two processes A and B. The process_A task is used to trigger an event e1 and the process_B task is used to wait for the event.
Type A: An event is triggered after waiting for the event trigger
The process_A task has a 10ns delay which makes sure event e1 triggers after waiting for the event trigger. The wait for the event to be triggered using the wait_trigger method call that will be unblocked once the e1 event is triggered.
`include "uvm_macros.svh"
import uvm_pkg::*;
module event_example();
uvm_event e1;
task process_A();
#10;
$display("@%0t: Before triggering event e1", $time);
e1.trigger;
$display("@%0t: After triggering event e1", $time);
endtask
task process_B();
$display("@%0t: waiting for the event e1", $time);
e1.wait_trigger;
$display("@%0t: event e1 is triggered", $time);
endtask
initial begin
e1 = new();
fork
process_A();
process_B();
join
end
endmodule
Output:
@0: waiting for the event e1
@10: Before triggering event e1
@10: After triggering event e1
@10: event e1 is triggered
Type B: An event is triggered before waiting for the event trigger
The process_B task has a 10ns delay which makes sure event e1 triggers before waiting for an event trigger. The wait for the event to be triggered will not be unblocked since the e1 event is triggered before. Hence, statements after waiting for the trigger will not be executed.
`include "uvm_macros.svh"
import uvm_pkg::*;
module event_example();
uvm_event e1;
task process_A();
$display("@%0t: Before triggering event e1", $time);
e1.trigger;
$display("@%0t: After triggering event e1", $time);
endtask
task process_B();
#10;
$display("@%0t: waiting for the event e1", $time);
e1.wait_trigger;
$display("@%0t: event e1 is triggered", $time);
endtask
initial begin
e1 = new();
fork
process_A();
process_B();
join
end
endmodule
Output:
@0: Before triggering event e1
@0: After triggering event e1
@10: waiting for the event e1
Type C: An event is triggered at the same time as waiting for the event trigger
The process_A and process_B have no delay involved to ensure the triggering of an event and waiting for the event trigger to happen at the same time. Since both processes are triggered at the same time, the wait_trigger method will not detect an event triggering. The uvm_event provides a wait_ptrigger method to solve this race-around problem (Check 2. Type C).
`include "uvm_macros.svh"
import uvm_pkg::*;
module event_example();
uvm_event e1;
task process_A();
$display("@%0t: Before triggering event e1", $time);
e1.trigger;
$display("@%0t: After triggering event e1", $time);
endtask
task process_B();
$display("@%0t: waiting for the event e1", $time);
e1.wait_trigger;
$display("@%0t: event e1 is triggered", $time);
endtask
initial begin
e1 = new();
fork
process_A();
process_B();
join
end
endmodule
Output:
@0: Before triggering event e1
@0: After triggering event e1
@0: waiting for the event e1
II. Event is triggered and waiting for the event to be triggered via the wait_ptrigger method
For example, there are two processes A and B. The process_A task is used to trigger an event e1 and the process_B task is used to wait for the event using the wait_ptrigger.
Type A: An event is triggered after waiting for the event trigger.
The process_A task has a 10ns delay which makes sure event e1 triggers after waiting for the event trigger. The wait of the event to be triggered via the wait_ptrigger() method will be unblocked once the e1 event is triggered.
`include "uvm_macros.svh"
import uvm_pkg::*;
module event_example();
uvm_event e1;
task process_A();
#10;
$display("@%0t: Before triggering event e1", $time);
e1.trigger;
$display("@%0t: After triggering event e1", $time);
endtask
task process_B();
$display("@%0t: waiting for the event e1", $time);
e1.wait_ptrigger;
$display("@%0t: event e1 is triggered", $time);
endtask
initial begin
e1 = new();
fork
process_A();
process_B();
join
end
endmodule
Output:
@0: waiting for the event e1
@10: Before triggering event e1
@10: After triggering event e1
@10: event e1 is triggered
Type B: An event is triggered before waiting for event trigger
The process_B task has a 10ns delay which makes sure event e1 triggers before waiting for an event trigger. The wait of the event to be triggered via wait() construct will not be unblocked since the e1 event is triggered before. Hence, statements after waiting for the trigger (with @ operator) will not be executed.
`include "uvm_macros.svh"
import uvm_pkg::*;
module event_example();
uvm_event e1;
task process_A();
$display("@%0t: Before triggering event e1", $time);
e1.trigger;
$display("@%0t: After triggering event e1", $time);
endtask
task process_B();
#10;
$display("@%0t: waiting for the event e1", $time);
e1.wait_ptrigger;
$display("@%0t: event e1 is triggered", $time);
endtask
initial begin
e1 = new();
fork
process_A();
process_B();
join
end
endmodule
Output:
@0: Before triggering event e1
@0: After triggering event e1
@10: waiting for the event e1
Type C: An event is triggered at the same time as waiting for the event trigger.
`include "uvm_macros.svh"
import uvm_pkg::*;
module event_example();
uvm_event e1;
task process_A();
$display("@%0t: Before triggering event e1", $time);
e1.trigger;
$display("@%0t: After triggering event e1", $time);
endtask
task process_B();
$display("@%0t: waiting for the event e1", $time);
e1.wait_ptrigger;
$display("@%0t: event e1 is triggered", $time);
endtask
initial begin
e1 = new();
fork
process_A();
process_B();
join
end
endmodule
Output:
@0: Before triggering event e1
@0: After triggering event e1
@0: waiting for the event e1
@0: event e1 is triggered
III. Event is triggered with data and waiting for the event to be triggered and retrieve data using wait_on and get_trigger_data.
For example, there are two processes A and B. The process_A task is used to trigger an event e1, sends the transaction object as data and the process_B task is used to wait for the event and retrieve data.
Type A: retrieve data using wait_on and get_trigger_data.
The process_A task has a 10ns delay which makes sure event e1 triggers after waiting for the event trigger. The wait for the event to be triggered using the wait_on method call that will be unblocked once the e1 event is triggered. The get_trigger_data is used to retrieve data provided by the last call to trigger method.
`include "uvm_macros.svh"
import uvm_pkg::*;
class transaction extends uvm_object;
rand bit [7:0] addr;
rand bit [7:0] data;
function new(string name = "transaction");
super.new(name);
endfunction
`uvm_object_utils_begin(transaction)
`uvm_field_int(addr, UVM_PRINT);
`uvm_field_int(data, UVM_PRINT);
`uvm_object_utils_end
endclass
module event_example();
uvm_event e1;
task process_A();
transaction tr_A = new();
#10;
$display("@%0t: Before triggering event e1", $time);
assert(tr_A.randomize);
tr_A.print();
e1.trigger(tr_A);
$display("@%0t: After triggering event e1", $time);
endtask
task process_B();
uvm_object event_data;
transaction tr_B;
$display("@%0t: waiting for the event e1", $time);
e1.wait_on();
event_data = e1.get_trigger_data();
$cast(tr_B, event_data);
$display("@%0t: event e1 is triggered and data received = \n%s", $time, tr_B.sprint());
endtask
initial begin
e1 = new();
fork
process_A();
process_B();
join
end
endmodule
Output:
@0: waiting for the event e1
@10: Before triggering event e1
-------------------------------------
Name Type Size Value
-------------------------------------
transaction transaction - @336
addr integral 8 'ha3
data integral 8 'h8f
-------------------------------------
@10: After triggering event e1
@10: event e1 is triggered and data received =
-------------------------------------
Name Type Size Value
-------------------------------------
transaction transaction - @336
addr integral 8 'ha3
data integral 8 'h8f
-------------------------------------
Similarly, wait_on and get_ptrigger_data can be used.
Type B: retrieve data using wait_trigger_data
The process_A task has a 10ns delay which makes sure event e1 triggers after waiting for the event trigger. The wait for the event to be triggered using the wait_trigger_data method call that will be unblocked once the e1 event is triggered.
wait_trigger_data = wait_trigger + get_trigger_data.
// wait_trigger_data definition
virtual task wait_trigger_data (output T data);
wait_trigger();
data = get_trigger_data();
endtask
Example:
`include "uvm_macros.svh"
import uvm_pkg::*;
class transaction extends uvm_object;
rand bit [7:0] addr;
rand bit [7:0] data;
function new(string name = "transaction");
super.new(name);
endfunction
`uvm_object_utils_begin(transaction)
`uvm_field_int(addr, UVM_PRINT);
`uvm_field_int(data, UVM_PRINT);
`uvm_object_utils_end
endclass
module event_example();
uvm_event e1;
task process_A();
transaction tr_A = new();
#10;
$display("@%0t: Before triggering event e1", $time);
assert(tr_A.randomize);
tr_A.print();
e1.trigger(tr_A);
$display("@%0t: After triggering event e1", $time);
endtask
task process_B();
uvm_object event_data;
transaction tr_B;
$display("@%0t: waiting for the event e1", $time);
e1.wait_trigger_data(event_data);
$cast(tr_B, event_data);
$display("@%0t: event e1 is triggered and data received = \n%s", $time, tr_B.sprint());
endtask
initial begin
e1 = new();
fork
process_A();
process_B();
join
end
endmodule
Output:
@0: waiting for the event e1
@10: Before triggering event e1
-------------------------------------
Name Type Size Value
-------------------------------------
transaction transaction - @1798
addr integral 8 'h2f
data integral 8 'hb3
-------------------------------------
@10: After triggering event e1
@10: event e1 is triggered and data received =
-------------------------------------
Name Type Size Value
-------------------------------------
transaction transaction - @1798
addr integral 8 'h2f
data integral 8 'hb3
-------------------------------------
Similarly, wait_ptrigger_data can be used.
UVM Tutorials