一、工厂的注册、创建和覆盖机制
工厂机制_知识回顾
- 背景:有时候无法直接修改验证平台的代码,比如①别人正在用,修改会影响别人使用;②验证IP你没有办法直接看到,所以也无法修改。
- 作用:为了更方便地替代验证环境中的实例或者注册类型
- 核心三要素:注册、创建、覆盖
1、注册:要用 uvm_component_utils()或者uvm_object_utils()注册
-
uvm_component常见的组件有:uvm_driver、uvm_monitor、uvm_sequencer、uvm_agent、uvm_scoreboard、uvm_env、uvm_test,凡是继承他们的组件都需要用
uvm_component_utils()进行注册;

-
除了上述提到的组件外,几乎所有的类都派生自uvm_object,常见的有uvm_sequence_item、uvm_sequence、config等
-
引用《UVM实战》里的一段话来加深对uvm_object的认识:
uvm_object是一个分子, 用这个分子可以搭建成 许许多多的东西, 如既可以搭建成动物, 还可以搭建成植物, 更加可以搭建成没有任何意识的岩石、 空气等。 uvm_component就 是由其搭建成的一种高级生命, 而sequence_item则是由其搭建成的血液, 它流通在各个高级生命( uvm_component) 之间, sequence则是众多sequence_item的组合, config则是由其搭建成的用于规范高级生命( uvm_component) 行为方式的准则。
2、创建:UVM中创建实例的方法有很多,常用xxx::type_id::create来创建;注意,如果用new()来创建则无法使用工厂的覆盖
3、覆盖
覆盖并不是工厂机制的发明,所有面向对象的语言都支持函数/任务重载。
采用工厂进行覆盖有以下条件:
- 原类型和新类型都需要注册到工厂里;
- 需要用工厂机制来创建;
- 覆盖的类和被覆盖的类有继承关系,并且被覆盖的方法要声明为virtual。不过有例外:component和object之间不能相互覆盖(虽然component是object的子类,但血缘关系太远了)
若有多层覆盖时,最终覆盖的类必须是最初被覆盖类的子类;多层覆盖,以最后一个覆盖结果为准
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
f.create_object_by_type(trans::get_type, get_full_name,"t3");//factory method
create_object("trans","t4");// pre-defined method inside component
endfunction
endclass
说明:
- get_full_name可以完整地得到当前component的路径
- void’作用:减少编译器报warning,告诉编译器函数可能有返回值,但我不关心,将其转换为空值就行了
- 参考代码里t3和t4加了动态转换cast,但好像没有什么必要,这里没有父类句柄指向子类对象的问题。这里加不加打印消息都一样。
void'($cast(t3,f.create_object_by_type(trans::get_type, get_full_name,"t3")));
void'($cast(t4,create_object("trans","t4")));
仿真命令:
vsim -novopt -classdebug +UVM_TESTNAME=object_create work.factory_mechanism
仿真结果:

问:这里使用工厂创建时为什么名称没有传进去? 在仿真结果那里依然是trans type[trans] created,而不是trans type[t2] created;
答:questasim添加的uvm版本为1.2,所以有这个问题。最新uvm的版本已经解决这个问题。
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();
super.build_phase(phase);
u1 = new("u1");
u2 = unit::type_id::create("u2", this);
void'(f.create_component_by_type(unit::get_type(),get_full_name,"u3",this));
void'(create_component("unit","u4"));
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());
super.build_phase(phase);
endfunction
endclass
仿真命令:
vsim -novopt +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
注意set_type_override_by_type()和set_type_override()的区别,前者函数内部要写类型,通过xx::get_type()获取,后者函数内部写类名,更方便。
仿真命令:
vsim -novopt +UVM_TESTNAME=component_override work.factory_mechanism
仿真结果:

结果分析:
在实例化时, UVM会通过factory机制在自己内部的一张表格中查看是否有相关的重载(也就是覆盖)记录。 set_type_override_by_type或者set_type_override语句相当于在factory机制的表格中加入了一条记录。 当查到有重载记录时, 会使用新的类型来替代旧的类型。以u2的覆盖为例。借助《uvm实战》p611页的图进行修改得到下图:

疑问:如果是按照上图进行判断的话,那感觉结果应该只会出现big_unit 类型,为什么还会出现unit类型的打印消息?

我在138、139行设了断点,并运行。

发现覆盖完,138行结束后,unit type和big_unit type是同时打印出来的,所以感觉真实的覆盖不是阻止unit类型的产生,而是通过将unit类型对应的句柄给到big_unit的对象来实现覆盖的。

二、域的自动化和uvm_object的常用方法
域的自动化_知识回顾
- 作用:通过将成员变量在下方代码中进行注册,可以直接赋予变量常用的操作,比如复制、克隆、打印、比较等,节省了用户的编码时间
`uvm_object_utils_begin(trans)
`uvm_field_int(ARG, FLAG)//整形
`uvm_field_enum(T, ARG, FLAG)//枚举
`uvm_field_string(ARG, FLAG)//字符串
`

本文详细介绍了UVM验证环境中的工厂机制,包括组件和对象的注册、创建和覆盖,以及如何通过工厂进行类型重载。此外,还探讨了域自动化,展示了如何通过uvm_object_utils宏自动化处理成员变量,以及phase机制的作用和执行顺序。在配置机制部分,讲解了如何使用uvm_config_db进行接口、单一变量和配置对象的传递。最后,讨论了消息管理,包括如何通过设置报告级别和ID来过滤不必要的消息输出,以优化仿真效率。
最低0.47元/天 解锁文章
3162





