uvm_event 与 system Verilog 中的 event 是类似的,只是 uvm中将 sv的 event进行了 封装和升级,uvm提供了一些额外的方法,有需要的可以看看源码。
uvm_event支持的方法有如下表所示:
序号 | 方法 | 描述 |
1 | wait_on | 等待事件on。事件触发函数trigger中会将on置一,若事件已经被触发直接返回,返回前可定义#0以避免进程竞争;若事件未触发,等待触发且num_waiters计数加一 |
2 | wait_off | 等待事件off。事件reset函数中会将on置零,若事件触发后已被reset则直接返回,返回前可定义#0以避免进程竞争;若事件触发后尚未reset,等待事件reset,且num_waiters计数加一 |
3 | wait_trigger | 等待事件触发。@m_event且num_waiters++。该函数不会判断此前事件是否已被触发,若事件早前已被触发,则等待下次触发 |
4 | wait_ptrigger | 等待事件触发,若此前事件已触发,则直接返回 |
5 | get_trigger_time | 返回事件的触发事件,在事件触发函数trigger中会记录该时间 |
6 | is_on | 判断事件是否on,事件触发之前on=0,事件触发后on=1,reset中on=0,即判断事件是否处于trigger后reset前 |
7 | is_off | 判断事件是否off,即判断事件是否处于reset后trigger前 |
8 | reset | reset事件,num_waiters置零,trigger_time置零,on置零。用户还可以指定输入参数bit wakeup=1来触发事件释放所有阻塞住的进程,默认不触发 |
9 | cancel | num_waiters减一,多用于某进程被kill/disable之后 |
10 | get_num_waiters | 获取num_waiters值 |
11 | get_type_name | 返回type_name |
12 | do_print | 钩子函数,把on/num_waiters/trigger_time变量注册进printer.print_field_int,在调用print进行打印的时候能够打印出来 |
13 | do_copy | 钩子函数,类型转换 |
14 | wait_trigger_data | 调用wait_trigger等待事件触发,调用get_trigger_data获取触发数据 |
15 | wait_ptrigger_data | 跟wait_trigger的唯一区别是调用了wait_ptigger而非wait_trigger |
16 | trigger | 触发事件 |
17 | get_trigger_data | 获取触发数据 |
uvm_event的使用
关于uvm_event的使用,最大的好处是摆脱了system Verilog中对event使用时必须按照路径引用的办法,而在uvm中只需要将 uvm_event放到 uvm_event_pool中即可,这在进行移植验证环境时,是非常便利的事情,并且我们在使用时,也不需要关心event的路径,只需要从event_pool中get到这个event就可以了。比如说,我们在tc里的main_phase中发完包之后,一般都会设置drain_time来等带dut将数据吐完,我们就可以在scoreboard中设置一个uvm_event等待socreboard接收完数据,然后再通过uvm_event通知tc,触发main_phase中的uvm_event.trigger,结束仿真。下面我们来看实现。
class my_component extends uvm_comopnent;
...
...
...
uvm_event my_event ;
`uvm_component_utils(my_component)
function void build_phase(uvm_phase phase);
super.build_phase(phase);
my_event = uvm_event_pool::get_global("my_event");
endfunction
task main_phase(uvm_phase phase);
...
...
...
set_trigger();
...
...
...
endtask
task set_trigger();
my_event.trigger();
endtask
endclass
class get_component extends uvm_comopnent;
...
...
...
uvm_event get_my_event ;
`uvm_component_utils(get_component)
function void build_phase(uvm_phase phase);
super.build_phase(phase);
get_my_event = uvm_event_pool::get_global("my_event");
endfunction
task main_phase(uvm_phase phase);
...
...
...
set_trigger();
...
...
...
endtask
task set_trigger();
...
get_my_event.wait_trigger();
...
endtask
endclass
通过 my_event = uvm_event_pool::get_global("my_event") 这种方法将my_event 注册到event_pool中;在set_component中将uvm_event放到event_pool中,并设置好触发条件,在get_component中,从uvm_event_pool中取出来,通过wait_trigger捕获这次事件。(这里用component只是作为例子使用,实际上在object中也可以这么做)。
对于uvm_event_pool的使用,也可以用下面的方法进行替换:
events_pool = uvm_event_pool::get_global_pool();
my_event = events_pool.get("my_event");
对于uvm_event提供的其他方法,我们可以看看uvm源码,这部分源码很简单,建议有时间可以看看,浮于表面的方法,大多都在底层有着很深层次的实现逻辑,实现这一系列逻辑并不是一件轻松的事情!