Tutorials

Learn More

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

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