UVM覆盖方法

一、工厂机制——覆盖(override)

  • 覆盖机制可以将原来所属的类型替换为另一个新的类型。
  • 在覆盖之后,原本原来创建原属类型的请求,将由工厂来创建新的替换类型。无需再修改原始代码,继而保证了原有代码的封装性。新的替换类型必须与被替换类型相兼容,否则稍后的句柄赋值将失败,所以使用继承。
  • 做顶层修改时非常方便,允许灵活的配置,例如可使用子类来覆盖原本的父类,可使用不同的对象来修改其代码行为。
  • 要实现覆盖的特性,原有类型和新类型都需要注册。
  • 当使用create()来创建对象时,工厂会检查是否原有类型被覆盖,如果是则会创建一个新类型的对象,如果没有,那么会创建一个原有类型的对象。
  • 覆盖发生时,可以使用“类型覆盖”或者“实例覆盖”。“类型覆盖”是指UVM层次结构下所有原有类型都被覆盖类型所替换。“实例覆盖”是指,在某些位置中的原有类型会被覆盖类型所替代。

二、覆盖方法

set_type_override()

static function void set_type_override(uvm_object_wrapper override_type, bit replace=1);

uvm_object_wrapper override_type
这并不是某一个具体实例的句柄,实际上是注册后的某一个类在工厂中注册时的句柄,使用new_type::get_type()可以找到它。

bit replace=1
1:如果已经有覆盖存在,那么新的覆盖会替代旧的覆盖。
0:如果已经有覆盖存在,那么该覆盖将不会生效。

set_type_override()
这是一个静态函数,使用方式orig_type::type_id::set_type_override(new_type::get_type())

set_inst_override()

static function void set_inst_override(uvm_object_wrapper override_type, string inst_path, uvm_component parent=null);

string inst_path
指向的是组件结构的路径字符串

uvm_component parent=null
如果缺省,表示使用inst_path内容为绝对路径,如果有值传递,则使用{parent.get_full_name(), ‘.’, inst_path}来作为目标路径。

set_inst_override()
这是一个静态函数,使用方式orig_type::type_id::set_inst_override(new_type::get_type(),“orig_inst_path”)

需要注意的是,有不止一个类提供与覆盖有关的函数,然而名称与参数列表可能各不相同。因此,需要实现类型替换,也有不止一种方式,可以通过orig_type::type_id来调用覆盖函数,还可以在uvm_component的域中直接调用,或者使用uvm_factory来做覆盖。

三、覆盖实例

module factory_override;
	import uvm_pkg::*;
	`include "uvm_macros.svh"

	class comp1 extends uvm_component;
		`uvm_component_utils(comp1)
		
		function new(string name="comp1", uvm_component parent=null);
			super.new(name, parent);
			$display($sformatf("comp1::%s is created", name));
		endfunction

		virtual function void hello(string name);
			$display($sformatf("comp1::%s 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 said hello!", name));
		endfunction
	endclass

	comp1 c1, c2;
	initial begin
		comp1::type_id::set_type_override(comp2::get_type());
		c1 = new("c1");
		c2 = comp1::type_id::create("c2", null);
		c1.hello("c1");
		c2.hello("c2");
	end
endmodule

仿真结果:
UVM覆盖方法
c1和c2都是comp1类型,但是c1是通过new()函数创建的,所以调用c1.hello()打印comp1::c1 said hello!,而c2是通过工厂创建的,调用c2.hello()打印comp2::c2 said hello!。这说明set_type_override()影响到了由工厂创建的对象,工厂会进行类型替换。

我们只执行

initial begin
		comp1::type_id::set_type_override(comp2::get_type());
		c2 = comp1::type_id::create("c2", null);
end

跑一下仿真,看一下打印出来的日志
UVM覆盖方法
可以看出,当通过工厂创建对象c2时,comp1类型会被comp2类型覆盖,但是仍然会调用comp1的new()打印comp1::c2 said hello!,然后再调用comp2的new()函数打印出comp2::c2 said hello!。所以在有了注册类型词典和覆盖类型队列的信息之后,当c2通过factory创建时,会查看被创建类型是否已经被覆盖,如果被覆盖则从uvm_default_factory::m_type_overrides中取得覆盖类型的信息。
UVM覆盖方法
comp1::type_id::set_type_override(comp2::get_type())使得comp2覆盖了comp1类型,紧接着对c1和c2对象进行了创建,可以从输出结果看到,c1的所属类型仍然是comp1,c2的所属类型则变成了comp2,这说明了factory的覆盖机制只会影响通过factory注册并且创建的对象。所以通过type_id::create()factory类型覆盖可以实现对象所属类型在例化时的灵活替换。在例化c2之前,首先应该用comp2来替换comp1的类型,只有先完成了类型替换,才可以在后面的例化时由factory选择正确的类型。在后面发生了类型替换以后,如果原有的代码不做更新,那么c2句柄的类型仍然为comp1,但是却指向了comp2类型的对象,这就要求comp2应该是comp1的子类,只有这样,句柄的指向才是安全合法的。c2在调用hello()方法时,由于首先是comp1类型,那么会查看comp1::hello(),又由于该方法在定义时被指定为虚函数,这就通过了多态性的方法调用,转而调用comp2::hello()函数,因此,打印的结果是comp2::c2 said hello!

上一篇:【文章翻译】A Reusable Verification Environment for NoC Platforms Using UVM


下一篇:APB协议UVM验证环境的搭建