uvm_event

106 篇文章 11 订阅

在sv中达成同步的方式有 event, semaphore和mailbox。还有uvm_barrier
而在UVM中event进化成uvm_event,不仅仅拥有达成不同组件进程之间同步的功能,还能像TLM通信一样传递数据,并且作用范围更广(TLM通信只能在uvm_component之间,而uvm_event不限于此)。

  • uvm_event 是uvm_event_base的子类;
  • wait_trigger是uvm_event_base的方法;
  • 通过uvm_event对象的方法trigget () 和wait_trigger ()达成同步
  • event是sv的数据类型;
    在这里插入图片描述

uvm_event_pool

uvm_event_pool是一个参数为uvm_event类型的uvm_object_string_pool,而uvm_object_string_pool又是继承于uvm_pool。uvm_event_pool和uvm_pool没有太大差别,也不是很复杂,在这里不是重点。
UVM : uvm_event, uvm_event_pool

module test
  import uvm_pkg::*;
  
  initial begin
    // get a reference to the global singleton object by 
    // calling a static method
    uvm_event_pool ev_pool = uvm_event_pool::get_global_pool();

    // either create a uvm_event or return a reference to it
    // (which depends on the order of execution of the two
    //  initial blocks - the first call creates the event,
    //  the second and subsequent calls return a reference to
    //  an existing event.)
    uvm_event ev = ev_pool.get("ev"); //调用get()方法得到一个uvm_event对象的的句柄
    
    // wait (an arbitrary) 10 and then trigger the event
    #10 ev.trigger();
    $display("%t: event ev triggered", $time);
  end
  
  initial begin
    // get a reference to the global singleton object by 
    // calling a static method
    uvm_event_pool ev_pool = uvm_event_pool::get_global_pool();

    // either create a uvm_event or return a reference to it
    uvm_event ev = ev_pool.get("ev");
    
    // wait for the trigger
    ev.wait_trigger();
    $display("%t: event ev trigger received", $time);
  end

endmodule
  • 调用get_global_pool()会返回一个类型为uvm_event_pool的句柄,句柄指向的对象是全局并且单例的。也就是说两个initial块中两次调用get_global_pool都是返回同一个uvm_event_pool类型对象的句柄,只是先调用的那个get_global_pool函数会创建这个对象。
  • 两个initial块两次调用get(),是为了获得同一个pool[string]对象的句柄,先调用的那个get()会创建这个pool[string],而后调用的那个只是获得这个pool[string]对象的句柄。这个过程和systemverilog中event的传递是一样的,是在两个进程中完成同步的基础。
  • event无法携带更多的信息,而uvm_event可以通过trigger(uvm_event data = null)的可选参数,将所要伴随触发的数据信息都写入到该触发事件中,而等待该事件的对象可以通过方法wait_trigger_data(output uvm_object data)来获取事件触发时写入的数据对象。这实际上是一个句柄的传递,句柄的类型是uvm_object,也就是说传递的对象句柄得是uvm_object类型的。那如何传递非uvm_object类型的对象呢,首先这个对象必须是uvm_object的子类或者子类的子类,然后才能将其句柄作为trigger()方法的参数,然后wait_trigger ()的参数必须是uvm_object类型的,可以用一个uvm_object类型的tmp作为参数传递句柄,然后使用$cast赋值给目标类型句柄。参考
  • get_global (string key)中集合了get_global_pool()和 get()方法,于是下面两部可以合成一句话,
  • 都是在uvm_event_pool::m_global_pool这个静态全局单例中的创建了一个uvm_event对象,并存放在关联数组uvm_event_pool::m_global_pool.pool[string]中,索引就是get or get_global ()的参数, 如果这个字符串索引已经存在,那么就返回这个pool[string]句柄。
  • uvm_event/sv mailbox/config_db/tlm 使用场景有啥区别 都能传东西;
  • uvm_tlm_fifo 就是基于mailbox来实现的;而不同的地方在于uvm_tlm_fifo提供了各种端口供用户使用;
