类封装了数据和操作这些数据的子程序。
在SystemVerilog中,可以把类定义在program、module、package中,或者在这些块之外的任何地方。类可以在程序和模块中使用。
类(Class):包含变量和子程序的基本构件块。
对象(Object):类的一个实例。
句柄(Handle):指向对象的指针。
属性(Property)
方法(Method)
原型(Prototype):程序的头,包括程序名、返回类型和参数列表。程序体包含了执行代码。
Transaction tr; //声明一个句柄。在声明一个句柄时,它被初始化为特殊值null
Tr=new(); //new函数为Transaction分配空间,将变量初始化为默认值
//(二值变量为0,四值变量为X),并返回保存对象的地址。
new函数也成为构造函数,因为它创建对象。构造函数除了分配内存外,它还初始化变量。可以通过自定义new函数修改变量的默认数值。但是new函数不能有返回值,因为构造函数总是返回一个指向对象的句柄,其类型就是类本身。
//简单用户定义的new()函数
class Transaction;
logic[31:0] addr,crc,data[8];
function new;
addr=3;
foreach(data[i])
data[i]=5;
endfunction
endclass
//addr和crc被设为固定数值,但crc仍然被初始化为默认值X
//一个带有参数的new()函数
class Transaction;
logic[31:0]addr,crc,data[8];
function new(logic[31:0] a=3,d=5);
addr = a;
foreach(data[i])
data[i]=d;
endfunction
endclass
initial begin
Transaction tr;
tr=new(10); //data使用默认值5
end
每一个类都有自己的new函数,在调用new函数时,SystemVerilog通过赋值操作符左边的句柄类型来决定使用哪个new函数:
class Transaction;
...
endclass:Transaction
class Driver;
Transaction tr;
function new(); //Driver的new函数
tr=new(); //调用Transaction的new函数
endfunction;
endclass:Driver
注意:应该避免在声明一个句柄的时候调用构造函数,即new函数。这样构造函数在第一条声明语句前就被调用了,初始化的顺序便不能被控制了。
每个对象都有自己的局部变量,这些变量不和任何其他对象共享。但有时候你需要一个某种类型的变量,被所有对象所共享,此时就需要静态变量(如果没有OOP,可能需要创建一个全局变量)。
当你打算创建一个全局变量的时候,首先应该考虑创建一个类的静态变量。一个类应该是自给自足的,对外部的引用越少越好。
静态变量:在SystemVerilog中,可以在类中创建一个静态变量。该变量将被这个类的所有实例所共享,并且它的使用范围仅限于这个类。
//以下是一个含有静态变量的类
class Transcation;
static int count=0; // 使用static关键字声明一个int类型的静态变量
int id;
funtion new();
id=count++;
endfunction
endclass
Transaction t1,t2;
initial begin
t1=new();
t2=new();
$display("Second id=%d,count=%d",t2.id,t2.count);
end
静态变量可以累积,动态变量离开函数后自动清空。
// 方法1:使用句柄访问静态变量
tr.StaticVariable
// 方法2:使用 类名+作用域符“:”
Transcation::StaticVariable
静态变量通常在声明时初始化。不能简单地在类的构造函数中初始化静态变量,因为每一个新的对象都会调用构造函数。
在SystemVerilog中,可以在类中创建一个静态方法用于读写静态变量,甚至可以在第一个实例产生之前读写静态变量。SystemVerilog不允许静态方法读写非静态变量,例如id。
class Transaction;
static Config cfg;
static int count=0;
int id;
//显示静态变量的静态方法
static function void display_statics();
$display("Transcation cfg.mode=%s,count=%0d",cfg.mode.name(),count);
endfunction
endclass
Config cfg;
initial begin
cfg=new(MODE_ON);
Transaction::cfg=cfg;
Transaction::display_statics(); //调用静态方法
end
一个类的功能应该尽可能简单,不应该承担过多的责任,也不应该承担不符合它的职责。类作为载体,不会将成员变量直接暴露给外部,通过public,protected,local关键词来设置成员变量方法的外部权限访问。
在SystemVerilog中,所有成员都是公有的,除非标记为local或者protected。你应该尽量使用默认值,以保证对DUT行为的最大程度控制,这比软件的长期稳定性更加重要。
Public:(SystemVerilog默认类型)子类和外部类型均可以访问成员。
Protected:只有子类可以访问成员,外部访问是非法的。
Local:只有该类可以访问,子类和外部都不能。