1, event
1.1 differences between event in UVM and event in SV
The difference between event in UVM and event in SV is that the same object is mainly IPC in SV. UVM is not limited to one object. In order to solve the synchronization problem of different component threads, it also needs to maintain the closure of UVM. Therefore, it establishes new synchronous communication means (uvm_event, uvm_event_pool and uvm_event_callback)
- ->Trigger: 1) trigger method: after event is triggered by - > trigger, trigger the object @ waiting for the event; uvm_event is triggered by trigger(), and wait is used for triggering_ trigger() is the object waiting for the event. 2) Wait for the event to trigger again. Event only needs to be triggered again with - > uvm_event needs to reset the initial state through reset() method, and then trigger with trigger()
- Information carrying: event cannot carry information. uvm_event can write the data objects accompanying the trigger into the trigger event through trigger(T data = null), and the objects waiting for the event can use the wait method_ trigger_ Data (output t data) to obtain the data object written when the event is triggered;
- The callback function event cannot be triggered directly, UVM_ Event can be added_ Callback (uvm_event_callback CB bit append B = 1) function adds a callback function;
- Get the number of waiting processes event cannot be obtained directly, uvm_event can be accessed through get_num_waiters() to get the number of processes waiting for it;
Event can be regarded as a singleton pattern, and different components can share a uvm_event, which does not need to pass UVM across the hierarchy_ Event handle to realize sharing, which is not in line with the principle of component closure of UVM. It is through uvm_event_pool this global resource pool to share object handles.
1.2 uvm_event class
FUNCTION | explain |
---|---|
virtual function viod trigger( T data = null) | Trigger event to reset all waiting processes. Data objects can be attached |
virtual task wait_trigger() | Wait for a new event to trigger |
virtual task wait_ptrigger() | Wait event triggered |
virtual function T wait_trigger_data() | Returns the data of the last trigger |
virtual task wait_trigger_data(ouput T data) | Wait for the event to trigger and return data |
virtual task wait_ptrigger_data(ouput T data) | Wait for the event to trigger and return data |
virtual task wait_on(bit delta = 0) | Wait for the first activation of the event |
virtual task wait_off(bit delta = 0) | If the event has been triggered to the on state, wait to be reset to the off state |
virtual function bit is_on() | Is the event currently on |
virtual function bit is_off() | Is the event currently off |
virtual function time get_trigger_time() | The time when the event was last triggered. If it was not triggered or reset, 0 is returned |
virtual function int get_num_waiters() | Number of waiting processes |
1.3 wait_trigger and wait_ The difference between ptrigger
//=============wait_trigger======== virtual task wait_trigger(); num_waiters++; @m_event; endtask //=============wait_ptrigger======== virtual task wait_ptrigger(); if(m_event.triggered) return; num_waiters++; @m_event; endtask
- event about SV , if the trigger occurs before @ then @ cannot be detected, which requires @ to wait in advance all the time. If it is not captured, it will be blocked all the time. In the case of trigger, the whole timeslot can detect. The trigger attribute is a way to query whether the event has been triggered, rather than just checking the current time. The thread only waits for the result, not blocking at @ all;
- If @ m_event and - > m_event occurs at the same time or before, wait_trigger can't wait for event Here SV has an additional m_event.triggered can be implemented. In this time slot, as long as the trigger passes, the following statements will be executed;
- wait_ptrigger is executed as long as it has been triggered;
- wait_trigger needs a new event to trigger the next execution;
1.4 wait_trigger code example
module uvm_events_ex; //declaring uvm_event ev_1 uvm_event ev_1; initial begin //Creating an event ev_1 = new(); fork //process-1, triggers the event begin #40; $display($time," Triggering The Event"); ev_1.trigger; end //process-2, wait for the event to trigger begin $display($time," Waiting for the Event to trigger"); ev_1.wait_on; $display($time," Event is on"); #100; $display($time," Event is on"); end join end endmodule
result
0 Waiting for the Event to trigger 40 Triggering The Event 40 Event is on 140 Event is on
2, uvm_pool
uvm_ The definition of pool includes key value pairs, index key and value T. it is a shared resource pool to communicate with other component s or object s. Here, it is a bit like the associative array in SV.
class uvm_pool#(type KEY = int,T = uvm_void)extends uvm_object;00000
2.1 uvm_pool function
function | explain |
---|---|
static function this_type get_global_pool | Returns or creates an instance that allows items to be shared across component s in the authentication environment |
static function T get_global(KEY key) | Return the T value according to the key. If it does not exist, it will be created on the first call |
virtual function T get(KEY key) | Return the T value according to the key. If the key does not exist, return the default value of T type |
virtual function void add(KEY key,T item) | Add element, overwrite if present |
virtual function int num() | Returns the number of elements |
virtual function void delete(KEY key) | Delete the key index and the corresponding T value |
virtual function int exists(KEY key) | Judge whether there is a key value index. If it exists, it is 1 and if it does not exist, it is 0 |
2.2 uvm_pool instance
If it is between two components, you can use config_db mechanism. If it is a component and an object, it can be passed through event_pool for communication and interaction
//===================component===================== class apb_driver extends uvm_driver#(apb_trans); `uvm_component_utils(apb_driver) virtual apb_interface vif; uvm_pool#(string,int)drv_pool;//1. Establish uvm_pool resource pool virtual protected task run_phase(uvm_phase phase); super.run_phase(phase); //event_pool drv_pool = drv_pool.get_global_pool();//2. Create an instance and share the item drv_pool.add("aa",10);//3. Add element to resource pool drv_pool.add("bb",11); endtask ... endclass //=================object============================ class vseq_0 extends base_v_sequence; uvm_pool#(string,int)seq_pool;1. Establish uvm_pool resource pool virtual task body(); string s_key; #200; seq_pool = seq_pool.get_global_pool();//2. Create an instance and share the item `uvm_info("seq",$sformatf("seq_pool.aa = %d",seq_pool.get("aa")),UVM_LOW);//3. Get elements from resource pool `uvm_info("seq",$sformatf("seq_pool.cc = %d",seq_pool.get("cc")),UVM_LOW); `uvm_info("seq",$sformatf("seq_pool.bb.exites = %d",seq_pool.exites("bb")),UVM_LOW); `uvm_info("seq",$sformatf("seq_pool.dd.exites = %d",seq_pool.exites("dd")),UVM_LOW); `uvm_info("seq",$sformatf("seq_pool.num = %d",seq_pool.num()),UVM_LOW); seq_pool.delete("bb"); seq_pool.add("cc",12); seq_pool.add("dd",13); `uvm_info("seq",$sformatf("seq_pool.cc = %d",seq_pool.get("cc")),UVM_LOW); seq_pool.first(s_key); `uvm_info("seq",$sformatf("seq_pool.first_key = %s",s_key),UVM_LOW); seq_pool.last(s_key); `uvm_info("seq",$sformatf("seq_pool.last_key = %s",s_key),UVM_LOW); s_key = "aa"; seq_pool.next(s_key); `uvm_info("seq",$sformatf("seq_pool.next_key = %s",s_key),UVM_LOW); endtask ... endclass
- 1. Establish uvm_pool resource pool
- 2. Create an instance and share the item
- 3. Add / get element to resource pool
- There is no cc, and then a cc is created, but its value is 0;
- The whole is like a queue
2.3 uvm_object_string_pool
class uvm_object_string_pool#(type T = uvm_object)extends uvm_pool#(string,T);
Used to manage uvm_barrier and uvm_event object, the first parameter is string, which is extended uvm_barrier and uvm_event, their keys are all strings, but value is other types that can be specified;
2, uvm_event_pool
//============component==== class apb_monitor extends uvm_monitor; `uvm_component_utils(apb_monitor) virtual apb_interface vif; uvm_analysis_port#(apb_trans) apb_mon_port; uvm_event mon_tr_e; uvm_event_pool event_pool; apb_trans tr; virtual task run_phase(uvm_phase phase); super.run_phase(phase); event_pool = uvm_event_pool::get_global_pool(); mon_tr_e = event_pool.get("mon_tr_e"); tr = new(); tr.addr = 3; #10; mon_tr_e.trigger(tr); ... //================object========= class vseq_1 extends base_v_sequence; uvm_event_pool event_pool; uvm_event mon_tr_e; virtual task body(); apb_trans tr; uvm_object obj; //The first method event_pool =uvm_event_pool::get_global_pool(); mon_tr_e = event_pool.get("mon_tr_e");//Return event mon_tr_e.wait_ptrigger_data(obj);//trigger sends a tr at the same time $cast(tr,obj);//After conversion after acceptance `uvm_info("seq",$sformatf("tr.addr = %d",tr.addr),UVM_LOW); //The second method uvm_event e; e = uvm_event_pool::get_global("mon_tr_e"); ...
-
In order to realize the communication between component and object, UVM_ event_ Communicate with pool;
-
get_global_pool+get=get_global, the two plus implement the same function, so there are two methods to implement the shared event_pool and return event functions;
-
The first method is to see if it is created. Both monitor and sequence get_ event_ The action of pool, but we don't know who comes first and who comes later. Mon on both sides_ tr_ e. The same string is indexed on both sides, and mon is returned_ tr_ Handle to E. Will return a uvm_event. At #10 time, the monitor will be on the monitor_ tr_ E will trigger and send an APB at the same time_ Tr of type trans, and then wait in the sequence_ ptrigger_ Data (obj), the trigger waiting for the #10 moment, and the uvm_object type variable obj. However, the type of TR is different from that of obj, and APB cannot be used_ Trans to accept this tr type. Here, UVM is used_ The object type is obj to accept it, but APB is required_ Trans type $cast is converted to tr type. This is because of wait_ptrigger_data(obj), which is specified. You must use the object type to receive it, so if you need to send it directly, there will be an error.