UVM的phase机制

一、概述

SV的验证环境构建中,传统的硬件设计模型在仿真开始前,已经完成例化和连接了,而SV的软件部分对象例化则需要在仿真开始后执行。虽然对象例化通过调用构建函数new()来实现,但是单单通过new()函数无法解决在验证环境实现层次化时,无法保证例化的先后关系,以及各个组件在例化后的连接。如果需要实现高级功能,例如在顶层到到底层的配置时,SV也无法在底层组件例化之前完成对底层的配置逻辑。因此,UVM在验证环境构建时,引入了phase机制,通过该机制可以将UVM仿真阶段层次化,不单单是各个phase的先后执行顺序,而且处于同一phase中的层次化组件之间的phase也有先后关系。

二、9个phase执行机制

对于UVM组件,主要关心各个phase执行的先后顺序。在定义了各个phase虚方法后,UVM环境会按照phase的顺序分别调用这些方法。

在这里插入图片描述
这9个phase对于一个测试环境的生命周期而言,是有固定的先后执行顺序的,同时对于同一个phase中的组件,执行也会按照层次的顺序或者自顶向下或者自顶向上来执行。对于build_phase,执行顺序按照自顶向下,这符合验证结构建设的逻辑,因为只有先例化高层组件,才会创建空间来容纳底层组件。只有uvm_component及其继承于uvm_component的子类,才会按照phase机制将上面的9个phase先后执行完毕,这些phase在uvm_component中通过_phase的后缀完成了虚方法的定义,比如build_phase()可以定义一些组件例化和配置的任务。

class subcomp extends uvm_component;
	`uvm_component_utils(subcomp)
	function new(string name, uvm_component parent);
		super.new(name, parent);
	endfunction
	
	function void build_phase(uvm_phase phase);
		`uvm_info("build_phase", "", UVM_LOW)
	endfunction
	
	function void connect_phase(uvm_phase phase);
		`uvm_info("connect_phase", "", UVM_LOW)
	endfunction
	
	function void end_of_elaboration_phase(uvm_phase phase);
		`uvm_info("end_of_elaboration_phase", "", UVM_LOW)
	endfunction
	
	function void start_of_simulation_phase(uvm_phase phase);
		`uvm_info("start_of_simulation_phase", "", UVM_LOW)
	endfunction
	
	task run_phase(uvm_phase phase);
		`uvm_info("run_phase", "", UVM_LOW)
	endtask
	
	function void extract_phase(uvm_phase phase);
		`uvm_info("extract_phase", "", UVM_LOW)
	endfunction
	
	function void check_phase(uvm_phase phase);
		`uvm_info("check_phase", "", UVM_LOW)
	endfunction
	
	function void report_phase(uvm_phase phase);
		`uvm_info("report_phase", "", UVM_LOW)
	endfunction
	
	function void final_phase(uvm_phase phase);
		`uvm_info("final_phase", "", UVM_LOW)
	endfunction
endclass

