1、前言:
在跟着路科视频学习UVM时,学的有点快,没有仔细搞清楚,用的时候就不知道具体在哪里设置set哪里设置get,今天再继续学一学。
2、config_db机制
1、set与get各自用该放在哪里
set与get一般都成对出现。
set:自顶层向下set,如从top_tb向driver设置参数,即在top_tb中set。
uvm_config_db#(int)::set(this, "env.agt.drv", "num", 100);
第一个参数this与第二个参数“env.agt.drv”——构成目标路径;因此也可以为(this.env, "agt.drv", "num", 100)
第三个参数是传给该路径的哪个成员;
第四个参数是要设置的值。
get:从底层向顶层get,如从driver中的build_phase使用get。
uvm_config_db#(int)::get(this, "","num", pre_num);
第一个参数必须是uvm_component实例的指针,第二个参数是相对此实例的路径。一般的,如果第一个参数被设置成this,第二个参数可以是一个空的字符串。
第三个参数要与set中的第三个参数严格一致。
第四个参数是要设置的值。
有些情况下get可以省略:
这里的关键在于:build_phase中的super.build_phase语句,当执行到driver的的super.build_phase时,会自动执行get语句。
class my_driver extends uvm_driver#(my_transaction);
virtual my_if vif;
int pre_num;
`uvm_component_utils_begin(my_driver)
`uvm_field_int(pre_num, UVM_ALL_ON)
`uvm_component_utils_end
function new(string name = "my_driver", uvm_component parent = null);
super.new(name, parent);
pre_num = 3;
endfunction
virtual function void build_phase(uvm_phase phase);
`uvm_info("my_driver", $sformatf("before super.build_phase, the num is %0d", pre_num), UVM_LOW)
super.build_phase(phase);
`uvm_info("my_driver", $sformatf("after super.build_phase, the num is %0d", pre_num), UVM_LOW)
if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
`uvm_fatal("my_driver", "virtual interface must be set for vif!!!")
endfunction
extern task main_phase(uvm_phase phase);
extern task drive_one_pkt(my_transaction tr);
endclass
这种做法的前提是:
1)my_driver必须使用宏注册。
2)num必须使用uvm_field_int宏注册。
3)在调用set函数时,set函数的第三个参数必须要与get函数中变量的名字相一致,必须为num。
2、当多个层次多次发送set时,最终得到哪个
1)先以时间为准,最近收到的具有最高权威;
2)当收到时间相同时,层次越高,优先级越低。例如,uvm_test_top与env都对driver进行了设置,则使用uvm_test_top的设置。
3、config_db的set和get一般都用在build_phase阶段
check_config_usage可以显示截至到此函数调用时有哪些参数时被设置过但是却没有被获取过。此函数一般在connect_phase被调用。
4、config_db使用场景
1)传递virtual interface到环境中。一般driver、moniter与DUT连接时使用config_db传递virtual interface。SV中层次化的interface的索引传递,不利于软件环境的封装和复用。
2)设置单一变量值,例如int、string、enum。
3)传递配置对象(config object)到环境。
5、实战
1)运行代码
interface uvm_config_if;
logic [31:0] addr;
logic [31:0] data;
logic [ 1:0] op;
endinterface
package uvm_config_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"
class config_obj extends uvm_object;
int comp1_var;
int comp2_var;
`uvm_object_utils(config_obj)
function new(string name = "config_obj");
super.new(name);
`uvm_info("CREATE", $sformatf("config_obj type [%s] created", name), UVM_LOW)
endfunction
endclass
class comp2 extends uvm_component;
int var2;
virtual uvm_config_if vif;
config_obj cfg;
`uvm_component_utils(comp2)
function new(string name = "comp2", uvm_component parent = null);
super.new(name, parent);
var2 = 200;
`uvm_info("CREATE", $sformatf("unit type [%s] created", name), UVM_LOW)
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("BUILD", "comp2 build phase entered", UVM_LOW)
//TODO-4.1
//Please get the interface and check if it is got
if(!uvm_config_db#(virtual uvm_config_if)::get(this, "", "vif", vif))
`uvm_error("GETVIF", "no virtual interface is assigned")
`uvm_info("GETINT", $sformatf("before config get, var2 = %0d", var2), UVM_LOW)
//TODO-4.3
//Please get the var2 from config_db
uvm_config_db#(int)::get(this, "", "var2", var2);
`uvm_info("GETINT", $sformatf("after config get, var2 = %0d", var2), UVM_LOW)
//TODO-4.2
//Please get the config object
uvm_config_db#(config_obj)::get(this, "", "cfg", cfg);
`uvm_info("GETOBJ", $sformatf("after config get, cfg.comp2_var = %0d", cfg.comp2_var), UVM_LOW)
`uvm_info("BUILD", "comp2 build phase exited", UVM_LOW)
endfunction
endclass
class comp1 extends uvm_component;
int var1;
comp2 c2;
config_obj cfg;
virtual uvm_config_if vif;
`uvm_component_utils(comp1)
function new(string name = "comp1", uvm_component parent = null);
super.new(name, parent);
var1 = 100;
`uvm_info("CREATE", $sformatf("unit type [%s] created", name), UVM_LOW)
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("BUILD", "comp1 build phase entered", UVM_LOW)
//TODO-4.1
//Please get the interface and check if it is got
if(!uvm_config_db#(virtual uvm_config_if)::get(this, "","vif",vif))
`uvm_error("GERINT","no virtual interface is assigned")
`uvm_info("GETINT", $sformatf("before config get, var1 = %0d", var1), UVM_LOW)
//TODO-4.3
//Please get the var1 from config_db
uvm_config_db#(int)::get(this,"","var1",var1);
`uvm_info("GETINT", $sformatf("after config get, var1 = %0d", var1), UVM_LOW)
//TODO-4.2
//Please get the config object
uvm_config_db#(config_obj)::get(this,"","cfg",cfg);
`uvm_info("GETOBJ", $sformatf("after config get, cfg.comp1_var = %0d", cfg.comp1_var), UVM_LOW)
c2 = comp2::type_id::create("c2", this);
`uvm_info("BUILD", "comp1 build phase exited", UVM_LOW)
endfunction
endclass
class uvm_config_test extends uvm_test;
comp1 c1;
config_obj cfg;
`uvm_component_utils(uvm_config_test)
function new(string name = "uvm_config_test", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("BUILD", "uvm_config_test build phase entered", UVM_LOW)
cfg = config_obj::type_id::create("cfg");
cfg.comp1_var = 100;
cfg.comp2_var = 200;
//TODO-4.2
//Please config the object to c1 and c2 by config_db
uvm_config_db#(config_obj)::set(this,"*","cfg",cfg);
//TODO-4.3
//Please config the c1.var1=20, c2.var2=20 by config_db
uvm_config_db#(int)::set(this,"c1","var1",10);
uvm_config_db#(int)::set(this,"c1.c2","var2",20);
c1 = comp1::type_id::create("c1", this);
`uvm_info("BUILD", "uvm_config_test build phase exited", UVM_LOW)
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
`uvm_info("RUN", "uvm_config_test run phase entered", UVM_LOW)
phase.raise_objection(this);
#1us;
phase.drop_objection(this);
`uvm_info("RUN", "uvm_config_test run phase exited", UVM_LOW)
endtask
endclass
endpackage
module uvm_config;
import uvm_pkg::*;
`include "uvm_macros.svh"
import uvm_config_pkg::*;
uvm_config_if if0();
//TODO-4.1
//Please set interface to the c1 and c2 in the environment
initial begin
uvm_config_db#(virtual uvm_config_if)::set(uvm_root::get(),"uvm_test_top.*","vif",if0);
run_test(""); // empty test name
end
endmodule
2)代码结构层次:实线代表componen 虚线代表object,橙色为变量
3)代码运行结果
4)总结:
(1)接口传递一定要在run_test之前;
(2)config_db操作要在c1、c2例化之前,例化前设置才能够创建实例后,将变量值设置进去。