文章目录
- 1.UVM Phase
- 2.phase的执行
- 3.仿真开始
- 4.仿真结束
- 4.1 objection机制
1.UVM Phase
uvm利用phase机制实现了各个组件之间的同步。因为每个组件都包括一些预定义的同名phase,在没有执行完所有组件的当前phase之前绝对不会去执行所有组件的下一个phase。
phase机制存在的意义:
- 传统的硬件设计模型在仿真开始之前就已经完成了例化和连接,而SV的软件部分对象例化则在仿真开始之后执行
- 只通过new()函数对对象例化,无法解决一个重要问题,就是验证环境在实现层次化时,如何保证例化的先后关系,以及各个组件在例化后的连接
- 引入phase机制,通过该机制可以将UVM仿真阶段层次化
- 层次化不仅仅指各个phase的先后执行顺序,处于同一phase中的层次化组件之间的phase也有先后关系
phase的分类:
在定义了各个虚方法后,UVM环境会按照phase的顺序分别调用这九种phase。
- phase按照是否消耗仿真时间的特性,可以分成两大类:一类是function phase 八种,一类是task phase 一种,run_phase又可以细分为十二种
- phase只有run_phase是一个可以消耗时间的任务,这意味着该phase可以完成一些等待、激励、采样的任务;其他的phase都是函数,必须立即返回
- phase对于function phase ,在同一时间只有一个phase在执行;但是task phase中,run_phase和pre_reset_phase等12个小的phase并行运行
为了避免不必要的干扰,用户可以选择run_phase或者12个phase中的若干来完成激励,但不要将它们混合使用,容易导致执行关系不明确。
2.phase的执行
phase按照运行顺序可分为三大类:
-
前四种属于build time phase
-
第五种为run time phase
-
后四种属于clean_up phase
在run_phase中,用户如果要完成测试,通常需要组织下面的激励序列: -
上电
-
复位
-
寄存器配置
-
发送主要测试内容
-
等待DUT完成测试
需要注意的地方有: -
对于build phase,执行顺序按照自顶向下,这符合验证结构建设的逻辑。因为只有先创建高层的组件,才会创建空间来容纳底层的组件。
-
只有uvm_component及其继承uvm_component的子类,才会按照phase机制将上面九个phase先后执行完毕
UVM世界中的编译和运行顺序:
-
首先在加载硬件模型调用仿真器之前,需要完成编译和建模阶段
-phase 开始仿真之前,分别执行硬件的always/initial语句,以及UVM的调用测试方法run_test和几个phase,分别是build_phase,connect_phase,end_of_elaboration_phase,start_of_simulation_phase; -
phase 在仿真开始后,执行run_phase或对应的12个细分的phase;
-
phase 在仿真结束后,执行剩余的phase,分别是extract_phase,check_phase,report_phase,final_phase
对phase机制的建议: -
尽量不使用12个细分的phase
-
避免phase的跳跃
3.仿真开始
必须要在顶层test中调用全局函数,两种方式run_test()
- 通过全局函数(由uvm_pkg提供) run_test() 来选择性的指定要运行哪个uvm_test,test均派生自uvm_test,指定的test将被例化并指定为顶层的组件,一般来说,run_test函数可以在合适的module/program中的initial块中调用;
- 如果没有任何参数传递给run_test,可以在仿真时通过传递参数 +UVM_TESTNAME=<test_name> 指定仿真时要调用的uvm_test,当然,即使run_test函数在调用时已经有test参数传递,也可以通过+UVM_TESTNAME=<test_name>从顶层覆盖指定的test
在uvm_pkg中,有且只有一个顶层类uvm_root例化对象,即uvm_top
uvm_top的核心职责:
-
作为隐形的UVM的顶层,任何其他的组件实例都是在它之下,通过创建组件时指定parent来构建层次
-
如果component在创建时,parent为null,那么它将作为uvm_top的子组件
-
phase顺序控制
-
索引功能
-
报告机制
-
全局报告设备
通过uvm_top调用方法run_test(),uvm_top做了如下的初始化: -
得到正确的test_name
-
初始化objection机制
-
创建uvm_test_top实例
-
调用phase控制方法,安排所有组件的phase方法执行顺序
-
等待所有phase执行结束,关闭phase控制进程
-
报告总结和结束仿真
4.仿真结束
4.1 objection机制
结束仿真的机制有且只有一个,就是利用objection挂起机制来控制仿真结束
- uvm_objection类提供了一种供所有component和sequence共享的计数器。如果有组件挂起objection,还应该落下objection
- 使用objection机制的各组件可以独立挂起objection,防止run_phase退出。当所有的组件都落下objection后,uvm_objection共享的counter才会变成0,才会退出run_phase
对于uvm_objection类,用来反停止的控制方法包括:
raise_object(uvm_object obj=null,string description = "",int count=1)挂起objection
drop_object(uvm_object obj=bull, string description = "",int count=1)落下objection
set_drain_time(uvm_object obj=null,time drain)设置退出时间
注意:
- 在run_phase阶段,至少要有一个组件把objection挂起,否则uvm会退出run_phase,进入后面的phase
- 要在componnent中挂起objection,建议在一进入run_phase()后就挂起,保证objection counter及时被增加
使用建议:
1.对于component()而言,用户可以在run_phase()中使用phase.raise_objection()/phase.drop_object()来控制run phase 退出
2.最好为description字符串参数提供说明,有利于后期的调试
3.使用默认的count值
4.对于uvm_top或者uvm_test_top尽可能少使用set_drain_time()
class my_driver extends uvm_driver;'uvm_component_utils(my_driver)function new(string name = "my_driver", uvm_component parent = null);super.new(name,parent);'uvm_info("my_driver","new is called",UVM_LOW);endfunctionextern virtual task main_phase(uvm_phase phase);
endclass
task my_driver::main_phase(uvm_phase pahse);phase.raise_objection(this);//开启phase'uvm_info("my_driver","main_pahse is called",UVM_LOW);top_tb.rxd <= 8'b0;top_tb.rx_dv <= 1'b0;while(!top_tb.rst_n)@(posedge top_tb.clk);for(int i = 0; i < 256; i++)begin@(posedge top_tb.clk);top_tb.rxd <= $urandom_range(0, 255);top_tb.rx_dv <= 1'b1;`uvm_info("my_driver", "data is drived", UVM_LOW);end@(posedge top_tb.clk);top_tb.rx_dv <= 1'b0;phase.drop_objection(this);//结束phase
endtask
- raise_phase和drop_phase都是成对出现的,raise_phase语句必须出现在run_phase中第一条消耗时间的语句之前,否则无法起作用
- sequence中,一般在body()方法中调用raise_objection()和drop_objection()方法
参考:
https://blog.csdn.net/bleauchat/article/details/90673946