Synchronous communication (event) - UVM

Posted by homer.favenir on Sun, 16 Jan 2022 09:13:21 +0100

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

FUNCTIONexplain
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

functionexplain
static function this_type get_global_poolReturns 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.

Topics: uvm