目录
1.Phase机制
1.1 phase机制的意义
在SV环境中,需要考虑验证环境在搭建过程中,各个组件例化的先后与连接关系,句柄之间的传递,会提升组件之间的耦合度,同时容易引起句柄为空的现象,因此引发了UVM-phase机制的需求。phase机制根据component树形结构例化和连接组件,同时将phase分为9大phase,各个部分各司其职,将搭建验证平台时例化和连接组件的过程规范化,解决了因代码杂乱可能引发的问题。
1.2 phase机制的说明
phase机制共可以分为9大phase:
build_phase:组件的例化,配置的传递(config)。
connect_phase:组件之间的连接。
end_of_elaboration:显示验证结构,为组件增加额外配置。
start_of_simulation:设置断点,设置初始运行的配置值。
run_phase:发送激励、采集数据、数据对比。
run_phase又可分为12个小phase,进行更精细化的控制。即
pre_reset_phase reset_phase post_reset_phase : 复位、初始化
pre_configure_phase configure_phase post_configure_phase :与DUT相关的配置
pre_main_phase main_phase post_main_phase :DUT运行主要在main phase完成
pre_shutdown_phase shutdown_phase post_shutdown_phase : 与DUT相关断电操作
extract_phase:从测试平台提取剩余数据,从设计观察最终状态。
check_phase:检查不期望的数据。
report_phase:报告测试结果,将结果写入文件。
final_phase:关闭文件,结束联合仿真引擎。
- phase的九大phase是从上而下顺序执行的,执行完一个phase进入到下一个phase,即从build_phase开始到final_phase结束。
- build_phase和final_phase是自顶向下的,其余phase自底向上。(run_phase自底向上与别的不同,实际上是通过fork join_none形式全部启动,同时在运行)
- 除了run_phase是task,其他phase都是function,不耗时。
- run_phase和12个分支phase是并行执行。
- run_phase通常进行上电、复位、寄存器配置、发送主要测试内容以及等待DUT完成测试等操作。
- phase执行的方式是深度优先,即若执行的层次还有分支,则把这一分支全部执行完,再执行同一层次的其余语句。(同一层次语句,按照字典顺序执行,如a_component先于c_component执行)
1.3 phase的跳转
phase的跳转是通过jump函数实现的。
示例:
function void uvm_phase:jump(uvm_phase phase);
//uvm源码
task main_phhase(uvm_phase phase);
fork
……
begin
@(negedge vif.rstn) ;
phase.jump(uvm_reset_phase::get()); //监测到复位信号就跳转到reset_phase
end
join
endtask
- phase跳转时需要注意objection的清理。
- jump的类型必须是一个uvm_phase类型的变量
- 向前跳转的phase只能从pre_reset_phase后面的动态运行的phase开始。
- 向后跳转,除了动态运行的phase外,还可以是function。如main_phase可以跳转到final_phase。
2. objection机制
uvm中,控制仿真结束是通过objection机制来实现的。(SV通过$finish(),或者通过program的自动结束仿真(所有program的initial过程块完成后结束仿真))
objection机制通过全局共享的一个计数器以及raise_objection(+1)和drop_objection(-1)来控制仿真的运行和结束,当计数器变0时,退出run_phase。
objection机制一般用于run_phase和sequence的body()中,来控制仿真的结束。
示例:
class test1 extends uvm_test;
……
task run_phase(uvm_phase phase);
phase.raise_objection(this);
`uvm_info("run_phase","entered",UVM_LOW)
#10us;
`uvm_info("run_phase","exited",UVM_LOW)
phase.drop_objection(this);
endtask
- objection机制需要在第一个非耗时的语句前执行,否则run_phase在0时刻监测到没有任何挂机的objecttion,就会直接结束仿真。
- 如果十二个小phase有raise_objection,那么run_phase不需要raise_objection就可以自动执行,因为run_phase和动态运行的十二个phase是并行的。
3. UVM编译和运行的顺序
编译和链接 (0时刻前)→ 启动always块和initial块,顶层tb initial块调用run_test 依次执行run_phase前不消耗时间的function_phase (0时刻)→执行run_phase以及十二个分支phase →run_phase 和十二个分支phase执行完毕,执行剩余的function_phase
- run_test 来指定执行哪一个uvm_test(所以所有test都要继承于uvm_test),或者通过在仿真时传递参数+UVM_TESTNAME = <test_name> 来指定所需要执行的test。
示例:
task run_test(string test_name = "");
uvm_root top;
uvm_coreservice_t cs;
cs = uvm_coreservice_t::get();
top = cs.get_root();
top.run_test(test_name);
endtask
uvm-1.2/base/uvm_globals.svh
在uvm_pkg中,uvm_root唯一的例化对象为uvm_top,通过run_test(test_name)实现以下功能:
- 得到正确的test_name()。
- 初始化objection机制
- 创建uvm_test_top实例(test_name例化得到)
- 调用phase控制方法,安排phase执行顺序。
- 等待phase执行结束,关闭phase控制进程
- 报告总结和结束仿真。
uvm_top作为UVM的顶层,所有实例都在它之下。可以通过uvm_top来索引组件实例,控制全局的verbosity,全局报告设备。
4. domain的应用
domain的出现是为了满足将不同的时钟域的需求,将两个时钟域中的run_time的phase隔离开(其他phase还是同步的)。(如不同domain的reset_phase是独立运行的,不用等另一个运行完再进入下一个phase)
示例:
class A extends uvm_component;
uvm_domain domain_A; //声明domain
……
function new(string name,uvm_component parent);
super.new(name,parent);
domain_A = new("domain_A") //实例化
endfunction
virtual function void connect_phase(uvm_phase phase);
set_domain(domain_A); //connect_phase将A加入到此domain中
endfunction
endclass
function void uvm_component::set_domain(uvm_domain domain,int hier = 1);
// 第二个参数表示是否递归调用
其他的component默认位于common_domain,这样就可以将两个component分隔开来,使其run_phase在各自的domain运行。