先导知识:SV中需要了解的基础的面向对象编程的概念

数字芯片验证主要使用的验证语言SystemVerilog,验证方法学是UVM。SV集成了面向对象编程的特点,具有封装、继承、多态等功能。面向对象编程(OOP)是一个大课题,本节仅记录帮助自己了解SV中关于面向对象的编程特点,更好地使用UVM。

OOP的三大优点:
1、代码重用
2、代码维护
3、内存管理

一 、OOP能有上述优点,是基于类“class”开始:

封装

语法:用class关键字定义类,不需要使用大括号,而是用endclass关键字。类中的变量称作类的数据成员,类中的方法称作方法。
注意点:分配内存方面,仿真器对类和结构体的方式不同。结构体对变量声明就分配内存了。而类,需要用户显式调用new() 函数来为对象显式地分配内存。SV会处理所有的内存分配,调用new()的时候分配内存,不再引用时回收内存。
用一个例子表示类:

class rectangle;
	int length;                 //数据成员
	int width;

	function new(int l,int w);   //类似C++的构造函数,每个类都必须要的函数
		length = l;              //作用:传入参数
		width = w;               //注意点:函数名前不用加void 固定格式 
	endfunction

	function int area();       //方法
		return length * width;
	endfunction 
endclass

rectangle rectangle_h   //声明一个对象
rectangle_h = new(50,20); //例化对象,为对象分配内存

继承

继承是指:在父类的基础上,衍生一些独特的成员的类。
例如:正方形是矩形的特殊形式,因此正方形可以继承矩形类

class square extends rectangle
	function new(int side);
		super.new(side,side);
		//super关键字只是编译器显式调用父类中的成员或方法
		//在这指示编译器调用rectangle中的构造函数并将side值传入rectangle的长度和宽度参数
	endfunction
endclass

可以看到,square继承了rectangle,具有了rectangle的所有成员变量和方法。并且在构造函数里显式地调用了父类的构造函数。

多态

多态的表现形式是: 它是指在父类中定义的属性和方法被子类 继承之后,可以具有不同的数据类型或表现出不同的行为。(说实话,丹丹看这句话有点抽象)
所以我们先理解这句话:父类句柄可以指向一个子类对象,但子类句柄不可以指向一个父类的对象。

问题1:何为句柄,何为对象?

句柄是对象的指针,可以利用句柄来访问对象。通过类的声明来生成句柄
对象是类的实例化,具有内存空间。
在不同的位置上句柄可以指向不同的对象,但在一个确定的位置上句柄一定指向一个确定的对象。(有点拗口,)
父类句柄可以指向一个子类对象:是指父类句柄调用他能调用的所有值,子类对象中都存在,子类句柄指向一个父类的对象的话,子类句柄调用的方法和成员变量可能是父类对象中不存在的。可以通过图显示:
在这里插入图片描述

在代码中表现出

rectangle rect_h;
square squ_h;
squ_h = new(50);
rect_h = squ_h;

在这里插入图片描述
可以看出长方形句柄也是可以指向一个正方形的对象的。

问题2:随之而来,会出现一种情况,如果父类和子类同时具有一个函数名相同的方法,究竟哪一个方法被调用呢?

示例,lion继承了animal类,重载了make_sound函数
父类:animal
子类:lion

lion lion_h;
lion_h = new(1);
lion_h.make_soud();
//输出:The Lion says Roar
//子类句柄指向子类对象,句柄调用方法时,调用的是子类的方法
lion lion_h;
animal animal_h;
lion_h = new(1);
animal_h = lion_h;
animal_h.make_soud();
//输出:Fatal:Generic animals don't have sound!
//父类句柄指向子类对象时,父类句柄调用的是父类的方法

问题3:能否用animal类型的句柄操纵lion对象并且让它吼呢?也就是说在父类句柄指向子类对象时时,调用的方法何时是句柄类型的,何时是对象类型的?

因而提出了虚方法
虚方法的作用:当将一个方法定义为虚方法时,是在指示SV语言忽略句柄(变量)类型的表面限制,去深入地查看存放在句柄里的对象的类型,找到真正调用的方法。定义虚方法的类型,就是在方法前加virtual
虚方法的表现形式:在父类中定义一个virtual类型的方法,在子类重载中这个方法。
当父类句柄指向子类对象时,父类句柄调用对象是调用的是子类的方法。

拓展一下

抽象类和纯虚函数
抽象类:只能用来做基类,不能用抽象类来例化一个对象,否则运行错误
纯虚函数:这些方法没有实体,重载时需要强制重载这些方法,不重载就会得到编译错误。可以理解为必须重载的方法。

二、静态变量和静态方法

问题1:为什么OOP中会需要静态变量?

我认为它是为了替代全局变量而出现的。
全局变量是个灾难,此处不赘述。OOP 通过类定义中的静态变量和静态方法提供了这种功能. 这简化了全局变量和方法的定义, 使用和维护。
1、静态变量的内存分配:上述介绍了类声明的时候不会为对象分配内存,只有调用new()函数之后,才会为一个对象分配内存。但静态变量不同,如果类的成员变量前加上static关键字,类创建时,这个static变量内存就会被分配。
2、这个static变量只有一份内存空间,无论这个类的对象创建了多少个。
下面一个例子:我们利用静态变量创建了一个狮子笼的类,专门用来装狮子。
3、静态变量和方法的作用域范围:任意位置可以时钟,而局部变量只能在声明这个类的方法和任务中使用。
在这里插入图片描述
在这里插入图片描述

问题2:为什么需要有静态方法?

通过一种更高效、安全、简单地方式来操作静态变量,为操作静态变量提供一个接口。
下面这个例子,我们不需要将手动将狮子压入堆栈中(狮子的队列调用压栈函数),而只需要大吼一声“臭狮子,你给我进去”(调用静态方法,该方法实现了把狮子放进笼子,不需要再去操作静态变量了)。
在这里插入图片描述
在这里插入图片描述

三、类的参数化

我的拙见,参数化的类,可以大大减少相同功能的代码的书写提高编码效率。
比如上述例子,我们创建了一个装狮子的笼子,但是我们还需要装猪,装牛呀,各种各样的笼子。最笨的方法就是我们再一个一个创建这些相似的笼子(类)。但SV是面向对象的编程,同样是笼子,都是用来装东西的,只是东西的类型不同,只需要更改类型即可。
那么该如何实现,会更简洁呢?

//建一个动物笼子,动物的类型是T
class animal_cage #(type T) //type是关键字,
	protected static T cage[$];

	static function void cage_animal(T l);
		cage.push_back(l);
	endfunction
endclass
//将不同的动物装不同的笼子
lion lion_h = new(23,"yqd");
pig pig_h = new(23,"wxh");
animal_cage #(lion)::cage_animal(lion_h);//把叫yqd的狮子放入狮子笼子
animal_cage #(pig)::cage_animal(pig_h);//把叫wxh的猪放在猪圈里

//可以看出animal_cage是一个参数化的类,所以只需要在使用静态方法时提供类型就可以创建对应的笼子

OK,以上是在学习UVM之前、至少需要了解的(不了解也不会咋样只是犯的错误多一点deebug慢一点)、SV关于面向对象的知识点。学习资料来自<>中文翻译版,有很多理解可能也还不到位,如有错误,请多指教。

最后分享一段这本书中的一段话:

自发的思维转换几乎是不可能的,你必须坚持学习然后等待顿悟,最后你会对这个世界有全新的视角。

  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值