在使用UVM搭建環境時,遇到問題時,調試方式有千千萬萬,但很有必要了解下UVM庫提供了哪些內建的調試手段,可以少走彎路,大大提升效率,而不是瘋狂加各種打印消息。
UVM庫給各個主要機制都提供了易于使用的內置調試方法,來輔助定位使用UVM環境遇到的問題。
一、調試config_db機制問題
UVM庫內實現了一個資源庫,它用于存儲配置信息,TB里各個組件可以根據情況使用config_db往里面存或者取各種類型數據。config_db存(set())和取(get())的關鍵在于字符串匹配,為此UVM庫提供了一些功能來幫助調試這些字符串匹配。
1. 使用+UVM_CONFIG_DB_TRACE和+UVM_RESOURCE_DB_TRACE命令行參數
UVM庫在Command Line上提供了+UVM_CONFIG_DB_TRACE和+UVM_RESOURCE_DB_TRACE命令行參數,當運行仿真命令時,如果帶上上述的參數,那么在log中會打印出對資源庫的存和取的信息。+UVM_CONFIG_DB_TRACE用于uvm_config_db進行的存取,+UVM_RESOURCE_DB_TRACE用于uvm_resource_db進行的存取。比如我們在Questasim工具的vsim命令后加上+UVM_CONFIG_DB_TRACE,然后有以下的uvm_config_db的set()和get()調用:
// In the TB env:
uvm_config_db #(int)::set(this, "*", "var", 666);
// In the TB driver:
int get_value;
if ( !uvm_config_db #(int)::get(this, "*", "var", get_value) ) begin
`uvm_fatal(get_type_name(), "var is missing in config_db")
end else begin
`uvm_info(get_type_name(), $sformatf("get var from env"), UVM_LOW)
end
那么在log中 可以找到以下打印信息:
UVM_INFO …/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0.000ns: reporter
// db類型 匹配字符串 數據類型 路徑 數據值
[CFGDB/SET] Configuration 'uvm_test_top.env.*.var' (type int) set by uvm_test_top.env = (int) 666
UVM_INFO …/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0.000ns: reporter [CFGDB/GET] Configuration
'uvm_test_top.env.d_agent.drv_h.*.var' (type int) read by uvm_test_top.env.d_agent.drv_h = (int) 666
從log信息可以看出,UVM會把對資源庫的set()和get()的數據類型,數據值、存取路徑、存取類型和匹配字符都打印出來,這樣就很方便我們去定位uvm_config_db的匹配問題了。
2. 調用UVM component內置函數
在uvm_component內部提供了print_config()內建函數,使用它可以打印出當前uvm_component范圍可見的所有config_db操作內容。如果參數recurse為1,會把所有子components的可見的config_db操作內容也遞歸調用打印出來。如果audit為1,會把調用config_db進行操作的時間、次數和操作者路徑也打印出來。print_config()的函數定義如下:
function void uvm_component::print_config(bit recurse = 0, audit = 0);
假如我們在之前例子的TB driver里調用:
print_config(.recurse(0), .audit(1));
那么將會有以下log輸出:
# var [/^uvm_test_top\\.env\\..*$/] : (int) 666
# UVM_INFO .../uvm-1.2/src/base/uvm_resource.svh(564) @ 0.000ns: reporter [UVM/RESOURCE/ACCESSOR]
uvm_test_top.env reads: 0 @ 0.000ns writes: 1 @ 0.000ns
# uvm_test_top.env.d_agent.drv_h reads: 1 @ 0.000ns writes: 0 @ 0.000ns
它會把TB driver上config_db操作的字符串匹配、數據類型和數據值都打印出來,另外,由于我們指定audit為1,因此也會把config_db操作的時間、次數和操作者路徑打印出來了。這個一個很強大的debug功能。
建議可以在end_of_elaboration_phase里去調用這個函數,因為這時候config_db操作基本都已經完成了。
3. dump整個資源庫
如果遇到奇怪的訪問資源庫問題無法解決,另一種暴力debug方式就是將整個資源庫都打印出來。UVM提供了uvm_config_db #()::dump()函數,可以將當前資源庫的信息都打印出來,其中可以指定任何類型,主要是因為dump()是個static的函數,提供任何類型最終訪問的dump()函數是同一個,打印出的資源庫信息也是一樣的。
比如我們仍在TB driver里調用:
uvm_config_db #(bit)::dump();
在log里增加的信息將有:
# UVM_INFO .../uvm-1.2/src/base/uvm_resource.svh(1347) @ 0.000ns: reporter
[UVM/RESOURCE/DUMP]
# === resource pool ===
...
# var [/^uvm_test_top\\.env\\..*$/] : (int) 666
...
# UVM_INFO .../uvm-1.2/src/base/uvm_resource.svh(1354) @ 0.000ns: reporter
[UVM/RESOURCE/DUMP] === end of resource pool ===
也是建議可以在end_of_elaboration_phase里去調用這個函數,因為這時候config_db操作基本都已經完成了。
結合上述的三個方法,可以說100%的config_db相關的問題都可以搞定了。
二、調試objection機制問題
Objection用于控制消耗時間的uvm_phase在何時結束,TB中raise和drop的objection次數要一樣,但如果在多個地方進行raise或drop的話,遇到objection沒有啟動或無法結束時,就比較難調試了。因此,UVM庫提供了用于跟蹤objection raise和drop的命令行參數+UVM_OBJECTION_TRACE。
比如我們在Questasim工具的vsim命令后加上+UVM_OBJECTION_TRACE。那么log里將增加以下類似信息。
# UVM_INFO @ 0.000ns: run [OBJTN_TRC] Object uvm_test_top raised 1 objection(s)
(START basetest): count=1 total=1
# UVM_INFO @ 0.000ns: run [OBJTN_TRC] Object uvm_top added 1 objection(s) to its
total (raised from source object uvm_test_top, START basetest): count=0 total=1
...
# UVM_INFO @ 14190.000ns: run [OBJTN_TRC] Object uvm_test_top dropped 1 objection(s)
(END basetest): count=0 total=0
# UVM_INFO @ 14190.000ns: run [OBJTN_TRC] Object uvm_test_top all_dropped 1 objection(s)
(END basetest): count=0 total=0
# UVM_INFO @ 14190.000ns: run [OBJTN_TRC] Object uvm_top subtracted 1 objection(s)
from its total (dropped from source object uvm_test_top, END basetest): count=0 total=0
# UVM_INFO @ 14190.000ns: run [OBJTN_TRC] Object uvm_top subtracted 1 objection(s)
from its total (all_dropped from source object uvm_test_top, END basetest): count=0 total=0
三、調試phase機制問題
為了幫助用戶查看各個uvm_phase在何時開始和結束,UVM庫提供了+UVM_PHASE_TRACE命令行參數。
比如我們在Questasim工具的vsim命令后加上+UVM_PHASE_TRACE。那么log里將增加以下類似信息。
# UVM_INFO .../uvm-1.2/src/base/uvm_phase.svh(1620) @ 0.000ns: reporter [PH/TRC/DONE]
Phase 'common.connect' (id=37) Completed phase
# UVM_INFO .../uvm-1.2/src/base/uvm_phase.svh(1655) @ 0.000ns: reporter [PH/TRC/SCHEDULED]
Phase 'common.end_of_elaboration' (id=40) Scheduled from phase common.connect
# UVM_INFO .../uvm-1.2/src/base/uvm_phase.svh(1345) @ 0.000ns: reporter [PH/TRC/STRT]
Phase 'common.end_of_elaboration' (id=40) Starting phase
# UVM_INFO .../uvm-1.2/src/base/uvm_phase.svh(1620) @ 0.000ns: reporter [PH/TRC/DONE]
Phase 'common.end_of_elaboration' (id=40) Completed phase
四、調試factory機制問題
UVM庫的factory機制用于創建對象,它是1個singleton對象,我們可以通過調用uvm_factory::get()獲得它的句柄。當我們對factory機制創建的對象有疑問時,可以使用factory機制提供的函數去調試有誰注冊了factory,factory override機制覆蓋了誰,最終factory為給定類型返回什么對象。Factory機制提供了3個函數去輔助debug。
1. print()
這個函數會根據參數all_types的不同,打印出當前factory中注冊的類型、實例覆蓋和類型覆蓋。它的定義為:
function void print (int all_types=1);
比如我們仍在TB driver中使用以下代碼:
uvm_factory f = uvm_factory::get();
f.print();
那么輸出log將增加以下類似信息:
#### Factory Configuration (*)
#
# No instance overrides are registered with this factory
#
# Requested Type Override Type
# -------------- -------------
# seq_base seq1
#
# All types registered with the factory: 288 total
# Type Name
# ---------
# ...
# (*) Types with no associated type name will be printed as < unknown >
從log中可以很清楚的看出,factory注冊了多少類型,類型之間的override關系,instance之間的override關系,基本上factory的問題看這個信息都可以搞定了。
2. debug_create_by_type()和debug_create_by_name()
這兩個函數對factory的搜索算法類似于create_ by_type()和create _by_type(),但它們不創建新對象。相反,它們提供了關于將返回的對象類型的詳細信息,和列出了override相關信息。具體傳遞參數用法,大家可以查詢UVM手冊。
總結上面的三個方法,不管有沒有factory問題,推薦統一都在TB base testcase的end_of_elaboration_phase里調用factory的print()函數,方便大家查詢。
五、調試TLM 問題
UVM中的組件是通過TLM ports/exports/imps連接在一起的。UVM提供了兩個函數都可以在port/export/imp上使用,可以幫助用戶理解哪些對象連接在一起的。這兩個函數是get_connected_to()和get_provided_to(),這兩個函數返回的是uvm_port_component_base類型的關聯數組。TLM ports通常是fanout類型的,所以它通常會使用get_connected_to(),TLM exports/imps通常是fanin類型的,所以它一般會使用get_provided_to()。
在IEEE 1800.2中,增加了debug_connected_to() 和debug_provided_to(),它們的功能與上述兩個函數其實一樣,只不過它們返回的是可視化文本消息,方便用戶查看。個人比較推薦使用這兩個函數。
這四個函數的定義如下:
function void get_connected_to (ref uvm_port_list list);
function void get_provided_to (ref uvm_port_list list);
function void debug_connected_to (int level=0, int max_level=-1);
function void debug_provided_to (int level=0, int max_level=-1);
這些函數需要在end_of_elaboration_phase里或之后調用,由于這時候TLM的port連接才完成了。
六、調試callback問題
Callback允許標準對象的外部對象上調用函數和任務,來擴展額外的功能。如果在UVM TB中使用callback功能,可以調用uvm_typed_callbacks#(type T=uvm_object)里的display()函數打印出當前注冊的所有callback。display()函數定義如下:
static function void display( T obj = null )
這個函數也是需要在end_of_elaboration_phase里調用,而且它是靜態類型的,可以使用uvm_callbacks(xxx)::display()方式使用。
UVM也給callback的調試增加了+define+UVM_CB_TRACE_ON編譯選項,當編譯帶上UVM_CB_TRACE_ON宏時,在log會也會打印出callback的跟蹤信息。
七、其它調試方式**
1.打印UVM層次結構
在UVM環境搭建后之后,我們可以通過print_topology()函數將UVM層次結構打印出來。
比如我們在TB里以下任一種方法代碼:
// 方法1:
uvm_top.print_topology(); // 需要UVM hierarchy建立之后調用
// 方法2:
uvm_top.enable_print_topology = 1; // 在end_of_elaboration phase之前調用
在log中會出現以” [UVMTOP] UVM testbench topology:”開頭的打印信息,里面詳細列出了當前UVM結構。
2. uvm_info打印控制
在UVM中,可以指定verbosity來有選擇性的打印出uvm_info里的消息。UVM提供了全局式和分布式的控制方法。
全局式:這種控制方法是使用+UVM_VERBOSITY命令行參數來完成的。
分布式:這種控制方法是使用每個組件自帶的verbosity設置方法完成的,通過使用+uvm_set_verbosity命令行參數。當然也可以直接在組件里使用set_report_verbosity_level()等方法設置的。
-
UVM
+關注
關注
0文章
182瀏覽量
19228 -
TLM
+關注
關注
1文章
32瀏覽量
24780
發布評論請先 登錄
相關推薦
評論