目录
1. 核心基类uvm_object
主要提供与数据操作的相关服务:
- copy
- clone
- compare
- pack/unpack
域的自动化(field automation)
使用户在注册UVM类的同时,可以声明参与到对象copy、clone、print等操作的成员变量
`uvm_{component, object}_utils_begin(object_type)
`uvm_field_{int, object,string ...}(ARG, FLAG);
`uvm_{component, object}_utils_end
class box extends uvm_object;
int volume = 120;
color_t color = WHITE;
string name = "box";
`uvm_object_utils_begin(box)
`uvm_field_int(volume, UVM_ALL_ON);
`uvm_field_enum(color_t, color, UVM_ALL_ON);
`uvm_field_string(name, UVM_ALL_ON);
`uvm_object_utils_end
endclass
copy
copy:默认创建好对象,只数据进行拷贝;
clone:自动创建对象并对source object进行数据拷贝,返回target object句柄
- 进行copy时,默认进行 的是深拷贝
浅拷贝:拷贝就是拷贝指向对象的指针,意思就是说:拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一块空间,浅拷贝只是一种简单的拷贝,让几个对象公用一个内存
深拷贝是创建一个全新的对象或数组,并递归地复制原始数据中的所有值和嵌套对象。深拷贝会创建独立的副本,使得新对象和原始对象完全独立,互不影响。
比较compare
当比较错误发生时,不会再进行后续的比较
打印print
打包和解包pack&unpack
2. phase机制
phase的自动执行
将UVM仿真阶段层次化(各个phase的先后执行顺序,处于同一phase中的层次化组件之间的phase的先后关系)
9个主要phase
- uvm_component及其继承于uvm_component的子类
- 只有run_phase方法是耗时任务
- task phase(消耗仿真时间)和function phase(不消耗仿真时间)
- 自顶向下、自底向上
12个分支phase
-
run_phase任务和12个phase是并行的
-
start_of_simulation_phase任务执行以后,run_phase和reset_phase开始执行,在shutdown_phase执行完成以后,需要等待run_phase执行完才可以进入extract_phase
-
reset_phase:对DUT进行复位、初始化等操作
-
configure_phase:进行DUT的配置
-
main_phase:DUT的运行
-
shutdown_phase:做一些与DUT断电有关的操作
UVM编译和运行顺序
- 加载硬件模型调用仿真器之前,需要完成编译和建模阶段
- 开始仿真阶段之前,分别执行硬件的always/initial语句,以及UVM调用测试方法run_test和几个phase,分别是build、connect、end_of_elaboration和start_of_simulation
- 开始仿真后,执行run_phase或对应的12个细分phase
- 仿真结束后,执行剩余的phase,分别是extract、check、report和final
3. 仿真结束— objection机制
利用objection挂起机制控制仿真结束
raise_objection(uvm_objection obj=null, string description="", int count=1) //挂起objection
drop_objection(uvm_objection obj=null, string description="", int count=1) //落下objection
set_drain_time(uvm_object obj=null, time drian) //设置退出时间
- 对于component()而言,可以在run_phase()中使用phase.raise_objection()/phase.drop_objection()来控制run phase退出
- 最好为description字符串提供说明,有利于后期调试
- 使用默认count值
- uvm_top或uvm_test_top尽可能少使用set_drain_time()
- 在component中挂起objection,建议一进入run_phase()后就挂起,保证objection counter及时被增加
4. config_db机制
在UVM验证平台间传递参数
成对出现,get、set函数
get_full_name()获取component的路径
- 传递virtual interface到环境中
- 设置单一变量值,如int、string、enum等
- 传递配置对象(config object)到环境
语法
uvm_config_db#(T)::set(uvm_component cntxt, string inst_name, string field_name, T value);
uvm_config_db#(T)::get(uvm_component cntxt, string inst_name, string field_name, inout T value);
uvm_config_db#(int)::set(this,"env.i_agt.drv", "p_num", 100);
uvm_config_db#(int)::get(this,"","p_num",pre_num);
T-设置传递类型
第一个和第二个参数组合起来组成目标路径
(uvm_component实例的指针【寄信人】+相对此实例的路径)
第三个参数是传给目标中的哪个成员(set和get中第三个参数一致)
第四个参数是设置的变量
- 在调用set函数时第一个参数尽量使用this,在无法得到this指针的情况下(如在top_tb),使用null或uvm_root::get()
- 跨层次时,高层次的set设置优先;同层次时,时间优先
机理
唯一全局变量uvm_pkg::uvm_resources,用来存储和释放配置资源信息;该实例中有两个resource数组用来存放配置信息,一个由层次名字索引,一个有类型索引,通过这两个关联数组可以存放通过层次配置的信息。
- uvm_config_db::set()通过层次和变量名,将信息放置到uvm_resources。
- uvm_config_db::get()通过传递的参数构成索引层次,在uvm_resources已有配置信息池中索引该配置,索引到返回1,否则返回0。
interface传递
- 接口传递发送在run_test()之前,这保证了在进入build_phase之前,virtual interface已经被传递到uvm_config_db中
- 在传递过程中的类型应当为virtual interface,即实际接口的句柄
interface intf1;
logic enable=0;
endinterface
class comp1 extends uvm_component;
`uvm_compoent_utils(comp1)
virtual intf1 vif;
...
function void build_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.enble=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#(virutal intf1)::set(uvm_root::get(), "uvm_test_top.c1", "vif", intf);
run_test("test1");
end
输出结果:
UVM_INFO @0: reporter [RNTST] Running test test1...
UVM_INFO @0: uvm_test_top.c1 [SETVAL] vif.enable is 0 before set
UVM_INFO @0: uvm_test_top.c1 [SETVAL] vif.enable is 1 after set
变量设置
class comp1 extends uvm_component;
`uvm_component_utils(comp1)
int val1 = 1;
string str1 = "null";
endclass
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);
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
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);
uvm_config_db#(string)::set(this,"c1","str1","comp1");
c1 = comp1::type_id::create("c1",this);
endfunction
endclass
输出结果:
UVM_INFO @0: uvm_test_top.c1 [SETVAL] val1 is 1 before get
UVM_INFO @0: uvm_test_top.c1 [SETVAL] str1 is null before get
UVM_INFO @0: uvm_test_top.c1 [SETVAL] val1 is 100 after get
UVM_INFO @0: uvm_test_top.c1 [SETVAL] str1 is comp1 after get
object传递
class config1 extends uvm_object;
int val1 = 1;
string 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_tb#(uvm_object)::get(this,"","cfg",tmp);
void'($cast(cfg,tmp));
`uvm_info("SETVAL",$sformatf("cgf.val1 is %d after get", cfg.val1),UVM_LOW)
`uvm_info("SETVAL",$sformatf("cgf.str1 is %s after get", cfg.str1),UVM_LOW)
endfunction
endclass
class test1 extends uvm_object;
`uvm_object_utils(test1)
comp1 c1, c2;
config1 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);
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
注意事项
- set/get的传递的参数类型上下保持一致;对于uvm_object等实例的传递,不一致,应通过$cast()完成类型转换,再对类型转换后的对象进行操作
- uvm_config_db::set()在相关配置组件创建前调用。只有先完成配置,相关组件在例化前才可以得到配置值继而正确地例化(先set再create)
- 高层组件覆盖低层组件配置,后面的配置覆盖前面的配置
5. 消息管理
get_report_verbosity_level()
函数得到某个component的冗余度阈值
set_report_verbosity_level()
函数设置某个特定component的默认冗余度阈值
set_report_verbosity_level_hier()
函数递归设置冗余度阈值
set_report_id_verbosity("ID",verbosity);
区分不同ID的冗余度阈值
set_report_id_verbosity_hier("ID",verbosity);
递归
消息方法
只要有引入uvm_pkg,均可以通过下面的方法来按照消息的严重级别和冗余度来打印消息
uvm_report_info
uvm_report_warning
uvm_report_error
uvm_report_fatal
严重级别(severity)、消息ID、消息、冗余度、文件名、行号
严重级别:UVM_INFO、UVM_WARNING、UVM_ERROR、UVM_FATAL
消息ID:可以使任意字符串,用来标记该消息
消息:消息文本的主体
冗余度:低于过滤的开关,该消息会打印出来,否则不会被打印
文件名和行号:用来提供消息发生时所在的文件和行号,UVM后台自动填补
消息处理
与每一条消息对应的是如何处理这些消息。通常情况下,消息处理的方式是同消息的严重级别对应的。
自定义消息处理方式,uvm_report_object类,完成消息打印和管理
消息机制