UVM--phase机制

1 phase机制

•   SV的验证环境构建中,我们可以发现,传统的硬件设计模型在仿真开始前,已经完成例化和连接了;而SV的软件部分对象例化则需要在仿真开始后执行。

•    虽然对象例化通过调用构建函数new()来实现,但是单单通过 new()函数无法解决一个重要问题,那就是验证环境在实现层次化时,如何保证例化的先后关系,以及各个组件在例化后的连接

• 此外如果需要实现高级功能,例如在顶层到底层的配置时,SV也无法在底层组件例化之前完成对底层的配置逻辑。

• 因此UVM在验证环境构建时,引入了phase机制,通过该机制我们可以很清晰地将UVM仿真阶段层次化。

• 这里的层次化,不单单是各个phase的先后执行顺序,而且处于同一phase中的层次化组件之间的phase也有先后关系。

执行机制

在定义了各个phase虚方法后, UVM环境会按照phase 的顺序分别调用这些方法。

•    对于build phase, 执行顺序按照自顶向下,这符合验证结构建设的逻辑。因为只有先例化高层组件,才会创建空间来容纳低层组件。

•    只有uvm_component及其继承于uvm_component的子类,才会按照phase机制将上面的九个phase先后执行完毕。

•    常用的phase包括build、connect、run和report, 它们分别完成了组件的建立、连接、运行和报告。这些phase在uvm_component中通过_phase的后缀完成了虚方法的定义,比如build_phase()可以定义一些组件例化和配置的任务。

•   在所有的phase机制中,只有run_phase方法是一个可以耗时的任务,这意味着该方法可以完成一些等待,激励,采样的任务。对于其他phase对应的方法都是函数,必须立即返回(0耗时)。

•    在run_phase中,用户如果要完成测试,通常需要组织下面的激励序列:
•    上电
•    复位
•    寄存器配置
•    发送主要测试内容
•    等待DUT完成测试

在用户发送激励的一种简单方式是,在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_pbase
•    post_ shutdown _phase

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

然run_phase与细分的12个phase足并行的,但12个phase也是按·先后顺序执行的。
为了避免不必要的干扰, 用户可以选择run_phase, 或者12个 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 cl, c2;
	...
	function void build_phase(uvm_phase phase);
	'uvm_info("build_phase", "", UVM_LOW) 
    cl = subcomp::type_id::create("cl", this);
	c2 = subcomp::type_id::create("c2", this);
	endfunction 
    endclass 
	    
    class testl extends uvm_test;
	topcomp tl;
	...
	function void build_phase{uvm_phase phase);
	t1 = topcomp::type_id::create{"tl", this); 
	endfunction 
    endclass

输出结果:

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

UVM仿真开始

仿真开始时建立验证环境, 用户可以考虑选择下面几种方式:

1.可以通过全局函数(由 uvm_pkg 提供) run_test()来选择性地指定要运行哪一个uvm_test。这里的 test 类均继承于 uvm_test。这样的话, 指定的 test 类将被例化并指定为顶层的组件,一般而言,run_test函数可以在合适 module/program 中的 initial进程块中调用。

2.如果没有任何参数传递给 run_test( ), 可以在仿真时通过传递参数+UVM_ TESTNAME = <test_name>指定仿真时要调用的 uvm_test。当然, 即便 run_test()函数在调用时已经有 test 名称传递, 在仿真时+UVM_ TESTNAME=<test_ name>也可以从顶层覆盖已指定的 test。这种方式使得仿真不需要通过再次修改 run_test()调用的 test 名称和重复编译, 就可以灵活选定 test。

无论哪一种方式,都必须在顶层调用全局函数run_test(), 用户可以考虑不传递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
    UVlll-1.2/base/uvm_globals.svh 

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

uvm_top担任的核心职责包括:

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

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

UVM仿真结束

UVM1.1之后,结束仿真的机制有且只有一种,利用objection挂起机制来控制仿真结束。

•    uvm—objection类提供了一中供所有component和sequence共享的计数器。 如果有组件来挂起objection, 那么它还应该记得落下objection。
•    参与到objection机制中的参与组件, 可以独立的各自挂起objection, 来防止run phase退出, 但是只有这些组件都落下objection后, uvm_objection共享的counter才会变为0, 这意味run phase退出的条件满足,因此可以退出run phase。

 对于uvm—objection类, 用来反停止的控制方法包括:
