1. field_automation机制
1.1 介绍
利用`uvm_field_* 宏,将类中的成员变量注册到UVM中,UVM可自动为其实现compare、copy、print、pack/unpack等方法,不需要自己去定义。解决 逐字段对transaction进行操作 的问题,极大地简化了验证平台的搭建,提高了效率。
1.2 用法
使用uvm_object_utils_begin和uvm_object_utils_end来实现my_transaction的factory注册,在这两个宏中间,使用uvm_field宏注册所有字段。uvm_field系列宏随着transaction成员变量的不同而不同。
1.3 相关宏
简单的uvm_field系列宏
`define uvm_field_int(ARG,FLAG)
`define uvm_field_real(ARG,FLAG)
`define uvm_field_enum(T,ARG,FLAG)
`define uvm_field_object(ARG,FLAG)
`define uvm_field_event(ARG,FLAG)
`define uvm_field_string(ARG,FLAG)
动态数组:
`define uvm_field_array_enum(ARG,FLAG)
`define uvm_field_array_int(ARG,FLAG)
`define uvm_field_array_object(ARG,FLAG)
`define uvm_field_array_string(ARG,FLAG)
静态数组:
`define uvm_field_sarray_int(ARG,FLAG)
`define uvm_field_sarray_enum(ARG,FLAG)
`define uvm_field_sarray_object(ARG,FLAG)
`define uvm_field_sarray_string(ARG,FLAG)
队列:
`define uvm_field_queue_enum(ARG,FLAG)
`define uvm_field_queue_int(ARG,FLAG)
`define uvm_field_queue_object(ARG,FLAG)
`define uvm_field_queue_string(ARG,FLAG)
联合数组:(第一个类型是存储数据类型,第二个类型是索引类型)
`define uvm_field_aa_int_string(ARG, FLAG)
`define uvm_field_aa_string_string(ARG, FLAG)
`define uvm_field_aa_object_string(ARG, FLAG)
`define uvm_field_aa_int_int(ARG, FLAG)
`define uvm_field_aa_int_int_unsigned(ARG, FLAG)
`define uvm_field_aa_int_integer(ARG, FLAG)
`define uvm_field_aa_int_integer_unsigned(ARG, FLAG)
`define uvm_field_aa_int_byte(ARG, FLAG)
`define uvm_field_aa_int_byte_unsigned(ARG, FLAG)
`define uvm_field_aa_int_shortint(ARG, FLAG)
`define uvm_field_aa_int_shortint_unsigned(ARG, FLAG)
`define uvm_field_aa_int_longint(ARG, FLAG)
`define uvm_field_aa_int_longint_unsigned(ARG, FLAG)
`define uvm_field_aa_string_int(ARG, FLAG)
`define uvm_field_aa_object_int(ARG, FLAG)
2. config_db机制
2.1 介绍
用来传递参数,一般有以下三种应用场景:
(1)传递virtual interface到环境中。
(2)设置单一变量值,例如int、string、enum等。
(3)传递配置对象到环境。
2.2 用法
set函数是寄信,而get函数是收信。如在某个测试用例的build_phase中可以使用如下方式寄信:uvm_config_db#(int)::set(this,"env.i_agt.drv","pre_num",100);
其中第一个和第二个参数联合起来组成目标路径,与此路径符合的目标才能收信。第一个参数必须是一个uvm_component实例的指针,第二个参数是相对此实例的路径。第三个参数表示一个记号,用以说明这个值是传给目标中的哪个成员的,第四个参数是要设置的值。
在driver中的build_phase使用如下方式收信:uvm_config_db#(int)::get(this,"","pre num",pre num);
get函数中的第一个参数和第二个参数联合起来组成路径。第一个参数也必须是一个uvm_component实例的指针,第二个参数是相对此实例的路径。一般的,如果第一个参数被设置为this,那么第二个参数可以是一个空的字符串。第三个参数就是set函数中的第三个参数,这两个参数必须严格匹配,第四个参数则是要设置的变量。
2.3 使用实例
2.3.1 interface传递
在实现接口传递的过程中需要注意:
(1)在传递过程中的类型应当为virtual interface,即实际接口的句柄。
(2)接口传递应该发生在run_test()之前。这保证了在进入build phase之前,virtual interface已经被传递到uvm_config_db中。
interface intf1;
logic enable=0;
endinterface
class compl extends uvm component;
`uvm_component_utils(comp1)
virtual intf1 vif;
function void build_phase(uvm phase phase);
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 before set", vif. enable), UVM LOW)
vif.enable=1;
`uvm info("SETVAL",$sformatf("vif. enable is b after set", vif. enable), UVM LOW)
endfunction
endclass
class testl extends uvm_test;
`uvm_component_utils(test1)
comp1(c1)
endclass
intf1 intf();
initial begin
uvm_config_db#(virtual intf1)::set(uvm root::get(),"uvm test top. cl","vif", intf);
run test("test1");
end
//输出结果:
UVM_INFO @ 0:reporter [RNTST] Running test test1...
UVM_INFO @ 0:uvm_test_top.cl [SETVAL] vif.enable is 0 before set
UVM_INFO @ 0:uvm_test_top.cl [SETVAL] vif.enable is 1 after set
2.3.2 变量传递
在各个test中, 可以在build phase对底层组件的变量加以配置, 进而在环境例化之前完成配置, 使得环境可以按照预期运行。
代码与2.3.1类似。
2.3.3 object传递
在test配置中,需要配置的参数不只是数量多,而且可能还分属于不同的组件,如果每个变量单独传递,容易出错,还不能复用。因此我们可以将每个组件中的变量加以整合,首先放置到一个uvm_object中,再对中心化的配置对象进行传递,会更有利于整体环境的修改维护。
class configl extends uvm object;
int val1=1;
int str1="null";
uvm_object_uti1s(config1)
...
endclass
class comp1 extends uvm_component;
`uvm_component_uti1s(comp1)
configl cfg;
...
function void build_phase(uvm phase phase);
uvm_object_tmp;
uvm_config_db#(uvm_object):: get(this,"","cfg", tmp);
void'($cast(cfg, tmp));
uvm_info("SETVAL",$sformatf("cfg.vall is %d after get", cfg. val1), UVM_LOW)
uvm_info("SETVAL",$sformatf("cfg.str1 is %s after get", cfg. str1), UVM_LOW)
endfunction
endclass
class test1 extends uvm_test;
`uvm component utils(test1)
comp1 c1,c2;
config1 cfgl,cfg2;
...
function void build_phase(uvm_phase phase);
cfg1=config1::type id::create("cfg1");
cfg2=configl::type_id::create("cfg2");
cfg1.val1=30;
Cfg1.strl="c1";
Cfg2.val1=50;
cfg2.strl="c2";
uvm_config_db#(uvm_object):set(this,"cl","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
3. factory机制
3.1 介绍
工厂模式的主要解决的问题是,将原来分布在各个地方的对象创建过程单独抽离出来,交给工厂类负责创建。其他地方想要使用对象直接找工厂(即调用工厂的方法)获取对象。
对象由工厂生产是利用工厂生产模具可灵活替代的好处,在不修改原有验证环境层次和验证包的同时,实现对环境内部组件类型或者对象的覆盖(override,或译成重载)。
3.2 用法
3.2.1 定义->注册->构建 缺一不可
component 构建函数function new (string name = " name", uvm_component parent = null)
创建对象comp_type::type_id::create(string name,uvm_component parent);
object 构建函数function new (string name = “name”)
创建对象object_type::type_id::create(string name);
class comp1 extends uvm_component;//1.定义
`uvm_component_utils(comp1)//2.注册
//3.构建函数
function new (string name = "comp1", uvm_component parent = null);
super.new(name,parent);
endfunction:new
endclass
class obj1 extends uvm_object;//1.定义
`uvm_object_utils(obj1)//2.注册
function new(string name = "obj1");//3.构建函数
super.new(name);
endfunction:new
endclass
//创建对象
comp1 c1,c2;
obj1 o1,o2;
initial begin
c1 = new("c1");
o1 = new("o1");
//建议使用下面方法创建对象
c2 = comp1::type_id::create("c2",null);
o2 = obj1::type_id::create("o2");
end
3.2.2 覆盖方法
覆盖机制可以将其原来所属类型替换为另一个新类型。
在覆盖之后,原本用来创建原型类型的请求,将由工厂来创建新的替换类型。
(1)无需修改原始代码,保证了原有代码的封装性
(2)新的替换类型必须与被替换的类型相兼容,否则稍后的句柄赋值将失败,所以使用继承。
(3)做顶层修改时,非常方便
使用create()来创建对象时:
(1)工厂会检查,是否有类型被覆盖,如果是,它会创建一个新类型的对象,如果不是,它会创建一个原有类型的对象
覆盖发生时,可以使用“类型覆盖”或者“实例覆盖”:
(1)类型覆盖(set_type_override())指,UVM层次结构下的所有原有类型都被覆盖类型所替换。
(2)实例覆盖(set_inst_override())指,某些位置中原有类型会被覆盖类型所替换

