【转载】SystemVerilog中有关class类的基础知识

202 阅读3分钟

 

1

class中的变量、宏定义等称为类的属性,函数和任务称为类的方法

2

声明对象时可以指定input/output/inout/ref

3

复制对象,复制的是句柄而不是对象的内容。 
类的每个对象,对于属性、方法等都有自己的副本

4

?

123456<code>``class c;``...``endclass c c0;``</code>

//“c”就是对象c0的句柄,在此处仅相当于一个name,类似于仅是创建了一个c类型的变量c0,而这个变量保存类c对象  的句柄,但其初始化值为NULL  此时,这个对象时不存在,也不包含任何实际的句柄,知道进行初始化:c0 = new()  此时,对象c0的句柄尚未被初始化,因此,为默认值;Null。因此,检测一个对象是否被初始化,与值Null进行比对即可:  值为Null的句柄不可以访问非静态成员和虚方法

?

1``2``3``4``5``6``7``8<code>class obj_example;``...``endclass`` ``task task1(integer a, obj_example myexample);`` if (myexample == null) myexample = new; //初始化``endtask``</code>

4_1

类对象支持的算术/逻辑运算:  —支持的操作—–操作对象—-含义  == 对象/Null  != 同上  === 同上  !== 同上  条件操作  类型兼容的对象间互相赋值  赋值Null

5

初始化函数new(),非阻塞,没有返回值类型(但初始化过程中,但暗含的返回值类型就是赋值等号左侧变量的类型)  new()函数,可不人为定义,在对象初始化时会调用默认的new函数,也可以人为定义new函数,以便规定初始化操作。  6、基类、扩展类new()函数的执行:  先调用基类的new函数——super.new(),

eg:

?

1``2``3``4``5``6``7``8``9``10``11``12``13``14``15``16``17``18``19``20``21``22``23``24<code>class C;`` int c1 = 1;`` int c2 = 1;`` int c3 = 1;`` `` function new(int a);``  c2 = 2;``  c3 = a;`` endfunction``endclass`` `` ``class D extends C;`` int d1 = 4;`` int d2 = c2;`` int d3 = 6;`` function new;``  super.new(d3);`` endfunction``endclass`` ``D obj_d;``obj_d = new(d3);``</code>

解释:  会先执行基类C的初始化new函数(即类C的属性、方法的初始和定义等),c1 = 1,c2 = 2;  c3,基类C中new函数的输入参数a此时为d3,但此时d3尚未定义,所以,c3为未定义值;  基类的各种初始完成后开始进行扩展类的初始操作,即执行扩展类的new函数,d1 = 4,d2 = 2(基类中的变量c2,基类此时已初始化完成,所以c2为确定的值),d3 = 6,

7

类声明中的静态属性,只创建、初始化一次,之后则可以为所有的对象访问,并且,可以以无创建对象的方式被访问

?

1``2``3``4<code>class Packet ;`` static integer fileID = $fopen( "data", "r" );``endclass``</code>

8

类声明中的静态方法,类的全范围内可以调用,也可以无创建对象的方式被访问,不可以访问非静态的成员(属性和其他方法);  不能声明为virtual,声明中不能使用this句柄;

?

1``2``3``4``5``6``7``8``9<code>static task t();`` ...``endtask//正确格式,说明了类中方法的lifetime(理解为:存活时间)`` `` ``task static t();`` ...``endtask//错误格式,说明的是方法的参数及方法声明中的各个变量的lifetime``</code>

9

this指针,涉及类的属性、变量参数、对象本地的变量参数或方法,应用在非静态方法中

10

类对象的复制:  (1)  class c;  …  endclass

?

1``2``3``4<code>c c0, c1;``c0 = new();``c1 = c0;``</code>

解释:new只执行一次,只涉及到一个句柄,所以说,只有一个对象,只是对于对象的句柄而言有两个名字,分别为:c0和c1

(2)

?

1``2``3``4``5``6``7``8<code>class c;`` ...``endclass`` ``c c0, c1;``c0 = new();``c1 = new c0;``</code>

