在Systemverilog搭建的验证平台中,需要对各组件进行参数配置,但是配置各组件必须得在各组件实例化之后才能配置参数,例如test中必须得执行env = new();才能配置env.i_agt.drv.pen_num = 10;。再比如接口指针,需要就需要为每个组件设定设定set_interface();方法,非常繁琐。
而UVM提供的config_db机制可在组件实例化前就设定好配置信息,这样就可在tb的initial块中就进行设定了。真正将这些配置信息落实在各component,是在testbench运行过程build_phase中。
UVM提供了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, inout T value);
在UVM:类库中提到了UVM树和各component路径索引的概念,此处再强调一下,config_db机制需要写明路径。
component路径索引就是UVM树中从树根到对应component的路径,使用uvm_component类的get_full_name()方法
即
function void my_agent::build_phase(uvm_phase);
super.build_phase(phase);
drv = my_driver::type_id::create("drv",this); //在i_agt的build_phase中这样例化drv
...
endfunction
function void my_driver::build_phase(uvm_phase);
super.build_phase(phase);
uvm_report_info("my_driver",get_full_name(),UVM_LOW); //消息打印路径索引
endfunction
//打印消息为:"uvm_test_top.env.i_agt.drv"
注意,打印的路径是从uvm_test_top实例开始的,这是因为开发者只需定义my_test,而UVM树根uvm_top实例是自动创建的无需开发者定义。
打印出来的路径中,取的是各component的name,而不是对象名称!
也就是说如果drv = my_driver::type_id::create(“driver”,this);,那么打印的路径就变成了"uvm_test_top.env.i_agt.driver",但绝不推荐这么做,强烈建议各component的name与对象名保持一致!
get_full_name()可获取索引路径,还有其他一些方法可获取该component的其他信息。
//...\questasim\verilog_src\uvm-1.2\src\base\uvm_component.svh
function void uvm_component::get_children(ref uvm_component children[$]);
function int uvm_component::get_first_child(ref string name);
function int uvm_component::get_next_child(ref string name);
function uvm_component uvm_component::get_child(string name);
function int uvm_component::get_num_children();
function string uvm_component::get_full_name();
function uvm_component uvm_component::get_parent ();
function int unsigned uvm_component::get_depth();
//...\questasim\verilog_src\uvm-1.2\src\base\uvm_root.svh
extern static function uvm_root uvm_root::get(); //即返回指向实例uvm_top的uvm_root类句柄,注意是static类型
接口的传递从硬件世界到UVM环境中的传递可以通过uvm_config_db来实现。
在实现的过程中需要注意几点:
接口的传递应该发生在 run_test() 之前。这保证了在进入build_phase之前virtual interface已经被传递到uvm_config_db中;
应当把interface和virtual interface 的声明分开,在传递的过程中的类型应该为virtual interface(接口句柄)
interface intf1;
logic enable = 0;
endinterface
class comp1 extends uvm_component;//底层组件拿到config
`uvm_component_utils(comp1);
virtual intf1 vif;//声明接口要带virtual
...
function void build_phase(uvm_phase phase);
//这里的this的绝对路径是root.test.c1.vif
//第二个参数"",表示要找comp1里面的vif
if(!uvm_config_db#(virtual intf1)::get(this, "", "vif", vif))begin//判断是否有误
`uvm_error("GETVIF", "no virtual interface is assigned")
end
`uvm_info("SETVAL", $sformatf("vif.enable is %b after set", vif.enable),UVM_LOW)
vif.enable = 1;
endfunction
endclass
class test1 extends uvm_test;//顶层test中传递config
`uvm_component_utils(test1)
comp1 c1;
...
endclass
module tb;
intf1 intf();
initial begin
uvm_config_db#(virtual intf1)::set(uvm_root::get(), "uvm_test_top.c1", "vif", intf);//在run_test之前,将配置发送出去
run_test("test1");
end
endmodule
在各个test中,可以在build phase对底层组件的变量加以配置,进而在环境例化之前完成配置,使得环境可以按照预期运行
class comp1 extends uvm_component;
'uvm_component_utils(comp1)
int val1 = 1;
string str1 = "null";
...
function void build_phase(uvm_phase phase);
'uvm_info("SETVAL", $sformatf("vall is %d before get", vall), UVM_LOW)
'uvm_info("SETVAL", $sformatf("str1 is %s before get", str1), uvm_low)
uvm_config_db#(int)::get(this,"","vall",vall);
uvm_config_db#(string)::get(this,"","str1",str1);
endfunction
endclass
class test1 extends uvm_test;
'uvm_component_utils(test1)
comp1 c1;
...
function void build_phase(uvm_phase phase);
uvm_config_db#(int)::set(this,"c1","vall",100);//例化之前set
uvm_config_db#(string)::set(this,"c1","str1","comp1");
c1 = comp1::type_id::create("c1",this);
endfunction
endclass
如果要给底层配置的参数很多,就可以把封装在一个object类中,在顶层test中将类的实例对象句柄进行set传递;
底层通过get拿到对象句柄,就可以通过句柄获取配置类中的变量设置
//将参数封装到object中
class config1 extends uvm_object;
int vall = 1;
int str1 = "null";
'uvm_object_utils(config1)
endclass
//底层组件拿到config
class comp1 extend uvm_component;
'uvm_component_util(comp1)
config1 cfg;
...
function void build_phase(uvm_phase phase);
uvm_object tmp;
uvm_config_db#(uvm_object)::get(this, "","cfg", tmp);
//传递的是父类uvm_object,要获得子类的成员变量,所以要做类型转换
void'($cast(cfg,tmp));
'uvm_info("SETVAL",
$sformatf("cfg.vall is %d after get",cfg.vall),UVM_LOW)
'uvm_info("SETVAL",
$sformatf("cfg.str1 is %s after get", cfg.srt1),UVM_LOW)
endfunction
endclass
//顶层test中传递config
class test1 extends uvm_test;
'uvm_component_utils(test1)
comp1 c1,c2;
config cfg1,cfg2;
...
function void build_phase(uvm_phase phase);
cfg1 = config1::type_id::create("cfg1");
cfg2 = config1::type_id::create("cfg2");
cfg1.val1 = 30;
cfg1.str1 = "c1";
cfg2.val1 = 50;
cfg2.str1 = "c2";
//设置set
uvm_config_db#(uvm_object)::set(this, "c1", "cfg", cfg1);
uvm_config_db#(uvm_object)::set(this, "c2", "cfg", cfg2);
c1 = comp1::type_id::create("c1", this);
c2 = comp1::type_id::create("c2", this);
endfunction
endclass
版权声明:本文为CSDN博主「Starry丶」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Starry__/article/details/123007408
版权声明:本文为CSDN博主「卢卡猫」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sinat_41774721/article/details/121796065