面向对象编程的历史
OOP源于20世纪60年代在挪威开发的一种叫做Simula的早期硬件描述语言(Hardware Description Language,HDL,硬件描述语言)。设计者可以将硬件视为由各个组件连接成的集合。因此,HDLs对于对象是非常有利的。Verilog在很多方面都被认为是一种早期的面向对象编程语言。它的基本对象是模块,模块被实例化以构成一个设计。 C++是将C和Simula两种语言的元素融合而来的 。但是C和C++的一大问题在于内存管理能力的不足。这就导致容易出现引用无效内存或破坏他人的内存。需要花费更多的时间去调试他人的代码而非自己的代码 。 在二十世纪90年代,Sun Microsystems开发了Java作为C++的高可靠性替代品。Java向用户提供了内存管理机制并很好的保护了易受破坏的代码。(Java最初被称为 ‘C++--’ ,意思是去除C++不合理部分的C++。) 大约在同一时间,Sun的硬件团队开始意识到即使Verilog是一款可以完成硬件设计和功能验证的语言,但是它用于进行功能验证的部分已经是不合格的了。因此, Sun将Java中的许多概念和Verilog相结合创造出了 Vera语言 。而Vera的不足之处在于其是一款专用于Verilog仿真器的独立专用语言。最终, Vera被并入Verilog成为现在IEEE System Verilog标准的一部分 。 OOP在验证环境中也支持编写可复用代码 。编写硬件功能测试是一个软件问题。而OOP在编写抽象、高复用性和高维护度的代码方面是一种行之有效的方法。相应的,class(类)适用于对可复用验证环境及运行在这一环境的抽象数据和方法的建模。OOP包括以下的关键概念:封装——创建数据容器及其相关行为,即对数据进行操作的代码。
继承——使用其他数据和新的行为扩展或覆盖容器。
数据隐藏——隐藏细节以减少复杂性并提高抽象水平。
泛用编程——编写可广泛用于各种应用程序的代码;类似在Verilog中覆盖模块实例上的参数。
多态——根据现有的对象类型,用相同的代码来描述不同的行为。多态将许多其他的概念联系在一起。
SystemVerilog中class(类)的术语
与其他的OOP语言类似,SystemVerilog使用术语class(类)来定义组成对象的子集。在封装过程中,我们将事物分为较小的类别。例如,我们可以使用一个class(类)来表示音频流,使用另一个class(类)表示视频流。 一旦有了一个class(类)的定义,我们就可以动态构造一个class(类)对象。编程人员构造的class(类)总是动态的, 这就 意味着只有在调用一个例程来例化class(类)时它们才真正存在于内存之中 。然后我们将句柄存储在class(类)变量中。其他一些编程语言中使用了“指针”这个术语,例如指向内存中特定区域的指针。但 在SystemVerilog中,用“句柄”来表示不透明指针或安全指针更合理一些。 当用户有一个对象的句柄时,只能得知它是指特定对象及其数据的集合,而不能得知句柄具体的值 。SystemVerilog不允许用户查看句柄的值。用户只能使用它来引用对象及其内容。 可以看出,单词"class"根据上下文有着许多不同的含义,这需要一些时间来适应。然而工程师在使用 class type(类类型) 、class object(类对象),class handle(类句柄)或class variable(类变量) 时,都使用了class作为代替。本文中除非特殊说明,否则不会单独使用"class"一词。类的基础
如图1所示的结构体或枚举类型一样,类也是数据类型。 声明类仅创建新的类型,不会分配任何存储空间 。因此在例化前,没有与类这个数据类型所关联的存储空间。 图1 类的定义是通过关键词 class/endclass完成的。三个变量 Command,Status 和Data 称为属性,函数GetStatus和任务SetCommand称为方法。 软件世界中,在数据类型类中声明的变量称为属性。SystemVerilog使用关键词property(单词propert意为属性)声明断言 。这是完全不同的两个"属性",因此请注意进行区分。 子例程(在Verilog中称为任务和函数)是类的方法。属性和方法都是类的成员,亦是类封装的基础。 每个类都有一个名为new()的内置方法。 用户必须调用该方法来例化对象。new()也称为构造函数。构造一个对象后会分配相应的存储空间用于保存对象的属性。通过覆盖内置版本的方法添加用户所需的任何程序代码,可以实现定义自己的构造函数。用户也可以通过自定义参数来传递给构造函数。需要注意的是, new()函数是没有返回类型的。新方法隐式地将句柄返回给类的对象( 图2中的Packet)。该变量存储在类myPkt中。现在myPkt引用了一块内存,其中包含了图1中定义的三个类的属性。 图2 调用new()创建一个实例并分配内存 SystemVerilog的句柄具有一些有趣的特性。 C/C++程序员倾向于将句柄视为指针,尽管他们确实是安全的指针 。安全指针意味着一个类的变量只能引用一个有效的对象或者在无引用时指向特殊值"null"。 句柄的值无法被操作,或者说是不可见的 。并且可以在句柄上执行的操作类型是受到限制的: <1>用户可以从另一个类变量或构造函数为类变量分配一个句柄;<2>用户可以将一个类变量和另一个类变量进行比较以检查它们是否指向同一对象;<3>用户可以将变量与特殊值"null"进行比较。SystemVerilog通过在例化对象时为其分配内存并在不使用时取消分配的方式,来管理对象的所有内存。这样做的好处是,类变量无法引用内存的“坏”区域。
类对象内的变量是类属性。属性的生命周期是起始于例化类对象的时刻。类属性具有动态的生命周期,即对象的寿命。类的属性可以是任何数据类型的变量,包括其他的类变量。使用类变量中的对象句柄可以访问类属性。用空变量引用属性会导致错误。实际上,引用空对象是用户编写代码时常见的几种错误之一。幸运的是,空对象引用的错误通常易于定位和修复。
一个类中的任务和函数称为该类的方法。用户引用它们的方式与引用属性的方式相同。任务和函数与Verilog语言中有着相同的含义。执行任务可能会占用一些时间。而函数的执行时间为0并且可以返回值。因此函数可以用作表达式的一部分。
我希望这门简短的课程可以使您下次阅读或听到“class”一词时有着更清晰的理解,并且使在您和同事也变得更加清晰!在接下来的有关继承、多态性以及OOP示例的文章中,我们将更深入地研究OOP和SystemVerilog的关键概念。
原文出处:https://www.edn.com/design/systems-design/4461326/A-short-course-on-SystemVerilog-classes-for-UVM-verification往期精彩:
30w+还送股送房?60+IC企业2019薪资全面攀升!
UVM RAL模型:用法和应用
我们准备做第二期线下培训,依旧认真且严肃
如果你突然被裁员了,你的Plan B是什么?
[彩虹糖带你入门UVM]
理解UVM-1.2到IEEE1800.2的变化,掌握这3点就够