解释:new函数执行两次,创建了两个对象:c0和c1,c1是复制的c0,但只是复制了c0的句柄,也可以认为是一个对象有两个名字  注:这种方式的复制,对于嵌入式的约束,在新的对象中为Null

(3)

?

1``2``3``4``5``6``7``8``9<code>class c;`` ...``endclass`` ``c c0, c1;``c0 = new();``c1 = new();``c1.copy(c0);``</code>

解释:c0中的任何内容全部复制给了c1,更常用。

11

扩展类对象的句柄可赋值给基类变量

?

1``2``3``4``5``6``7``8``9``10``11<code>class c;`` class cc extends c;``  ......`` endclass``endclass`` ``c c0;``cc cc0;``cc0 = new();``c0 = cc0;``</code>

注:扩展类中的属性或方法被重写覆盖时,通过以上方法,可以获得基类中各成员的原始值/内容  且当基类中为纯虚方法、扩展类中方法的定义也必然是虚方法,这种情况下,基类变量可以直接访问扩展类的方法

?

1``2``3``4``5``6``7``8``9``10``11``12``13<code>class c;`` class cc extends c;``  int i = 1;``  int i = 2;`` endclass``endclass`` ``c c0;``cc cc0;``cc0 = new();``c0 = cc0;``j = c0.i; //j = 1,而不是等于2,所以说,扩展类中变量i进行何种操作,基类都会保留变量i的原始值``</code>

注:扩展类声明变量(cc cc0;)可以赋值给基类声明变量(c c0;)或更高层次类的声明,反过来则是错误的,除非基类中调用了扩展类

12

super 访问当前类的上一层次的类的成员

?

1``2``3``4<code>super.new //先于当前类的new执行,可以用户手动添加,或者编译器会自动添加执行super.new的阶段``function new(); //扩展类中new函数``super.new(5);//启动当前类基类的new函数,并且是带有参数的,会传递给基类的初始化函数``</code>

13

类中数据的封装与保护:定义成员关键字含义local和protected

?

1``2``3<code>local//只有当前类中方法可以访问,不同对象间可以互相访问,但扩展类中方法不能访问``protected  //同local定义基本相同,唯一差别在于可以被继承、扩展类可以访问``</code>

14

类中属性/成员:const、local、protected、static  类中方法:virtual  const:定义只读变量,分为global const和instace const,

区别在于:前者声明时进行赋值,同static,所有的对象均可访问,且内容一样;后者只是声明,实例化时才会赋值

?

1``2``3<code>const int max_size = 9 * 1024; // global constant,也可以声明为static``const int size; // instance constant``</code>

15

抽象类:可以看作是模板或原型

?

1``2``3``4<code>virtual class BasePacket;`` ...``endclass``</code>

无法直接创建抽象类的对象.

纯虚方法:定义在抽象类中的虚方法,具体的实现则是在扩展类(非抽象类)中定义完成的

?

1``2``3``4``5``6``7``8``9``10``11<code>virtual class BasePacket;`` pure virtual function integer send(bit[31:0] data); // No implementation``endclass`` ``class EtherPacket extends BasePacket;`` virtual function integer send(bit[31:0] data);``  // body of the function``  ...`` endfunction``endclass``</code>

当基类中为纯虚方法、扩展类中方法的定义也必然是虚方法,这种情况下,基类变量可以直接访问扩展类的方法

?

1``2``3``4``5``6``7``8``9``10<code>BasePacket packets[100];``EtherPacket ep = new; // extends BasePacket``TokenPacket tp = new; // extends BasePacket``GPSSPacket gp = new;  // extends EtherPacket`` ``packets[0] = ep;``packets[1] = tp;``packets[2] = gp;``packets[1].send();//invoke the send method associated with the TokenPacket class``</code>

16

类的嵌套:嵌套的类可以访问被嵌套类的local、protected、static等成员,有完全访问权

?