class edata extends uvm_object;      //--创建trigger()触发时传递的数据信息
   int data;
   `uvm_component_utils(edata)
   ...
endclass

calss ecb extends uvm_event_callback;     //--创建add_callback()添加的回调函数
   ...
   function bit pre_trigger(uvm_event e,uvm_object data=null);
      `uvm_info("EPRETRIG",$sformatf("before trigger event %s",e.get_name()),UVM_LOW)
      return  0;
   endfunction
   function void post_trigger(uvm_event e,uvm_object data=null);
      `uvm_info("EPRETRIG",$sformatf("after trigger event %s",e.get_name()),UVM_LOW)
   endfunction   
endclass

class comp1 extends uvm_component;       //组件comp1
   ...
   uvm_event  e1;                                   //**1.声明事件变量(句柄)**
   function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      e1 = uvm_event_pool::get_global("e1");       //**2.在资源池中创建一个共享事件e1,并赋值给本地事件e1** 
   endfunction
   task run_phase(uvm_phase phase);
      edata  d = new();      //实例化数据包
      ecb  cb = new();       //实例化回调函数类
      d.data = 100;
      #10ns;
      e1.add_callback(cb);                    //**3.通过add_callback()调用回调类中的回调函数**
      e1.trigger(d);                        //**4.触发事件,同时将数据包对象d传递给等待事件**
      `uvm_info("ETRIG",$sformatf("trigger sync event at %t ps",$time),UVM_LOW)
   endtask
endclass

class comp2 extends uvm_component;       //组件comp1
   ...
   uvm_event  e1;       //1.声明事件变量(句柄)
   function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      e1 = uvm_event_pool::get_global("e1");       //2.在资源池中创建一个共享事件e1,并赋值给本地事件e1 
   endfunction
   task run_phase(uvm_phase phase);
      uvm_object   tmp;
      edata    d;
      `uvm_info("ESYNC",$sformatf("wait sync event at %t ps",$time),UVM_LOW)      
      e1.wait_trigger_data(tmp);              //4.等待事件,同时将接收触发事件发来的数据包对象
      void`($cast(d,tmp));               //5.类型转换,将tmp对象中的值赋给d中
        `uvm_info("ESYNC",$sformatf("get data %0d after sync at %t ps",d.data,$time),UVM_LOW)     
   endtask
endclass

class env1 extends uvm_env;
   comp1   c1;
   comp2   c2;
   ...
endclass     

不同的组件可以共享同一个uvm_event,这不是通过跨层次传递uvm_event对象句柄来实现共享的,因为这并不符合组件环境封闭的原则。这种共享同一个uvm_event对象是通过uvm_event_pool这一全局资源池来实现的。这个资源池类是uvm_object_string_pool #(T)的子类,它可以生成和获取通过字符串来索引的uvm_event对象。通过全局资源池对象(唯一的),在环境中任何一个地方的组件都可以从资源池中获取共同的对象,这就避免了组件之间的互相依赖。

uvm_eventevnet
trigger()来触发,使用wait_trigger()等待的对象再次等待事件触发,需要先通过reset()方法重置初始状态,再使用trigger()触发->触发,使用@等待的对象再次等待事件触发,只需要再次用->触发
通过trigger(uvm_object data = null)的可选参数,可携带数据对象信息,可通过wait_trigger_data(output uvm_object data)等待事件获取写入的数据对象。->触发事件时无法携带信息
可通过get_num_waiters()获取等待进程数目无法获取等待它的进程数目
可通过add_callback(uvm_event_callback cb, bit append = 1)函数来添加回调函数触发时无法直接触发回调函数
  • uvm_event / uvm_barrier : 对多个组件进行同步协调,同时为了解决组件独立运作的封闭性需要;
  • Callback机制:在不修改类的本身的前提下,去修改类中某些成员方法,或者扩展新的方法;
  • 工厂的override机制:在不修改原有验证环境层次和验证包的代同时,实现对验证环境内部组件类型或者对象的覆盖(override);

barrier

uvm_barrier可以设置一定的等待阈值(threshold),待有不少于该阈值的进程在等待该对象时,才触发该事件,同时激活所有正在等待的进程,使得可以继续进行。
uvm_barrier

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值