uvm通信-uvm_event & uvm_event_pool & uvm_event_callback
参考资料
(1) UVM通信篇之六:同步通信元件(上) - 路科验证的日志 - EETOP 创芯网论坛 (原名:电子顶级开发网) -
(2) 《Practical UVM Step by Step with IEEE》
1.同步的方法
1.1 sv与uvm中同步的方法
(1) 在sv中,用于同步的方法有event, semaphore和mailbox;
(2) 在UVM中,用于同步的方法为uvm_event(uvm_event派生于uvm_object);
(3) uvm_event不仅能实现不同组件进程间同步的功能,还能像TLM通信一样传递数据,并且作用范围更广(TLM通信只能局限于uvm_component之间,而uvm_event不限于此);
1.2 什么情况下会使用uvm_event呢?
(1) 组件之间的常规的数据流向是通过TLM通信方法实现的,比如sequencer与driver之间,或者monitor与scoreboard之间。然而有些时候,数据的传输的偶然触发的,并且需要立即响应,这个时候uvm_event就是得力的助手了。
(2) uvm_event也解决了一个重要问题,那就是在一些uvm_object和uvm_component对象之间如果要发生同步,那么无法通过TLM传输,因为TLM传输必须是在组件(component)和组件之间进行的。如果在sequence与sequence之间要进行同步,或者sequence与driver之间要进行同步,都可以借助uvm_event来实现。
2.uvm_event的使用示例(已实践,非常好用)
(1)通过uvm_event_pool::get_global_pool()函数获取全局的单实例类uvm_event_pool类型对象的句柄;
(2)两个initial块中调用get_global_pool返回同一个uvm_event_pool类型对象的句柄;
(3)通过uvm_event_pool.get(“ev”)可以得到一个名字为”ev”的uvm_event对象的句柄;如果名字为"ev"的uvm_event对象不存在,会在第一次调用get_global()函数时创建这样一个对象。
(4)在uvm_event中,触发的方式是uvm_event.trigger(); 而等待触发的方式是wait_ptrigger() (电平触发)和wait_trigger()(上升沿触发);
1 //示例2 2 //step1.The event is created in the top-level test; 3 //step2.The event is placed in config_db; 4 class eth_transmit_event_sync_test extends eth_blk_env_test; 5 ... 6 uvm_event transmit_barrier_ev=new("transmit_complete_event"); 7 ... 8 virtual function void build_phase(uvm_phase phase); 9 super.build_phase(phase); 10 uvm_config_db #(uvm_event)::set(null,"","transmit_b",transmit_barrier_env); 11 endfunction 12 endclass 13 14 //step3.The transmit_sequence picks it from config_db; 15 //simple transmit sequence with events; 16 virtual task body(); 17 uvm_config_db #(uvm_event)::get(null,"","transmit_b",send_2_pkt_event); 18 ... 19 send_2_pkt_event.trigger(); 20 ... 21 endtask 22 23 //step4.The interrupt sequence picks it from config_db; 24 class tx_interrupt_event_seq extends base_sequence; 25 ... 26 uvm_event int_event; 27 ... 28 virtual task body(); 29 ... 30 uvm_config_db #(uvm_event)::get(null,"","transmit_b",int_event); 31 int_event.wait_ptrigger(); 32 ... 33 endtask 34 35 endclass
3.uvm_event相关function/task
注1: uvm_event主要有三类function: trigger函数(如trigger(), get_trigger_data(), get_trigger_time()等),状态函数(is_on(),is_off(),reset(), get_num_waiters()等),callback函数(add_callback(), delete_callback()等);
3.1 wait_on
(1) 等待事件处于activated状态,如果事件已经被触发,这个task会立即返回;一旦事件被触发,它将一直保持"on"状态直到事件reset;
3.2 wait_off
(1) 如果事件已经被触发,并且处于"on"状态,该task会等待该事件通过调用reset而关掉;
(2) 如果事件没有被触发,该task会立即返回;
3.3 trigger
3.4 wait_trigger
(1) 等待事件被触发;
3.5 wait_trigger_data
3.6 wait_ptrigger
3.7 wait_ptrigger_data
3.8 reset
3.9 is_on
3.10 is_off
3.11 get_trigger_time
4.uvm_event与event的区别
(1) uvm_event的基础是event,只不过对event的触发与等待进行了扩展;
(2) event被->触发后,会触发用@/wait(event.triggered())等待该事件的对象; uvm_event通过trigger()来触发,会触发使用wait_trigger()/wait_ptrigger()/wait_trigger_data()/wait_ptrigger_data()等待的对象;
(3) 如果再次触发事件,event只需使用->来触发; uvm_event需要先通过reset()方法重置初始状态,再使用trigger()来触发;
(4) event无法携带更多的信息; uvm_event可以通过trigger(uvm_event data=null)的可选参数,将要伴随触发的数据对象都写到该触发事件中,而等待该事件的对象可以通过方法wait_trigger_data(output uvm_object data)来获取事件触发时写入的数据对象;
注1:如果uvm_event.trigger不传递参数,不传递额外的信息,则等待该事件的对象可以调用wait_trigger,而不是wait_trigger_data;
(5) event触发时无法直接触发回调函数; uvm_event可通过add_callback函数来添加回调函数;
(6) event无法直接获取等待它的进程数目,而uvm_event可以通过get_num_waiters()来获取等待它的进程数目;
5.uvm_event_pool
(1) 不同的组件可以共享同一个uvm_event,这不需要通过跨层次传递uvm_event对象句柄来实现共享的,因为这并不符合组件环境封闭的原则。这种共享同一个uvm_event对象是通过uvm_event_pool这一全局资源池来实现的。
(2) uvm_event_pool这个资源池类是uvm_object_string_pool #(T)的子类,它可以生成和获取通过字符串来索引的uvm_event对象。通过全局资源池对象(唯一的),在环境中任何一个地方的组件都可以从资源池中获取共同的对象,这就避免了组件之间的互相依赖。
6.uvm_event_callback(派生于uvm_callback)
(1) 可以从uvm_event_callback进行类的派生,并实现pre_trigger与post_trigger函数,之后将该派生类通过add_callback函数添加到uvm_event中;
(2) pre_trigger()有返回值,如果返回值为1,则表示uvm_event不会被trigger,也不会再执行post_trigger()方法;如果返回值为0,则会继续trigger该事件对象。
注1:对于uvm_event的callback而言,不用采用示例2中通用的callback机制方法,可以直接使用uvm_event已经实现好的函数(如add_callback等);
1 //示例1 2 class edata extends uvm_object; 3 `uvm_object_utils(edata) 4 int data; 5 ... 6 endclass 7 8 class ecb extends uvm_event_callback; 9 `uvm_object_utils(ecb) 10 ... 11 function bit pre_trigger(uvm_event e, uvm_object data=null); 12 `uvm_info("EPRETRIG",$sformatf("before trigger event %s", e.get_name()),UVM_NONE) 13 return 0; 14 endfunction 15 16 function void post_trigger(); 17 `uvm_info("EPOSTTRIG",$sformatf("after trigger event %s", e.get_name()),UVM_NONE) 18 endfunction 19 endclass 20 21 class comp1 extends uvm_component; 22 `uvm_component_utils(comp1) 23 uvm_event e1; 24 ... 25 function void build_phase(uvm_phase phase); 26 super.build_phase(phase); 27 e1=uvm_event_pool::get_global("e1"); 28 endfunction 29 30 task run_phase(uvm_phase phase); 31 edata d=new(); 32 ecb cb=new(); 33 d.data=100; 34 #10ns; 35 e1.add_callback(cb); 36 e1.trigger(d); 37 endtask 38 endclass 39 40 class comp2 extends uvm_component; 41 `uvm_component_utils(comp2) 42 uvm_event e1; 43 ... 44 function void build_phase(uvm_phase phase); 45 super.build_phase(phase); 46 e1=uvm_event_pool::get_global("e1"); 47 endfunction 48 49 task run_phase(uvm_phase phase); 50 uvm_object tmp; 51 edata d; 52 e1.wait_trigger_data(tmp); 53 void'($cast(d,tmp)); 54 endtask 55 endclass 56 57 class env1 extends uvm_env; 58 comp1 c1; 59 comp2 c2; 60 ... 61 endclass
1 //示例2 2 //step1.create event callback class; 3 class int_event_callbacks extends uvm_event_callback; 4 function new(string name="int_event_callbacks"); 5 super.new(name); 6 endfunction 7 8 virtual function bit pre_trigger(uvm_event e, uvm_object data=null); 9 `uvm_info("UVM_EVENT_CALLBACK",$sformatf("UVM EVENT pre_trigger callback triggered"),UVM_LOW) 10 endfunction 11 12 virtual function void post_trigger(uvm_event e, uvm_object data=null); 13 `uvm_info("UVM_EVENT_CALLBACK",$sformatf("UVM EVENT post_trigger callback triggered"),UVM_LOW) 14 endfunction 15 endclass 16 17 //step2.instantiate callback class; 18 typedef uvm_callbacks #(uvm_event, int_event_callbacks) cbs; 19 int_event_callbacks interrupt_event_cbk=new("interrupt_event_cbk"); 20 21 //step3.register callback class; 22 uvm_config_db#(uvm_event)::set(null,"","transmit_b",transmit_barrier_ev); 23 cbs::add(transmit_barrier_ev, interrupt_event_cbk);