如何在有效的使用uvm_config_db來搭建uvm驗證環境對於許多驗證團隊來說仍然是一個挑戰。一些驗證團隊完全避免使用它,這樣就不能夠有效利用它帶來的好處;另一些驗證團隊卻過多的使用它,這讓驗證環境變得不穩定。
本文討論如何簡單有效平衡的在驗證環境中使用uvm_config_db,讓它驗證環境貢獻最多的力量,卻又不會成為驗證環境搭建的累贅。
接下來=通過三部分來進行闡述:
-
uvm_config_db的使用方法
-
uvm_config_db的作用對象
-
uvm_config_db的具體應用
第一部分:uvm_config_db的使用方法
uvm_config_db作用是把驗證環境的一些資源配置為類似全局變量一樣,使得它對於整個驗證環境來說是可見的。最常見的是在驗證環境頂層通過它對一些組件進行配置,組件可以在建立的階段讀取這些配置實現組件不同工作模式的切換,下面是使用uvm_config_db的語法:
uvm_config_db#(T)::set(uvm_component cntxt, string inst_name, string field_name, T value);
uvm_config_db#(T)::get(uvm_component cntxt, string inst_name, string field_name, ref T value);
例子:
uvm_config_db#(virtual my_if)::set(null, "uvm_test_top", "vif", input_if)
uvm_config_db#(virtual my_if)::get(this, "", "vif", vif)
在以上兩個函數set和get是使用它時要調用的函數,set表示把要處理的資源放進全局可見的數據庫,get表示從全局可見的數據庫輸出需要的資源,使用set和get函數時有五個參數需要制定,第一個是uvm_config_db類的參數#(T),T表示要set或get的資源的類型,它可以是虛擬接口,sequencer等等,第二個cntxt和第三個參數inst_name一起定義了uvm_config_db中set或get函數的作用范圍。第四個參數決定了是對作用范圍中的哪個對象或變量進行操作,第五個參數value會存儲當前操作對象的句柄或者操作變量的值。需要注意的是,當制定第二個參數是一個uvm組件時,uvm會用它的全局名字取替換它,而全局名字會通過uvm的get_full_name來獲取。
第二部分:uvm_config_db的作用對象
在uvm驗證環境中並不是所有的資源我們都會用uvm_config_db去配置,這樣會讓我們的驗證環境變得不可維護,下面是一些典型的在驗證環境中使用uvm_config_db去配置的資源:
-
虛擬接口,虛擬接口提供了一個訪問真實虛接口的入口,我們會把虛擬接口的句柄放到全局的數據庫中,uvm中的這些組件會通過get函數拿到虛擬接口的句柄對接口數據進行操作。
-
配置數據,負責配置環境的類中包含許多可以控制驗證環境的變量,它會改變這些變量,並且通過set函數把它放到我們全局的數據庫中,其他的組件通過get函數來取到這些變量的值,再根據這些值去改變工作模式
-
sequencers,在uvm中sequencers負責把我們寫的sequence進行排隊送到driver上去,所以sequence需要有對sequencer的訪問入口,我們同樣通過uvm_config_db的方式來把sequencer的句柄傳給sequence
第三部分:uvm_config_db的具體應用
上圖是我們的一個設計實例,下面介紹針對上圖的實例我們應該如何使用uvm_config_db,首先我們把上圖中可以配置的資源用一張更清晰的表列出來,如下:
在上面的表中,一共有四列,分別列出了五個接口的描述,類型,傳送的數據類型以及它們自己唯一性的名字,下面把它對應到uvm_config_db的調用函數set和get中。
對於第二列type類型,我們會把它放入uvm_config_db的第一個參數#(T)的位置,表示處理的數據類型是axi_if,如下:
uvm_config_db#(virtual vif axi_if)::get(...
uvm_config_db#(virtual vif axi_if)::set(..
而對於第三列,transaction是在配置sequencer時需要制定的傳送類型,然后再把sequencer放到全局數據庫中去,如下:
typedef uvm_sequencer#(axi_transaction) axi_sequencer_t;
uvm_config_db#(axi_sequencer_t)::set(...
uvm_config_db#(axi_sequencer_t)::get(...
對於identifier這一列會被放在前面語法解析部分中的inst_name部分,這一列的名字要求是唯一的,但是如果接口或者sequencer的類型不同,則允許重復,例如如果都是axi_if類型,那么要求名字必須具有唯一性,因為它們處於同一個數據庫(axi_if數據庫)中,而如果一個類型是ahb_if,另一個是axi_if,則不要求唯一性,因為它們處於不同數據庫的區域中。
typedef uvm_sequencer#(axi_transaction) axi_sequencer_t;
uvm_config_db#( virtual axi_if )::set(cntxt, inst_name, "primary_master",...
uvm_config_db#(axi_sequencer_t)::set(cntxt, inst_name, "primary_master",...
uvm_config_db#( virtual axi_if )::get(cntxt, inst_name, "primary_master",...
uvm_config_db#(axi_sequencer_t)::get(cntxt, inst_name, "primary_master",...
上面為了能夠更清楚的展示細節,所有的identifier都是用字符串,但在實際項目中為了以后的復用,我們會考慮定義一個package文件,把所有的identifier都用一個全局變量代替,這樣方便以后維護,具體如下圖:
// In a test level parameters package
// This code defines the unique string used to identify each interface in the resource database
// A parameter is used to eliminate runtime errors due to typing errors.
parameter string PRIMARY_MASTER = "primary_master";
parameter string SECONDARY_MASTER = "secondary_master";
parameter string CONFIG_MASTER = "config_master";
parameter string MEMORY_SLAVE = "memory_slave";
parameter string PERIPHERAL_SLAVE = "peripheral_salve";
配置interface到全局數據庫
// In the module where the interfaces reside
uvm_config_db#(virtual axi_if)::set(null, "VIRTUAL_INTERFACES", PRIMARY_MASTERS, primary_axi_master_bus);
uvm_config_db#(virtual axi_if)::set(null, "VIRTUAL_INTERFACES", SECONDARY_MASTER, secondary_axi_master_bus);
uvm_config_db#(virtual apb_if)::set(null, "VIRTUAL_INTERFACES", CONFIG_MASTER, config_apb_master_bus);
uvm_config_db#(virtual axi_if)::set(null, "VIRTUAL_INTERFACES", MEMORY_SLAVE, axi_memory_slave_bus);
uvm_config_db#(virtual ahb_if)::set(null, "VIRTUAL_INTERFACES", PERIPHERAL_SALVE, peripheral_ahb_slave_bus);
配置sequencer為默認sequencer
//In the agents class declaration file
//Each protocol would have its own agent class: axi_agent, apb_agent, etc.
//For this example xxx represent axi,apb or ahb
class xxx_agent extends uvm_agent #(...
//This variable is a handle to thihs agents configuration class
xxx_configuration xxx_config;
function void build_phase(uvm_phase phase);
//Get this agents configuration
uvm_config_db#(xxx_configuration)::get(this, "", "AGENT_CONFIG", xxx_config);
...
//Place this agents sequencer in the uvm_config_db using the interface identifier
uvm_config_db#(uvm_sequencer #(xxx_transaction))::set(null, "SEQUENCERS", xxx_config.interface_name, xxx_sequencer);
配置發送數據波形可見
總結
本篇論文詳細介紹了uvm_config_db在uvm驗證環境中的應用(interface,config,sequencer),它的使用可以極大的方便我們對一些需要全局可見的變量或類的處理,讓我們能夠更容易的去管理驗證環境中的一些組件,也在一定程度上方便了構建測試激勵的驗證人員,他們無須關注驗證環境的細節便可以構建測試場景對設計行為進行驗證。