1.前言
本次講一下UVM中的uvm_config_db,在UVM中提供了一個(gè)內(nèi)部數(shù)據(jù)庫,可以在其中存儲(chǔ)給定名稱下的值,之后可以由其它TB組件去檢索。這樣的數(shù)據(jù)庫允許我們以不同的名稱存儲(chǔ)不同的配置設(shè)置,這些配置可以在需要時(shí)潛在地配置TB組件,而無需修改實(shí)際的TB代碼。比如說,我們需要TB打開某個(gè)checker,我們只需要提供這個(gè)checker的路徑并將數(shù)據(jù)庫中的變量設(shè)置為1,checker就可以檢查這個(gè)變量值,如果它打開了,就開始檢查DUT功能。uvm_config_db提供了訪問這個(gè)數(shù)據(jù)庫的接口,最常見的就是get()和set()函數(shù),函數(shù)定義如下:
static function void set(uvm_component cntxt,
string inst_name,
string field_name,
T value);
static function bit get(uvm_component cntxt,
string inst_name,
string field_name,
inout T value);
這兩個(gè)函數(shù)如何使用我想大家都清楚,調(diào)用一次set()就是往數(shù)據(jù)庫內(nèi)設(shè)置1個(gè)scope為{cntxt,”.”, inst_name},匹配符為field_name,值為value的配置。其中inst_name和field_name是支持正則匹配或glob類型匹配的。調(diào)用一次get()就是用scope為{cntxt,”.”, inst_name},匹配符為field_name的訪問方式在數(shù)據(jù)庫里檢索是否有匹配的設(shè)置,注意,這里的inst_name和field_name不支持正則匹配或glob類型匹配的,下面會(huì)具體說明。如果get()返回1就是找到了,返回0就算沒有找到。上述兩個(gè)函數(shù)中,如果cntxt傳遞的是null,那么UVM自動(dòng)會(huì)使用uvm_root::get()替換它。大家如果需要調(diào)試uvm_config_db的話,可以使用+UVM_CONFIG_DB_TRACE或uvm_config_db_options類內(nèi)的turn_on_tracing()/turn_off_tracing()/is_tracing()函數(shù)來進(jìn)行。
多啰嗦一下,如果uvm_config_db::set()對同1個(gè)配置在不同時(shí)間或不同地點(diǎn)設(shè)置了多次,那么uvm_config_db::get()的時(shí)候?qū)?huì)采用哪一次的呢?UVM會(huì)給它們指定不同的優(yōu)先級(jí),結(jié)論就是:如果是在build_phase指定的話,是按UVM hierarchy來的,層次越高優(yōu)先級(jí)越高,也就是uvm_test的優(yōu)先級(jí)會(huì)高于uvm_env,以此類推。但如果兩個(gè)組件是同一個(gè)UVM hierarchy的話,就是按時(shí)間順序來的,越往后set優(yōu)先級(jí)越高。在build_phase之后,就不在于UVM hierarchy了,都是按照時(shí)間順序來的,越往后set優(yōu)先級(jí)越高。
那么UVM中是如何做到uvm_config_db::set()和uvm_config_db::get()的匹配呢?這就涉及到了本文的主題了。簡單說就是字符串的正則匹配,在UVM內(nèi)部是通過uvm_glob_to_re()和uvm_re_match()這兩個(gè)函數(shù)來實(shí)現(xiàn)的,它們是在uvm_config_db背后默默工作的功臣。
在TB調(diào)用uvm_config_db::set()的時(shí)候,set函數(shù)會(huì)將參數(shù)cntxt和inst_name拼接起來后,調(diào)用用uvm_glob_to_re()轉(zhuǎn)換格式,再存到uvm_resource類里的scope字符串變量,set()的值也是放在uvm_resource類里。當(dāng)TB調(diào)用uvm_config_db::get()的時(shí)候,get函數(shù)也會(huì)將參數(shù)cntxt和inst_name拼接起來,再調(diào)用uvm_re_match()與uvm_resource_base類里的scope字符串進(jìn)行匹配,如果匹配成功,就返回這個(gè)uvm_resource類的值。這就完成了set()設(shè)置值和get()查找值的過程了。uvm_glob_to_re()和uvm_re_match()在其中扮演重要的角色,我們就來看看這兩個(gè)函數(shù)
這兩個(gè)函數(shù)都支持C版本和SV版本,兩個(gè)版本的功能有點(diǎn)差別,默認(rèn)是使用C版本,功能更強(qiáng)大點(diǎn)。如果TB沒有定義了UVM_REGEX_NO_DPI或UVM_NO_DPI宏的話,那么用的是DPI-C import進(jìn)來的C版本,反之是Systemverilog版本的。
2. uvm_glob_to_re()函數(shù)
C版本的uvm_glob_to_re()函數(shù)定義如下:
const char * uvm_glob_to_re(const char *glob)
import "DPI-C" function string uvm_glob_to_re(string glob);
它會(huì)將輸入的glob字符串(glob類型匹配格式)轉(zhuǎn)成真正的正則表達(dá)式格式(POSIX regular expression)。也就是把輸入字符串中g(shù)lob元字符替換為正則元字符,并在開頭和結(jié)尾分別加上/^和$/。glob類型匹配和正則匹配區(qū)別,大家可以自行查找資料下。
SV版本的uvm_glob_to_re()函數(shù)定義如下:
function string uvm_glob_to_re(string glob);
return glob;
endfunction
從這個(gè)函數(shù)內(nèi)容就可以看出,它不對輸入的字符串做任何處理。
3. uvm_re_match()函數(shù)
C版本的uvm_re_match()函數(shù)定義如下:
int uvm_re_match(const char * re, const char *str)
import "DPI-C" function int uvm_re_match(string re, string str);
可以看到它有兩個(gè)參數(shù),第一個(gè)參數(shù)(re)是匹配的正則表達(dá)式,第二個(gè)參數(shù)(str)匹配的字符串,如果re在str里找到它要匹配的字符串,就返回0,反之返回1。
SV版本的uvm_re_match()函數(shù)定義如下:
function int uvm_re_match(string re, string str);
它的參數(shù)和返回值與C版本定義一樣,不過它是支持glob類型匹配,也就是re必須是glob類型格式的。
對于uvm_config_db來說,在調(diào)用get()函數(shù)檢索數(shù)據(jù)庫的時(shí)候,get()函數(shù)傳遞的{cntxt,”.”, inst_name}會(huì)作為uvm_re_match()的str的實(shí)參,set()函數(shù)設(shè)置的{cntxt,”.”, inst_name}在經(jīng)過uvm_glob_to_re()處理后作為uvm_re_match()的實(shí)參,這也就是為什么set()參數(shù)的inst_name支持正則格式,而get()參數(shù)的inst_name只是簡單字符而已。
4. 例子分析
測試源代碼如下:
str_re = "uvm_test_top.*monitor";
$display("uvm_glob_to_re() converts %s to %s", str_re, uvm_glob_to_re(str_re));
str = "uvm_test_top.a.b.c.monitor";
$display("%s and %s, match result is: %s", str_re, str,
uvm_re_match(uvm_glob_to_re(str_re), str)==1'b0 ? "MATCH" : "MISMATCH");
uvm_config_db #(bit)::set(null, str_re, "test_var", 1'b1);
if ( uvm_config_db #(bit)::get(null, str, "test_var", test_var) )
$display("Get the test_var from path: %s", str);
else
$display("Not get the test_var from path: %s", str);
str = "uvm_test.*.monitor";
$display("%s and %s, match result is: %s", str_re, str,
uvm_re_match(uvm_glob_to_re(str_re), str)==1'b0 ? "MATCH" : "MISMATCH");
uvm_config_db #(bit)::set(null, str_re, "test_var", 1'b1);
if ( uvm_config_db #(bit)::get(null, str, "test_var", test_var) )
$display("Get the test_var from path: %s", str);
else
$display("Not get the test_var from path: %s", str);
str_re = "zhuanxinzhizhier";
str = "yes_zhuanxinzhizhier_yes";
$display("%s and %s, match result is: %s", str_re, str,
uvm_re_match(str_re, str)==1'b0 ? "MATCH" : "MISMATCH");
當(dāng)TB沒有定義UVM_REGEX_NO_DPI或UVM_NO_DPI宏時(shí),也就是函數(shù)采用C版本函數(shù),Questasim輸出的結(jié)果為:
# uvm_glob_to_re() converts uvm_test_top.*monitor to /^uvm_test_top\\..*monitor$/
# uvm_test_top.*monitor and uvm_test_top.a.b.c.monitor, match result is: MATCH
# Get the test_var from path: uvm_test_top.a.b.c.monitor
# uvm_test_top.*monitor and uvm_test.*.monitor, match result is: MISMATCH
# Not get the test_var from path: uvm_test.*.monitor
# zhuanxinzhizhier and yes_zhuanxinzhizhier_yes, match result is: MATCH
當(dāng)TB有定義UVM_REGEX_NO_DPI或UVM_NO_DPI宏時(shí),也就是函數(shù)采用SV版本,Questasim輸出的結(jié)果為:
# uvm_glob_to_re() converts uvm_test_top.*monitor to uvm_test_top.*monitor
# uvm_test_top.*monitor and uvm_test_top.a.b.c.monitor, match result is: MATCH
# Get the test_var from path: uvm_test_top.a.b.c.monitor
# uvm_test_top.*monitor and uvm_test.*.monitor, match result is: MISMATCH
# Not get the test_var from path: uvm_test.*.monitor
# zhuanxinzhizhier and yes_zhuanxinzhizhier_yes, match result is: MISMATCH
從上述兩個(gè)log的最后一行打印我們可以看出C版本函數(shù)功能還是更加強(qiáng)大。大家使用uvm_config_db::set()和uvm_config_db::get()時(shí),要牢記set()的參數(shù)inst_name是支持正則匹配的,而get()的參數(shù)inst_name是不支持正則匹配的也就是get()的參數(shù)inst_name里就算包含*/?/+等特殊字符,也是會(huì)當(dāng)作普通字符而已,而不會(huì)被處理成正則匹配里的元字符。
-
UVM
+關(guān)注
關(guān)注
0文章
182瀏覽量
19171 -
DUT
+關(guān)注
關(guān)注
0文章
189瀏覽量
12384
發(fā)布評(píng)論請先 登錄
相關(guān)推薦
評(píng)論