【IC验证】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)进行声明;类中的成员(变量、方法、方法中的变量)可以转换为静态,当成员转换为静态时,可以在类声明前调用成员;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值