參考資料:
(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語句塊);