- 类和对象的概述
-
- 类和对象
- 为什么要OOP(面向对象编程)/li>
- OOP的概念要素
- 创建对象
- 句柄的传递
- 对象的销毁
- 句柄的使用
- 静态变量
- 静态方法
- 类的成员
-
- 概述
- 类的封装
- 一些类的思考
- 类的继承
-
- 概述
- 验证环境中类继承的案例
- 成员覆盖
- 句柄的使用
-
- 句柄的传递
- 句柄的动态修改
- 命名空间
复习整理下。安利下 路科验证。
类和对象的概述
类和对象
- 对象编程语言更符合人对自然的理解(属性property和功能function)
- 无数的类(class)和对象(object)构成代码世界。类是将相同的个体抽象出来的描述方式,对象是实体,其具备有独立行为的能力,一个对象是万千世界中的“一粒沙”。
- 具有相同属性和功能的对象属于同一类,而不同的类之间可能有联系(继承关系)或者没有联系。
- 在C语言中,编程基于过程方法(function);在Verilog中,提供了笨拙的类对象编程可能性,即在module中定义方法,而后调用module实例中的方法。
- Verilog的module+method的方式与SV的class定义有本质上的差别,即面向对象编程的三要素 :封装(Encapsulation)继承(Inheritance)和多态(Polymorphism)。
- 类的定义核心即是属性声明(property declaration)和方法定义(method definition),所以类是数据和方法的自洽体(self-compatible),即可以保存数据和处理数据。这是与struct结构体在数据保存方面的重要区别,因为结构体只是单纯的数据集合,而类则可以对数据做出符合需要的处理。
为什么要OOP(面向对象编程)/h2>
-
验证环境的不同组件其功能和所需要处理的数据内容是不相同的
-
同环境的同一类型的组件其所具备的功能和数据内容是相似的
-
基于以上两点,验证世界的各个组件角色明确、功能分立,使用面向对象编程与验证世界的构建原则十分符合。
-
示例激励数据类:一个transaction事务类
OOP的概念要素
验证环境的不同组件其功能和所需要处理的数据内容是不相同的
同环境的同一类型的组件其所具备的功能和数据内容是相似的
基于以上两点,验证世界的各个组件角色明确、功能分立,使用面向对象编程与验证世界的构建原则十分符合。
示例激励数据类:一个transaction事务类
官方OOP三要素;封装、继承、多态
- Class类: 基本模块包含成员变量和方法。在Verilog中module也可以包含变量和方法,只不过它是硬件盒子’,而class是软件盒子。
- Ojbect对象: 类的实例。Verilog中module也可以例化,这是硬件”例化,在SV中可以使用class来例化,这是软件”例化。
- Handle句柄(指针): 用来指向对象的指针。在Verilog中,可以通过层次化的索引来找到结构中的设计实例,而在SV的对象索引时,需要通过句柄来索引对象的变量和方法。
- Property属性(变量): 在类中声明的存储数据的变量。在Verilog中,它可以是wire或者reg类型。
- Method方法:类中可以使用task或者function来定义方法以便处理自身或者外部传入的数据。在Verilog中可以在module中定义task/function,也可以使用initial/always处理数据。
创建对象
-
Verilog的例化和SV class例化的差别:
- 两者的共同点在于使用相同的模板来创建内存实例
- 不同点在于Veriloa的例化是静态的,即在编译链接时完成,而SV class的例化是动态的,可以在住意时间点发生,这也使得类的例化方式更加灵活和节省空间。
- Verilog中没有句柄的概念,即只能通过层次化的索引方式A.B.sigX,而SV class通过句柄可以将对象的指针赋予其它句柄,使得操作更加灵活。
- 在创建对象时,需要注意什么是**“声明”,什么是“创建”(即例化)**
- 所谓创建对象即开辟新的内存间,用来存放新的成变量和方法
- 创建对象时,可以通过自定义构建函数(constructor)来完成变量的初始化和其它初始操作。
- 示例
- 构建函数new()是系统预定义函数,不需要指定返回值,函数会隐式地返回例化后的对象指针。
- 构建函数也可以定义多个参数作为初始化时外部传入数值的手段。
上述代码中完成初始化后,tr.addr=10。new(10),将10传给了a。赋值在初始化之后,初始化的值被改变了,所以tr.addr不再是初值的’h10,而是10。
句柄的传递
- 在区分了类(抽象)和对象(具体)之后,还需要区分对象(存储空间)和句柄(空间指针)。也就是说,在创建了对象之后,该对象的空间位置不会更改,而指向该空间的句柄可以有多个。
对象的销毁
- 软件编程的灵活在于可以动态地开辟使用空间,在资源闲置或者不再需要时,可以回收空间,这样使得内存空间保持在一个合理的区间。
- C++语言中的类除了有构建函数,还有析构函数。析构函数的作用即在于手动释放空间,但这对编程人员的细心和经验提出了要求;Java和Python等后续面向对象语言则不再需要手动定义析构函数并且释放空间,这意味着空间的回收利用也是自动的。
- sv也采用了自动回收空间的处理方式,使得用户不再软件空间的开销而烦恼。那么,自动回收空间的基本原理是什么呢,当一个对象,在整个程序中没有任何一个地方再需要”它时,便会被销毁,即回收其空间。这里需要的意思即指的是有句柄指向该对象。
问:假设wd = new(1)所需要开辟1B的空间,那么在initial2的display语句处,需要为对象例化开辟多少空间呢br> 答:因为wd=new(i),已经执行了4次,所以在1ps处,wd这个句柄指向第四个例化的对象,前面三个对象没有句柄指向了,因此这个对象占据4个B。
如下例中,对象的销毁:
此例中,句柄中因为被automatic了,所以句柄不在了,也不再保存这个值。
句柄的使用
- 可以通过句柄来使用对象中的成员变量或者成员方法
静态变量
- 与硬件域例如module,interface不同的是,在class中声明的变量其默认类型为动态变量,即其生命周期在仿真开始后的某时间点开始到某时间点结束。具体来讲,其声明周期始于对象创建,终于对象销毁。
- 那么如果使用关键字static来声明class内的变量时,则其为静态变量。根据之前课程对变量声明周期的描述,静态变量的生命开始于编译阶段,贯穿于整个仿真阶段。
- 如果在类中声明了静态变量,那么可以直接引用该变量class::var(域索引),或者通过例化对象引用object.var.类中的静态变量声明以后,无论例化多少个对象(0…N),只可以共享一个同名的静态变量,因此类的静态变量在使用时需要注意共享资源的保护。
静态方法
- 类似于静态变量,在class中定义的方法默认类型是动态方法,而我们也可以通过关键词static修改其类型为静态方法。
- 静态方法内可以声明并使用动态变量,但是不能使用类的动态成员变量。原因是因为在调用静态方法时,可能并没有创建具体的对象,也因此没有为动态成员变量开辟空间,因此在静态方法中使用类的动态成员变量是禁止的,可能会造成内存泄漏,但是静态方法可以使用类的静态变量,因为静态方法同静态变量一样在编译阶段就已经为其分配好了内存空间。
类的成员
概述
- 类是成员变量和成员方法的载体,之所以称之为自洽体,是因为其变量和方法应符合聚拢原则,即一个类的功能应该尽可能简单,不应当承担过多的职责,更不应该承担不符合它的职责,这在设计模式中称之为单一职责原则(SRP Single Responsibility Principle)。
- 类作为载体,也具备了天生的闭合属性,即将其属性和方法封装在内部,不会直接将成员变量暴露给外部,通过protected和local关键词来设置成员变量和方法的外部访问权限。所以封装属性在设计模式中称之为开放封闭原则(OCP Open Closed Principle)
class clock local bit is_summer = 0; local int nclock = 6; function int get_clock (); if (! is_summer) return this.nclock; else return this.nclock+1; endfunction function bit set_summer (bit s); this.is_summer = s; endfunction endclassclock ck; initial begin ck = new声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!