class topcomp extends subcomp;
	subcomp c1, c2;
	...
	function void build_phase(uvm_phase phase);
		`uvm_info("build_phase", "", UVM_LOW)
		c1 = subcomp::type_id::create("c1", this);
		c2 = subcomp::type_id::create("c2", this);
	endfunction
endclass

class test1 extends uvm_test;
	topcomp t1;
	...
	function void build_phase(uvm_phase phase);
		t1 = topcomp::type_id::create("t1", this);
	endfunction	
endclass

仿真结果:
在这里插入图片描述
从输出结果来看,build是一个自顶向下的执行顺序,先把顶层的t1创建出来,然后再创建t1里面的c1c2,然后connect是自底向上的执行顺序,先创建c1c2然后再创建t1,其他也同样按照phase所规定的执行顺序进行创建。

在所有的phase中,只有run_phase方法是一个可以耗时的任务,这意味着该方法可以完成一些等待、激励、采样的任务。对于其它phase对于的方法都是函数,必须立即返回(0耗时)。在run_phase中,如果要完成测试,通常需要组织下面的激励序列:上电、复位、寄存器配置、发送主要测试内容、等待DUT完成测试。

三、12个分支phase

发送激励的一种简单方式是,在run_phase中完成上面所有的激励,另一种方式是,可以将上面几种典型序列划分到不同区间,让对应的激励按区间顺序发送的话,可以让测试更有层次。因此run_phase又可以分为以下12个phase:

  • pre_reset_phase
  • reset_phase
  • post_reset_phase
  • pre_configure_phase
  • configure_phase
  • post_configure_phase
  • pre_main_phase
  • main_phase
  • post_main_phase
  • pre_shutdown_phase
  • shutdown_phase
  • post_shutdown_phase

在这里插入图片描述
实际上run_phase任务和上面细分的12个phase是并行的,即在start_of_simulation_phase任务执行以后,run_phasereset_phase开始执行,而在shutdown_phase执行完成之后,需要等待run_phase执行完才可以进入extract_phase

四、UVM编译和运行顺序

在这里插入图片描述

  • 首先在加载硬件模型调用仿真器之前,需要完成编译和建模阶段。
  • 接下来在开始仿真之前,会分别执行硬件的always/initial语句,以及UVM的调用测试方法run_test和几个phase,分别是build、connect、end_of_elaboration、start_of_simulation。
  • 在开始仿真后,将会执行run_phase或者对应的12个细分phase。
  • 在仿真结束后,将会执行剩余的phase,分别是extract、check、report和final。

UVM仿真开始

要在仿真开始时建立验证环境,可以选择:

  • 可以通过全局函数(由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名称传递,在仿真时也可以从顶层覆盖已指定的test。

无论上面哪一种方式,都必须在顶层调用全局函数run_test(),而全局函数run_test()的重要性,正是从uvm_root创建了一个UVM世界。

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顶层类uvm_root,该类也继承于uvm_component,它也是UVM环境结构中的一员,而它可以作为顶层结构类。它提供了一些像run_test()的这种方法,来充当了UVM世界中的核心角色。在uvm_pkg中,有且只有一个顶层类uvm_root所例化的对象,即uvm_top

uvm_top的核心作用包括:

  • 作为隐形的UVM验证结构的顶层,任何其它的组件实例都在它之下,通过创建组件时指定parent来构成层次。如果parent设置为null,那么它将作为uvm_top的子组件。
  • 控制所有组件的phase顺序。
  • 索引功能。通过层次名称来索引组件实例。
  • 报告配置。通过uvm_top来全局配置报告的繁简度。
  • 全局报告设备。由于可以全局访问到uvm_top实例,所以UVM报告设备在组件内部和组件外部(例如modulesequence)都可以访问。

通过uvm_top调用方法run_test(test_name),uvm_top做了如下的初始化:

  • 得到正确的test_name
  • 初始化objection机制(控制仿真退出)。
  • 创建uvm_test_top实例。
  • 调用phase控制方法,安排所有组件的phase方法执行顺序。
  • 等待所有phase执行结束,关闭phase控制进程。
  • 报告总结和结束仿真。

UVM仿真结束

UVM结束仿真的机制有且只有一种,那就是利用objection挂起机制来控制仿真结束。uvm_objection类提供了一种供所有componentsequence共享的计数器,如果有组件来挂起objection,那么它还应该记得落下objection。参与到objection机制中的参与组件,可以独立的各自挂起objection,来防止run_phase退出,但是只有这些组件都落下objection后,uvm_objection共享的counter才会变为0,这意味run_phase退出的条件满足,因此可以退出run_phase

对于uvm_objection类,用来反停止的控制方法包括:

//挂起objection
raise_objection(uvm_object obj=null, string description="", int count=1)
//落下objection
drop_objection(uvm_object obj=null, string description="", int count=1)
//设置退出时间
set_drain_time(uvm_object obj=null, time drain)

这几种方法,对于component()而言,可以在run_phase()中使用phase.raise_objection()或者phase.drop_objection()来控制run_phase退出。最好为参数description字符串提供说明,利于后期的调试,应该使用默认count值,对于uvm_top或者uvm_test_top应该尽可能少地使用set_drain_time()

objection防止仿真退出

class test1 extends uvm_test;
	...
	task run_phase(uvm_phase phase);
		phase.raise_objection(this);
		`uvm_info("run_phase", "entered...", UVM_LOW)
		#1us;
		`uvm_info("run_phase", "exited...", UVM_LOW)
		phase.drop_objection(this);
	endtask
endclass
  • 5
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值