一、工厂的注册、创建和覆盖机制
工厂机制_知识回顾
- 工厂是为了更方便的替换验证环境中的实例或注册了的类型,带来配置的灵活性
- 背景:有时候无法直接修改验证平台的代码,比如①别人正在用,修改会影响别人使用;②验证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_component_utils()注册;然后是new函数,第二个参数是parent,必须调用super.new();最后是build_phase()函数,也是必须调用super.build_phase(p)函数
class comp1 extends uvm_component;
`uvm_component_utils (comp1)//注册组件;new函数必须只有两个参数
function new (string name=:comp1", uvm_component parent=null);//parent是指上一层,当前实例是谁例化的,谁就是这个实例parent
super.new(name, parent);//继承父类new函数
$display($sformatf("%s is created", name));//已例化当前类
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase (phase);
endfunction: build_phase
endclass
2、创建:UVM中创建实例的方法有很多,常用xxx::type_id::create来创建;注意,如果用new()来创建则无法使用工厂的覆盖
例化component用c2 = comp1::type_id::create ("c2",null);也是两个参数
例化object用o2 = obj1::type_id::create("o2");
comp1 c1, c2;
obj1 o1,o2;
initial begin
c1 = new ("c1");//任何对象的例化最终都是通过new()函数来实现,sv的方法
o1 = new ("o1");
c2 = comp1::type_id::create ("c2",null);//这个也是例化的写法,factory提供的方法
o2 = obj1::type_id::create("o2");
end
3、覆盖
覆盖并不是工厂机制的发明,所有面向对象的语言都支持函数/任务重载。
采用工厂进行覆盖有以下条件:
原类型和新类型都需要注册到工厂里;
需要用工厂机制来创建;
覆盖的类和被覆盖的类有继承关系,并且被覆盖的方法要声明为virtual。不过有例外:component和object之间不能相互覆盖(虽然component是object的子类,但血缘关系太远了)
若有多层覆盖时,最终覆盖的类必须是最初被覆盖类的子类;多层覆盖,以最后一个覆盖结果为准
set_inst_override ( uvm_object_wrapper override_type, string inst_path);
//uvm_object_wrapper override_type是注册过后的某一个类在工厂中注册时的句柄,用new_type::get_type()找到
module factory_override;
import uvm_pkg::*;//可直接import和include,编译器已经包含了
`inculde "uvm_macros.svh"
class comp1 extends uvm_component;//1声明
`uvm_component_utils(comp1)//2注册
function new (string name="comp1", uvm_component parent= null);//3new函数
super.new(name, parent);
$display ($sformatf("comp1::%s is created", name));
endfunction
virtual function void hello (string name);//virtual是关键
$display ( $sformatf("comp1:: %s is said hello!", name);
endfunction
endclass
class comp2 extends comp1;//要覆盖的类一定要继承于被覆盖的类
`uvm_component_utils(comp2)
function new (string name="comp2", uvm_component parent= null);
super.new(name, parent);
$display ($sformatf("comp2::%s is created", name));
endfunction
function void hello (string name);
$display ( $sformatf("comp2:: %s is said hello!", name);
endfunction
endclass
comp1 c1, c2;//两个句柄都是comp1的类型
initial begin
comp1::type_id::set_type_override (comp2::get_type());//调用覆盖函数,如上段例码
c1= new("c1");//例化c1(comp1),没有通过工厂。打印comp1::c1 is created,
c2= comp2::type_id::creare("c2",null);//工厂创建的对象,create返回一个comp2句柄给c2
//但是c2是comp1的句柄,却指向了comp2类型的对象。这里就是子类句柄覆盖父类句柄。所以必须是继承关系
//用工厂注册,就一定要用工厂来创建,达到便利的目的
//打印comp1::c2 is created,comp2::c2 is created
c1.hello("c1");//调用comp1的hello,打印 comp1::c1 is said hello
c2.hello("c2");//调用comp2的hello,打印 comp2::c2 is said hello
end
endmodule