UVM中config_db机制的使用方法

set函数与get函数的参数

config_db机制用于在UVM验证平台间传递参数。他们通常是成对出现的。set函数时寄信,get函数是收信。
如在某个测试用例的build_phase中可以使用如下方式寄信:
uvm_config_db#(int)::set(this, "env.i_agt.drv" "pre_num", 100);
其中第一个参数和第二个参数联合起来组成目标路径,与此路径符合的目标才能收信。第一个参数必须是一个uvm_component实例的指针,第二个参数是相对此实例的路径。一般的,如果第一个参数被设置为this,那么第二个参数可以是一个空的字符串。第三个参数就是set函数中的第三个参数,这两个参数必须严格匹配,第四个参数则是要设置的变量。

在top_tb中通过config_db机制的set函数设置virtual interface时,set函数的第一个函数为null。在这种情况下,UVM会自动把第一个单数替换为uvm_root::get(),即uvm_top。换句话说,以下两种写法完全等价:

uvm_config_db#(virtual my_if)::set(null, "uvm_test_top.env.i_agt.drv", "vif", input_vif);
uvm_config_db#(virtual my_if)::set(uvm_root::get(), "uvm_test_top.env.i_agt.drv", "vif", input_vif);

set及get函数中第三个参数可以与get函数中第四个参数不一样。

umv_config_db#(int)::set(this, "env.i_agt.drv", "p_num", 100);
umv_config_db#(int)::set(this, "", "p_num", pre_num);

省略get语句
src/ch3/section3.5/3.5.3/my_driver.sv

7 int pre_num;
8 `uvm_component_utils_begin(my_driver)
9 `uvm_field_int(pre_num, UVM_ALL_ON)
10 `uvm_component_utils_end
11
12 function new(string name = "my_driver", uvm_component parent = null);
13 super.new(name, parent);
14 pre_num = 3;
15 endfunction
16
17 virtual function void build_phase(uvm_phase phase);
18 `uvm_info("my_driver", $sformatf("before super.build_phase, the pre_num is %0d", pre_num), UVM_LOW)
19 super.build_phase(phase);
20 `uvm_info("my_driver", $sformatf("after super.build_phase, the pre_num is %0d", pre_num), UVM_LOW)
21 if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
22 `uvm_fatal("my_driver", "virtual interface must be set for vif!!!")
23 endfunction

uvm_config_db#(int)::get(this, "", "pre_num", pre_num);
这里的关键是build_phase中的super.build_phase语句,当执行到driver的super.build_phase时,会自动执行get语句。这种做法的前
提是:第一,my_driver必须使用uvm_component_utils宏注册;第二,pre_num必须使用uvm_field_int宏注册;第三,在调用set函数
的时候,set函数的第三个参数必须与要get函数中变量的名字相一致,即必须是pre_num。

跨层次的多重设置

在图3-4中,假如uvm_test_top和env中都对driver的pre_num的值进行了设置,在uvm_test_top中的设置语句如下:
文件:src/ch3/section3.5/3.5.4/normal/my_case0.sv

32 function void my_case0::build_phase(uvm_phase phase);
33 super.build_phase(phase);
…
39 uvm_config_db#(int)::set(this,
40 "env.i_agt.drv",
41 "pre_num",
42 999);
43 `uvm_info("my_case0", "in my_case0, env.i_agt.drv.pre_num is set to 999",UVM_LOW)

在env的设置语句如下:
文件:src/ch3/section3.5/3.5.4/normal/my_env.sv

19 virtual function void build_phase(uvm_phase phase);
20 super.build_phase(phase);
…
31 uvm_config_db#(int)::set(this,
32 "i_agt.drv",
33 "pre_num",
34 100);
35 `uvm_info("my_env", "in my_env, env.i_agt.drv.pre_num is set to 100",UVM_LOW)
36 endfunction

那么driver中获取到的值是100还是999呢?答案是999。UVM规定层次越高,那么它的优先级越高。这里的层次指的是在UVM
树中的位置,越靠近根结点uvm_top,则认为其层次越高。uvm_test_top的层次是高于env的,所以uvm_test_top中的set函数的优先
级高。
上述结论在set函数的第一个参数为this时是成立的,但是假如set函数的第一个参数不是this会如何呢?假设uvm_test_top的set语句是:
文件:src/ch3/section3.5/3.5.4/abnormal/my_case0.sv
32 function void my_case0::build_phase(uvm_phase phase);
33 super.build_phase(phase);

39 uvm_config_db#(int)::set(uvm_root::get(),
40 “uvm_test_top.env.i_agt.drv”,
41 “pre_num”,
42 999);
43 `uvm_info(“my_case0”, “in my_case0, env.i_agt.drv.pre_num is set to 999”, UVM_LOW)

而env的set语句是:
文件:src/ch3/section3.5/3.5.4/normal/my_env.sv
19 virtual function void build_phase(uvm_phase phase);
20 super.build_phase(phase);

31 uvm_config_db#(int)::set(uvm_root::get(),
32 “uvm_test_top.env.i_agt.drv”,
33 “pre_num”,
34 100);
35 `uvm_info(“my_env”, “in my_env, env.i_agt.drv.pre_num is set to 100”,UVM_LOW)
36 endfunction
这种情况下,driver得到的pre_num的值是100。由于set函数的第一个参数是uvm_root::get(),所以寄信人变成了uvm_top。在这种情况下,只能比较寄信的时间。UVM的build_phase是自上而下执行的,my_case0的build_phase先于my_env的build_phase执行。所以my_env对pre_num的设置在后,其设置成为最终的设置。
假如uvm_test_top中set函数的第一个参数是this,而env中set函数的第一个参数是uvm_root::get(),那么driver得到的
pre_num的值也是100。这是因为env中set函数的寄信人变成了uvm_top,在UVM树中具有最高的优先级。
因此,无论如何,在调用set函数时其第一个参数应该尽量使用this。在无法得到this指针的情况下(如在top_tb中),使用null
或者uvm_root::get()。

同一层次的多重设置

当跨层次来看待问题时,是高层次的set设置优先;当处于同一层次时,上节已经提过,是时间优先。

uvm_config_db#(int)::set(this, "env.i_agt.drv", "pre_num", 100);
uvm_config_db#(int)::set(this, "env.i_agt.drv", "pre_num", 109);

当上面两个语句同时出现在测试用例的build_phase中时,driver最终获取到的值将会是109。像上面的这种用法看起来完全是
胡闹,没有任何意义。
验证中写代码的一个原则是同样的语句只在一个地方出现,尽量避免在多个地方出现。解决这个问题的办法就是在base_test的
build_phase中使用config_db::set进行设置,这样,当由base_test派生而来的case1~case99在执行super.build_phase(phase)时,都会进行设置:

classs base_test extends uvm_test;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
uvm_config_db#(int)::set(this, "env.i_agt.drv", pre_num_max, 7);
endfunction
endclass
class case1 extends base_test;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
endclass
…
class case99 extends base_test;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
endclass

但是对于第100个测试用例,则依然需要这么写:

class case100 extends base_test;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
uvm_config_db#(int)::set(this, "env.i_agt.drv", pre_num_max, 100);
endfunction
endclass

case100的build_phase相当于如下所示连续设置了两次:

uvm_config_db#(int)::set(this, "env.i_agt.drv", "pre_num", 7);
uvm_config_db#(int)::set(this, "env.i_agt.drv", "pre_num", 100);

按照时间优先的原则,后面config_db::set的值将最终被driver得到。

你可能感兴趣的:(UVM,uvm_config_db)