[CU]objection机制1-objection的作用与特点,objection与phase/set_drain_time的联系,objection的控制与调试
参考资料:
(1) UVM——phase objection · 大专栏 (dazhuanlan.com)
(2) 《UVM1.1应用指南及源代码分析》
(3) 《uvm user guide 1.2》chapter 3.11-Managing end of test;
(4) 《uvm cookbook》End of test mechanisms章节;
(5) 《Practical UVM Step by Step with IEEE》
1. objection的作用及特点
(1) 在验证平台中,通过drop_objection来通知系统可以关闭验证平台,简言之,控制仿真的终止.
(2) 在进入某一phase时, UVM会收集此phase raise的所有objection,并且实时监测所有objection是否已经被撤销. 当发现所有objection都已经被撤销后,会关闭此phase,开始进入下一phase. 当所有phase都执行完毕后,会调用$finish将整个验证平台关掉.
(3) 在进入某一phase时,如果UVM发现此phase没有提出任何objection,那么将会直接跳转到下一个phase中;
(4) 由于run_phase与run-time phase是并行运行的,如果12个动态运行的phase有objection被提起,那么run_phase根本不需要raise_objection就可以自动执行.
(5) 如果想执行一些耗费时间的代码,那么在此phase(run-time phase/run_phase)下任意一个component中至少进行一次raise_objection操作;
注1:如果run-time phase中有objection的raise, run_phase没有,run-time phase和run_phase中内容都会执行;
注2:如果run-time phase中没有objection的raise,run_phase有,run-time phase不会执行,而run_phase会得到执行;
2. objection与phase的联系
(1) 每一个phase都有一个内建的objection,用于components和objects activity的同步,用于表明什么时候可以安全结束phase,最终结束测试;
1 class uvm_phase extends uvm_object; 2 ... 3 uvm_objection phase_done; 4 ... 5 endclass
(2) raise_objection必须通过phase.raise_objection来完成.
(3) objection的引入是为了解决何时结束仿真的问题,它更多的面向main_phase等task_phase,而不是function_phase.
(4) UVM的所有的phase自动执行函数/任务的参数中,都有一个phase,这是为了便于在任何component的phase中都能raise_objection;
1 task my_case0::run_phase(uvm_phase phase); 2 phase.raise_objection(this); 3 #100; 4 phase.drop_objection(this); 5 endtask
3. objection与set_drain_time/phase_ready_to_end的联系
(1) 功能模块存在处理延时,如果发送完毕最后一个transaction,此时立即drop_objection,可能会导致某些数据包无法接收到.因此,UVM为所有的objection设置drain_time这一属性.
注1:如果为objection设置过drain_time,当objection数目变成0后,当前phase会等待drain_time时间,然后跳出该phase;
注2:如果在drain_time期间,另外一个objection被raise, phase objection机制会再次启动,然后等待objection数目变为0;
1 task base_test::main_phase(uvm_phase phase); 2 phase.phase_done.set_drain_time(this,200); 3 endtask
注3:set_drain_time语句可以放置于main_phase中raise_objection语句之前;
1 virtual task main_phase(uvm_phase phase); 2 uvm_objection objection; 3 super.main_phase(phase); 4 objection=phase.get_objection(); //phase.phase_done; 5 //function uvm_objection get_objection(); return this.phase_done; endfunction 6 objection.set_drain_time(this,100ns); 7 ... 8 endtask
注4:如果有transaction正在进行,也可以使用phase_ready_to_end() task重新raise objection,可以达到与set_drain_time相似的效果;
(2) phase_done是uvm_phase的一个成员变量. 当调用phase.raise_objection或phase.drop_objection时,实质是调用phase_done的raise_objection和drop_objection.
1 uvm_objection phase_done; // phase done objection
1 function void uvm_phase::raise_objection (uvm_object obj, 2 string description="", 3 int count=1); 4 if (phase_done != null) 5 phase_done.raise_objection(obj,description,count); 6 else 7 m_report_null_objection(obj, description, count, "raise"); 8 endfunction
1 function void uvm_phase::drop_objection (uvm_object obj, 2 string description="", 3 int count=1); 4 if (phase_done != null) 5 phase_done.drop_objection(obj,description,count); 6 else 7 m_report_null_objection(obj, description, count, "drop"); 8 endfunction
(3) 当UVM检测到当前phase所有的objection被撤销后,会检查有没有设置drain_time;如果没有设置,则马上进入到下一个phase,否则延迟drain_time后再进入下一个phase.
(4) 一个phase对应一个drain_time,并不是所有phase共享一个drain_time;在没有设置的情况下, drain_time的默认值为0.
问题: 如果在task phase内进行objection的raise与drop,并且在task phase内使用set_drain_time,具体该怎么实现?
答案: 在raise_objection后,drop_objection前的任意一处都可以进行drain_time的设置;由于set_drain_time()是一个function,因此也可以放在raise_objection语句前;
4. objection的控制
4.1. sequence中控制objection
4.1.1 normal seq or virtual seq中控制objection(virtual seq!!!)
1.在sequence中可以使用starting_phase来控制验证平台的关闭; 但是starting_phase需要不是null.
注1:将sequence作为sequencer的某动态运行phase的default sequence时,其starting_phase不为null.
注2:其他方式启动sequence时(比如采用uvm_do宏启动),此sequence中的starting_phase是null,需要手动为其starting_phase赋值(把父sequence的starting_phase赋值给子sequence的starting_phase,只要顶层的sequence的starting_phase不为null, 那么下面所有由其启动的sequence的starting_phase也不为null).
2.一般来说,只在最顶层的virtual sequence中控制objection;因为virtual sequence是起统一调度作用的,这种统一调度不只体现在transaction上,也体现在objection的控制上;
注1:virtual sequence一般充当最顶层sequence的角色,并且通常最顶层的sequence不会作为uvm_do系列宏的参数,通常将其作为sequencer的default_sequence;所以,可以在virtual sequence中使用starting_phase.drop_objection来控制验证平台的关闭;
1 class drv0_seq extends uvm_sequence #(my_transaction); 2 ... 3 virtual task body(); 4 if(starting_phase!=null) begin 5 starting_phase.raise_objection(this); 6 `uvm_info("drv0_seq","raise_objection",UVM_MEDIUM) 7 end 8 else begin 9 `uvm_info("drv0_seq","starting_phase is null, can't raise objection",UVM_MEDIUM) 10 end 11 endtask 12 ... 13 endclass 14 15 class cas0_vseq extends uvm_sequence; 16 ... 17 virtual task body(); 18 drv0_seq seq0; 19 if(starting_phase!=null) 20 starting_phase.raise_objection(this); 21 `uvm_do_on(seq0,p_sequencer.p_sqr0); 22 if(starting_phase!=null) 23 starting_phase.drop_objection(this); 24 endtask 25 26 endclass
注1:上图中drv0_seq的starting_phase为null,因为case0_vseq中采用uvm_do_on宏启动drv0_seq,但是uvm_do系列宏不提供starting_phase的传递功能;
4.1.2 phase aware sequences-explict or implict objection
4.1.2.1 explict objection
(1) 在启动sequence前,为其starting_phase变量赋值;
(2) sequence显式地raise/drop objection(可以放在pre/post_body或者pre/post_start或者body中);
1 class test extends uvm_test; 2 task run_phase(uvm_phase phase); 3 seq.set_starting_phase(phase); 4 seq.start(seqr); 5 endtask 6 endclass 7 8 class seq extends uvm_sequence #(data_item); 9 task body(); 10 uvm_phase p=get_starting_phase(); 11 if(p) p.raise_objection(this); 12 //some critical logic; 13 if(p) p.drop_objection(this); 14 endtask 15 endclass
4.1.2.2 implict objection
(1) 在启动sequence前,指定其starting phase;
(2) 在sequence内部,通常是sequence的new函数内, user调用set_automatic_phase_objection(1)函数;
(3) uvm_sequence_base会在pre/post_start之前或之后自动处理phase的raise与drop;
1 class test extends uvm_test; 2 ... 3 task run_phase(uvm_phase phase); 4 ... 5 seq.set_starting_phase(phase); 6 seq.start(seqr); 7 ... 8 endtask 9 ... 10 endclass 11 12 class seq extends uvm_sequence #(data item); 13 function new(string name="seq"); 14 super.new(string name="seq"); 15 set_automatic_phase_objection(1); 16 endfunction 17 18 task body(); 19 //sequence logic with no objection as it is already handled in the base class; 20 endtask 21 22 endclass
4.2. uvm_component中控制objection(如uvm_test或其派生类)
(1) 在base_test的run_phase进行objection的raise与drop,在raise与drop之间进行virtual sequence的执行;
(2) 该种方法中, sequence本身不处理objection;
注1:如果使用default sequence机制启动sequence,该种objection控制方法需要做些调整才能使用;
1 class test extends uvm_test; 2 ... 3 task run_phase(uvm_phase phase); 4 phase.raise_objection(this); 5 seq.start(seqr); 6 phase.drop_objection(this); 7 endtask 8 ... 9 endclass
5. objection的调试
1 <sim command> +UVM_OBJECTION_TRACE
6. 超时退出
3-phase的超时退出(timeout,仅限于run_phase,内含wait(0)以及phase.get_name()) - 蚕食鲸吞 - 博客园 (cnblogs.com)
6.1. 为什么需要设置超时退出set_timeout?
(1) 验证平台运行时,会出现测试用例hang的情况,这种状态下,仿真时间一直向前走,driver或monitor并没有发出或收到transaction,也没有UVM_ERROR出现.
(2) 一个测试用例的运行时间可以估计,如果超出这个时间,可以终止testcase.
6.2. 超时退出的设置方式(代码中/命令行)
1 function boid base_test::build_phase(uvm_phase phase); 2 super.build_phase(phase); 3 env=my_env::type_id::create("env",this); 4 uvm_top.set_timeout(500ns,0); 5 endfunction
1 <sim command> +UVM_TIMEOUT=<timeout>,<override>
7.testcase结束的管理
(1) 并行线程1之task phase raise_objection+seq执行完+task phase drop_objection(all phase done, run_test内会调用$finish);
(2) 并行线程2之global watch dog,会超时结束整个验证平台的执行,不然(1)中出现hang而无法正常结束(注意必须有global watch dog语句块);