UVM(1)——OOP overview

面向对象的编程OOP

首先回顾SystemVerilog中class的三大特性——封装性、继承性和多态性

封装性

SV中的class中的成员包括:

  • 变量:用于数据建模
  • 子程序:用于数据操作
    在这里插入图片描述

继承性

class可以通过基类(父类)派生新类(子类),新类会继承基类的所有数据和数据处理(方法)。
在这里插入图片描述
派生类兼容基类
在这里插入图片描述

函数的形参为父类,同时也可以传入基类的子类。
父类和子类可以相互转换。

多态性

多态性涉及到虚方法(virtual method),实方法看句柄的类型,虚方法看对象的类型。
在这里插入图片描述
方法不带virtual,看句柄的类型,无论传入的实参是什么
在这里插入图片描述
如果是虚方法:
在这里插入图片描述
利用虚方法可以将传入的不同对象,调用不同的方法:
在这里插入图片描述
在这里插入图片描述
建议method都定义成virtual,这样才能利用多态的属性,只要基类的方法定义成virtual,子类的方法无所谓
在class之外定义子程序
在这里插入图片描述
在这里插入图片描述
4. 参数化类
参数化类声明例化对象时可以设置不同的数组大小或者数据类型(type)。参数化类的参数可以是一个变量、也可以是type关键词定义的数据类型。

eg:

class vector #(int size = 1);//参数是一个变量
    bit [size-1:0] a;
endclass
 
vector #(10) vten;        // object with vector of size 10
vector #(.size(2)) vtwo;  // object with vector of size 2
typedef vector#(4) Vfour; // Class with vector of size 4
 
class stack #(type T = int);//参数是一个数据类型
    local T items[];
    task push( T a ); ... endtask
    task pop( ref T a ); ... endtask
endclass
 
stack is;             // default: a stack of ints
stack#(bit[1:10]) bs; // a stack of 10-bit vector
stack#(real) rs;      // a stack of real numbers

注:任何类型(type)都可以作为一个参数,包括user定义的class或者struct等类型(type)。

一个参数化类可以被扩展成其他参数化累,例如:

class C #(type T = bit); ... endclass           // base class
class D1 #(type P = real) extends C;            // T is bit (the default)
class D2 #(type P = real) extends C #(integer); // T is integer
class D3 #(type P = real) extends C #(P);       // T is P
class D4 #(type P = C#(real)) extends P;        // for default T is real

4.1 参数化类中类作用域操作符的使用
当缺省参数化类作为类解析操作符前缀时,应该显式的使用#()。例如:

class C #(int p = 1);
    parameter int q = 5; // local parameter
 
    static task t;
        int p;
        int x = C::p; // C::p disambiguates p
                      // C::p is not p in the default specialization
    endtask
endclass
 
int x = C::p;     // illegal; C:: is not permitted in this context
int y = C#()::p;  // legal; refers to parameter p in the default specialization of C
 
typedef C T;      // T is a default specialization, not an alias to the name "C"
 
int z = T::p;     // legal; T::p refers to p in the default specialization
int v = C#(3)::p; // legal; parameter p in the specialization of C#(3)
int w = C#()::q;  // legal; refers to the local parameter
 
T obj = new();
int u = obj.q;    // legal; refers to the local parameter
bit arr[obj.q];   // illegal: local parameter is not a constant expression

参数化类使用extern关键在在类外声明方法。

class C #(int p = 1, type T = int);
    extern static function T f();
endclass
function C::T C::f();
    return p + C::p;
endfunction
 