•    raise_objection (uvm_object obj=null, string description ='"', int count = 1)挂起objection
•    drop_objection (uvm_object obj=null, string description = "" , int count = 1) 落下objection
•    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()。

//防止仿真退出
	 class test1 extends uvm_test;
	 ...
	 task run_phase(uvm_phase phase);
	 phase.raise_objection(this);
	 `uvm_info("run_phase", "entered .. " , UVM _ LOW) 
	 #lus; 
    `uvm_ info("run_phase", "exited .. ",  UVM LOW)
	phase.drop objection(this);
	endtask 
    endclass 
	/*输出结果:
    UVM_INFO @ 0: uvm_test_top [run_phase] entered..
    UVM_INFO @ 1000000: uvm_test_top [run_phase] exited..
    UVM_INFO @ 1000000: reporter [TEST_DONE]'run'phase is ready to proceed to the 'extract' phase 
    UVM_INFO @ 1000000: reporter [UVM/REPORT/CATCHER] 

uvm_pkg::uvm_test_done实例会在test1的run_phase()执行完毕之后,才会退出run_phase。
这得益于test1::run_phase()在仿真一开始就挂起了objection,而在执行完毕后才落下了objection。这时uvm_pkg::uvm_test_done认为run_phase已经可以退出,进而转向下个extract_phase。 直到退出所有phase之后, UVM进入了报告总结阶段。

如果进入run_phase 没有立即挂起objection,则进入run_phase会立即退出,进而转向下个extract_phase。

以下案例涵盖本小结所有重点

package phase_order_pkg;
  import uvm_pkg::*;
  `include "uvm_macros.svh"

  class comp2 extends uvm_component;
    `uvm_component_utils(comp2)
    function new(string name = "comp2", uvm_component parent = null);
      super.new(name, parent);
      `uvm_info("CREATE", $sformatf("unit type [%s] created", name), UVM_LOW)
    endfunction
    //TODO-3.1
    //Refer comp1 and define methods:
    // - build_phase()
    // - connect_phase()
    // - run_phase()
    // - report_phase()
	function void build_phase(uvm_phase phase);
	  super.build_phase(phase);
	  `uvm_info("BUILD","comp2 build phase entered",UVM_LOW)
	  `uvm_info("BUILD","comp2 build phase exited",UVM_LOW)
	endfunction
	function void connect_phase(uvm_phase phase);
	  super.connect_phase(phase);
	  `uvm_info("CONNECT","comp2 connect phase entered",UVM_LOW)
	  `uvm_info("CONNECT","comp2 connect phase exited",UVM_LOW)
	endfunction 
	task run_phase(uvm_phase phase);
	  super.run_phase(phase);
	  `uvm_info("RUN","comp2 run phase entered",UVM_LOW)
	  `uvm_info("RUN","comp2 run phase exited",UVM_LOW)
	endtask
	function void report_phase(uvm_phase phase);
	   super.report_phase(phase);
	  `uvm_info("REPORT","comp2 report phase entered",UVM_LOW)
	  `uvm_info("RERPORT","comp2 report phase exited",UVM_LOW)
	endfunction
  endclass
  
  class comp3 extends uvm_component;
    `uvm_component_utils(comp3)
    function new(string name = "comp3", uvm_component parent = null);
      super.new(name, parent);
      `uvm_info("CREATE", $sformatf("unit type [%s] created", name), UVM_LOW)
    endfunction
    //TODO-3.1
    //Refer comp1 and define methods:
    // - build_phase()
    // - connect_phase()
    // - run_phase()
    // - report_phase()
	function void build_phase(uvm_phase phase);
	    super.build_phase(phase);
	    `uvm_info("BUILD","comp3 build phase entered",UVM_LOW)
		`uvm_info("BUILD","comp3 build phase exited", UVM_LOW)
	endfunction
	function void connect_phase(uvm_phase phase);
	    super.connect_phase(phase);
		`uvm_info("CONNECT","comp3 connect phase entered",UVM_LOW)
		`uvm_info("CONNECT","comp3 connect phase exited", UVM_LOW)
	endfunction
	task run_phase(uvm_phase phase);
	    super.run_phase(phase);
		`uvm_info("RUN","comp3 run phase entered",UVM_LOW)
		`uvm_info("RUN","comp3 run phase exited",UVM_LOW)
	endtask
	function void report_phase(uvm_phase phase);
	    super.report_phase(phase);
		`uvm_info("REPORT","comp3 report phase entered",UVM_LOW)
		`uvm_info("REPORT","comp3 report phase exited",UVM_LOW)
	endfunction
  endclass
  
  class comp1 extends uvm_component;
    comp2 c2;
    comp3 c3;
    `uvm_component_utils(comp1)
    function new(string name = "comp1", uvm_component parent = null);
      super.new(name, parent);
      `uvm_info("CREATE", $sformatf("unit type [%s] created", name), UVM_LOW)
    endfunction
    function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      `uvm_info("BUILD", "comp1 build phase entered", UVM_LOW)
      c2 = comp2::type_id::create("c2", this);
      c3 = comp3::type_id::create("c3", this);
      `uvm_info("BUILD", "comp1 build phase exited", UVM_LOW)
    endfunction
    function void connect_phase(uvm_phase phase);
      super.connect_phase(phase);
      `uvm_info("CONNECT", "comp1 connect phase entered", UVM_LOW)
      `uvm_info("CONNECT", "comp1 connect phase exited", UVM_LOW)
    endfunction
    task run_phase(uvm_phase phase);
      super.run_phase(phase);
      `uvm_info("RUN", "comp1 run phase entered", UVM_LOW)
      `uvm_info("RUN", "comp1 run phase entered", UVM_LOW)
    endtask
    function void report_phase(uvm_phase phase);
      super.report_phase(phase);
      `uvm_info("REPORT", "comp1 report phase entered", UVM_LOW)
      `uvm_info("REPORT", "comp1 report phase exited", UVM_LOW)   
    endfunction
  endclass

  class phase_order_test extends uvm_test;
    comp1 c1;
    `uvm_component_utils(phase_order_test)
    function new(string name = "phase_order_test", uvm_component parent = null);
      super.new(name, parent);
    endfunction
    function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      `uvm_info("BUILD", "phase_order_test build phase entered", UVM_LOW)
      c1 = comp1::type_id::create("c1", this);
      `uvm_info("BUILD", "phase_order_test build phase exited", UVM_LOW)
    endfunction
    function void connect_phase(uvm_phase phase);
      super.connect_phase(phase);
      `uvm_info("CONNECT", "phase_order_test connect phase entered", UVM_LOW)
      `uvm_info("CONNECT", "phase_order_test connect phase exited", UVM_LOW)
    endfunction
    task run_phase(uvm_phase phase);
      super.run_phase(phase);
      `uvm_info("RUN", "phase_order_test run phase entered", UVM_LOW)
      phase.raise_objection(this);
      #1us;
      phase.drop_objection(this);
      `uvm_info("RUN", "phase_order_test run phase exited", UVM_LOW)
    endtask
    function void report_phase(uvm_phase phase);
      super.report_phase(phase);
      `uvm_info("REPORT", "phase_order_test report phase entered", UVM_LOW)
      `uvm_info("REPORT", "phase_order_test report phase exited", UVM_LOW)    
    endfunction
    
    //TODO-3.2
    //Refer to phase_order_test::run_phase and define phase tasks:
    // - reset_phase()
    // - main_phase()
    //Ask each task to be finished within 1us
	task reset_phase(uvm_phase phase);
	     super.reset_phase(phase);
		 `uvm_info("RESET","phase_order_test reset phase entered",UVM_LOW);
		 phase.raise_objection(this);
		 #1us;
		 phase.drop_objection(this);
		 `uvm_info("RESET","phase_order_test reset phase exited",UVM_LOW);
	endtask
	task main_phase(uvm_phase phase);
	     super.main_phase(phase);
		 `uvm_info("MAIN","phase_order_test main phase entered",UVM_LOW);
		 phase.raise_objection(this);
		 #1us;
		 phase.drop_objection(this);
		 `uvm_info("MAIN","phase_order_test main phase exited",UVM_LOW);
	endtask

  endclass
endpackage

module phase_order;

  import uvm_pkg::*;
  `include "uvm_macros.svh"
  import phase_order_pkg::*;

  initial begin
    run_test(""); // empty test name
  end

endmodule

  • 2
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

创芯人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值