1. 工厂的注册、创建和覆盖
1.1 注册
object组件使用宏'uvm_obeject_ultis(string name)来创建,component组件使用'uvm_object_ultis(string name, parent)来创建
class trans extends uvm_object;/*定义*/
bit[31:0] data;
'uvm_object_ultis(trans)/*注册*/
function new(string name = "trans");/*构建*/
super.new(name);
'uvm_info("CREATE", $sformatf("trans type [%s] created", name),UVM_LOW)
/*使用宏来进行消息管理。'uvm_info(ID, message,verbosity)*/
endfunction
endclass
1.2 创建
class object_create extends top;
trans t1, t2, t3, t4;
'uvm_component_ultis(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();/*创建uvm_factory实例*/
super.build_phase(phase);
/*对象的创建*/
/*方法1,使用new函数来做*/
t1 = new("t1");
/*方法2,使用create*/
/*string name = comp_type::type_id::create("string name", uvm_component parent = null)*/
t2 = trans::type_id::create("t2", this);//trans是uvm_object类型的,为什么用component的来创建?
/*方法3,使用uvm_factory的函数来做*/
/*get_full_name()用于返回当前对象的完整层次名称
create_object_by_name (string requested_type_name,string parent_inst_path = "",string name = "")*/
void'($cast(t3, f.create_object_by_type(trans::get_type(), get_full_name(), "t3")));
/*方法4,使用create_object方法*/
void'($cast(t4, create_object("trans", "t4")));//为什么要使用cast来实现类型转换
/*因为 create_object_by_type 返回的是通用类型 uvm_object,为了使用对象的特定方法和属性,
需要将其转换为具体的类型。这是通过 $cast 语句完成的*/
endfunction
endclass
1.3 覆盖
class object_override extends object_create;
'uvm_component_ultis(object_override)
function new(string name = "object_override", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_pahse phase);
set_type_override_by_type(trans, bad_trans, bit replace = 1);
trans::type_id::set_type_override(bad_trans::get_type());//这种创建方法是不是也可以
super.build_phase(phase);
endfunction
endclass
1.4 问题
为何对t1,t2,t3,t4报告名称不对
仿真器的原因,VCS可以。Questa Sim对于component组件可以传递进去name,但是object不行
2. 域的自动化与uvm_object常用方法
2.1 域的自动化
'uvm_object_utils_begin(trans)
'uvm_field_int(addr, UVM_ALL_ON)
'uvm_field_int(data, UVM_DEFAULT)
'uvm_field_enum(op_t, op, UVM_ALL_ON)
/*`uvm_field_enum(T, ARG,FLAG=UVM_DEFAULT),
T is an enumerated type, ARG is an instance of that type*/
'uvm_field_string(name, UVM_DEFAULT)
'uvm_objectr_utils_end
2.2 compare()
do_compare是compare的回调函数,在调用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_warnning("CREATE", $sformatf(addr %8x != %8x, addr, t.addr))
end
if(data != t.data)begin
do_compare = 0;
'uvm_warnning("CREATE", $sformatf(addr %8x != %8x, data, t.data))
end
if(op != t.op)begin
do_compare = 0;
'uvm_warnning("CREATE", $sformatf(addr %8x != %8x, op, t.op))
end
if(name != t.name)begin
do_compare = 0;
'uvm_warnning("CREATE", $sformatf(addr %8x != %8x, name, t.name))
end
endfunction
is_equal = t1.compare(t2);
uvm_default_compare.show_max = 10;
/*uvm_default_compare 是一个默认的比较对象,用于控制比较时的显示行为。
show_max 是它的一个属性,表示在比较时最多显示多少个不匹配项*/
if(!is_equal)
'uvm_warning("COMPARE", "t1 is not equal to t2")
else
'uvm_info("COMPARE", "t1 is equal to t2")
2.3 print() 与copy()
'uvm_info("COPY", "Before uvm_object copy() taken", UVM_LOW)
t1.print();
uvm_default_printer = uvm_default_line_printer;/*修改打印的默认格式*/
t2.print(();
'uvm_info("COPY", "After uvm_object copy() taken", UVM_LOW)
t1.copy(t2);/*将t2拷贝给t1*/
uvm_default_printer = uvm_default_tree_printer;
t1.print();
uvm_default_printer = uvm_default_line_printer;/*修改打印的默认格式*/
t2.print(();
3. phase机制
9个phase之间顺序执行,只有run_phase耗时因此采用task。run_phase必须有挂起和落下机制,否则该phase不被执行。run_phase与之对应的有12个并列的子Phase,12个子phase是顺序执行,但是和run_phase是并行执行。一般不建议在有run_phase的情况下采用其子phase
3.1 代码
class comp2 extends uvm_component
'uvm_component ultis(comp2)
function new(string name = "comp2", uvm_component parent = null);
super.new(name, parent);
'uvm_info("CREATE", $sformatf("unit type [%s] create", name), UVM_LOW)
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
'uvm_info("BUILD", "comp2 build_phase completed", UVM_LOW)
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
'uvm_info("CONNECT", "comp2 connect_phase completed", UVM_LOW)
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
'uvm_info("RUN", "comp2 run_phase completed", UVM_LOW)
endtask
function void report_phase(uvm_phase phase);
super.report_phase(phase);
'uvm_info("REPORT", "comp2 report_phase completed", UVM_LOW)
endfunction
endclass
class comp3 extends uvm_component
'uvm_component ultis(comp3)
function new(string name = "comp3", uvm_component parent = null);
super.new(name, parent);
'uvm_info("CREATE", $sformatf("unit type [%s] create", name), UVM_LOW)
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
'uvm_info("BUILD", "comp1 build_phase completed", UVM_LOW)
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
'uvm_info("CONNECT", "comp1 connect_phase completed", UVM_LOW)
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
'uvm_info("RUN", "comp1 run_phase completed", UVM_LOW)
endtask
function void report_phase(uvm_phase phase);
super.report_phase(phase);
'uvm_info("REPORT", "comp1 report_phase completed", UVM_LOW)
endfunction
endclass
class comp1 extends uvm_component
comp2 c2;
comp3 c3;
'uvm_component ultis(comp1)
function new(string name = "comp1", uvm_component parent = null);
super.new(name, parent);
'uvm_info("CREATE", $sformatf("unit type [%s] create", name), UVM_LOW)
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
'uvm_info("BUILD", "comp1 build phase begin", UVM_LOW)
c2 = comp2::type_id::create("c2", this);
c3 = comp3::type_id::create("c3", this);
'uvm_info("BUILD", "comp1 build phase end", UVM_LOW)
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
'uvm_info("CONNECT", "comp1 connect_phase completed", UVM_LOW)
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
'uvm_info("RUN", "comp1 run_phase completed", UVM_LOW)
endtask
function void report_phase(uvm_phase phase);
super.report_phase(phase);
'uvm_info("REPORT", "comp1 report_phase completed", UVM_LOW)
endfunction
endclass
class phase_order_test extends uvm_test
comp1 c1;
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 begin", UVM_LOW)
c1 = comp2::type_id::create("c2", this);
'uvm_info("BUILD", "phase_order_test build phase end", UVM_LOW)
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
'uvm_info("CONNECT", "phase_order_test connect_phase completed", UVM_LOW)
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
'uvm_info("BUILD", "phase_order_test task begin", UVM_LOW)
phase.raise_objection(this);
#1us;
phase.drop_objection(this);
'uvm_info("BUILD", "phase_order_test task end", UVM_LOW)
endtask
task reset_phase(uvm_phase phase);
'uvm_info("RESET", "reset_phase begin", UVM_LOW)
phase.raise_objection(this);
#1us;
phase.drop_objection(this);
'uvm_info("RESET", "reset_phase end", UVM_LOW)
endtask
task main_phase(uvm_phase phase);
'uvm_info("MAIN", "main_phase begin", UVM_LOW)
phase.main_objection(this);
#1us;
phase.main_objection(this);
'uvm_info("MAIN", "main_phase end", UVM_LOW)
endtask
endclass
3.2 仿真结果
从仿真结果可以看出来,run_phase和main_phase, reset_phase都是在1us的时候仿真结束。
3.3 问题
为什么是在c1关于run_phase所有的信息被打印完了以后才去打印c2和c3的run_phase相关信息呢?
因为一旦进入c1的run_phase,就必须得要等到执行完毕退出以后才能去执行其他的,而c1的run_phase是有时延的。在每个
run_phase
和子phase方法中,如果包含了延迟或等待语句(如#1us
),那么仿真时间会在该方法中停留,直到延迟结束后才会继续执行下一个组件的run_phase
。但是各个组件的其他phase可以并行执行
4. config机制
4.1 代码
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] has been created", name), UVM_LOW)
endfunction
endclass
class comp2 extends uvm_component;
int var2;
virtual uvm_config_if vif;
config_obj cfg;
'uvm_object_utils(comp2)
function new(string name = "comp2", uvm_component parent = null);
super.new(name, parent);
var2 = 200;
'uvm_info("CREATE", $sformatf("unit type [%s] has been 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("GET VIF", "no virtual interface is assigned")
'uvm_info("GET INT", $sformatf("before config get, var2 = %0d", var2), UVM_LOW)
uvm_config_db#(int)::get(this, "", "var2", var2);
'uvm_info("GET INT", $sformatf("after config get, var2 = %0d", var2), UVM_LOW)
uvm_config_db#(config_obj)::get(this, "", "cfg", cfg);
'uvm_info("GET OBJ", $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 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] has been created", name), UVM_LOW)
endfunction
endclass
class comp1 extends uvm_component;
int var1;
virtual uvm_config_if vif;
config_obj cfg;
comp2 c2;
'uvm_object_utils(comp1)
function new(string name = "comp2", uvm_component parent = null);
super.new(name, parent);
var1 = 100;
'uvm_info("CREATE", $sformatf("unit type [%s] has been 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("GET VIF", "no virtual interface is assigned")
'uvm_info("GET INT", $sformatf("before config get, var1 = %0d", var1), UVM_LOW)
uvm_config_db#(int)::get(this, "", "var1", var1);
'uvm_info("GET INT", $sformatf("after config get, var1 = %0d", var1), UVM_LOW)
uvm_config_db#(config_obj)::get(this, "", "cfg", cfg);
'uvm_info("GET OBJ", $sformatf("after config get, cfg.comp1_var = %0d", cfg.comp1_var), UVM_LOW)
'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;
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
endpackage
4.2 仿真结果
5. 消息管理
set_report_verbosity_level_hier(UVM_NONE);/*冗余度高于UVM_NONE的都不会被打印出来*/
set_report_id_verbosity_hier("BUILD", UVM_NONE);/*只对BUILD ID做限制*/
uvm_root::get().set_report_id_verbosity_hier("BUILD", UVM_NONE);/*从顶层做配置*/