目录
3.1 uvm_component派生自uvm_object
三、UVM基础
3.1 uvm_component派生自uvm_object
事实说明了uvm_component拥有uvm_object的特性,同时又有自己的一些特质。但是uvm_component的一些特性,uvm_object则不一定具有。这是面向对象编程中经常用到的一条规律。
uvm_component有两大特性是uvm_object所没有的:
一是通过在new的时候指定parent参数来形成一种树形的组织结构,
二是有phase的自动执行特点。
从uvm_object派生出了两个分支,所有的UVM树的结点都是由uvm_component组成的,只有基于uvm_component派生的类才可能成为UVM树的结点;最左边分支的类或者直接派生自uvm_object的类,是不可能以结点的形式出现在UVM树上的。
uvm_object:分子,可以搭建成许多的东西
uvm_component:高级生命
sequence_item:则是由其搭建成的血液,它流通在各个高级生命(uvm_component)之间sequence:则是众多sequence_item的组合;
config:是由其搭建成的用于规范高级生命(uvm_component)行为方式的准则。
常用的派生自uvm_object的类:
uvm_sequence、config、uvm_sequence_item、寄存器相关的众多的类
注意config与config_db的区别。在上一章中已经见识了使用config_db进行参数配置,这里的config其实指的是把所有的参数放在一个object中,如10.5节所示。然后通过config_db的方式设置给所有需要这些参数的component。
uvm_component的限制
1、uvm_component无法使用clone函数,但是可以使用copy函数.
2、位于同一个父结点下的不同的component,在实例化时不能使用相同的名字。
3.2 UVM的树形结构
m_children与parent:
当b_inst实例化的时候,指定一个parent的变量,同时在每一个component的内部维护一个数组m_children,当b_inst实例化时,就把b_inst的指针加入到A的m_children数组中。只有这样才能让A知道b_inst是自己的孩子,同时也才能让b_inst知道A是自己的父母。当b_inst有了自己的孩子时,即在b_inst的m_children中加入孩子的指针。
UVM树的根
uvm_top是一个全局变量,它是uvm_root的一个实例(而且也是唯一的一个实例 [1],它的实现方式非常巧妙),而uvm_root派生自uvm_component,所以uvm_top本质上是一个uvm_component,它是树的根。
每个component都是一个节点。
如果一个component在实例化时,其parent被设置为null,那么这个component的parent将会被系统设置为系统中唯一的uvm_root的实例uvm_top。
如果一个component在实例化时,其parent被设置为null,那么这个component的parent将会被系统设置为系统中唯一的uvm_root的实例uvm_top
层次结构相关函数
与get_parent不同的是,get_child需要一个string类型的参数name,表示此child实例在实例化时指定的名字。因为一个component
只有一个parent,所以get_parent不需要指定参数;而可能有多个child,所以必须指定name参数
3.3 field automation机制的常用函数
把某个A实例复制到B实例中,那么应该使用B.copy(A)。
要比较A与B是否一样,可以使用A.compare(B),也可以使用B.compare(A)。当两者一致时,返回1;
pack_bytes函数用于将所有的字段打包成byte流
pack函数用于将所有的字段打包成bit流
unpack函数用于将一个bit流逐一恢复到某个类的实例中
3.4 UVM中打印信息的控制
冗余度阈值
UVM会比较要显示信息的冗余度级别与默认的冗余度阈值,如果小于等于阈值,就会显示,否则不会显示。
默认的冗余度阈值是UVM_MEDIUM,所有低于等于UVM_MEDIUM(如UVM_LOW)的信息都会被打印出来。
重载打印信息的严重性
.set_report_severity_override(UVM_WARNING, UVM_ERROR);
WARNING变成----ERROR(类比赋值)
UVM_ERROR到达一定数量结束仿真
set_report_max_quit_count()函数
get_max_quit_count,可以用于查询当前的退出阈值
设置计数的目标
set_report_severity_action函数。
set_report_id_action所有信息加入到计数中,无论是UVM_INFO,还是UVM_WARNING或者是UVM_ERROR、UVM_FATAL
env.i_agt.set_report_id_action_hier("my_drv", UVM_DISPLAY| UVM_COUNT);
hier代表递归,上述代码把ID为my_drv的所有信息加入到计数中
UVM的断点功能
当env.i_agt.drv中出现UVM_WARNING时,立即停止仿真,进入交互模式,方便调试。
这里用到了set_report_severity_action函数:
env.i_agt.drv.set_report_severity_action(UVM_WARNING, UVM_DISPLAY| UVM_STOP);
env.i_agt.set_report_id_action_hier("my_drv", UVM_DISPLAY| UVM_COUNT);
只要将其中的UVM_COUNT替换为UVM_STOP,就可以实现相应的断点功能
将输出信息导入文件中
按照重要性env.i_agt.drv.set_report_severity_file(UVM_INFO, info_log);
按照ID地址env.i_agt.drv.set_report_id_file("my_driver", driver_log);
两者结合env.i_agt.drv.set_report_severity_id_file(UVM_INFO, "my_drv", drv_log);
控制打印信息的行为
typedef enum
{UVM_NO_ACTION = 'b000000, //不做任何操作
UVM_DISPLAY = 'b000001, //输出到标准输出上
UVM_LOG = 'b000010, //输出到日志文件中
UVM_COUNT = 'b000100, //作为计数目标
UVM_EXIT = 'b001000, //直接退出仿真
UVM_CALL_HOOK = 'b010000, //调用一个回调函数
UVM_STOP = 'b100000 // 停止仿真,进入命令行交互模式(断点)
} uvm_action_type;
3.5 config_db机制
config_db机制用于在UVM验证平台间传递参数。它们通常都是成对出现的。
set函数是寄信,而get函数是收信。
set与get函数的参数
uvm_config_db#(int)::set(this,
"env.i_agt.drv",
"pre_num",
100);
第一、二个参数联合起来组成目标路径,与此路径符合的目标才能收信。
第一个参数必须是一个uvm_component实例的指针,
第二个参数是相对此实例的路径。
第三个参数表示一个记号,用以说明这个值是传给目标中的哪个成员的,
第四个参数是要设置的值。
跨层次的多重设置
1、先比较层级:
UVM规定层次越高,那么它的优先级越高。越靠近根结点uvm_top,则认为其层次越高。uvm_test_top的层次是高于env的,所以uvm_test_top中的set函数的优先级高。
2、再比较时间:
UVM的build_phase是自上而下执行的,my_case0的build_phase先于my_env的
build_phase执行。所以my_env对pre_num的设置在后,其设置成为最终的设置
注意:在调用set函数时其第一个参数应该尽量使用this。在无法得到this指针的情况下(如在top_tb中),使用null或者uvm_root::get()。
同一层次的多重设置
当跨层次来看待问题时,是高层次的set设置优先;当处于同一层次时,是时间优先。
写代码的一个原则是同样的语句只在一个地方出现,尽量避免在多个地方出现。解决这个问题的办法就是在base_test的build_phase(一种function)中使用config_db::set进行设置(设置好数值),这样,当由base_test派生而来的case1~case99在执行super.build_phase(phase)时,都会进行相同的设置。
——————————————————————————————————————————————————
爱吃鱼的嗷大喵(知乎同号),走过很多弯路的材料专业在读硕士,
正在转行中,
不定期发布心得体会,
有兴趣可以关注我。