systemverilog_静态与动态
一.序言
systemverilog中,静态与动态分为两大类问题进行讨论,分别为变量和方法。
准备知识:
静态关键字是static,动态关键字是automatic;
二.定义及特点
1.静态变量与动态变量
静态变量:创建于编译阶段,存在于整个仿真过程,同一变量在不同实例间共享;
动态变量:创建于调用时刻,调用结束对象销毁,同一变量在不同实例中分别存在;
2.静态方法与动态方法
静态方法:创建于编译阶段,存在于整个仿真过程,不同实例共享存储空间;
动态方法:创建与调用时刻,调用结束被销毁,不同实例各自分配存储空间;
3.注意点及特殊用法
(1)模块(module)中的成员(变量、方法、方法中的变量、声明的类)默认是静态的;
(2)类(class)中的成员(变量、方法、方法中的变量、声明的类)默认是动态的;
(3)静态变量只会在编译时刻初始化一次,动态变量在每次实例化都会初始化一次;
(4)静态方法中的成员(变量和方法)只能是静态的,动态方法中的成员既可以是静态的又可以是动态的;
(5)模块中的方法可以转换为动态,只需在定义方法时,在方法类型关键字(function/task)后用动态关键字(automatic)进行声明;
(6)类中的成员(变量、方法、方法中的变量)可以转换为静态,当方法转换为静态时,可以在类声明前调用方法;
(7)模块中声明的类是静态的,所以编译后声明类的句柄就存在,只是此时的句柄为空(null),不指向任何对象;类的实例化(new)操作,是在仿真后才会执行(可以理解为动态),句柄才会指向具体的对象;
三.例子
(1)例1:模块中的方法内的成员变量(静态)
代码:
module Mymodule1;
task Mytask1(output int b);
static int a = 0;
a = a +1;
b = a;
endtask
endmodule
module tb1;
Mymodule1 m1();
initial begin
static int dout = 0;
m1.Mytask1(dout);
$display("data1 out = %0d",dout);
m1.Mytask1(dout);
$display("data2 out = %0d",dout);
end
endmodule
结果:
说明:
模块中的方法是静态的,静态方法中的成员变量只能时静态的,所以方法只会初始化一次,所以方法每次调用值的改变都会在上次的调用基础上进行;
注意点:
(a)tb1的initial过程块中的dout变量,默认是静态的,前面的static关键字可以省去
但是省去后编译时可能会警告,所以这里用static修饰更严谨一点;
(b)模块只能在过程块外进行声明,每个声明对象对应单独电路,单独分配存储空间(这与前面的静态知识点有点不同)
;
(2)例2:类中的成员(动态)
例子:
class Myclass1;
int a = 0;
task Mytask2;
a = a +1;
endtask
endclass
module tb2;
initial begin
Myclass1 c1;
c1 = new();
c1.Mytask2();
$display("data1 out = %0d",c1.a);
c1.Mytask2();
$display("data2 out = %0d",c1.a);
c1 = new();
c1.Mytask2();
$display("data3 out = %0d",c1.a);
end
endmodule
结果:
说明:
类中的成员创建于实例化时刻,所以在第一次实例化后,调用多次方法对其进行操作,操作的是同一对象。在第二次进行实例化后,会对其重新分配存储空间,原来的值被释放掉。
(3)例3:类中方法内的成员(动态)
代码:
class Myclass2;
task Mytask3(output int b);
int a = 0;
a = a+1;
b = a;
endtask
endclass
module tb3;
initial begin
static int b = 0;
Myclass2 c2 = new();
c2.Mytask3(b);
$display("data1 out = %0d",b);
c2.Mytask3(b);
$display("data2 out = %0d",b);
end
endmodule
结果:
说明:
类中的方法,创建于调用时刻,调用结束即释放,所以每次调用就会分配新的存储空间;
(4)例4:模块中的方法可以转化为动态
语法:
task/function后加automatic;
代码:
module Mymodule4;
task automatic Mytask4;
int a = 0;
a = a+1;
$display("data1 out = %0d",a);
endtask
endmodule
module tb4;
Mymodule4 m4();
initial begin
for(int i = 0 ;i <4;i++)begin
fork
m4.Mytask4();
join_none
end
end
endmodule
结果:
对比代码:
task Mytask4;
static int a = 0;
a = a+1;
$display("data1 out = %0d",a);
endtask
endmodule
module tb4;
Mymodule4 m4();
initial begin
for(int i = 0 ;i <4;i++)begin
fork
m4.Mytask4();
join_none
end
end
endmodule
对比结果:
(5)例5:类中的变量可以转换为静态
语法:
成员开始加static;
//成员调用(在实例化/声明之前):
方法名::成员
//成员调用(在实例化/声明之前):
句柄名.成员
代码1:
class Myclass5;
int a = 0;
static int b = 0;
task Mytask5;
a = a + 1;
b = b + 1;
$display("a = %0d,b = %0d",a,b);
endtask
endclass
module tb5;
initial begin
Myclass5 c5;
c5 = new();
c5.Mytask5();
c5 = new();
c5.Mytask5();
end
endmodule
结果1
代码2:
class Myclass8;
static int data1 = 5;
endclass
module tb8;
Myclass8 c1;
initial begin
$display("data1 is %0d",Myclass8::data1);
$display("data1 = %0d",c1.data1);
end
endmodule
结果:
(6)例6:类中的方法可以转换为静态
语法:
在方法前用static关键字修饰;
方法调用:类名::方法名();
代码:
class Myclass6;
static int staticvar = 0;
int dynamicvar = 0;
static function void static_method();
$display("static var: %0d",staticvar);
//error
// $display("Dynamic var: %0d",dynamicvar);
endfunction
function void dynamic_method();
$display("static var: %0d",staticvar);
$display("dynamic var: %0d",dynamicvar);
endfunction
endclass
module tb6;
initial begin
Myclass6 mc;
Myclass6::static_method();
mc = new();
mc.dynamic_method();
end
endmodule
结果:
结果说明:
静态方法static_method内部只能调用静态成员,而动态方法dynamic_method内部既可以调用静态成员又可以调用动态成员;
静态方法static_method可以在类声明/实例化前就可以调用,tb6中mc的声明是因为后续动态方法的调用需要声明和实例化类,而类的声名必须方法过程块开始;
(7)例7:类中方法中的变量可以转换为静态
语法:
在方法中需要转化为静态的变量前用static关键字修饰;
代码:
class Myclass7;
task Mytask7;
static int a = 0;
a = a + 1 ;
$display("a = %0d",a);
endtask
endclass
module tb7;
initial begin
Myclass7 c7 = new();
c7.Mytask7();
c7.Mytask7();
end
endmodule
结果:
(8)例8:模块中的类的创建与实例化
代码:
class Myclass3;
int data = 0;
endclass
module tb3;
int a = 1;
Myclass3 c1 = new();
initial begin
int b = 1;
Myclass3 c2 = new();
end
endmodule
编译后:静态变量和类均存在,只不过类的句柄均为空(null);
仿真0us(一个很小的时刻):句柄指向的对象创建了,表示new函数执行了;
四.总结
(1)模块中所有的成员(变量、方法、方法中的变量、声明的类)都是静态的,类中所有的成员(变量、方法、方法中的变量、声明的类)都是动态的,类的实例化一定是动态的。
(2)静态成员创建于编译时刻,初始化一次,存在于整个仿真过程;动态成员创建于实例化时刻,每次实例化都会初始化,调用结束即被释放。
(3)静态方法中的成员只能是静态的,动态方法中的成员既可以是静态也可以是动态;
(4)模块中的方法可以转换为动态,只需在定义方法时,在方法类型关键字(function/task)后用动态关键字(automatic)进行声明;类中的成员(变量、方法、方法中的变量)可以转换为静态,当成员转换为静态时,可以在类声明前调用成员;