一、工厂的注册、创建和覆盖机制
UVM中只有两种用例注册的宏
`uvm_component_utils(T)
`uvm_object_utils(T)
编译仿真factory_mechanism.sv文件
object_create
类
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
void'($cast(t4,create_object("trans", "t4"))); // pre-defined method inside component
endfunction
endclass
仿真时执行命令
vsim -novopt -classdebug +UVM_TESTNAME=object_create work.factory_mechanism
component_create
类
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
仿真时执行命令
vsim -novopt -classdebug +UVM_TESTNAME=component_create work.factory_mechanism
object_override
类
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()); //bad_trans替换trans
super.build_phase(phase);
endfunction
endclass
仿真时执行命令
vsim -novopt -classdebug +UVM_TESTNAME=object_override work.factory_mechanism
component_override
类
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
仿真结果:
二、域的自动化和uvm_object
的常用方法
使用域自动化的宏方法
`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
uvm_object::compare()
方法
比较t1和t2是否相等
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);
全局控制对象
uvm_default_comparer
(uvm_comparer
类型)是默认的UVM全局比较器,show_max可以设置最大比较结果。
uvm_default_comparer.show_max = 10;
回调函数
执行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
uvm_object::print()
方法及uvm_object_copy()
方法
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)
三、phase机制
phase机制使得验证环境从组建、连接、执行,得以分阶段执行,按照层次结构和phase顺序严格执行,继而避免一些依赖关系,也使得可以正确地将不同的代码放置到不同的phase块中。
comp2
类
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
comp3
类
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
comp1
类
comp1
中声明了comp2
、comp3
作为成员变量,并且在build_phase
中做了例化
执行仿真命令
vsim -novopt -classdebug +UVM_TESTNAME=object_methods_test work.object_methods
仿真结果:
phase_order_test
类
创建验证结构,uvm_test
一定是顶层结构,而uvm_test
的引擎是uvm_root
。phase_order_test
中包含了comp1 c1
,并且在build_phase
中也创建了c1
。
class phase_order_test extends uvm_test;
comp1 c1;
`uvm_component_utils(phase_order_test)
function new(string name = "phase_order_test", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("BUILD", "phase_order_test build phase entered", UVM_LOW)
c1 = comp1::type_id::create("c1", this);
`uvm_info("BUILD", "phase_order_test build phase exited", UVM_LOW)
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
`uvm_info("CONNECT", "phase_order_test connect phase entered", UVM_LOW)
`uvm_info("CONNECT", "phase_order_test connect phase exited", UVM_LOW)
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
`uvm_info("RUN", "phase_order_test run phase entered", UVM_LOW)
phase.raise_objection(this);
#1us;
phase.drop_objection(this);
`uvm_info("RUN", "phase_order_test run phase exited", UVM_LOW)
endtask
function void report_phase(uvm_phase phase);
super.report_phase(phase);
`uvm_info("REPORT", "phase_order_test report phase entered", UVM_LOW)
`uvm_info("REPORT", "phase_order_test report phase exited", UVM_LOW)
endfunction
task reset_phase(uvm_phase phase);
`uvm_info("RESET", "phase_order_test reset phase entered", UVM_LOW)
phase.raise_objection(this);
#1us;
phase.drop_objection(this);
`uvm_info("RESET", "phase_order_test reset phase exited", UVM_LOW)
endtask
task main_phase(uvm_phase phase);
`uvm_info("MAIN", "phase_order_test main phase entered", UVM_LOW)
phase.raise_objection(this);
#1us;
phase.drop_objection(this);
`uvm_info("MAIN", "phase_order_test main phase exited", UVM_LOW)
endtask
endclass
执行仿真命令
vsim -novopt -classdebug +UVM_TESTNAME=phase_order_test work.phase_order
根据test、c1、c2、c3的验证结构层次以及打印信息可以看出,build_phase
、connect_phase
、run_phase
、report_phase
都是按照自顶向下或者自底向上的顺序依次执行的。而run_phase
是9种phase唯一的task,与run_phase
平行执行的是12个分支phase,所以在0时刻,run_phase
和reset_phase
是并行的,但是要等到reset_phase
在执行完成之后,run_phase
才能执行完,继而进入下一个extract_phase
阶段。reset_phase
和main_phase
之间却是有先后顺序的,先执行reset_phase
在1000时刻结束,然后main_phase
才开始执行,在2000时刻结束。所以整个仿真最后耗时Time=2us。
四、config机制
接口传递
实现接口从uvm_config
模块到验证环境中的传递,使得c1
和c2
可以得到接口,并且检查接口是否最终得到。
接口uvm_config_if
interface uvm_config_if;
logic [31:0] addr;
logic [31:0] data;
logic [ 1:0] op;
endinterface
comp2
类
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
comp1
类,在comp1
中包含一个comp2
对象
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
uvm_config
模块
module uvm_config;
import uvm_pkg::*;
`include "uvm_macros.svh"
import uvm_config_pkg::*;
uvm_config_if if0(); //在module模块才可以看得到interface,实现例化
initial begin
//在验证环境中设置interface到c1、c2
uvm_config_db#(virtual uvm_config_if)::set(uvm_root::get(), "uvm_test_top.*", "vif", if0);
run_test(""); // empty test name
end
endmodule
单一变量传递
实现在顶层uvm_config_test
对c1.var1
和c2.var2
的变量设置。
uvm_config_test
类
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); //将config_obj通过config_db传递给c1和c2
uvm_config_db#(int)::set(this, "c1", "var1", 10); //c1.var1和c2.var2的变量设置。
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
对象传递
实现配置对象config_obj
从uvm_config_test
到c1
和c2
的传递。
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
执行仿真命令
vsim -novopt -classdebug +UVM_TESTNAME=uvm_config_test work.uvm_config
仿真结果:
五、消息管理
使用消息过滤方法set_report_verbosity_level_hier()
在uvm_message_test::build_phase()
中屏蔽所有层次的消息,也就是不允许有任何uvm_message_test
及其以下组件的消息在仿真时打印出来。
执行仿真命令
vsim -novopt -classdebug +UVM_TESTNAME=uvm_message_test work.uvm_message
仿真结果:
对比这两次的打印消息,可以看出只是屏蔽了[BUILD]和[RUN]这两种消息,但是uvm_message
模块的[TOPTB],uvm_message_test
的[BUILD],config_obj
的[CREATE],comp1
和comp2
的[CREATE]仍然被打印出来。
使用set_report_id_verbosity_level_hier()
来过滤ID的消息,即“Build”、“CREATE”、“RUN”。
uvm_root::get().set_report_id_verbosity_hier("CREATE", UVM_NONE);
uvm_root::get().set_report_id_verbosity_hier("BUILD", UVM_NONE);
uvm_root::get().set_report_id_verbosity_hier("RUN", UVM_NONE);
仿真结果:
在end_of_elaboration_phase
中使用set_report_id_verbosity_level_hier()
来过滤ID的消息,可以使得uvm_message_test
的[BUILD]顺利执行完,继而执行完c1
和c2
的[BUILD]。
function void end_of_elaboration_phase(uvm_phase phase);
set_report_id_verbosity_hier("BUILD", UVM_NONE);
set_report_id_verbosity_hier("CREATE", UVM_NONE);
set_report_id_verbosity_hier("RUN", UVM_NONE);
endfunction
所有的打印消息,无论屏蔽与否,都会将config_obj的[CREATE]消息以及uvm_message模块里面的[TOPTB]消息打印出来。
可以使用消息过滤方法uvm_root::get()
来获取最顶层的(即uvm_message_test的顶层),来控制过滤[CREATE]、[TOPTB]消息。
uvm_root::get().set_report_id_verbosity_hier("TOPTB", UVM_NONE);