phase分类
UVM中的phase,按照其是否消耗仿真时间($time打印出的时间)的特性,可以分成两大类,一类是function phase,如build_phase、connect_phase等,这些phase都不耗费仿真时间,通过函数来实现;另外一类是task phase,如run_phase等,它们耗费仿真时间,通过任务来实现。给DUT施加激励、监测DUT的输出都是在这些phase中完成的。UVM中的phase如下,会自上而下自动运行 (时间上的自上而下)
function phase的运行
对于function phase而言,除build_phase为自上而下运行以外,其余的均自下而上运行,如connect_phase先执行driver和monitor的connect_phase,再执行agent的connect_phase。需要注意的是,build_phase中的自上而下是空间上的概念,即自顶层开始一层层开始往下执行。,且对于同一层次的组件会以字典序进行例化,如:monitor在new时指定的名字为aaa,而driver的名字为bbb,那么将会先执行monitor的build_phase。反之若monitor为mon,driver为drv,那么将会先执行driver的build_phase。
task phase的运行
run_phase、main_phase等task_phase也都是按照自下而上的顺序执行的。但是与前面function phase自下而上执行不同的是,这种task phase是耗费时间的,所以它并不是等到“下面”的phase(如driver的run_phase)执行完才执行“上面”的phase(如agent的run_phase),而是将这些run_phase通过fork…join_none的形式全部启动。所以,更准确的说法是自下而上的启动,同时在运行。
- 对于同一component来说,其12个run-time的phase是顺序执行的,但是它们也仅仅是顺序执行,并不是说前面一个phase执行完就立即执行后一个phase。如在A组件中,main_phase在100个时间单位时执行完毕,而B组件在200个时间单位时才会执行完main_phase。所以,对于A组件,在100时刻,不会立即进入post_main_phase,而是等B组件执行完main_phase以后,在200个时间单位时一起进入post_main_phase。
super.phase
除build_phase外,在写其他phase时,完全可以不必加上super.xxxx_phase语句,super.main_phase都可以去掉。当然,这个结论只适用于直接扩展自uvm_component的类。如果是扩展自用户自定义的类,如base_test类,且在其某个phase,如connect_phase中定义了一些重要内容,那么在具体测试用例的connect_phase中就不应该省略super.connect_phase。
对于build_phase来说,uvm_component对其做的最重要的事情就是自动获取通过config_db::set设置的参数。
如果要关掉这个功能,可以在自己的build_phase中不调用super.build_phase
phase机制的意义
Verilog中有非阻塞赋值和阻塞赋值,相对应的,在仿真器中要实现分为NBA区域和Active区域,这样在不同的区域做不同的事情,可以避免因竞争关系导致的变量值不确定的情况。同样的,验证平台是很复杂的,要搭建一个验证平台是一件相当繁杂的事情,要正确地掌握并理顺这些步骤是一个相当艰难的过程。在不同时间做不同的事情,这就是UVM中phase的设计哲学。但是仅仅划分成phase是不够的,phase的自动执行功能才极大方便了用户。同时,phase的引入在很大程度上解决了因代码顺序杂乱可能会引发的问题在很大程度上减少验证平台开发者的工作量,使其从一部分杂乱的工作中解脱出来。
注:
本文参考自《UVM实战》,仅供学习