本期將講解 UVM 環(huán)境運行以及他的樹狀結(jié)構(gòu)。
主要參考資料為:
[白皮書]: http://bbs.eetop.cn/thread-320165-1-1.html
[紅寶書]: http://rockeric.com/
上期推送中,我們講解了整體環(huán)境的構(gòu)成,以及他們之間的關(guān)系。那么當仿真開始時,整個環(huán)境又將如何建立起來呢,組件按照什么順序進行組件實例化,如何將組件之間的通訊構(gòu)建起來,以及在運行時我們需要做什么呢?
?
樹狀結(jié)構(gòu)
整體的驗證環(huán)境由許多的組件實現(xiàn),作為環(huán)境組件,UVM 提供了 uvm_component,所有下圖中的測試組件都繼承于 uvm_component,只有 uvm_component 能夠作為組件構(gòu)建起整個環(huán)境。
上圖中可以看到框圖一層套一層,實際上就是 UVM 環(huán)境的樹狀結(jié)構(gòu)的體現(xiàn)。下圖是一個典型的測試環(huán)境的樹狀結(jié)構(gòu)圖。結(jié)合上下兩圖,uvm_top 是一個全局變量,它是 uvm_root 的一個實例(而且也是唯一的一個實例 ,它的實現(xiàn)方式非常巧妙),而 uvm_root 派生自 uvm_component,所以 uvm_top 本質(zhì)上是一個 uvm_component,它是樹的根。uvm_test_top 的 parent 是 uvm_top,而 uvm_top 的 parent 則是 null。
這里我們要注意區(qū)分,uvm 平臺中的 parent 和我們在 oop 中所說的父類是不同的概念,這里指的是節(jié)點,而非類的繼承關(guān)系,上圖的箭頭就像是鉤子,從上至下一個鉤住一個。通常我們不會接觸到 uvm_root 這個類,他是一個全局變量,構(gòu)建環(huán)境我們需要構(gòu)建 uvm_test_top 及其以下的組件。
而具體每個組件的作用,可以參照上一期的推送。
?
運行機制
仿真的進程分為幾個基本階段,例化組件,連接組件,仿真運行和報告階段。但實際上 UVM 在運行時提供了更加細致的階段劃分,將不同的任務(wù)劃分到對應(yīng)的階段中。UVM 稱這種機制為 phase 機制,一共包括九個 phase。
?
仿真開始后,phase 將從上至下,依次自動運行。phase 的引入在很大程度上解決了代碼順序雜亂可能會引發(fā)的問題。它本質(zhì)上是通過把代碼順序強制固定來實現(xiàn)這個目的的,如 build_phase 的代碼一定在 connect_phase 之前執(zhí)行 ,而 connect_phase 的代碼一定在 end_of_elaboration_phase 之前執(zhí)行等等。遵循 UVM 的這種代碼順序劃分原則,可以在很大程度上減少驗證平臺開發(fā)者的工作量,讓其從一部分雜亂的工作中解脫出來。
?function phase:不消耗仿真時間,而其也可分成兩大類:
1. 繼承自 uvm_bottomup_phase, 在 UVM component 樹中,自下而上的執(zhí)行, 如 connect_phase2. 繼承自 uvm_topdown_phase, 在 UVM component 樹中,自上而下執(zhí)行, 如 build_phase
?task phase:消耗仿真時間的,也稱動態(tài)運行(run-time)phase.
在初學 UVM 進行驗證過程中,只需要關(guān)注其中幾個 phase 即可。將組件的例化在 build_phase 實現(xiàn),組件連接在 connect_phase 實現(xiàn),測試的過程在 run_phase 中實現(xiàn)。就像下面 cfg_monitor 的代碼一樣,分步驟完成環(huán)境的構(gòu)建。
class cfg_monitor extends uvm_monitor;
local virtual cfg_intf intf;
uvm_blocking_put_port #(cfg_item) mon_bp_port;
`uvm_component_utils(cfg_monitor)
function new(string name="cfg_monitor", uvm_component parent);
endfunction
function void set_interface(virtual cfg_intf intf);
endfunction
task run_phase(uvm_phase phase);
endtask
task mon_trans();
endtask
endclass: cfg_monitor
從前面的圖中可以看到,run_phase 和旁邊十二個小的 phase 是并行的,UVM 為仿真提供了非常細致的階段劃分,即十二個小 phase,但是只使用 run_phase 也可以完成仿真。
?
工廠機制
在講解我們在 build_phase 所需,要完成的任務(wù)前,我們需要了解 UVM 中一個非常重要的機制 - 工廠機制。這并非是 UVM 獨創(chuàng)的機制,而是在設(shè)計模式中一種常用的機制。簡而言之,就是我們在編寫每個類時,都是在繪制圖紙,當我們完成圖紙以后,將圖紙遞交到工廠。仿真運行時,我們就能通過工廠,使用圖紙的名字,創(chuàng)建出不同的類。
繪制圖紙的過程就是在編寫類的代碼,而提交圖紙這個過程,體現(xiàn)在代碼中就是通過 UVM 的宏進行注冊,告訴工廠圖紙的名字。宏 uvm_component_utils 將 cfg_agent 注冊到工廠,而在構(gòu)造函數(shù)中,可以同時指定對象的默認名字。
注意 new 方法的參數(shù)中,string 是我們在創(chuàng)建組件時所需要傳遞的內(nèi)容,一定要與句柄的名字一直,否則在后續(xù)其他步驟中會出現(xiàn)意想不到的錯誤。而第二個參數(shù) parent 就是前面所提到的樹狀結(jié)構(gòu)的鉤子,父節(jié)點。
class cfg_agent extends uvm_agent;
`uvm_component_utils(cfg_agent)
function new(string name = "cfg_agent", uvm_component parent);
super.new(name, parent);
endfunction
endclass:cfg_agent
?
build_phase 的內(nèi)容
通過工廠機制我們可以很輕松地完成組件對象的實例化,下面就是一個示例。
class cfg_agent extends uvm_agent;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
driver = cfg_driver::type_id::create("driver", this);
monitor = cfg_monitor::type_id::create("monitor", this);
sequencer = cfg_sequencer::type_id::create("sequencer", this);
endfunction
endclass:cfg_agent
使用 component_name::type_id::create()就能通過工廠實例化對象,create 是 uvm_component 的一個靜態(tài)函數(shù),會返回組件的句柄,第一個參數(shù)就是我們 new 中的 string,建議與句柄名保持一致,第二個參數(shù)通常使用 this,表示創(chuàng)建的組件是在當前的組件的子節(jié)點上,從而構(gòu)建樹狀結(jié)構(gòu)。
有了創(chuàng)建組件的方法,我們就能通過 build_phase 實現(xiàn)組件的構(gòu)建。我們知道,整個環(huán)境是一個樹狀結(jié)構(gòu),那么檢索樹狀結(jié)構(gòu)就有兩個方向,自頂向下和自底向上。我們觀察 create 的參數(shù),發(fā)現(xiàn)需要傳遞父節(jié)點的句柄,那么很顯然,build_phase 是自頂向下的。從下面的代碼就能看到,在 build_phase 中,我們需要完成與本節(jié)點相連的子節(jié)點的創(chuàng)建,這樣一層一層的勾起組件,從根到最末端,所有的 build_phase 完成以后再進入下一個 phase。
class conv_base_test extends uvm_test;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
this.env = conv_env::type_id::create("env", this);
endfunction
endclass: conv_base_test
class conv_env extends uvm_env;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
this.chker = conv_checker::type_id::create("chker", this);
this.cfg_agt = cfg_agent::type_id::create("cfg_agt", this);
this.fmi_agt = mem_in_agent::type_id::create("fmi_agt", this);
this.wt_agt = mem_in_agent::type_id::create("wt_agt", this);
this.bias_agt = mem_in_agent::type_id::create("bias_agt", this);
this.fmo_agt = mem_out_agent::type_id::create("fmo_agt", this);
this.cvrg = conv_coverage::type_id::create("cvrg", this);
this.virt_sqr = conv_virtual_sequencer::type_id::create("virt_sqr", this);
endfunction
endclass: conv_env
class cfg_agent extends uvm_agent;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
driver = cfg_driver::type_id::create("driver", this);
monitor = cfg_monitor::type_id::create("monitor", this);
sequencer = cfg_sequencer::type_id::create("sequencer", this);
endfunction
endclass:cfg_agent
?
本期總結(jié)
1.UVM 的組件是樹狀連接的,環(huán)境中的 parent 和 oop 的父類是不一樣的
2.UVM 的運行劃分成多個 phase,每個 phase 負責不同的任務(wù),run_phase 與旁邊的十二個 phase 是并行的。整體運行從上至下順序運行。只有 run_phase 和并行的 phase 是 task,其他都是 funtion。
3. 使用宏在工廠中注冊,然后就能夠通過 create 靜態(tài)方法實現(xiàn)組件實例化
4. 在 build_phase 中順序創(chuàng)建字節(jié)點的組件,從而構(gòu)建整個環(huán)境