initial $display(%0d %0d”, C#()::f(),C#(5)::f()); // output is "2 10"

自定义的class

在这里插入图片描述

Static property 静态变量/数据

在这里插入图片描述

静态方法

在这里插入图片描述
类名::静态方法可以直接调用静态方法。

Singleton class单例类

  • 用于定义全局行为,如打印,工厂
  • 单例类不存在对象(不能new和create)
  • 只包含静态变量/子函数,不允许有非静态的成员变量

单例类的打印函数(统计错误次数)

class print;
	static int err_count = 0, max_error = 10;
	static function void error(string msg);
		$display("@%t:ERROR %s", $realtime, msg);
		if(err_count++ > max_errors) $finish;
	endfunction
endclass

调用打印函数

if(expect != actual)
	print::error("Actual did not match expected");

单例对象

  • 单例对象是一个全局可见/可操作的对象,提供定制化服务/函数。
    (1) 有且仅有一个对象(在编译时创建)。
    (2) 在仿真时全局可见/可操作
    (3) 可以有静态或者非静态成员
class factory;
	static singleton me = get();
	static function singleton get();	//反回singleton类型的函数
		if(me == null) me = new(); return me;
	endfunction
	
	local function new();
	endfunction

	extern function void print();
endclass
factory f = factory::get(); //使用get()方法保证单例对象全局只有一个对象

由于factory对象中new函数是local,因此不能在外部调用:factory fa = new(),只能调用其get()

代理类

  • 提供**creat()**等通用型的子函数
class proxy_class #(type T = base);
	typedef proxy_class #(T) this_type;
	static this_type me = get();	//构建一个代理类的对象
	
	static function this_type get();
		if(me = null) me = new(); return me; //返回代理类的一个单例对象
	endfunction
	
	static function T create(); //创建T的对象,即组件的对象
		create = new();
	endfunction
endclass

代理类产生的是单例对象。
调用create可以创建一个T类型的对象。

class transaction extends base;
	typedef proxy_class #(transaction) proxy; 
endclass
//-------------------------------------------
class driver extends base;
	typedef proxy_class #(driver) proxy;
endclass
class environment;
	transaction tr; driver drv;
	function new();
		tr  = transaction::proxy::create();//利用代理类创建一个transaction对象
		drv = driver::proxy::create();     //创建一个driver对象
	endfunction
endclass

用create函数代替了new函数

工厂机制

  • 创建工厂,需要两层代理类
    (1) 虚代理类(Virtual proxy base class)(空壳)
    (2) 派生代理类,实现全部功能

虚代理基类
(1) 代理基类要具有多态属性
(2) 为代理服务提供抽象的接口应用程序
i 创建对象(create_object)
ii 获取类型名称(get_typename)

//虚代理基类
virtual class proxy_base;
	virtual function base create_object(string type_name);	//虚方法可实现多态
		return null;
	endfunction
	
	pure virtual function string get_typename();
endclass

pure virtual function 是只有定义,没有实体的方法,只可以在virtual class中定义。pure virtual function 只有在扩展类中定义了实体,才可以使用
virtual class, 可被声明,可以被extend, 但是不能被实例化。

class factory;
	/* 0. 代理基类的注册表 */
	static proxy_base registery[string]; //数组的索引是字符串
	/* 1. 获得工厂的单例对象 */
	static factory me = get();
	static function factory get();
		if(me == null) me = new(); return me; //factory是单例对象
	endfunction
	/* 2. 代理基类的注册机制 */
	function void register(proxy_base proxy);
		registry[proxy.get_typename()] = proxy;	//类型名称对应其代理类
	endfunction
	/* 3. 分配每个组件的对象 */
	function base create_object_by_type(proxy_base proxy,string name);
		proxy = find_override(proxy);
		return proxy.create_object(name);//分配每个组件的对象
	endfunction
  • 维护被覆盖的代理登记表
    (1) 如果代理类被覆盖,创建覆盖后的类的对象
/* 4. 替换列表 */
static string override[string];	//组件原来名字和替换的组件名字

static function void override_type(string type_name, override_typename);
//type_name原来的名字,override_typename替换的名字
	override[type_name] = override_typename;
endfunction

/* 5.找组件是否有替换 */
function proxy_base find_override(proxy_base proxy);
	if(override.exists(proxy.get_typename()))	//查看组件是否被注册
		return registry[override[proxy.get_typename()]]; //注册返回其替换的组件的基类
	return proxy;	//没有注册返回本省的基类
endfunction

endclass

Proxy class代理类(完善虚代理类的功能)

  • 完成抽象的接口函数
  • 在工厂中登记
  • 利用工厂创建对象
class proxy_class #(type T=base, string Tname="none") extends proxy_base;//传参:组件和组件名字
	typedef proxy_class #(T,Tname) this_type;
	static string type_name = Tname;	//传入的名字
	static this_type me = get();	//获得代理类的一个单例对象
	
	static function this_type get();
		factory f = factory::get();	//获得一个工厂对象me
		if(me=null) begin
			me = new();	//获得this_type的对象
			f.register(me);	//注册,每个class都会注册
		end
		return me;//返回一个this_type对象
	endfunction

	static function T creat(string name);	//分配对象
		factory f = factory::get();
		$cast(creat, f.create_object_by_type(me,name));
	endfunction

	virtual function base create_object(string name);
		T object_represented = new(name);
		return object_represented;
	endfunction
endclass

测试案例可以使用工厂机制替换验证平台创建的任何对象,但却不要修改验证平台的代码,提高了代码的可重用性
在这里插入图片描述

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值