目录
具体地,对于方法compare如何写?uvm_pkg例化的对应全局数据操作配置成员是什么?
2.3 uvm_pkg中的全局控制对象uvm_default_comparer
2.5 2.6 uvm_object::print()和copy()
4.3 在顶层uvm_config_test配置变量c1和c2中的var
实验目标
问题清单
UVM的核心基类有哪些?
- factory类(2)
- transaction类和sequence类(3)
- 结构创建类(4)
- 环境组件类env component(5)
- 通信管道类(6)
- 信息报告类(7)
- 寄存器模型类(8)
- 线程同步类(9)
- 事务接口类(10)
什么是工厂?
- 工厂是为了更方便的替换验证环境中的实例或注册了的类型,带来配置的灵活性
工厂的注册、创建、覆盖机制是如何实现的?
首先是`uvm_component_utils()注册;然后是new函数,第二个参数是parent,必须调用super.new();最后是build_phase()函数,也是必须调用super.build_phase(p)函数
- 一旦注册,type_id::create()函数就可以通过uvm_factory::create_component_by_type()实现
class comp1 extends uvm_component;
`uvm_component_utils (comp1)//注册组件;new函数必须只有两个参数
function new (string name=:comp1", uvm_component parent=null);//parent是指上一层,当前实例是谁例化的,谁就是这个实例parent
super.new(name, parent);//继承父类new函数
$display($sformatf("%s is created", name));//已例化当前类
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase (phase);
endfunction: build_phase
endclass
然后是利用工厂创建对象,也就是例化:
例化component用c2 = comp1::type_id::create ("c2",null);也是两个参数
例化object用o2 = obj1::type_id::create("o2");
class obj1 extends uvm_object;
`uvm_object_utils (obj1)
function new (string name="obj1");//object只有一个参数
super.new(name);
$display ($sformatf("%s is created",name));
endfunction: new
endclass
comp1 c1, c2;
obj1 o1,o2;
initial begin
c1 = new ("c1");//任何对象的例化最终都是通过new()函数来实现,sv的方法
o1 = new ("o1");
c2 = comp1::type_id::create ("c2",null);//这个也是例化的写法,factory提供的方法
o2 = obj1::type_id::create("o2");
end
最后就是覆盖了,两种覆盖方法如下
set_inst_override ( uvm_object_wrapper override_type, string inst_path);
//uvm_object_wrapper override_type是注册过后的某一个类在工厂中注册时的句柄,用new_type::get_type()找到
一般用这种
set_type_override ( uvm_object_wrapper override_type);
覆盖机制只会影响通过工厂注册并且例化的对象
调用覆盖函数用comp2覆盖com1的函数如下
orig_type::type_id::set_type_override (new_type::get_type())
//typedef 静态函数 静态函数
//用new_type新类型替换原来的类型orig_type::type_id
例码如下.
module factory_override;
import uvm_pkg::*;//可直接import和include,编译器已经包含了
`inculde "uvm_macros.svh"
class comp1 extends uvm_component;//1声明
`uvm_component_utils(comp1)//2注册
function new (string name="comp1", uvm_component parent= null);//3new函数
super.new(name, parent);
$display ($sformatf("comp1::%s is created", name));
endfunction
virtual function void hello (string name);//virtual是关键
$display ( $sformatf("comp1:: %s is said hello!", name);
endfunction
endclass
class comp2 extends comp1;//要覆盖的类一定要继承于被覆盖的类
`uvm_component_utils(comp2)
function new (string name="comp2", uvm_component parent= null);
super.new(name, parent);
$display ($sformatf("comp2::%s is created", name));
endfunction
function void hello (string name);
$display ( $sformatf("comp2:: %s is said hello!", name);
endfunction
endclass
comp1 c1, c2;//两个句柄都是comp1的类型
initial begin
comp1::type_id::set_type_override (comp2::get_type());//调用覆盖函数,如上段例码
c1= new("c1");//例化c1(comp1),没有通过工厂。打印comp1::c1 is created,
c2= comp2::type_id::creare("c2",null);//工厂创建的对象,create返回一个comp2句柄给c2
//但是c2是comp1的句柄,却指向了comp2类型的对象。这里就是子类句柄覆盖父类句柄。所以必须是继承关系
//用工厂注册,就一定要用工厂来创建,达到便利的目的
//打印comp1::c2 is created,comp2::c2 is created
c1.hello("c1");//调用comp1的hello,打印 comp1::c1 is said hello
c2.hello("c2");//调用comp2的hello,打印 comp2::c2 is said hello
end
endmodule
什么是域的自动化?如何实现?
今后会参与到的对象拷贝、克隆、打印等操作的成员变量
注册的时候顺便声明,就可以直接使用uvm_object预定义的一些方法
class box extends uvm_object;
int volume=120;
color_t color = white;
string name= "box";
`uvm_object_utils_begin(box)//注册box的同时
`uvm_filed_int(volume, UVM_ALL_ON)//声明了会参与到object数据操作的成员变量
`uvm_filed_enum(color_t, color, UVM_ALL_ON)
`uvm_filed_string(name, UVM_ALL_ON)//默认采取UVM_ALL_ON和UVM_DEFAULT,所有操作方法都打开
`uvm_object_utils_end
......
endclass
box b1, b2;
initial begin//声明过的成员变量将在数据操作时自动参与进来
b1 = new("box1");
b1.volume = 80;
b1.color = black;
b2 = new();
b2.copy(b1);//否则不会自动参与数据的操作,要自己定义数据操作方法
b2.name = "box2";
end
域的类型及其对应的宏声明非常多,还有数据操作列表,这里有两个图,就省略了
什么是uvm_object?
见类库地图,几乎是所有核心基类的最顶层
uvm_object有哪些方法可以使用?
copy,clone,compare,pare,pack和unpack
关于复制的例码,句柄赋值给另一个句柄b2,此时两个句柄指向同一个对象box,在b2句柄中修改name,box中也被修改,打印出来的是同一个name
typedef enum {RED, WHITE, BLACK} color_t;
class box extends uvm_object;
int volume=120;
color_t color=WHITE;
string name="box";
`uvm_objext_utils(box)
function new(string name="name");
super.new(name);
this.name=name;
endfunction
endclass
initial begin
b1=new("box1");
b2=b1;
b2.name="box2";
$display("b1 name is %s", b1.name);
$display("b2 name is %s", b2.name);
end
//结果如下
//b1 name is box2
//b2 name is box2
具体地,对于方法compare如何写?uvm_pkg例化的对应全局数据操作配置成员是什么?
function bit compare(uvm_object rhs, uvm_compare compare=null); 不做额外配置的话,第二个参数可以忽略,采用默认的比较配置
uvm_package::uvm_default_comparer 最大输出错误比较信息(show_max)是1,当错误发生后不再进行后续比较
如果不用默认,可以创建一个uvm_comparer对象,如下;也可以修改uvm_comparer对象
box b1, b2;
uvm_comparer cmpr;
initial begin
...
cmpr=new();
cmpr.show_max=10;
if(!b2.compare(b1)) begin
... end
具体地,print呢?
调用uvm_object::print()函数时自动打印出来
全局对象:uvm_default_printer,d和p中间可以加上tree、line、table,打印的方式
字符串返回信息uvm_object::sprint(),自定义回调函数do_print()
什么是phase机制?
对于验证环境层次化,保证例化先后关系的机制
phase机制有哪些phase,执行顺序又是如何?
只有build是自顶向下的执行
只有uvm_component及其子类才会按照图中的顺序执行,component!!!
只有run_phase是task,可以耗时,可以完成一些等待、激励、采样的任务
runphase通常需要组织的序列:上电;复位;reg配置;发送主要测试内容;等待dut完成测试
run_phase还有12个分支phase(reset,config,main,shutdown及其前后),并行执行。不要用
什么是config机制?
为了验证环境的复用性,配置更细致的环境调节中的变量,在仿真时通过变量设置来修改环境。在不破坏原有结构的前提去改变验证环境。
uvm_config_db#(T)::set(uvm_component cntxt, string inst_name, string field_name, T value);
// 传递一个实例句柄进来 实例名称 实例中的变量名 值
//第一个参数表示当前层次,如果是最高层可以是null,也可以uvm_root::get()
uvm_config_db#(T)::get(uvm_component cntxt, string inst_name, string field_name, inout T value);
- 方法:uvm_config_db配置类,几种方便的变量设置方法
- 使用方式1:传递virtual interface到环境中,连接软件和硬件世界
- 使用方式2:设置单一变量值
- 使用方式3:传递配置对象config object到环境
- 先配置,后例化
- 也就是,可以配置接口,可以配置变量,更可以配置对象
如何用config实现接口的传递(方式1)?
位置:在run_test()之前
类型:interface和virtual interface
例码如下:先声明接口,
interface intf1;
logic enable=0;
endinterface
class comp1 extends uvm_component;
`uvm_componnet_utils(comp1)
virtual intf1 vif;//拿到intf1的指针
......
function void build_phase (uvm_phase phase);
if(!uvm_config_db#(virtual intf1)::get(this, "", "vif", vif)) begin
//this表示当前的comp1(uvm_top.root.test.c1.vif),没有实例,变量是vif字符串要加“”,
`uvm_error("GETVIF", "no virtual interface is assigned")
end
`uvm_info("SETVAL", $sformatf("vif.enable is %b befor 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 test1 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.c1", "vif", intf);
//先set进intf1中,等下就get出来
run_test("test1");//root->test->c1->vif,分别对应set中的4个参数
end
如何用config实现变量配置(方式2)?
位置: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("val1 is %d before get", val1), UVM_LOW)
`uvm_info("SETVAL", $sformatf("str1 is %s before get", str1), UVM_LOW)
uvm_config_db#(int)::get(this, "", "val1", val1);//把配置好的get进来
uvm_config_db#(string)::get(this, "", "str1", str1);
`uvm_info("SETVAL", $sformatf("val1 is %d after get", val1), UVM_LOW)
`uvm_info("SETVAL", $sformatf("str1 is %s after get", str1), UVM_LOW)
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", "val1", 100);//先set再例化
uvm_config_db#(string)::set(this, "c1", "str1", "comp1");
c1=comp1::type_id::create("c1", this);
endfunction
endclass
如何用config实现对象配置(方式3)?
目的:将需要配置的参数变量放到一个uvm_object中,一次配置完毕
位置:build_phase
class config1 extends uvm_object;
int val1=1;
int str1="null";
`uvm_object_utils(config1)
......
endclass
class comp1 extends uvm_component;
`uvm_component_utils(comp1)
config1 cfg;
......
function void build_phase(uvm_phase phase)
uvm_object tmp;
uvm_config_db#(uvm_object)::get(this, "", "cfg", tmp);//得到的tmp是父类句柄
void'($cast(cfg, tmp));//传递的类型要保持一致!!
`uvm_info("SETVAL", $sformatf("cfg.val1 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;
config cfg1, cfg2;
......
function void build_phase(uvm_phase phase);
cfg1= config1::type_id::create("cfg1");
cfg2= config2::type_id::create("cfg2");
cfg1.val1=30;
cfg1.str1="c1";
cfg2.val1=50;
cfg2.str1="c2";
uvm_config_db#(uvm_object)::set(this, "c1", "cfg", cfg1);//类型从int换成object
uvm_config_db#(uvm_object)::set(this, "c2", "cfg", cfg2);
c1=comp1::type_id::create("c1", this);
c2=comp2::type_id::create("c2", this);
endfunction
endclass
如何运行uvm仿真?
之前的SV实验使用的是$sformatf()系统函数
initial begin
t1 = new();
t2 = new();
tests["mcdf_data_consistence_basic_test"] = t1;
tests["mcdf_full_random_test"] = t2;
if($value$plusargs("TESTNAME=%s", name)) begin
if(tests.exists(name)) begin
tests[name].set_interface(chnl0_if, chnl1_if, chnl2_if, reg_if, arb_if, fmt_if, mcdf_if);
tests[name].run();
end
else begin
$fatal($sformatf("[ERRTEST], test name %s is invalid, please specify a valid name!", name));
end
end
else begin
$display("NO runtime optiont +TESTNAME=xxx is configured, and run default test mcdf_data_consistence_basic_test");
tests["mcdf_data_consistence_basic_test"].set_interface(chnl0_if, chnl1_if, chnl2_if, reg_if, arb_if, fmt_if, mcdf_if);
tests["mcdf_data_consistence_basic_test"].run();
end
end
方式1:通过uvm_pkg提供的全局函数run_test()来指定运行某一个uvm_test,都继承于uvm_test
方式2:就是上面例码的+UVM_TESTNAME=<test_name>
uvm的消息管理机制是怎么样的?
实验任务
1.1 在object_create中用多种方法创建对象
class trans extends uvm_object;
bit[31:0] data;
`uvm_object_utils(trans)
function new(string name = "trans");
super.new(name);
`uvm_info("CREATE", $sformatf("trans type [%s] created", name), UVM_LOW)
endfunction
endclass
class object_create extends top;
trans t1, t2, t3, t4;
`uvm_component_utils(object_create)
function new(string name = "object_create", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
uvm_factory f = uvm_factory::get(); // get singleton factory
super.build_phase(phase);
t1 = new("t1"); // direct construction
t2 = trans::type_id::create("t2", this); // common method
void'($cast(t3,f.create_object_by_type(trans::get_type(), get_full_name(), "t3")));
// factory method用工厂提供的方法create_object_by_type()来创建对象
void'($cast(t4,create_object("trans", "t4"))); // 用component预定义的方法来创建对象
endfunction
endclass
1.2 同上,在component_create
class unit extends uvm_component;
`uvm_component_utils(unit)
function new(string name = "unit", uvm_component parent = null);
super.new(name, parent);
`uvm_info("CREATE", $sformatf("unit type [%s] created", name), UVM_LOW)
endfunction
endclass
class component_create extends top;
unit u1, u2, u3, u4;
`uvm_component_utils(component_create)
function new(string name = "component_create", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
uvm_factory f = uvm_factory::get(); // get singleton factory
super.build_phase(phase);
u1 = new("u1"); // direct construction
u2 = unit::type_id::create("u2", this); // common method
void'($cast(u3,f.create_component_by_type(unit::get_type(), get_full_name(), "u3", this))); // factory method
void'($cast(u4,create_component("unit", "u4"))); // pre-defined method inside component
endfunction
endclass
1.3 覆盖1.1,用bad_trans覆盖trans
和上面的方法set_type_override ( uvm_object_wrapper override_type);有一点区别的是这里是用set_type_override_by_type ( uvm_object_wrapper override_type, new_type::get_type());
想要表示type类型都要调用原来类型中的::get_type()
class bad_trans extends trans;
bit is_bad = 1;
`uvm_object_utils(bad_trans)
function new(string name = "trans");
super.new(name);
`uvm_info("CREATE", $sformatf("bad_trans type [%s] created", name), UVM_LOW)
endfunction
endclass
class object_override extends object_create;
`uvm_component_utils(object_override)
function new(string name = "object_override", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
set_type_override_by_type(trans::get_type(), bad_trans::get_type());
super.build_phase(phase);
endfunction
endclass
1.4 覆盖1.2,用big_unit覆盖unit
class big_unit extends unit;
bit is_big = 1;
`uvm_component_utils(big_unit)
function new(string name = "bit_unit", uvm_component parent = null);
super.new(name, parent);
`uvm_info("CREATE", $sformatf("big_unit type [%s] created", name), UVM_LOW)
endfunction
endclass
class component_override extends component_create;
`uvm_component_utils(component_override)
function new(string name = "component_override", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
set_type_override("unit", "big_unit");//!!!!!!!!!!!!!!!!!!!!!!
super.build_phase(phase);
endfunction
endclass
2.1 在注册的时候,声明域的自动化
class trans extends uvm_object;
bit[31:0] addr;
bit[31:0] data;
op_t op;
string name;
`uvm_object_utils_begin(trans)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_field_enum(op_t, op, UVM_ALL_ON)
`uvm_field_string(name, UVM_ALL_ON)
`uvm_object_utils_end
2.2 uvm_object::compare()
function bit compare (uvm_object rhs, uvm_comparer comparer=null)
直接调用对应对象.compare(待比较对象句柄)
2.3 uvm_pkg中的全局控制对象uvm_default_comparer
2.5 2.6 uvm_object::print()和copy()
class object_methods_test extends uvm_test;
`uvm_component_utils(object_methods_test)
function new(string name = "object_methods_test", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
task run_phase(uvm_phase phase);
trans t1, t2;
bit is_equal;
phase.raise_objection(this);
t1 = trans::type_id::create("t1");
t1.data = 'h1FF;
t1.addr = 'hF100;
t1.op = WRITE;
t1.name = "t1";
t2 = trans::type_id::create("t2");
t2.data = 'h2FF;
t2.addr = 'hF200;
t2.op = WRITE;
t2.name = "t2";
is_equal = t1.compare(t2);//调用比较函数
uvm_default_comparer.show_max = 10;//通过全局控制对象设置最大比较次数
is_equal = t1.compare(t2);
if(!is_equal)
`uvm_warning("CMPERR", "t1 is not equal to t2")
else
`uvm_info("CMPERR", "t1 is equal to t2", UVM_LOW)
`uvm_info("COPY", "Before uvm_object copy() taken", UVM_LOW)
t1.print();
t2.print();
`uvm_info("COPY", "After uvm_object t2 is copied to t1", UVM_LOW)
t1.copy(t2);//也是直接调用即可
t1.print();
t2.print();
`uvm_info("CMP", "Compare t1 and t2", UVM_LOW)
is_equal = t1.compare(t2);
if(!is_equal)
`uvm_warning("CMPERR", "t1 is not equal to t2")
else
`uvm_info("CMPERR", "t1 is equal to t2", UVM_LOW)
#1us;
phase.drop_objection(this);
endtask
endclass
2.4 回调函数do_compare
typedef enum {WRITE, READ, IDLE} op_t;
class trans extends uvm_object;
bit[31:0] addr;
bit[31:0] data;
op_t op;
string name;
`uvm_object_utils_begin(trans)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_field_enum(op_t, op, UVM_ALL_ON)
`uvm_field_string(name, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "trans");
super.new(name);
`uvm_info("CREATE", $sformatf("trans type [%s] created", name), UVM_LOW)
endfunction
//自定义回调函数,在上面的代码中执行完compare立即会执行以下的do_compare
function bit do_compare(uvm_object rhs, uvm_comparer comparer);
trans t;
do_compare = 1;
void'($cast(t, rhs));
if(addr != t.addr) begin
do_compare = 0;
`uvm_warning("CMPERR", $sformatf("addr %8x != %8x", addr, t.addr))
end
if(data != t.data) begin
do_compare = 0;
`uvm_warning("CMPERR", $sformatf("data %8x != %8x", data, t.data))
end
if(op != t.op) begin
do_compare = 0;
`uvm_warning("CMPERR", $sformatf("op %s != %8x", op, t.op))
end
if(addr != t.addr) begin
do_compare = 0;
`uvm_warning("CMPERR", $sformatf("name %8x != %8x", name, t.name))
end
endfunction
endclass
3.1 定义comp中的4个phase
build_phase中例化对象
class comp2 extends uvm_component;
`uvm_component_utils(comp2)
function new(string name = "comp2", uvm_component parent = null);
super.new(name, parent);
`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)
`uvm_info("BUILD", "comp2 build phase exited", UVM_LOW)
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
`uvm_info("CONNECT", "comp2 connect phase entered", UVM_LOW)
`uvm_info("CONNECT", "comp2 connect phase exited", UVM_LOW)
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
`uvm_info("RUN", "comp2 run phase entered", UVM_LOW)
`uvm_info("RUN", "comp2 run phase entered", UVM_LOW)
endtask
function void report_phase(uvm_phase phase);
super.report_phase(phase);
`uvm_info("REPORT", "comp2 report phase entered", UVM_LOW)
`uvm_info("REPORT", "comp2 report phase exited", UVM_LOW)
endfunction
endclass
class comp3 extends uvm_component;
`uvm_component_utils(comp3)
function new(string name = "comp3", uvm_component parent = null);
super.new(name, parent);
`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", "comp3 build phase entered", UVM_LOW)
`uvm_info("BUILD", "comp3 build phase exited", UVM_LOW)
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
`uvm_info("CONNECT", "comp3 connect phase entered", UVM_LOW)
`uvm_info("CONNECT", "comp3 connect phase exited", UVM_LOW)
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
`uvm_info("RUN", "comp3 run phase entered", UVM_LOW)
`uvm_info("RUN", "comp3 run phase entered", UVM_LOW)
endtask
function void report_phase(uvm_phase phase);
super.report_phase(phase);
`uvm_info("REPORT", "comp3 report phase entered", UVM_LOW)
`uvm_info("REPORT", "comp3 report phase exited", UVM_LOW)
endfunction
endclass
class comp1 extends uvm_component;
comp2 c2;
comp3 c3;
`uvm_component_utils(comp1)
function new(string name = "comp1", uvm_component parent = null);
super.new(name, parent);
`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)
c2 = comp2::type_id::create("c2", this);
c3 = comp3::type_id::create("c3", this);
`uvm_info("BUILD", "comp1 build phase exited", UVM_LOW)
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
`uvm_info("CONNECT", "comp1 connect phase entered", UVM_LOW)
`uvm_info("CONNECT", "comp1 connect phase exited", UVM_LOW)
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
`uvm_info("RUN", "comp1 run phase entered", UVM_LOW)
`uvm_info("RUN", "comp1 run phase entered", UVM_LOW)
endtask
function void report_phase(uvm_phase phase);
super.report_phase(phase);
`uvm_info("REPORT", "comp1 report phase entered", UVM_LOW)
`uvm_info("REPORT", "comp1 report phase exited", UVM_LOW)
endfunction
endclass
4.1 配置接口到c1和c2并检查是否得到
4.2 从test配置对象到c1和c2
4.3 在顶层uvm_config_test配置变量c1和c2中的var
在顶层test中set
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;
//在这里配置
uvm_config_db#(config_obj)::set(this, "*", "cfg", cfg);
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
在对应的class中get
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)
//配置接口
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)
//配置变量
uvm_config_db#(int)::get(this, "", "var2", var2);
`uvm_info("GETINT", $sformatf("after config get, var2 = %0d", var2), UVM_LOW)
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)
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, var1 = %0d", var1), UVM_LOW)
uvm_config_db#(int)::get(this, "", "var1", var1);
`uvm_info("GETINT", $sformatf("after config get, var1 = %0d", var1), UVM_LOW)
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