UVM - 9 (override - 2)
System Verilog本身就是一种面向对象的语言,即本身就支持重载(override),重载即当父类中定义一个virtual类型的函数或任务时,在子类中可以重载这个函数或任务。所以我们来先看一下System Verilog对重载的支持。
案例2
system verilog重载
- 本质是使用继承和多态的思想实现方法的重载
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); // 传入的bird_inst,根据多态的思想,调用的是bird的方法
print_hungry(parrot_inst); // virtual方法调用的是parrot的方法,普通方法调用的是bird中的方法
endfunction
// print_hungry(bird_inst);
"I am a bird, I am hungry"
"I am a bird, I am hungry2"
// print_hungry(parrot_inst);
"I am a parrot, I am hungry"
"I am a bird, I am hungry2" // hungry2()不是virtual方法,所以调用bird中的方法
- 类通过继承可以重载其中的方法,在使用多态的方式调用方法的时候,virtual方法通过子对象调用,可以表现出子对象新的行为
system verilog约束重载
System Verilog还有一个非常有用的特性是支持约束的重载。像我们已经在transaction里定义了某些变量的约束,如果我们需要修改约束的时候只需要派生一个新的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
变量crc_err已经在my_transacton里给定了约束,但是我们想更改这个约束,就从my_transaction里派生一个新的transaction,然后直接重载crc_err的约束即可。
uvm factoroy重载
function void my_case0::build_phase(uvm_phase phase);
// 用parrot替代bird类型
set_type_override_by_type(bird::get_type(), parrot::get_type());
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
"I am a parrot, I am hungry"
"I am a bird, I am hungry2"
"I am a parrot, I am hungry"
"I am a bird, I am hungry2"
- 实例化对象的时侯,实例化语句并不会立马生效,UVM会通过factory机制在自己内部的一张override表格中查看是否有相关的重载记录。 set_type_override_by_type语句相当于在factory机制的override表格中加入了一条记录。当查到有重载记录时,会使用新的类型来替代旧的类型。所以虽然在build_phase中写明创建bird的实例,但是最终却创建了parrot的实例。
- set_type_override_by_type()函数的作用就是在创建实例之前,将新的类型记录到override的表中
- 实例化的时候,factory会先查找override表中原类型是不是被override了,然后创建对象,如果没有override,就创建原对象,如过有override就创建新对象
连续重载
连续重载即factory机制查到一条重载记录时不会立马创建重载类的实例,而是全部查完后再创建,假设查到parrot派生自bird后又查到big_parrot派生自parrot,那么所有的bird和parrot的实例化都会被big_parrot重载掉,这就是连续重载。
class big_parrot extends parrot;
virtual function void hungry();
$display("I am a big_parrot, I am hungry");
endfunction
function void hungry2();
$display("I am a big_parrot, I am hungry2");
endfunction
`uvm_object_utils(big_parrot)
function new(string name = "big_parrot");
super.new(name);
endfunction
endclass
//////////////
function void my_case0::build_phase(uvm_phase phase);
bird bird_inst;
parrot parrot_inst;
super.build_phase(phase);
set_type_override_by_type(bird::get_type(), parrot::get_type());
set_type_override_by_type(parrot::get_type(), big_parrot::get_type());
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
# I am a big_parrot, I am hungry
# I am a bird, I am hungry2
替换重载
替换式重载即已经查到了一条重载记录是parrot重载bird,但再继续查找的过程中又找到了sparrow重载bird(sparrow也派生自bird),这样sparrow就会把上一条的parrot的重载替换掉(前提是重载函数的replace参数值为1,即default值)。
// 替换重载
class sparrow extends bird;
virtual function void hungry();
$display("I am a sparrow, I am hungry");
endfunction
function void hungry2();
$display("I am a sparrow, I am hungry2");
endfunction
`uvm_object_utils(sparrow)
function new(string name = "sparrow");
super.new(name);
endfunction
endclass
//////////////
function void my_case0::build_phase(uvm_phase phase);
bird bird_inst;
parrot parrot_inst;
super.build_phase(phase);
set_type_override_by_type(bird::get_type(), parrot::get_type());
set_type_override_by_type(bird::get_type(), sparrow::get_type());
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
# 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
uvm factory重载的条件
-
无论是重载的类(parrot) 还是被重载的类(bird) , 都要在定义时注册到factory机制中。
-
被重载的类(bird) 在实例化时, 要使用factory机制式的实例化方式, 而不能使用传统的new方式。
-
最重要的是, 重载的类(parrot) 要与被重载的类(bird) 有派生关系。 重载的类必须派生自被重载的类, 被重载的类必须是重载类的父类。
-
component与object之间互相不能重载
uvm重载方法
uvm_component中的重载方法
- 使用set_type_override_by_type函数可以实现两种不同类型之间的重载,
- set_inst_override_by_type函数(并不是希望把验证平台中的A类型全部替换成B类型,而只是替换其中的某一部分)
extern static function void set_type_override_by_type
(uvm_object_wrapper original_type,
//第一个参数是被重载的类型,父类
uvm_object_wrapper override_type,
//第二个参数是重载的类型。子类
bit replace=1);
extern function void set_inst_override_by_type(string relative_inst_path,
//其中第一个参数是相对路径,
uvm_object_wrapper original_type,
//第二个参数是被重载的类型,父类
uvm_object_wrapper override_type
//第二个参数是被重载的类型,子类
);
- 无论是set_type_override_by_type还是set_inst_override_by_type,它们的参数都是一个uvm_object_wrapper型的类型参数,这种参数通过xxx::get_type()的形式获得。
使用类的名称进行替换的方法:set_type_override/set_inst_override - 传入参数为字符串
set_type_override("bird","parrot");
set_inst_override("env.o_agt.mon","my_monitor","new_monitor");
tb_top中initial中的也可以用的重载函数
- 以下四个函数可以用于替换上述函数
- 这四个函数都是factory的重载函数
- 在component中也可以使用factory机制的重载函数
initial begin
factory.set_type_override_by_type(bird::get_type,parrot::get_type());
end
在命令行重载函数
+uvm_set_inst_override="my_monitor,new_monitor,env.o_agent.mon"
+uvm_set_type_override="my_monitor,new_monitor"