I am a Verification Engineer at Cadence Design System. I started the Verification blog to store solutions to small (and big) problems I've faced in my day to day work. I want to share them with the community in the hope that they may be useful to someone else.
The uvm_event#(type T = uvm_object) class is an extension of the abstract uvm_event_base class. The optional parameter T allows the user to define a data type which can be passed during an event trigger. uvm_event class is an abstract wrapper class around SystemVerilog event construct.
It provides additional services such as over traditional SystemVerilog event like,
1) pass data when event is triggered,
A traditional Systemverilog event does not have functionality to pass data when event is triggered. While uvm_event adds this functionality. So, you can pass the transaction class handle when some event is triggered.
By calling trigger task we can trigger the event and optionally give the data which we want to pass using uvm_event.
By calling wait_trigger()/wait_ptrigger() task of uvm_event we can wait for event to be trigger and then by calling get_trigger_data() function we can get data.
or we can directly use only one task wait_trigger_data()/wait_ptrigger_data() of uvm_event to wait for event to be triggered and to get the data.
2) setting callbacks,
We can also add callbacks whenever an event is triggered. This is done by registering a callback class with particular event.
3) maintaining the number of waiters,
We can get the number of processes waiting on the event (using get_num_waiters() function).
4) maintaining the time when event was triggered,
We can get the time that this event was last triggered (using get_trigger_time() function)
Like SystemVerilog event has trigger (@event) and persistent trigger (wait(event.triggered)) mode, uvm_event also has trigger (wait_trigger task) and persistent trigger (wait_ptrigger task).
Let's go through below example and see how we can transfer data using uvm_event and how we can disable uvm_event from triggering using callbacks of uvm_event.
As shown in above code, one uvm_event named PKT_TX_CMPLT_EV is taken in driver.
In build phase of driver we get global handle of event pool using static method get_event_pool of uvm_event_pool class.
Then PKT_TX_CMPLT_EV is added into associative array of uvm_event_pool using get/add method of uvm_event_pool. Note that here PKT_TX_CMPLT_EV event is added in associative array of uvm_event_pool using key (in string format) DRV_EVENT.
In run phase of driver when stimulus is driven, trigger method of uvm_event is called and transaction class is passed in argument of trigger method.
uvm_event also provides facility of callback when event is triggered.
In code my_event_callback (callback for uvm_event) class which extended from uvm_event_callback.
uvm_event_callback provides two hookups, 1) pre_trigger, 2) post_trigger.
Called just before triggering the associated event. If this function returns 1, then the event will not trigger and the post-trigger callback is not called.
Through uvm_event we can pass data(transaction class) when event is triggered, then why do we need TLM/Analysis ports in UVM?
If event is triggered again before receiver gets the data then data will be overwritten.