1``2``3``4``5``6``7``8``9``10``11``12``13``14``15``16``17``18<code>class Outer;`` int outerProp;`` local int outerLocalProp;`` static int outerStaticProp;`` static local int outerLocalStaticProp;`` `` class Inner;//类Inner为嵌套类``  function void innerMethod(Outer h); //类Outer声明``outerStaticProp = 0;// Legal, same as Outer::outerStaticProp``outerLocalStaticProp = 0; // Legal, nested classes may access local's in outer class``outerProp = 0;// Illegal, unqualified access to non-static outer``h.outerProp = 0; // Legal, qualified access.``h.outerLocalProp = 0;  // Legal, qualified access and locals to outer class allowed.``  endfunction`` endclass`` ``endclass``</code>

17

外部定义:在类内带extern关键字进行声明,类外定义时,需指明类作用域,用”::”符号  例子1:

?

1``2``3``4``5``6``7``8``9``10``11``12``13``14``15``16<code>class Packet;`` Packet next;`` `` function Packet get_next();// single line``  get_next = next;`` endfunction`` // out-of-body (extern) declaration`` extern protected virtual function int send(int value);``endclass`` ``function int Packet::send(int value);`` // dropped protected virtual, added Packet::`` // body of method`` ...``endfunction``</code>

例子2:

?

1``2``3``4``5``6``7``8``9``10``11``12``13``14``15<code>typedef real T;``class C;`` typedef int T;`` extern function T f();`` extern function real f2();``endclass`` ``function C::T C::f(); // the return must use the scope resolution,以区分"typedef real T"和"typedef int T"`` return 1;``endfunction`` ``function real C::f2();`` return 1.0;``endfunction``</code>

例子3:

?

1``2``3``4``5``6``7``8``9<code>typedef int T;``class C;`` extern function void f(T x);//原型中,T采用的是"typedef int T"`` typedef real T;``endclass`` ``function void C::f(T x);//error,在此处采用的是类中声明的"typedef real T"``endfunction``</code>

注:最好是用作用域符号”::”

18

参数化类:类似于C++中的模板

例子1:

?

1``2``3``4``5``6``7``8<code>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``</code>

例子2:

?

1``2``3``4``5``6``7``8``9``10<code>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 int’s``stack#(bit[1:10]) bs; // a stack of 10-bit vector``stack#(real) rs; // a stack of real numbers``</code>

例子3

?

1``2``3``4``5``6<code>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``</code>

18_2

还是讲参数化的类:  以两个例子说明参数化的类及声明静态变量时的情况:

eg:

?

1``2``3``4``5``6``7``8``9``10``11``12``13``14``15``16``17``18``19``20``21``22``23``24``25``26``27``28``29``30``31``32``33``34``35``36``37<code>program param_stack;`` class stack #(type T = int);``  int m_cnt;``  static int counter = 2;`` ``  function new;``m_cnt = counter++;``  endfunction: new`` `` endclass: stack`` `` class stacked extends stack #(real);``...`` endclass: stacked`` `` `` typedef stack #(byte) stack_byte;`` typedef stack #() stact_int;`` `` `` stack_byte S1 = new();`` stack_byte S2 = new();`` stack S3 = new();`` stack #(bit) S4 = new();`` stacked S5 = new();`` `` `` initial begin``  $display ("Counter value of S1 instance = %0d", stack #(byte)::counter);``  $display ("Counter value of S2 instance = %0d", stack_byte:: counter);``  $display ("Counter value of S3 instance = %0d", stack #()::counter);``  $display ("Counter value of S4 instance = %0d", stack#(bit)::counter);``  $display ("Counter value of S5 instance = %0d", stacked::counter);`` end`` ``endprogram: param_stack``</code>

打印的值依次为:

?

1``2``3``4``5``6<code>3``4``3``3``3``</code>

解释:虽然静态变量只会存在一个副本。

由于S1和S2均由stack_byte创建,所以S1时counter的值为3,S2为4;  S3则是由默认参数类创建,等同于程序中的stack_int,counter值为3;  S4则是type为bit的类创建,counter同样为3;  S5亦然。

即当参数类的参数不同时,他们是不同的类。