• systemverilog学习 ---- 类(完结)


    抽象类

    在systemverilog中,可以使用关键字virtual来声明一个类,说明这个类是抽象类。

    • 抽象类为子类设置prototype
    • 抽象类不可以被实例化,只可以被继承
    • 在抽象类中,可以只包含方法的原型,可以没有实现,就是一个方法的声明。
      在这里插入图片描述
      抽象类的声明如下:
    virtual class abc;
    	//Class defination
    endclass
    
    • 1
    • 2
    • 3

    接下来展示一个抽象类的例子:

    //abstract class
    virtual class packet;
        bit [31:0]  addr;
    endclass
    
    module virtual_address;
        initial begin
            packet p;
            p = new();
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在上面这个例子中,创建了一个虚拟类的对象,但是一个虚拟类只可以被继承,不可以被实例化,因此编译器会报错。
    在这里插入图片描述
    因此需要对虚拟类进行继承才可以。

    //abstract class
    virtual class packet;
        bit [31:0]  addr;
    endclass
    
    class extended_packet extends packet;
        function void display;
            $display("Value of addr is %0d", addr);
        endfunction
    endclass
    
    module virtual_address;
        initial begin
            extended_packet p;
            p = new();
            p.addr = 10;
            p.display();
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    其输出结果是:
    在这里插入图片描述

    抽象方法(abstract method)

    在systemverilog中方法也可以被抽象,可以在方法的前面加上virtual的关键字,,因为方法分为任务和函数两类,因此抽象方法也分为两类:

    • Virtual Functions
    • VIrtual Tasks

    在虚拟化的方法中,如果基类的句柄指向子类。那么子类的方法句柄将会被赋值给基类句柄。如下所示:

    base_class b_c;
    extended_class e_c;
    
    • 1
    • 2

    假设这两个类都有display的方法,此时我们把b_c = e_c。
    那么当我们访问b_c.display()

    • 若在基类中display的方法是抽象的,那么将会访问子类中的display方法
    • 若在基类中的display方法不是抽象的,那么将会访问基类中的方法。

    虚方法体现在当我们把子类句柄赋值给父类句柄时,通过给父类句柄就可以访问子类中重名的方法。
    虚拟函数和虚拟任务的声明形式如下:

    //vitural function
    virtual function function_name;
    	//function definition
    endfunction
    
    //virtual task
    virtual task task_namel
    	// task definition
    endtask
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    下面举一个例子:

    class base_class;
        function void display;
            $display("Inside base_class");
        endfunction
    endclass
    
    class extended_class extends base_class;
    
        function void display();
            $display("Inside extended class");
        endfunction
    endclass
    
    module virtual_address;
        initial begin
            base_class b_c;
            extended_class e_c;
    
            e_c = new();
            b_c = e_c;
    
            b_c.display();
        end
    
    endmodule
    
    • 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

    在上面这个例子中,我们发现在基类中的dispaly方法并没有用virtual关键字修饰,因此尽管父类对象已经指向了子类,但是调用的让然是父类的方法。
    在这里插入图片描述
    但是若是如下代码:

    在这里插入图片描述
    其输出结果是:
    在这里插入图片描述

    (域解析操作符)scope resolution Operator ::

    程序设计中,不可避免出现重名方法,sv也可以通过域控制不同版本的重名方法。域解析操作符由两个冒号组成,即::
    我们通过类域解析操作符,可以在类外访问静态成员,也可以在子类中访问父类的公有public成员和保护protected成员。

    //class
    class packet;
        bit [31:0]  addr;
        static bit [31:0]   id;
    
        function display(bit[31:0] a, b);
            $display("Values are %0d %0d", a, b);
        endfunction
    endclass
    
    //module
    module sro_class;
        int id = 10;
        initial begin
            packet p;
            packet::id = 20;
            p.display(packet::id, id);
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在上面的例子中,一个类中的静态成员被使用::来进行访问。
    其输出结果是:
    在这里插入图片描述

    class external methods

    如果一个方法的定义卸载类的外面,那么这个方法就做external method。但是,类内部还是要留个位置,即需要声明该方法,和c++类似,我们要在类内给出该方法的修饰(local/protected/virtual)以及完整的参数列表。在类外实现方法时,我们还要加上域操作符,说明这是哪个类的方法。

    //class with extern function
    
    class packet;
    
        bit [31:0]  addr;
        bit [31:0]  data;
    
        //function declaration - extern indicates out of body declaration
        extern virtual function void display();
    
    endclass
    
    //function implementation outside class body
    function void packet::display();
        $display("Addr = %0d Data = %0d", addr, data);
    endfunction
    
    module extern_method;
        initial begin
            packet p;
            p = new();
            p.addr = 10;
            p.data = 20;
            p.display();
        end
    endmodule
    
    • 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

    其模拟输出结果是:
    在这里插入图片描述
    此外类中和类外的函数声明应该时一样的。否则编译器会报错。
    在这里插入图片描述
    即:

    Error-[ECMDSMPD] Mismatched method definition
    testbench.sv, 11
    External class method definition should match prototype declaration.
    Argument names do not match. The signature of function 'packet::display'
    should match the corresponding prototype declaration at: "testbench.sv", 7.
    
    • 1
    • 2
    • 3
    • 4
    • 5

    typedef class

    typedef被用来为一个类提供前向声明。在一些情况下,这个类需要在类声明前被实例化。其声明形式如下:

    typedef class class_name;
    
    • 1

    如下面一个例子:

    //class - 1
    class c1;
        //using class c2 handle before declaring it
        c2 c;
    endclass
    
    //class - 2
    class c2;
        c1 c;
    endclass
    
    module typedef_class;
        initial begin
            c1 class1;
            c2 class2;
            $display("Inside typedef_class");
        end
    endmodule
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在上面这个例子中,c2 在c1中被实例化,c1在c2中被实例化。因此会导致编译器错误:
    在这里插入图片描述
    可以发现,类c1和c2,成员变量有对方的示例,不可避免出现未声明就实例化。解决办法使用typedef,通过typedeg我们可以声明一个实例化可以在声明前的类。
    在这里插入图片描述
    其仿真结果是:
    在这里插入图片描述

  • 相关阅读:
    ASEMI代理力特二极管LSIC2SD120A05,肖特基LSIC2SD120A05
    Go语言类库-context
    Linux升级gcc到最新版本gcc-11.2.0
    MinIO对象生命周期管理解析
    【Java】Java生成PDF工具类
    Reflection - 浅谈Python反射
    如何画产品架构图?
    如何干涉MySQL优化器使用hash join
    c# lock作用及缺点
    uniapp使用H5实现预览pdf文件
  • 原文地址:https://blog.csdn.net/weixin_45614076/article/details/126297476