SystemVerilog中的静态属性

一般来说,每个类实例都有它自己的变量,也就是说类的内存空间是动态分配和释放的。同一个类的不同实例,即使变量名称相同,实际上也是不同的东西。

有时候,我们希望一些变量在一个类的所有实例中共享,那么在声明这个变量时就需要使用关键字static。

可以理解为静态属性隶属于这个类,而不是某个类的实例,这个静态属性的内存空间在编译时就已经完成了分配,而不需要等待类的实例化。

静态属性内存空间的分配在仿真时间0之前就已经完成了。

下面是一个在不同类实例之间共享的静态属性示例

module class_TOP( );

class base;

static logic [31:0] data; //static property

endclass : base

base base1, base2;

initial begin;

base1 = new( );

base2 = new( );

base1.data = 32’h f00_f0f0;

$display(“base2.data = %h”,base2.data);

end

initial #10 $fnish(2);

endmodule

在这个例子中,我们将“data”声明为静态属性。然后,实例化为” base1 “和” base2 “。然后我们赋值“base1”实例中的“data”的值,并从“base2”实例访问。

仿真Log:

base2.data = ff00f0f0

$fnish at simulation time 10

V C S S i m u l a t i o n R e p o r t

从仿真log中可以看出,使用对象句柄“base1”赋值的属性,可以通过句柄“base2”访问到。这是因为“data”被声明为static,被所有实例共享。

如果把“static”去掉会发生什么?最终句柄“base2”访问的“data”值就是“XXXXXXXX”

下面是类中静态属性的最经典用法,统计这个类实例化了多少次?

module class_TOP( );

class packet;

static int packet_cnt;

function new( );

packet_cnt = packet_cnt+1;

$display(“From new ( ) :: packet_cnt =

%0d”,packet_cnt);

endfunction

endclass

initial begin

packet p1 = new;

packet p2 = new;

end

endmodule

仿真log:

From new ( ) :: packet_cnt = 1

From new ( ) :: packet_cnt = 2

V C S S i m u l a t i o n R e p o r t

在第二次实例化时,packet_cnt会在第一次实例化的基础上加1.

下面是展示静态属性和动态属性区别的一个例子:

class PCIe;

static int addr = 0; //Static property

int data = 0; //Dynamic property

function new ();

addr++;

data++;

$display (“addr=%0d data=%0d”, addr, data);

endfunction

endclass

module tb;

initial begin

PCIe p1, p2, p3;

p1 = new ();

p2 = new ();

p3 = new ();

end

endmodule

仿真log:

addr=1 data=1

addr=2 data=1

addr=3 data=1

V C S S i m u l a t i o n R e p o r t

我们可以看到addr被声明为static,而data默认是automatic。所以每一次实例化时,addr都会在前一个实例化的基础上加1,而data则每次都是1(因为每个实例化都有自己的data内存分配)

下面再看一个相对绕一点的例子:

module class_TOP( );

class packet;

static int packet_cnt; //Static property

int tag; //Dynamic property

function new( );

packet_cnt = packet_cnt+1;

tag = packet_cnt;

endfunction

function void disp( );

$display(“packet_cnt = %0d tag = %0d”,packet_cnt, tag);

endfunction

endclass

initial begin

packet p1 = new;

packet p2 = new;

p1.disp;

p2.disp;

end

endmodule

仿真log:

packet_cnt = 2 tag = 1

packet_cnt = 2 tag = 2

我们在packet实例化两次(p1和p2)之后分别执行p1和p2的disp函数。

此时packet_cnt已经被加到2,所以最后打印的packet_cnt均为2,因为tag是automatic的,所以p1的tag为1,不被p2影响。

审核编辑:汤梓红

发表评论