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.
A sequencer can be written by extending the uvm_sequencer parameterized with the seq_item type.
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
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.
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.
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
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
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.
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
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
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.
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)
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
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
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. ❮ PreviousNext ❯
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)
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
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]
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
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
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
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
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
We use cookies to ensure that we give you the best experience on our website. If you continue to use this site we will assume that you are happy with it.Ok