factory 机制的本质在没有factory 机制之前,要创建一个类的实例,只能使用 new 函数但是有了factory 机制之后,除了使用 new 函数外,还可以根据类名创建这个类的一个实例;另外,还可以在创建类的实例时根据是否有重载记录来决定是创建原始的类,还是创建重载的类.
所以,从本质上来看,factory 机制其实是对 SystemVerilog 中 new 函数的重载。因为创建重载的类的实例。这个原始的 new 函数实在是太简单了,功能太少了。经过 factory 机制的改良之后,进行实例化的方法多了很多。·这也体现了 UVM 编写的一个原则,一个好的库应该提供更多方便实用的接口,这种接口一方面是库自己写出来并开放给用户的,另外一方面就是改良语言原始的接口,使得更加方便用户的使用。
任务与函数的重载
SystemVerilog 是一种面向对象的语言。面向对象语言都有一大特征:重载。当在父类中定义一个函数/任务时,如果将其设置为 virtual 类型,那么就可以在子类中重载这个函数/任务。重载的最大优势是使得一个子类的指针以父类的类型传递时,其表现出的行为依然是子类的行为。
class bird extends uvm object;
virtual function void hungry();
display("I am a bird, I am hungry");
endfunction
function void hungry2();
display("I am a bird, I am hungry2");
endfunction
endclass
class parrot extends bird;
virtual function void hungry();
display("I am a parrot, I am hungry");
endfunction
function void hungry2() ;
display("I am a parrot,I am hungry2");
endfunction
endclass
function void my_case0: :print_hungry (bird b_ptr);
b_ptr.hungry();
b_ptr.hungry2();
endfunction
function void my_case0: :build phase (uvm phase phase) ;
bird bird_inst;
parrot parrot_inst;
super.build_phase (phase);
bird_inst = bird::type_id::create("bird inst");
parrot_inst = parrot::type_id::create("parrot inst");
print_hungry(bird_inst);
print_hungry(parrot_inst);
endfunction
约束的重载
SystemVerilog 中一个非常有用的特性是支持约束的重载。因此,依然
用第一种方式中 mytransaction 的定义,在其基础上派生一个新的 transaction:
class new_transaction extends my_transaction;
'uvm_object_utils(new transaction)
function new(string name= "new_transaction");
super.new(name);
endfunction
constraint crc_err_cons{
crc_err dist {0 := 2,1 := 1};
}
endclass
在这个新的 transaction 中将 crc_err_cons 重载了。因此,在异常的测试用例中,可以使用如下的方式随机化:
virtual task body();
new_transaction ntr;
repeat (10) begin
'uvm_do(ntr);
ntr.print();
end
endtask
如果在前面没有实例化,直接使用uvm_do宏
使用 factory 机制进行重载
虽然 bird_inst 在实例化以及传递给 hungry 的过程中,没有过与 parrot 的任何接触,但是它最终指向了一个parrot 的实例。这是因为 bird inst 使用了 UVM 的factory 机制式的实例化方式:bird inst = bird::type id::create("bird inst");
在实例化时,UVM 会通过 factory 机制在自己内部的一张表格中查看是否有相关的重载记录。set_type_override_by_type 语句相当于在factory 机制的表格中加人了一条记录。当查到有重载记录时,会使用新的类型来替代旧的类型。所以虽然在 build_phase 中写明创建bird 的实例,但是最终却创建了 parrot 的实例。
使用 factory 机制的重载是有前提的,并不是任意的类都可以互相重载。要想使用重载的功能,必须满足以下要求:
第一,无论是重载的类(parrot) 还是被重载的类(bird),都要在定义时注册到factory 机制中。
第二,被重载的类 (bird)在实例化时,要使用 factory 机制式的实例化方式,而不能使用传统的 new 方式。
第三,最重要的是,重载的类 (parrot)要与被重载的类(bird) 有派生关系。重载的类必须派生自被重载的类,被重载的类必须是重载类的父类。
第四,component 与 object 之间互相不能重载。虽然 uvm_component 是派生自uvmParent=null contxt=object,但是这两者的血缘关系太远了,远到根本不能重载。从两者的 new 参数的函数就可以看出来,二者互相重载时,多出来的一个parent 参数会使factory 机制无所适从。
重载的方式及种类
set_ype_overide_by_type
set_ype_overide_by_type 函数可以实现两种不同类型之间的重载。这个函数位于uvm_component中,其原型是:
extern static function void set_type_override_by_type (
uvm_object_wrapper original type,
uvm_object_wrapper override_type,
bit replace=1);
这个函数有三个参数,其中第三个参数是 replace,将会在下节讲述这个参数。在实际应用中一般只用前两个参数,第一个参数是被重载的类型,第二个参数是重载的类型。
set_ inst_override_by_type
但是有时候可能并不是希望把验证平台中的 A类型全部替换成 B类型,而只是替换其中的某一部分,这种情况就要用到 set_ inst_override_by_type 函数。
extern function void set_inst_override_by_type(
string_relative_inst_path,
uvm_object_wrapper_original_type,
uvm_object_wrapper_override_type);
其中第一个参数是相对路径,第二个参数是被重载的类型,第三个参数是要重载的类型。
假设要将 env.o_agtmon 替换成new monitor
set_inst_override_by_type("env.o_agt .mon", my_monitor::get type (), new_monitor::get type ());
无论是 set_type_override_by_type 还是set_inst_override_by_type, 它们的参数都是uvm_object_wrapper 型的类型参数,这种参数通过xxx::get _type() 的形式获得.
UVM还提供了另外一种简单的方法来替换这种晦涩的写法,字符串。
与set_type_override_by_type相对的是 set_type_override
extern atatie funetlon void set_type_override (
string original_type_name,
string override _type_name,
bit replace=1):
要使用 parrot 替换 bird,只需要添加如下语句;
set_type_override("bird”,"parrot")
与 set_inst_override_by_type 相对的是 set_inst_override
extern funetion void set_inst_override(
string relative_inst_path,
string original_type_name.
string override_type_name);
对于上面使用 new_monitor 重my_monitor 的例子,可以使用如下语句:
set_inst override("env.o_agt.mon","my_monitor", “new_monitor");
复杂的重载
连续重载
依然以 bird 与 parrot 的例子讲述,现在从 parrot 又派生出了一个新的类 big parrot:
build_phase:
set_type_override_by_type (bird::get_ype(), parrot::get_type());
set_type_override_by_type (parrot::get_type(), big_parrot::get_type());
print_hungry(bird_inst);
print_hungry(parrot_inst);
结果:
# I am a big parrot, I am hungry
# I am a bird,I am hungry2
替换重载
假如从 bird 派生出了新的鸟sparrow:
set_type_override_by_type (bird::get_ype(), parrot::get_type());
set_type_override_by_type (bird::get_type(), sparrow::get_type());
print_hungry(bird_inst);
print_hungry(parrot_inst);
结果
# I am a sparrow, I am hungry
# I am a bird,I am hungry2
# I am a parrot,I am hungry
# I am a bird,I am hungry2