文章目录
简介
- 工厂的存在,就是为了更方便地替换验证环境中的实例或者注册了的类型,同时工厂的注册机制也带来了配置的灵活性;
-
实例或者类型的替代,在UVM中称作覆盖
(override),而**被用来替换的对象或者类型,应该满足注册(registration)和多态(polymorphism)**的要求; - uvm的验证环境构成可以分为两个部分:一部分构成了环境的层次,通过ucm_component类完成;另一部分构成了环境的属性(例如配置)和数据传输,这部分通过uvm_object类完成。
- ucm_component类继承与uvm_object,这两种类也是进出工厂的主要模具和生产对象。之所以称为模具,是因为通过注册,可以利用工厂完成对象的创建;
- 之所以由工厂创建对象,也是利用了工厂生产模具可以灵活替代的好处,这使得在不修改原有验证环境层次和验证包的同时,实现了对环境内部组件类型或者对象的覆盖。
ucm_component和uvm_object的例化
-
必须要有的步骤:
定义——>注册——>构建
- 注册:`uvm_component_utils(T,parent) 或者 uvm_object_utils(T)
class comp1 extends uvm_component;//定义
`uvm_component_utils(comp1) //注册
function new(string name ="comp1",uvm_component parent = null);//构建函数
super.new(name,parent);
endfunction:new
endclass
class obj1 extends uvm_object;//定义
`uvm_object_utils(obj1) //注册
function new(string name ="obj1");//构建函数
super.ner(name);
endfunction:new
endclass
//两种对象的创建方式
comp1 c1,c2;
obj1 o1,o2;
initial begin
c1 = new("c1");
o1 = new("o1");
//uvm中要求用下面这种
c2 = comp1::type_id::create("c2",null);//利用工厂创建
o2 = obj1::type_id::create("o2");
end
为什么需要宏呢?
- 两个宏的作用就是将类注册到factory中。注意,factory是独有的,有且只有一个,这保证了多有的类都注册在一个“机构”中。
-
只要一个类使用宏uvm_component_utils注册,且被实例化了之后,这个类里面的run_phase就会被自动调用
uvm_coreservice_t类
这个类并不是uvm_component 和uvm_object,也并没有例化在UVM环境中,而是独立于UVM环境之外。
这个类内置了UVM世界核心的组件和方法,主要包括:
- 唯一的uvm_factory,该组件用来注册、覆盖和例化
- 全局的report_server,该组件用来做消息统筹和报告
- 全局的tr_database,该组件用来记录transaction
- get_root()方法用来返回当前UVM环境的结构顶层对象
uvm_coreservice_t只会被UVM系统在仿真开始时例化一次。用户无需,也不应该自行再额外例化该核心服务组件。
注册后的对象创建(component或者object)
-
最终创建出来的uvm_component是会在UVM层次结构中,而uvm_object则不会显示在层次中。
-
uvm_component::new(name,parent)保留两个参数,是为了通过parent起到“钩子”的作用,一层层由底层勾住上层,这样就能够将整个UVM结构串起来
-
uvm_object::new(name)中没有parent参数,所有不会显示在层次结构中
,只能作为configuration或者transaction等,用来做传递的配置结构体或者抽象数据传输的数据结构体,称为uvm_component的成员变量
component/object与工厂有关的方法
uvm_component和uvm_object提供的,配合工厂注册、创建和覆盖的方法:
- create()
- create_component()
- get()
- get_type_name()
- set_inst_override()
- set_type_override()
工厂创建component/object的方法
除了使用component/object来创建实例,也可以用factory来创建:
- create_component_by_name()
- create_component_by_type()
- create_object_by_name()
- create_object_by_type()
覆盖方法
覆盖(override)机制可以将原来所属的类型替换成另外一个新的类型
。
在覆盖之后,
原本用来创建原型类型的请求,将由工厂来创建新的替换类型
- 无需修改原始代码,继而保证了原有代码的封装性
- 新的替换类型必须与被替换类型相兼容,否则稍后的句柄赋值将失败,所以使用继承(用子类覆盖原来的父类)
- 做顶层修改时,非常方便
要想使用覆盖,
原有类型和新类型均需要注册
当时用create()来创建对象时:
- 工厂会检查,是否原有类型被覆盖;
- 如果是,那么工厂会创建一个新类型(覆盖后的)的对象;
- 如果不是,那么它会创建一个原有类型的对象;
覆盖发生时,可以使用“类型覆盖”或者“实例覆盖”
- 类型覆盖(set_type_override)是指,UVM层次结构下所有的原有类型都被覆盖类型所替换。
- 实例覆盖(set_inst_override )是指,在某些位置中的原有类型会被覆盖类型所替代。
set_type_override
()
static function void set_type_override(uvm_object_wrapper override_type,
bit replace = 1 );
//调用
origin_type::type_id::set_type_override(new_type::get_type())
-
uvm_object_wrapper override_type 是注册过后的某一个类在工厂中注册时的句柄。
怎么找到这个句柄?
使用静态函数new_type::get_type() -
bit replace = 1
1:如果已经有覆盖存在,那么新的覆盖会替代旧的覆盖
0:如果已经有覆盖存在,那么该覆盖将不会生效
set_inst_override()
static function void set_inst_override(uvm_object_wrapper override_type,
string inst_path,
uvm_component parent = null);
//调用
origin_type::type_id::set_type_override(new_type::get_type(),"orig_inst_path");
-
string inst_path指向的是组件结构的路径字符串,比如root里面的test,test里面有env,env有checker,这个路径就是 “root.test.env.checker”
-
uvm_component parent = null
如果缺省,表示inst_path内容为绝对路径
如果有传递值,则使用{parent.get_full_name(),’.’,inst_path}来作为目标路径
注意:
set_type_override()和set_inst_override()都是覆盖工厂创建的对象
,如果用new()调用,不是通过工厂创建对象
确保正确覆盖的代码要求
- 将UVM环境中的所有类都注册到工厂中,并通过工厂来创建对象。
- 在使用某些类时,确保该类已经被导入到当前域中
- 通过工厂创建对象时,句柄名称应该同传递到create()方法中的字符串名字相同。
-
覆盖操作在对象创建之前
-
覆盖类最好是原始类的子类,而调用成员方法(原始类中)也应当声明为虚方法
- 为了确保运行时覆盖类型句柄正确使用的方式,需要通过$cast()进行动态类型转换