UVM Sequencer

UVM Sequencer

  • The sequencer controls the flow of request and response sequence items between sequences and the driver
  • Sequencer and driver uses TLM Interface to communicate transactions
  • uvm_sequencer and uvm_driver base classes have seq_item_export and seq_item_port defined respectively. User needs to connect them using TLM connect method.

Example:

driver.seq_item_port.connect(sequencer.seq_item_export);

A sequencer can be written by extending the uvm_sequencer parameterized with the seq_item type.

uvm sequencer
uvm sequencer

UVM Sequencer Code

class mem_sequencer extends uvm_sequencer#(mem_seq_item);

   `uvm_sequencer_utils(mem_sequencer)
     
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

endclass : mem_sequencer

❮ Previous Next ❯

UVM Phases

UVM Phases top down

  • UVM Phases are a synchronizing mechanism for the environment
  • Phases are represented by callback methods, A set of predefined phases and corresponding callbacks are provided in uvm_component. The Method can be either a function or task.
  • Any class deriving from uvm_component may implement any or all of these callbacks, which are executed in a particular order

The UVM Phases are,

  • build
  • connect
  • end of elaboration
  • start of simulation
  • run
  • extract
  • check
  • report

the run phase is implemented as a task and remaining all are function.

UVM Phases
UVM Phases

Phases can be grouped into 3 categories,

1. Build Phases

build phase, connect phase and end_of_elobaration phase belongs to this category.
Phases in this categorize are executed at the start of the UVM testbench simulation, where the testbench components are constructed, configured and testbench components are connected.
All the build phase methods are functions and therefore execute in zero simulation time.

uvm run phase
uvm run phase

2. Run-time Phases

start of simulation and run phase belongs to run-time phases, the run phase will get executed from the start of simulation to till the end of the simulation.
the run phase is time-consuming, where the testcase is running

3. Clean up Phases

extract, check, report and final belong to this category.
where the results of the testcase are collected and reported. example: the number of error’s during the simulation is reported.

Phases Description:

Phase Description Execution Order
build Used to construct the testbenchcomponents top-down
connect Used to connect TLM ports of components bottom-up
end_of_elaboration Used to make any final adjustments to the structure, configuration or connectivity of the testbench before simulation starts bottom-up
start_of_simulation used for printing testbench topology or configuration information bottom-up
run Used for stimulus generation, driving, monitoring, and checking parallel
extract Used to retrieve and process information from scoreboards and functional coverage monitors
check Used to check that the DUT behaved correctly and to identify any errors that may have occurred during the execution of the test bench
report Used to display the results of the simulation or to write the results to file
final Used to complete any other outstanding actions that the test bench has not already completed

UVM run phase phases

the run phase has different phases, these are,

run Phase Description
pre_reset the pre_reset phase starts at the same time as the run phase. Its purpose is to take care of any activity that should occur before the reset, such as waiting for a power-good signal to go active
reset The reset phase is reserved for DUT or interface specific reset behavior. For example, this phase would be used to generate a reset and to put an interface into its default state
post_reset Intended for any activity required immediately the following reset
pre_configure pre_configure phase is intended for anything that is required to prepare for the DUT’s configuration process after reset is completed
configure configure phase is used to program the DUT and any memories in the testbench so that it is ready for the start of the test case
post_configure post_configure phase is used to wait for the effects of configuration to propagate through the DUT, or for it to reach a state where it is ready to start the main test stimulus
pre_main pre_main phase is used to ensure that all required components are ready to start generating stimulus
main This is where the stimulus specified by the test case is generated and applied to the DUT. It completes when either all stimulus is exhausted or a timeout occurs
post_main This phase is used to take care of any finalization of the main phase
pre_shutdown This phase is a buffer for any DUT stimulus that needs to take place before the shutdown phase
shutdown The shutdown phase is used to ensure that the effects of the stimulus generated during the main phase have propagated through the DUT and that any resultant data has drained away
post_shutdown Perform any final activities before exiting the active simulation phases. At the end of the post_shutdown phase, the UVM testbench The execution process starts the cleanup phases

❮ Previous Next ❯

UVM Driver example

UVM Driver

    • A driver is written by extending the uvm_driver
    • uvm_driver is inherited from uvm_component, Methods and TLM port (seq_item_port) are defined for communication between sequencer and driver
    • The uvm_driver is a parameterized class and it is parameterized with the type of the request sequence_item and the type of the response sequence_item

UVM_Driver Methods

get_next_item

This method blocks until a REQ sequence_item is available in the sequencer.

try_next_item

This is a non-blocking variant of the get_next_item() method. It will return a null pointer if there is no REQ sequence_item available in the sequencer.

item_done

The non-blocking item_done() method completes the driver-sequencer handshake and it should be called after a get_next_item() or a successful try_next_item() call.

put

The put() method is non-blocking and is used to place an RSP sequence_item in the sequencer.

 Writing Driver :

1. A driver is written by extending the UVM_DRIVER

class mem_driver extends uvm_driver #(mem_seq_item);

  `uvm_component_utils(mem_driver)

  // Constructor
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

endclass : mem_driver

2. Declare the virtual interface,

  // Virtual Interface
  virtual mem_if vif;the interface handle using get config_db, 

