其他分享
首页 > 其他分享> > [Systemverilog学习笔记] class

[Systemverilog学习笔记] class

作者:互联网

[Systemverilog学习笔记] class

文章目录

一、Class 基础知识

class的定义是什么?

​ class是一种用户自定义的数据结构,一个OOP()的构造结构,可以封装对应数据并产生对数据的任务和方法;

​ 亦可以表述:包含变量和子程序的基本构造块;

class中有什么?

​ 封装的数据类型和操作数据类型的任务和函数。

存在以下常用名称:

​ 属性 (property) :一个类中的数据类型;

​ 方法 (Method):操作数据的任务和函数;

​ 构造函数 (constructor) : 类中定义的new()函数,在类创建时自动调用;

​ 句柄 (handle) : 指向对象的指针 ;

​ 对象 (Object) : 一个创建的某个类的实例,需要使用new()函数进行创建,否则值为null;

如何定义一个类,并且使用它?

class Myclass; //class name 
    bit [2:0]   header;  //property
    bit         encode;
    bit [2:0]   mode;
    bit [7:0]   data;
    bit         stop;

	// constructor
    function  new(bit [2:0] header = 3'h1, bit [2:0] mode = 5);
        this.header = header;
        this.encode = 0 ;
        this.mode   = mode ;
        this.stop   = 1 ;
    endfunction : new
    
	//Method
    function  display();
        $display("Header = 0x%0h,Encode = 0x%0b,Mode = 0x%0h,Stop = 0x%0b",
                  this.header,this.encode,this.mode,this.stop);
    endfunction : display
    
endclass : Myclass
                  
module tb_top ();
    Myclass pkt0,pkt1;

    initial begin
        pkt0 =new(); //use default parameter
        pkt0.display();

        pkt1 =new(3'h2,2h'h3);
        pkt1.display();
    end
endmodule                  
                  

​ 代码分析:

1、new函数–构造函数

​ 类中定义的new() 即自定义构造函数,当tb_top模块中例化一个对象的时候,会为该对象申请一个新的内存块来保存对象的变量,大小为类中所定义的属性大小之和,然后初始化变量,当使用系统new函数(class中未自定义new)时,会将变量设置为默认值;当使用自定义new函数时,可以初始化默认值成我们想要的数值;

​ new函数会返回一个指向类的对象的句柄,其类型就是类本身,所以不能有返回值;

​ Sytemverilog 会优先调用赋值操作符左边的句柄类型,如下所示

class Transcation;
    //...
endclass : Transcation

class Driver;
    Transcation tr;
    function  new();
        tr =new();  //会调用Transcation类中的new函数
    endfunction : new
    
endclass : Driver

​ new() 和new[]的区别:

​ new(pram1,…,pramn) : 仅创建一个对象;

​ new[pram]:创建了一个含有pram个类的类数组,如下所示

module tb_top ();
    Myclass pkt0[3];

    initial begin
        for (int i = 0; i < 3; i ++) begin
            pkt0[i] =new(); //use default parameter
            pkt0[i].display();  //通过class_name.method_name 调用对应方法      
        end
    end
endmodule

2、this 关键词和作用域

this

​ this: 时一个预定义的对象句柄,指的是调用所使用方法的对象;被用于指代类性质,参数和当前实例的方法。只能在非静态方法、约束和覆盖组中使用

class Packet;
    bit [31:0] addr;

    function  new(bit [31:0] addr);
  		//类变量名addr = 局部变量addr
        this.addr = addr; //将方法中参数的值赋值给本地对象

    endfunction : new
    
endclass : Packet

​ 当存在歧义时,需要使用this关键词来指定对方法中类成员的访问

作用域

​ 作用域是一个代码块,例如一个module、process、class、task、function 、begin-end块。

foreach和for循环会自动创建一个块,其下标变量可以作为该循环作用域的局部变量来声明和创建;

​ 当使用一个变量名时,Systemverilog首先会在当前作用域内寻找,接着在上一级作用域内寻找,直到找到改变量

3、Super 关键词

​ 是什么? :在"子类"中使用Super关键词来引用“基类”的属性和方法;如果“父类”中的属性和方法被子类重写,则必须要使用super关键词来对其进行访问;

​ Super只能使用在派生自父类的子类中

​ 父类 (parent class) :也称作为基类

在这里插入图片描述

如上图中所示,父类就是Class B_C,子类从父类Class B_C中进行拓展生成,使用如下格式

class Myclass;
    bit [2:0]   header;
    bit         encode;
    bit [2:0]   mode;
    bit [7:0]   data;
    bit         stop;

    function  new(bit [2:0] header = 3'h1, bit [2:0] mode = 5);
        this.header = header;
        this.encode = 0 ;
        this.mode   = mode ;
        this.stop   = 1 ;
    endfunction : new
    
    function  display();
        $display("Header = 0x%0h,Encode = 0x%0b,Mode = 0x%0h,Stop = 0x%0b",
                  this.header,this.encode,this.mode,this.stop);
    endfunction : display
    
endclass : Myclass


class extclass extends Myclass;
    function  display();
        super.display();
        $display("[child]Header = 0x%0h,Encode = 0x%0b,Mode = 0x%0h,Stop = 0x%0b",
                  header,encode,mode,stop);
    endfunction : display
    
endclass : extclass


module tb ();
    Myclass p;
    extclass extp;

    initial begin
        ep = new();
        p =new();
        extp.display();
    end
    
endmodule

4、静态变量和全局变量

静态变量

静态变量: 在类中创建的静态变量将被这个类的所偶有实例所共享,并且它的使用范围仅限于这个类。即不管创建了多少个对象,这个类中的静态对象只存在一个,可以理解为静态变量保存在类中而非对象;

​ 静态变量通常在声明时进行初始化,并且可能需要另一个静态变量来作为标志,标识原始变量已被初始化

​ 一般使用方法如下所示

static variable_type name;

class Transcation;
    static  int count = 0;  、
    int id = 0;
    function  new();
        id = count++;
    endfunction : new
    
endclass : Transcation


Transcation t1,t2;

initial begin
    t1 = new();
    t2 = new();
    $display("second id = %0d,count =%0d",t2.id,t2.count); 
  
    //可以通过使用类名+ "::"操作符号来引用静态句柄 
    $display("%d Transcation were created",Transcation::count); //引用静态句柄
end


静态方法

​ 静态方法:与静态变量一样,我们也可以使用 static 修饰方法,称为静态方法或类方法

​ 静态方法遵循所有类的作用域和访问规则,但唯一的区别时它调用它时,它可以没有对应的实例,静态方法中可以直接调用同类中的静态成员,但不能直接调用非静态成员。静态方法也不能加virtual 关键词。同时在调用静态函数时,需要通过作用域运算符来进行::

​ 静态初始化块只在类加载时执行,且只会执行一次,同时静态初始化块只能给静态变量赋值,不能初始化普通的成员变量

class Transcation;
    static  int count = 0;  //静态变量
    int id = 0;
    function  new();
        id = count++;
    endfunction : new

    static function  display_static();
        $display("Transaction count = %0d",count);
    endfunction : display_static

    static function  display_static_err();  //在静态函数中调用非静态成员会导致编译错误
        $display("Transaction count = %0d",id);
    endfunction : display_static_err
    
    
endclass : Transcation


Transcation t1,t2;

initial begin
    t1 = new();
    t2 = new();
    $display("second id = %0d,count =%0d",t2.id,t2.count); 
  
    //可以通过使用类名+ "::"操作符号来引用静态句柄 
    $display("%d Transcation were created",Transcation::count); //引用静态句柄
    Transcation::display_static(); //引用静态函数
end

编译顺序-typedef

​ 当编译类时,这个类中包含一个尚未定义的类。声明这个被包含的类的句柄会引起错误,编译器会在此类的后面去找这个尚未定义类的定义,此时需要使用typedef 语句对类名进行声明

typedef class call_class;

class Transaction;
	call_class name;
	...;
endclass
    
class call_class;
	...;
endclass

​ typedef也可以和参数化对象一起使用

typedef XYZ;

module top;
	XYZ #(8'h3f,real)	xyz0;
    XYZ #(.ADDR(8'h(60),.T(real))	xyz1;
                
class XYZ #(parameter ADDR = 8'h00, type T = int);
endclass

4、Inheritance -继承

​ 继承是类中的一个概念,可以通过拓展来得到另外一个类,并且可以通过句柄获取基类中的所有方法和属性,可以让我们在不改变基类的情况下在新的类中添加新的属性和方法;

​ 如上代码所示,使用如下格式声明新类对基类进行继承

class extclass extends base_class_name;
	...
endclass : extclass

5、polymorphism - 多态

​ 是什么 : 多态指调用相同的名字和方法,得到的结果是不同的

virtual

​ 父类中的方法可以声明为virtual,在子类中可以声明相同名称不同功能的函数,将父类中的函数覆盖掉,但此种使用方法下两个类的返回值类型和参数的原型应保持不变

虚方法可参考如下文章

https://blog.csdn.net/liujingyu_1205/article/details/81563010
https://blog.csdn.net/immeatea_aun/article/details/89216857

6、类的参数化

​ 参数化类可以在实例化时实现不同的数组大小和数据类型;

​ 同时也可将数据类型作为参数进行传递,

class stack#(type T = int);
    T item;

    function T add_a(T a);
        return item + a;
    endfunction : add_a

    //表示此函数在外部实现
    extern function T add_b(T b);

endclass : stack

function T add_b(T b);
    return item - b;
endfunction : add_b


module tb;
    stack                   st;
    stack #(bit[3:0])       bs;
    stack #(real)           rs;
    stack #(float)          fs;

    initial begin
        st =new();
        bs =new();
        rs =new();


        st.item = -456;
        $display("st.item = %0d",st.add(10));

        bs.item = 8'hA1;
        $display("st.item = %0d",st.add(10));

        rs.item = 3.14;
        $display("st.item = %0.2f",st.add(10));

        fs.item = 12.34;
        $display("fs.item = %0.2f",st.add(10));
    end
    

endmodule

7、extern和local

extern

语法

class <name_of_class> #(<parameters>)
class Trans #(addr = 32);

<name_of_class> #(<parameters>) <name_of_inst>;
Trans #(.addr(16)) obj;

local

被声明为local的成员仅可用于同一类的方法中,同时不能被子类访问。但是访问local成员的非本地方法可以被子类继承和覆盖

标签:静态,笔记,display,new,bit,Transcation,class,Systemverilog
来源: https://blog.csdn.net/qq_36917568/article/details/122276408