0%

SV之类的封装与继承

本节主要介绍了SystemVerilog中类的封装与继承的基本内容、虚方法以及包的使用。

类的概述

  • 类的三要素:封装、继承、多态(虚方法)
  • 类是一种可以包含数据和方法的类型
  • OOP(Object-Oriented Programming)术语:
    • 类(class):包括成员变量和成员方法
    • 对象(object):类在例化后的实例
    • 句柄(handle):指向对象的指针,通过句柄可以索引对象的变量和方法
    • 原型(prototype):程序的声明部分,包含程序名、返回类型和参数列表

image-20230821173617016


类的封装

1.句柄的使用

  • 句柄指向一个对象时, SystemVerilog不会释放该对象的内存空间(对象的创建

  • 如果没有句柄指向个对象, Systemverilog将释放该对象的内存空间(对象的销毁

    1
    2
    3
    4
    5
    6
    Transaction t1, t2; //声明两个句柄
    t1 = new();//创建一个对象,并将t1指向该对象
    t2 = new();//创建一个对象,并将t2指向该对象
    t1 = t2; //将t2的值赋予t1,这时t1和t2指向同一对象,t1之前指向的对象被释放
    t1.display();//调用对象的成员方法
    t1.addr = 32'h42;//给对象成员赋值

2.静态变量和静态方法

  • 静态变量
    • class内部声明的变量默认为动态变量,其生命周期始于对象创建,终于对象销毁
    • 使用static声明class内部的变量时,其为静态变量。其生命周期始于编译阶段,贯穿于整个仿真阶段
    • 静态变量的引用:使用类名直接引用(Transaction::count)或者通过例化对象引用(tr.count)
  • 静态方法:静态方法内可以声明并使用动态变量,但不能使用类的动态成员变量

3.类的成员

  • 类中的成员默认是public,子类和外部均可访问

  • 但如果指明了类型为protected,那么只有该类或者子类可以访问

  • 如果访问类型为local,那么只有该类可以访问成员,子类和外部均不可访问

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class clock;
    local bit is_summer = 0;
    local bit nclock = 6;
    function int get_clock();
    ...
    endfunction
    endclass

    clock ck;
    initial begin
    ck = new();
    $display("now time is %0d",ck.get_clock);//成功访问
    ck.set_summer(1);
    $display("now time is %0d",ck.nclock); //报错,外部句柄不能访问local变量
    end

4.this

  • this是用来明确索引当前所在对象的成员

  • this只可以用来在类的非静态成员、约束和覆盖组中使用

  • this可以明确所指向变量的作用域

    1
    2
    3
    4
    5
    6
    class Demo;
    integer x;
    function new (integer x);
    this.x = x; //说明这时this.x代表成员变量integer x
    endfunction
    endclass

5.浅拷贝与深拷贝

  • 浅拷贝:new复制创建了一个新的对象,原对象的值被盲目的抄写到目的对象中,但如果类中包含了一个指向另一个类的句柄,那么只有最高一级的对象被new操作符复制,下层的对象不会被复制

    1
    b2 = new b1
  • 深拷贝:当使用深复制时,所有的变量都会被复制,包括下层的对象

    1
    b2.copy(b1);       //深复制,其中一个改变,不会影响另外一个

类的继承

  • 子类继承父类的所有数据成员和方法

  • 子类可以添加新的数据成员或者方法

  • 子类可以通过super操作符引用父类中的方法和成员

    1
    2
    3
    4
    5
    6
    class LinkedPacket extends Packet;
    LinkedPacket next;
    function LinkedPacked get_next();
    get_next = next;
    endfunction
    endclass
  • 通过extends,LinkedPacket继承于其父类Packet

  • 当子类成员与父类成员同名,必须使用super来指定访问其父类成员

  • 当父类的new没有参数时,子类也会自动先调用父类的new,当父类的new有参数时,需加上super.new(参数列表)使得子类先调用父类的new

  • 子类句柄赋值给父类之后,被赋值的父类句柄只能指向整个子类中属于父类的部分


虚方法

  • 通过在父类里定义虚方法(virtual task or function),可以在当父类句柄调用一个方法时候,前提是若是这个句柄指向了子类对象,则调用的方法为子类的方法而不是父类的方法

  • 使用系统函数$cast将父类句柄转化为子类句柄,,使其可以访问子类的变量


包的使用

  • 为了使得可以在多个模块(硬件)或者类(软件)之间共享用户定义的数据类型,SV添加了包
  • 通过package endpackage关键字来定义包
  • 可以通过package_name::var来索引包中的变量
  • 也可以通过import package_name::var在module中导入包中的变量
  • 或者通过import package_name::*,这代表当在module中找不到对应的变量时,就会在包中找

Reference

欢迎来到ssy的世界