3. Get the interface handle using get config_db,

  if(!uvm_config_db#(virtual mem_if)::get(this, "", "vif", vif))
       `uvm_fatal("NO_VIF",{"virtual interface must be set for: ",get_full_name(),".vif"});

4. Will place the get config_db in the build_phase,

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
     if(!uvm_config_db#(virtual mem_if)::get(this, "", "vif", vif))
       `uvm_fatal("NO_VIF",{"virtual interface must be set for: ",get_full_name(),".vif"});
  endfunction: build_phase

5. Add driving logic. get the seq_item and drive to DUT signals,

  // run phase
  virtual task run_phase(uvm_phase phase);
    forever begin
    seq_item_port.get_next_item(req);
     ......
     .. driving logic ..
     ......
    seq_item_port.item_done();
    end
  endtask : run_phase

The uvm driver example

below is the complete drive code.

`define DRIV_IF vif.DRIVER.driver_cb
class mem_driver extends uvm_driver #(mem_seq_item);

  // Virtual Interface
  virtual mem_if vif;

  `uvm_component_utils(mem_driver)
    
  //uvm_analysis_port #(mem_seq_item) Drvr2Sb_port;

  // Constructor
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
     if(!uvm_config_db#(virtual mem_if)::get(this, "", "vif", vif))
       `uvm_fatal("NO_VIF",{"virtual interface must be set for: ",get_full_name(),".vif"});
  endfunction: build_phase

  // run phase
  virtual task run_phase(uvm_phase phase);
    forever begin
    seq_item_port.get_next_item(req);
    //respond_to_transfer(req);
    drive();
    seq_item_port.item_done();
    end
  endtask : run_phase

  // drive 
  virtual task drive();
    req.print();
      `DRIV_IF.wr_en <= 0;
      `DRIV_IF.rd_en <= 0;
      @(posedge vif.DRIVER.clk);
      `DRIV_IF.addr <= req.addr;
    if(req.wr_en) begin
        `DRIV_IF.wr_en <= req.wr_en;
        `DRIV_IF.wdata <= req.wdata;
      //$display("\tADDR = %0h \tWDATA = %0h",req.addr,trans.wdata);
        @(posedge vif.DRIVER.clk);
      end
    if(req.rd_en) begin
        `DRIV_IF.rd_en <= req.rd_en;
        @(posedge vif.DRIVER.clk);
        `DRIV_IF.rd_en <= 0;
        @(posedge vif.DRIVER.clk);
        req.rdata = `DRIV_IF.rdata;
       // $display("\tADDR = %0h \tRDATA = %0h",trans.addr,`DRIV_IF.rdata);
      end
      $display("-----------------------------------------");
  endtask : drive

endclass : mem_driver

❮ Previous Next ❯

UVM Callback in uvm sequence

Callback in uvm_sequence

Callback hooks can be placed in uvm_sequnence. Different flavors of the sequence can be obtained by implementing custom callback methods.

In the previous example’s we have seen callback implementation in uvm_driver. In this section will see how to implement the callback in uvm_sequence.

Callback implementation in uvm_sequence

Callback implementation steps for uvm_sequence are the same as in uvm_driver. Before going through this section, it is required to refer to the UVM callback example.

Below are the testbench components.

callback in uvm_sequence
callback in uvm_sequence

Let’s implement the callback in uvm_sequence to modify the sequence_item before sending it to the driver.

Steps involved are,

  • Write callback class
  • Register the callback class
  • Place the callback hook
  • Implement the callback method
  • Create and register the callback object

Write Callback class

  • Callback class is written by extending the uvm_callback
class mem_callback extends uvm_callback;
   ...
endclass
  • Adding a virtual callback method
class mem_callback extends uvm_callback;
  virtual task update_pkt(ref mem_seq_item pkt); endtask
endclass
  • Complete callback class code
class mem_callback extends uvm_callback;
   
  `uvm_object_utils(mem_callback)
   
  function new(string name = "mem_callback");
    super.new(name);
  endfunction
   
  virtual task update_pkt(ref mem_seq_item pkt); endtask
endclass

Register the callback class

  • The callback class needs to be registered with the component. As the sequence is dynamic, the callback will be registered to a sequencer
  `uvm_register_cb(mem_sequencer,mem_callback)
  • Complete sequencer code
class mem_sequencer extends uvm_sequencer#(mem_seq_item);

  `uvm_component_utils(mem_sequencer) 
  `uvm_register_cb(mem_sequencer,mem_callback)
  
  //---------------------------------------
  //constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name,parent);
  endfunction
  
endclass

Place the callback hook

  • Callback hook is a call to callback method, and in this example, it is required to be placed in the sequence
   `uvm_do_obj_callbacks(mem_sequencer,mem_callback,p_sequencer,update_pkt(req));
  • Complete sequence code
class mem_sequence extends uvm_sequence#(mem_seq_item);
  
  `uvm_object_utils(mem_sequence)

  //--------------------------------------- 
  //Constructor
  //---------------------------------------
  function new(string name = "mem_sequence");
    super.new(name);
  endfunction
  
  `uvm_declare_p_sequencer(mem_sequencer)
  
  //---------------------------------------
  // create, randomize and send the item to driver
  //---------------------------------------
  virtual task body();
    req = mem_seq_item::type_id::create("req");
    wait_for_grant();
    req.randomize();
    `uvm_do_obj_callbacks(mem_sequencer,mem_callback,p_sequencer,update_pkt(req));
    send_request(req);
    wait_for_item_done();
  endtask
endclass

Implement the callback method

The callback will be implemented in the extended callback class.

  • Write user_callback class by extending mem_callback
class user_callback extends mem_callback;
  
  `uvm_object_utils(user_callback)
  
  function new(string name = "user_callback");
    super.new(name);
  endfunction

endclass
  • Implement the update_pkt callback method
    • the update_pkt method is implemented to invert the value of the address.
class user_callback extends mem_callback;
  
  `uvm_object_utils(user_callback)
  
  function new(string name = "user_callback");
    super.new(name);
  endfunction
  
  task update_pkt(ref mem_seq_item pkt);
    `uvm_info("USER_CALLBACK","[update_pkt] before packet modification",UVM_LOW);
    pkt.print();
    pkt.addr = ~pkt.addr;
    `uvm_info("USER_CALLBACK","[update_pkt] after packet modification",UVM_LOW);
    pkt.print();
  endtask
endclass

Create and register the callback object

  • Declare and create the callback
  user_callback callback_1;
  callback_1 = user_callback::type_id::create("callback_1", this);
  • Register the callback object with the component in which callback class is registered
  uvm_callbacks#(mem_sequencer,mem_callback)::add(env.mem_agnt.sequencer,callback_1);
  • Complete user_callback_test code
class user_callback_test extends mem_test;
  user_callback callback_1;
  
  `uvm_component_utils(user_callback_test)
  
  function new(string name = "user_callback_test", uvm_component parent=null);
    super.new(name,parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    callback_1 = user_callback::type_id::create("callback_1", this);
  endfunction
  
  function void end_of_elaboration();
    uvm_callbacks#(mem_sequencer,mem_callback)::add(env.mem_agnt.sequencer,callback_1);
  endfunction : end_of_elaboration
endclass

Simulator Output: (mem_test)

UVM_INFO mem_driver.sv(38) @ 0: uvm_test_top.env.mem_agnt.driver [mem_driver] Recived Drive packet
----------------------------------
Name     Type          Size  Value
----------------------------------
req      mem_seq_item  -     @575
addr   integral      4     'hb
wr_en  integral      1     'h0
rd_en  integral      1     'h1
wdata  integral      8     'h3f
----------------------------------
UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_objection.svh(1270) @ 50: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_report_server.svh(847) @ 50: reporter [UVM/REPORT/SERVER]

Simulator Output: (user_callback_test)

UVM_INFO user_callback.sv(14) @ 0: reporter [USER_CALLBACK] [update_pkt] before packet modification
----------------------------------
Name     Type          Size  Value
----------------------------------
req      mem_seq_item  -     @577
addr   integral      4     'hb
wr_en  integral      1     'h0
rd_en  integral      1     'h1
wdata  integral      8     'h3f
----------------------------------
UVM_INFO user_callback.sv(17) @ 0: reporter [USER_CALLBACK] [update_pkt] after packet modification
----------------------------------
Name     Type          Size  Value
----------------------------------
req      mem_seq_item  -     @577
addr   integral      4     'h4
wr_en  integral      1     'h0
rd_en  integral      1     'h1
wdata  integral      8     'h3f
----------------------------------
UVM_INFO mem_driver.sv(38) @ 0: uvm_test_top.env.mem_agnt.driver [mem_driver] Recived Drive packet
----------------------------------
Name     Type          Size  Value
----------------------------------
req      mem_seq_item  -     @577
addr   integral      4     'h4
wr_en  integral      1     'h0
rd_en  integral      1     'h1
wdata  integral      8     'h3f
----------------------------------
UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_objection.svh(1270) @ 50: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase

 Result Analysis 

From the above simulation result, we can make out that,
user_callback_test is enabling the implemented callback methods.

Click to execute on   

Note:
In Compile & Run Options Provide,
+UVM_TESTNAME=mem_test  to execute mem_test
+UVM_TESTNAME=user_callback_test  to execute user_callback_test
❮ Previous Next ❯

UVM Callback example

Callback Example

Callback to corrupt the stimulus

Let’s consider an example of a Slave Driver (Slave Driver: drives response to the master).

For simplicity, one callback hook is implemented and only response generation logic is captured in the code.

Components of slave_driver example are,

  • slave_driver – Normal driver to drive response
    • response types are OKAY, EXOKAY, SLVERR, DECERR
    • slave_driver is constrained to send OKAY response always to see to the callback usage difference
  • slave_env – Environment which has a slave driver created in it
  • basic_test – Which sends the normal response
  • driver_callback – Callback class
  • slv_err_test  – Testcase with callback used to generate an error response
  • err_error_callback  – extended callback class to implement callback method

By using a callback, will write the testcase to drive the SLVERR response.

For easy understanding will see through below steps,

  • Adding callback support
  • Implementing the callback methods
  • Using callback

Adding Callback Support

In order to have user-defined callbacks,

  • User has to write user-defined callback class by extending the uvm_callback class
class driver_callback extends uvm_callback;
  ...
endclass
  • Define the callback method in user-defined callback class
    • In this example update_resp() is the callback method.
  virtual task update_resp(ref resp_type resp); endtask

Complete user-defined class code

class driver_callback extends uvm_callback;
  
  `uvm_object_utils(driver_callback)
  
  function new(string name = "driver_callback");
    super.new(name);
  endfunction
  
  virtual task update_resp(ref resp_type resp); endtask
endclass

In order to use callbacks defined,

  • Callback class has to be registered with the object/component where callbacks are going to be used.
  • Callback class can be registered by using macro `uvm_register_cb
  `uvm_register_cb(slave_driver,driver_callback)

In order to call the callback methods,

  • Need to place method call’s (callback hook) to methods defined in user-defined callback class (update_resp())
  • Callback methods can be called by using macro `uvm_do_callbacks
  `uvm_do_callbacks(slave_driver,driver_callback,update_resp(resp));

Complete driver code

class slave_driver extends uvm_component;
  resp_type resp;
  
  `uvm_component_utils(slave_driver)
  `uvm_register_cb(slave_driver,driver_callback)
  
  function new(string name, uvm_component parent);
    super.new(name,parent);
  endfunction
  
  task run_phase(uvm_phase phase);
    repeat(2) begin //{
      std::randomize(resp) with { resp == OKAY;};
      `uvm_do_callbacks(slave_driver,driver_callback,update_resp(resp));
      `uvm_info("DRIVER",$sformatf("Generated response is %s",resp.name()),UVM_LOW);
    end //}  
  endtask
  
endclass

Implementing Callback Method

We have looked into, how to define the callback methods (In user-defined callback class) and placing hook to callback methods (In driver class using `uvm_do_callbacks macro)

Here will see how to add logic to callback methods.

  • Need to extend the user-defined callback class and write one more callback class slv_error_callback
class slv_error_callback extends driver_callback;
  ...
endclass
  • Implement the methods with logic in it (this example we are adding only display’s)
  task update_resp(ref resp_type resp);
    resp = SLVERR;
  endtask

Complete callback class code

class slv_error_callback extends driver_callback;
  
  `uvm_object_utils(slv_error_callback)
  
  function new(string name = "slv_error_callback");
    super.new(name);
  endfunction
  
  task update_resp(ref resp_type resp);
    resp = SLVERR;
  endtask
endclass

Using Callback

In the testcase where callbacks need to be applied,

  • Declare and create an object of callback class in which methods are implemented (slv_error_callback).
  slv_error_callback err_callback;
  err_callback = slv_error_callback::type_id::create("err_callback", this);
  • In order to execute the callback method, register the callback object to the driver using the ‘add’ method
  uvm_callbacks#(slave_driver,driver_callback)::add(env.driver,err_callback);

Complete test case code

class slv_err_test extends basic_test;
  slv_error_callback err_callback;
  
  `uvm_component_utils(slv_err_test)
  
  function new(string name = "slv_err_test", uvm_component parent=null);
    super.new(name,parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    err_callback = slv_error_callback::type_id::create("err_callback", this);
    
    uvm_callbacks#(slave_driver,driver_callback)::add(env.driver,err_callback);
  endfunction
endclass

slv_err_test is the test with callbacks added, and basic_test is without callbacks.
basic_test simulator output (Without Callback)

UVM_INFO @ 0: reporter [RNTST] Running test basic_test...
UVM_INFO slave_driver.sv(19) @ 0: uvm_test_top.env.driver [DRIVER] Generated response is OKAY
UVM_INFO slave_driver.sv(19) @ 0: uvm_test_top.env.driver [DRIVER] Generated response is OKAY
UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_report_server.svh(847) @ 0: reporter [UVM/REPORT/SERVER]

Click to execute on   

callback_test simulator output (With Callback)

UVM_INFO @ 0: reporter [RNTST] Running test slv_err_test...
UVM_INFO slave_driver.sv(19) @ 0: uvm_test_top.env.driver [DRIVER] Generated response is SLVERR
UVM_INFO slave_driver.sv(19) @ 0: uvm_test_top.env.driver [DRIVER] Generated response is SLVERR
UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_report_server.svh(847) @ 0: reporter [UVM/REPORT/SERVER]

Click to execute on   
In order to execute the particular testcase, change the inline argument.

  • +UVM_TESTNAME=basic_test
  • +UVM_TESTNAME=slv_err_test

❮ Previous Next ❯

UVM Callback add method

Callback add method

Add method implementation

static function void add(
T obj,
uvm_callback cb,
uvm_apprepend ordering = UVM_APPEND
)
  • Registers the callback object with the object in which callback is used
  • It is allowed to register multiple callbacks derived from the same callback
  • If ordering is UVM_APPEND (default), the callback will be executed after previously added callbacks, else the callback will be executed ahead of previously added callbacks

Using add method

The previous example shows the usage of the add method.

In order to execute the callback method, the Callback object needs to be registered to the object/component.

uvm_callbacks#(T, CB)::add(t,cb);

Multiple add for the same method

To the single callback hook, it is possible to have call to multiple flavors of the same method.
i.e if the same method is implemented in multiple extended classes, then it is possible to register all the methods to the same callback hook.

On calling of `uvm_do_callbacks macro all the callback methods executed in the order which methods are registered.

Example for Multiple flavors of the same method

uvm testbench with callback
uvm testbench with callback

Let’s consider the previous example and implement multiple flavors of the same method.

In the previous example, pre_drive() and post_drive() are callback methods and implemented them in user_callback class.

Now lets implement callback methods in user_callback_1 and user_callback_2 classes by extending driver_callback class.

user_callback_1

Below is user_callback_1 class implemented with displays USER_CALLBACK-1

class user_callback_1 extends driver_callback;
  
  `uvm_object_utils(user_callback_1)
  
  function new(string name = "user_callback_1");
    super.new(name);
  endfunction
  
  task pre_drive;
    `uvm_info("USER_CALLBACK-1","Inside pre_drive method",UVM_LOW);
  endtask
  
  task post_drive;
    `uvm_info("USER_CALLBACK-1","Inside post_drive method",UVM_LOW);
  endtask
endclass

user_callback_2

Below is user_callback_2 class implemented with displays USER_CALLBACK-2

class user_callback_2 extends driver_callback;
  
  `uvm_object_utils(user_callback_2)
  
  function new(string name = "user_callback_2");
    super.new(name);
  endfunction
  
  task pre_drive;
    `uvm_info("USER_CALLBACK-2","Inside pre_drive method",UVM_LOW);
  endtask
  
  task post_drive;
    `uvm_info("USER_CALLBACK-2","Inside post_drive method",UVM_LOW);
  endtask
endclass

Testcase

In the below test case’s user_callback_1 and user_callback_2 are registered using the add method.

user_callback_test

user_callback_1 is registered first and then user_callback_2.

class user_callback_test extends basic_test;
  user_callback_1 callback_1;
  user_callback_2 callback_2;
  
  `uvm_component_utils(user_callback_test)
  
  function new(string name = "user_callback_test", uvm_component parent=null);
    super.new(name,parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    callback_1 = user_callback_1::type_id::create("callback_1", this);
    callback_2 = user_callback_2::type_id::create("callback_2", this);
    
    uvm_callbacks#(driver,driver_callback)::add(env.driv,callback_1);
    uvm_callbacks#(driver,driver_callback)::add(env.driv,callback_2);
  endfunction
endclass

user_callback_2_test

Lets write one more testcase user_callback_2_test, with user_callback_2 is registered first and then user_callback_1.

class user_callback_2_test extends basic_test;
  user_callback_1 callback_1;
  user_callback_2 callback_2;
  
  `uvm_component_utils(user_callback_2_test)
  
  function new(string name = "user_callback_2_test", uvm_component parent=null);
    super.new(name,parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    callback_1 = user_callback_1::type_id::create("callback_1", this);
    callback_2 = user_callback_2::type_id::create("callback_2", this);
    
    uvm_callbacks#(driver,driver_callback)::add(env.driv,callback_2);
    uvm_callbacks#(driver,driver_callback)::add(env.driv,callback_1);
  endfunction
endclass

Simulator Output: (user_callback_test)

UVM_INFO @ 0: reporter [RNTST] Running test user_callback_test...
UVM_INFO user_callback.sv(18) @ 0: reporter [USER_CALLBACK-1] Inside pre_drive method
UVM_INFO user_callback.sv(39) @ 0: reporter [USER_CALLBACK-2] Inside pre_drive method
UVM_INFO slave_driver.sv(23) @ 0: uvm_test_top.env.driver [DRIVER] Inside drive_pkt method
UVM_INFO user_callback.sv(22) @ 0: reporter [USER_CALLBACK-1] Inside post_drive method
UVM_INFO user_callback.sv(43) @ 0: reporter [USER_CALLBACK-2] Inside post_drive method

Simulator Output: (user_callback_2_test)

UVM_INFO @ 0: reporter [RNTST] Running test user_callback_2_test...
UVM_INFO user_callback.sv(39) @ 0: reporter [USER_CALLBACK-2] Inside pre_drive method
UVM_INFO user_callback.sv(18) @ 0: reporter [USER_CALLBACK-1] Inside pre_drive method
UVM_INFO slave_driver.sv(23) @ 0: uvm_test_top.env.driver [DRIVER] Inside drive_pkt method
UVM_INFO user_callback.sv(43) @ 0: reporter [USER_CALLBACK-2] Inside post_drive method
UVM_INFO user_callback.sv(22) @ 0: reporter [USER_CALLBACK-1] Inside post_drive method

Click to execute on   

Form the above simulator output we could see the order of execution of callback methods,

In user_callback_test user_callback_1 method executed first and then user_callback_2 method.
In user_callback_2_test user_callback_2 method executed first and then user_callback_1 method.
❮ Previous Next ❯

UVM Callback

Callbacks

What is Callback?

Callbacks are empty methods with a call to them.

UVM Callback
UVM Callback

Before Starting with UVM Callbacks, It is good to go through  SystemVerilog Callback.

Where callbacks can be implemented?

Callbacks can be implemented in an object or component.

What are the benefits of callback?

Different flavors of the component can be obtained by customizing the empty callback methods.

About UVM Callbacks

UVM provides a set of classes, methods, and macros to implement the callbacks.

Only the required callback methods are explained here.

Callback Example

With a simple driver example will see to UVM Callback.
Below are components of example,

  • Driver
  • Environment
  • Test
uvm testbench without callback
uvm testbench without callback

The driver has drive() task, which revives the seq_item and drives to DUT (Current example code doesn’t have any logic to receive and drive seq_item).

In this example,
With help of callback, will add pre_drive() and post_drive() callbacks.

uvm testbench with callback
uvm testbench with callback

TestBench without callbacks

Driver

class driver extends uvm_component;
  
  `uvm_component_utils(driver)
  
  function new(string name, uvm_component parent);
    super.new(name,parent);
  endfunction
  
  task run_phase(uvm_phase phase); 
      drive_pkt();
  endtask
  
  task drive_pkt();
    `uvm_info("DRIVER","Inside drive_pkt method",UVM_LOW);
  endtask
  
endclass

Environment

class environment extends uvm_env;
  driver driv;
  
  `uvm_component_utils(environment)
  
  function new(string name, uvm_component parent);
    super.new(name,parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    driv = driver::type_id::create("driv", this);
  endfunction
  
endclass

TestCase

class basic_test extends uvm_test;
  environment env;
  
  `uvm_component_utils(basic_test)
  
  function new(string name = "basic_test", uvm_component parent=null);
    super.new(name,parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    env = environment::type_id::create("env", this);
  endfunction
endclass

Simulator Output:

UVM_INFO @ 0: reporter [RNTST] Running test basic_test...
UVM_INFO driver.sv(18) @ 0: uvm_test_top.env.driv [DRIVER] Inside drive_pkt method

Click to execute on   

TestBench with callbacks

For easy understanding will see through below steps,

  • Adding callback support
  • Implementing the callback methods
  • Using callback

Adding Callback Support

In order to have user-defined callbacks,

  • User has to write user-defined callback class by extending the uvm_callback class
class driver_callback extends uvm_callback;
  ...
endclass
  • Define callback methods in user-defined callback class
    • In this example pre_drive() and post_drive() are the callback methods.
  virtual task pre_drive; endtask
  virtual task post_drive; endtask

Complete user-defined class code

class driver_callback extends uvm_callback;
  
  `uvm_object_utils(driver_callback)
  
  function new(string name = "driver_callback");
    super.new(name);
  endfunction
  
  virtual task pre_drive; endtask
  virtual task post_drive; endtask
endclass

In order to use callbacks defined,

  • Callback class has to be registered with the object/component where callbacks are going to be used.
  • Callback class can be registered by using macro `uvm_register_cb
  `uvm_register_cb(driver,driver_callback)

In order to call the callback methods,

  • Need to place method call’s (callback hook) to methods defined in user-defined callback class (pre_drive() and post_drive())
  • Callback methods can be called by using macro `uvm_do_callbacks
  `uvm_do_callbacks(driver,driver_callback,pre_drive());
  `uvm_do_callbacks(driver,driver_callback,post_drive());

Complete driver code

class driver extends uvm_component;
  
  `uvm_component_utils(driver)
  `uvm_register_cb(driver,driver_callback)
  
  function new(string name, uvm_component parent);
    super.new(name,parent);
  endfunction
  
  task run_phase(uvm_phase phase);
      `uvm_do_callbacks(driver,driver_callback,pre_drive());
      
      drive_pkt();
      
      `uvm_do_callbacks(driver,driver_callback,post_drive());
  endtask
  
  task drive_pkt();
    `uvm_info("DRIVER","Inside drive_pkt method",UVM_LOW);
  endtask
  
endclass

Implementing Callback Method

We have looked into, how to define the callback methods (In user-defined callback class) and placing hook to callback methods (In driver class using `uvm_do_callbacks macro)

Here will see how to add logic to callback methods.

  • Need to extend the user-defined callback class and write one more callback class callback_1
class user_callback extends driver_callback;
  ...
endclass
  • Implement the methods with logic in it (this example we are adding only display’s)
  task pre_drive;
    `uvm_info("USER_CALLBACK","Inside pre_drive method",UVM_LOW);
  endtask
  
  task post_drive;
    `uvm_info("USER_CALLBACK","Inside post_drive method",UVM_LOW);
  endtask

Complete callback class code

class user_callback extends driver_callback;
  
  `uvm_object_utils(user_callback)
  
  function new(string name = "user_callback");
    super.new(name);
  endfunction
  
  task pre_drive;
    `uvm_info("USER_CALLBACK","Inside pre_drive method",UVM_LOW);
  endtask
  
  task post_drive;
    `uvm_info("USER_CALLBACK","Inside post_drive method",UVM_LOW);
  endtask
endclass

Using Callback

In the testcase where callbacks need to be applied,

  • Declare and create an object of callback class in which methods are implemented (callback_1).
  user_callback callback_1;
  callback_1 = user_callback::type_id::create("callback_1", this);
  • In order to execute the callback method, register the callback object to the driver using the ‘add’ method
  uvm_callbacks#(driver,driver_callback)::add(env.driv,callback_1);

Complete testcase code

class user_callback_test extends basic_test;
  user_callback callback_1;
  
  `uvm_component_utils(user_callback_test)
  
  function new(string name = "user_callback_test", uvm_component parent=null);
    super.new(name,parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    callback_1 = user_callback::type_id::create("callback_1", this);
    
    uvm_callbacks#(driver,driver_callback)::add(env.driv,callback_1);
  endfunction
endclass

callback_test is the test with callbacks added, and basic_test is without callbacks.
Simulator Output:

UVM_INFO @ 0: reporter [RNTST] Running test basic_test...
UVM_INFO driver.sv(23) @ 0: uvm_test_top.env.driv [DRIVER] Inside drive_pkt method

Click to execute on   

callback_test simulator output (With Callback)

UVM_INFO @ 0: reporter [RNTST] Running test user_callback_test...
UVM_INFO user_callback.sv(14) @ 0: reporter [USER_CALLBACK] Inside pre_drive method
UVM_INFO driver.sv(23) @ 0: uvm_test_top.env.driv [DRIVER] Inside drive_pkt method
UVM_INFO user_callback.sv(18) @ 0: reporter [USER_CALLBACK] Inside post_drive method

Click to execute on   

With the above result, we could see that displays added in callback methods are getting printed in callback_test.

The addition of logic to the callback methods will give more control on stimulus driving.

In the next example will see an example of how driving stimulus can be controlled using callbacks.

Callback Class and Macros

uvm_callback class

user-defined callback classes can be written by extending the uvm_callback class.
In it, the user defines one or more virtual methods.

These virtual methods are referred to as callback methods, these are empty methods with users have the option of overriding them.

  class CB extends uvm_callback;
    ...
  endclass

uvm_register_cb

`uvm_register_cb(T,CB)

This macro is used to register the Callback (CB) with the Object(T).

Where,
CB => user defined callback class.
T  => Object in which CB is used.

w.r.t above example:
CB => driver_callback class
T    => driver class

uvm_do_callbacks

`uvm_do_callbacks(T,CB,METHOD)

This macro calls the callback methods defined in the user-defined callback class.

CB     => user defined callback class.
T        => Object in which CB is used.
METHOD => callback method to be called

w.r.t above example:

CB => driver_callback class
T    => driver class
METHOD => pre_drive and post_drive

add method

uvm_callbacks#(T, CB)::add(t,cb);

Registers the callback object with the object in which callback is used.

CB   => user defined callback class type.
T      => Object type in which CB is used.
cb     => callback class object
t        => object in which callback is used

w.r.t above example:

CB => driver_callback class
T   => driver class
cb  => callback_1
t     => driver class (differs if multiple objects of same type present)
❮ Previous Next ❯

uvm event callback examples

uvm_event_callback examples

This section provides examples of,

  • Registering two callbacks to the same event
  • Disable the event trigger from pre_trigger
  • Registering callbacks to the event in a test case

Registering two callbacks to the same event

This example is a continuation of the previous example, in this example two callbacks event_callback_0 and event_callback_1 is registered to the same event ev_ab.

//Declaring the event callback classes
event_callback_0 ev_cb_0;
event_callback_1 ev_cb_1;

//Creating the objects
ev_cb_0 = new("ev_cb_0");
ev_cb_1 = new("ev_cb_1");

//Registering callbacks with an event ev
ev.add_callback(ev_cb_0);
ev.add_callback(ev_cb_1);

Complete comp_a code

class component_a extends uvm_component; 
  
  `uvm_component_utils(component_a)
  
  uvm_event        ev;
  event_callback_0 ev_cb_0;
  event_callback_1 ev_cb_1;
  
  //--------------------------------------- 
  // Constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

  //---------------------------------------
  // run_phase 
  //---------------------------------------
  virtual task run_phase(uvm_phase phase);
    phase.raise_objection(this);
    ev_cb_0 = new("ev_cb_0");
    ev_cb_1 = new("ev_cb_1");
    
    ev = uvm_event_pool::get_global("ev_ab");
    ev.add_callback(ev_cb_0);
    ev.add_callback(ev_cb_1);
    
    `uvm_info(get_type_name(),$sformatf(" Before triggering the event"),UVM_LOW)
    #10;
    
    ev.trigger();
    
    `uvm_info(get_type_name(),$sformatf(" After triggering the event"),UVM_LOW)

    phase.drop_objection(this);
  endtask : run_phase

endclass : component_a

Simulator Output

UVM_INFO @ 0: reporter [RNTST] Running test basic_test...
--------------------------------------
Name Type Size Value
--------------------------------------
uvm_test_top basic_test - @335 
 comp_a component_a - @348 
 comp_b component_b - @357 
--------------------------------------
UVM_INFO component_a.sv(32) @ 0: uvm_test_top.comp_a [component_a] Before triggering the event
UVM_INFO component_b.sv(26) @ 0: uvm_test_top.comp_b [component_b] waiting for the event trigger
UVM_INFO event_callback_0.sv(17) @ 10: reporter [event_callback_0] [Callback-0] Inside event pre_trigger callback
UVM_INFO event_callback_1.sv(17) @ 10: reporter [event_callback_1] [Callback-1] Inside event pre_trigger callback
UVM_INFO event_callback_0.sv(24) @ 10: reporter [event_callback_0] [Callback-0] Inside event post_trigger callback
UVM_INFO event_callback_1.sv(24) @ 10: reporter [event_callback_1] [Callback-1] Inside event post_trigger callback
UVM_INFO component_a.sv(37) @ 10: uvm_test_top.comp_a [component_a] After triggering the event
UVM_INFO component_b.sv(30) @ 10: uvm_test_top.comp_b [component_b] event got triggerd
UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_objection.svh(1270) @ 10: reporter [TEST_DONE] 
UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_report_server.svh(847) @ 10: reporter [UVM/REPORT/SERVER]

Click to execute on   

Disable the event trigger from pre_trigger

In this example, the pre_trigger method returns the value ‘1’, which will lead to disabling event_trigger. which leads to comp_b keep waiting for the event trigger.

pre_trigger method code

  virtual function bit pre_trigger(uvm_event e,uvm_object data);
    `uvm_info(get_type_name(),$sformatf(" [Callback] Inside event pre_trigger callback"),UVM_LOW)
    return 1;
  endfunction

Simulator Output

UVM_INFO @ 0: reporter [RNTST] Running test basic_test...
--------------------------------------
Name Type Size Value
--------------------------------------
uvm_test_top basic_test - @335 
 comp_a component_a - @348 
 comp_b component_b - @357 
--------------------------------------
UVM_INFO component_a.sv(29) @ 0: uvm_test_top.comp_a [component_a] Before triggering the event
UVM_INFO component_b.sv(26) @ 0: uvm_test_top.comp_b [component_b] waiting for the event trigger
UVM_INFO event_callback.sv(17) @ 10: reporter [event_callback] [Callback] Inside event pre_trigger callback
UVM_INFO component_a.sv(34) @ 10: uvm_test_top.comp_a [component_a] After triggering the event
UVM_FATAL /apps/vcsmx/etc/uvm-1.2/src/base/uvm_phase.svh(1489) @ 9200000000000: reporter [PH_TIMEOUT] 
Default timeout of 9200000000000 hit, indicating a probable testbench issue
UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_report_server.svh(847) @ 9200000000000: reporter [UVM/REPORT/SERVER]

Click to execute on   

Registering callbacks to the event in a test case

This example is a modification of the previous examples. In the previous examples, the event callback creation and registering with the event was done in the comp_a.

But in realtime use cases, it is required to create and register to an event from the test case, this example shows the registering callbacks to the event in a test case.

test case code

class basic_test extends uvm_test;

  `uvm_component_utils(basic_test)

  event_callback ev_cb; //Step-1: Declaring the event callback
  uvm_event      ev;
   
  //---------------------------------------
  // Components Instantiation
  //---------------------------------------
  component_a comp_a;
  component_b comp_b;

  //---------------------------------------
  // Constructor
  //---------------------------------------
  function new(string name = "basic_test",uvm_component parent=null);
    super.new(name,parent);
  endfunction : new

  //---------------------------------------
  // build_phase
  //---------------------------------------
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);

    comp_a = component_a::type_id::create("comp_a", this);
    comp_b = component_b::type_id::create("comp_b", this);
    
    //Step-2. Creating the event callback
    ev_cb = new("ev_cb");
    
    ev = uvm_event_pool::get_global("ev_ab");

    //Step-3. Registering callback with event
    ev.add_callback(ev_cb);
  endfunction : build_phase
  
  //---------------------------------------
  // end_of_elobaration phase
  //---------------------------------------  
  virtual function void end_of_elaboration();
    //print's the topology
    print();
  endfunction
endclass : basic_test

Simulator Output

UVM_INFO @ 0: reporter [RNTST] Running test basic_test...
--------------------------------------
Name Type Size Value
--------------------------------------
uvm_test_top basic_test - @335 
 comp_a component_a - @348 
 comp_b component_b - @357 
--------------------------------------
UVM_INFO component_a.sv(26) @ 0: uvm_test_top.comp_a [component_a] Before triggering the event
UVM_INFO component_b.sv(26) @ 0: uvm_test_top.comp_b [component_b] waiting for the event trigger
UVM_INFO event_callback.sv(17) @ 10: reporter [event_callback] [Callback] Inside event pre_trigger callback
UVM_INFO event_callback.sv(24) @ 10: reporter [event_callback] [Callback] Inside event post_trigger callback
UVM_INFO component_a.sv(31) @ 10: uvm_test_top.comp_a [component_a] After triggering the event
UVM_INFO component_b.sv(30) @ 10: uvm_test_top.comp_b [component_b] event got triggerd
UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_objection.svh(1270) @ 10: reporter [TEST_DONE] 
UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_report_server.svh(847) @ 10: reporter [UVM/REPORT/SERVER]

Click to execute on   

❮ Previous Next ❯

uvm event callback

uvm_event_callback

UVM provides the facility to add callbacks to a uvm_event trigger. The pre_trigger and post_trigger are the callback hooks placed with the event trigger method. for more on uvm callback refer to uvm_callback.

  • User can write user-defined callback class by extending the uvm_event_callback
  • User can override any or both pre_trigger and post_trigger methods in user-defined callback class
  • uvm_event method add_callback is used to register the callback with event

uvm event callbacks are an alternative to using processes that wait on events. When a callback is
attached to an event, the attached callback function/s is called each time the event is triggered.

Writing user-defined callback,

class user_defined_callback extends uvm_event_callback;
    
  --- 

endclass 

uvm_event_callback methods

new

Creates a new callback object.

pre_trigger

virtual function bit pre_trigger (
  uvm_event#(T) e,
  T data )

// e is the uvm_event#(T) that is being triggered
// data is the data associated with the event trigger
  • This will get called just before triggering the associated event
  • In extended class, the user can override this method in a derived class to implement any pre-trigger functionality
  • This method returns bit type
  • If the method returns 1, the event will not trigger and the post-trigger callback is not called. This provides a way for a callback to prevent the event from triggering

post_trigger

virtual function void post_trigger (
  uvm_event#(T) e,
  T data )

// e is the uvm_event#(T) that is being triggered
// data is the data associated with the event trigger
  • This will get called after triggering the associated event
  • In extended class, the user can  override this method to implement any post-trigger functionality

uvm event callback examples

In the below example,

  • comp_a, comp_b, and a user-defined callback class event_callback
  • comp_a and comp_b will get the event ev_ab from the uvm event pool
  • pre_trigger and post_trigger methods are implemented in the event_callback class
  • In the comp_a event_callback object is created with the name ev_cb
  • uvm_event add_callback method is used to register the callback with an event (ev.add_callback(ev_cb);)
  • On calling event.trigger pre_trigger and post_trigger methods will get called

Writing user-defined event callback class

class event_callback extends uvm_event_callback;
   
  `uvm_object_utils(event_callback)
   
  function new(string name = "event_callback");
    super.new(name);
  endfunction

  //---------------------------------------
  // pre trigger method
  //---------------------------------------
  virtual function bit pre_trigger(uvm_event e,uvm_object data);
    `uvm_info(get_type_name(),$sformatf(" [Callback] Inside event pre_trigger callback"),UVM_LOW)
  endfunction
  
  //---------------------------------------
  // post trigger method
  //---------------------------------------
  virtual function void post_trigger(uvm_event e,uvm_object data);
    `uvm_info(get_type_name(),$sformatf(" [Callback] Inside event post_trigger callback"),UVM_LOW)
  endfunction

endclass

Creating a callback object and registering with the event

//Declaring the event callback class
event_callback ev_cb;

//Creating object
ev_cb = new("ev_cb");

//Registering callback with an event ev
ev.add_callback(ev_cb);

Complete comp_a code

class component_a extends uvm_component; 
  
  `uvm_component_utils(component_a)
  
  uvm_event      ev;
  event_callback ev_cb;
  
  //--------------------------------------- 
  // Constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

  //---------------------------------------
  // run_phase 
  //---------------------------------------
  virtual task run_phase(uvm_phase phase);
    phase.raise_objection(this);
    ev_cb = new("ev_cb");
    
    ev = uvm_event_pool::get_global("ev_ab");
    ev.add_callback(ev_cb);
    
    `uvm_info(get_type_name(),$sformatf(" Before triggering the event"),UVM_LOW)
    #10;
    
    ev.trigger();
    
    `uvm_info(get_type_name(),$sformatf(" After triggering the event"),UVM_LOW)

    phase.drop_objection(this);
  endtask : run_phase

endclass : component_a

Simulator Output

UVM_INFO @ 0: reporter [RNTST] Running test basic_test...
--------------------------------------
Name Type Size Value
--------------------------------------
uvm_test_top basic_test - @335 
 comp_a component_a - @348 
 comp_b component_b - @357 
--------------------------------------
UVM_INFO component_a.sv(29) @ 0: uvm_test_top.comp_a [component_a] Before triggering the event
UVM_INFO component_b.sv(26) @ 0: uvm_test_top.comp_b [component_b] waiting for the event trigger
UVM_INFO event_callback.sv(17) @ 10: reporter [event_callback] [Callback] Inside event pre_trigger callback
UVM_INFO event_callback.sv(24) @ 10: reporter [event_callback] [Callback] Inside event post_trigger callback
UVM_INFO component_a.sv(34) @ 10: uvm_test_top.comp_a [component_a] After triggering the event
UVM_INFO component_b.sv(30) @ 10: uvm_test_top.comp_b [component_b] event got triggerd
UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_objection.svh(1270) @ 10: reporter [TEST_DONE]
UVM_INFO /apps/vcsmx/etc/uvm-1.2/src/base/uvm_report_server.svh(847) @ 10: reporter [UVM/REPORT/SERVER]

Click to execute on   

❮ Previous Next ❯

array of uvm event

uvm_event array

This section shows declaring the uvm_event with,

  • Fixed size array of uvm_event
  • A dynamic array of uvm_event
  • An associative array of uvm_event

Fixed size array of uvm_event

In the below example uvm_event is declared as a fixed size array with size 2.

There are four threads, two of which trigger the events and the other two will wait for the trigger.

module uvm_events_ex;
  uvm_event ev[2]; //declaring uvm_event ev_1
  
  initial begin
    foreach(ev[i]) ev[i] = new(); //Creating the event
    
    fork
      //------------------ ev[0] --------------------------
      //process-1, triggers the event
      begin
        #40;
        $display($time," [ev-0] Triggering the Event");
        ev[0].trigger;
      end
      
      //process-2, wait for the event to trigger
      begin
        $display($time," [ev-0] Waiting for the Event to trigger");
        ev[0].wait_trigger;
        $display($time," [ev-0] Event triggered");
      end
      //----------------------------------------------------
      
      //------------------ ev[1] --------------------------
      //process-1, triggers the event
      begin
        #50;
        $display($time," [ev-1] Triggering the Event");
        ev[1].trigger;
      end
      
      //process-2, wait for the event to trigger
      begin
        $display($time," [ev-1] Waiting for the Event to trigger");
        ev[1].wait_trigger;
        $display($time," [ev-1] Event triggered");
      end
      //----------------------------------------------------
    join
  end
endmodule

Simulator Output

0 [ev-0] Waiting for the Event to trigger
0 [ev-1] Waiting for the Event to trigger
40 [ev-0] Triggering the Event
40 [ev-0] Event triggered
50 [ev-1] Triggering the Event
50 [ev-1] Event triggered

Click to execute on   

A dynamic array of uvm_event

In the below example uvm_event is declared as a dynamic array and created the size 2.

There are four threads, two of which trigger the events and the other two will wait for the trigger.

module uvm_events_ex;
  uvm_event ev[]; 
  
  initial begin
    ev = new[2];
    
    foreach(ev[i]) ev[i] = new(); //Creating the event
    
    fork
      //------------------ ev[0] --------------------------
      //process-1, triggers the event
      begin
        #40;
        $display($time," [ev-0] Triggering the Event");
        ev[0].trigger;
      end
      
      //process-2, wait for the event to trigger
      begin
        $display($time," [ev-0] Waiting for the Event to trigger");
        ev[0].wait_trigger;
        $display($time," [ev-0] Event triggered");
      end
      //----------------------------------------------------
      
      //------------------ ev[1] --------------------------
      //process-1, triggers the event
      begin
        #50;
        $display($time," [ev-1] Triggering the Event");
        ev[1].trigger;
      end
      
      //process-2, wait for the event to trigger
      begin
        $display($time," [ev-1] Waiting for the Event to trigger");
        ev[1].wait_trigger;
        $display($time," [ev-1] Event triggered");
      end
      //----------------------------------------------------
    join
  end
endmodule

Simulator Output

0 [ev-0] Waiting for the Event to trigger
0 [ev-1] Waiting for the Event to trigger
40 [ev-0] Triggering the Event
40 [ev-0] Event triggered
50 [ev-1] Triggering the Event
50 [ev-1] Event triggered

Click to execute on   

An associative array of uvm_event

In the below example uvm_event is declared as an associative array with the type string.

There are four threads, two of which trigger the events and the other two will wait for the trigger.

module uvm_events_ex;
  uvm_event ev[string]; 
  
  initial begin
    
    ev["ev_1"] = new(); //Creating the event
    ev["ev_2"] = new();
    
    fork
      //------------------ ev[ev_1] --------------------------
      //process-1, triggers the event
      begin
        #40;
        $display($time," [ev_1] Triggering the Event");
        ev["ev_1"].trigger;
      end
      
      //process-2, wait for the event to trigger
      begin
        $display($time," [ev_1] Waiting for the Event to trigger");
        ev["ev_1"].wait_trigger;
        $display($time," [ev_1] Event triggered");
      end
      //----------------------------------------------------
      
      //------------------ ev[ev_2] --------------------------
      //process-1, triggers the event
      begin
        #50;
        $display($time," [ev-2] Triggering the Event");
        ev["ev_2"].trigger;
      end
      
      //process-2, wait for the event to trigger
      begin
        $display($time," [ev-2] Waiting for the Event to trigger");
        ev["ev_2"].wait_trigger;
        $display($time," [ev-2] Event triggered");
      end
      //----------------------------------------------------
    join
  end
endmodule

Simulator Output

0 [ev_1] Waiting for the Event to trigger
0 [ev-2] Waiting for the Event to trigger
40 [ev_1] Triggering the Event
40 [ev_1] Event triggered
50 [ev-2] Triggering the Event
50 [ev-2] Event triggered

Click to execute on   

❮ Previous Next ❯