class,是面向对象编程(object-oriented programming (OOP))的基础,而OOP可以让你创建更高抽象级别的验证环境(如UVM)。
class就是相对于verilog更高级别的抽象,因为verilog太过关注细节,不利于验证和建模。
随着SystemVerilog中class的引入,这一切都变了。
class包括变量(类属性,properties)和子程序(类方法,methods)。
SystemVerilog中的类方法一般就是SystemVerilog task(可能消耗时间)/function(不能消耗时间)。
简言之,类属性和类方法定义了这个类有什么以及能够干什么。
通过类属性和类方法,我们可以更加容易地创建模块化的验证平台,因为在事务级而不是RTL级别,能够更容易理解设计和编码验证用例。
一般,类中会有一个构造函数(new,我们可以理解为RTL中module的例化,只有调用构造函数后,才真正存在类的实体,在这之前就只是一个文本的定义而已。
在一个类没有指向任何的对象实体时,Systemverilog的垃圾回收机制会自动地释放相应的内存空间。
Base Class
基类是类层次结构中最顶层的类,从这个基类可以派生出更加丰富多彩的派生类。
下面是一个基类PCI的例子,类中有command、address,data,CycleType等属性。此外,这个基类还可以基于这些属性,做各种各样的事情,例如命令的发送。
每个设计中PCI总线支持的特性都是不同的,但是作为一个基类,PCI具有一些可以统一封装在定义中的公共属性和方法。
module class_TOP( );
class PCI;
//Class properties
logic [3:0] command;
logic [31:0] address;
logic [31:0] data;
logic [3:0] CycleType;
//base class constructor - initialization
function new( );
command = 0;
address = 0;
CycleType = 4'hf;
data = 64'bz;
$display("PCI Init: data=%h command=%b addr=%h
CycleType=%b", data, command, address, CycleType);
endfunction
task PCIWriteCycle (clk);
begin
command = $urandom;
address = $urandom;
CycleType = $urandom;
$display("PCI Write Cycle : clk=%b data=%h command=%b
addr=%h CycleType=%b", clk, data, command, address, CycleType);
end
endtask
endclass : PCI
bit clock;
PCI PCI1; //defne variable PCI1 of type PCI
initial begin
PCI1 = new( ); //instantiate class – allocate memory
//PCI1 now holds an object handle.
end
initial begin
clock = 0;
forever begin
#10; clock=!clock;
end
end
always @(posedge clock) begin
//access class property using object handle PCI1
PCI1.data = $urandom;
//Call Class method PCIWriteCycle
PCI1.PCIWriteCycle(clock);
end
initial #60 $finish(2);
endmodule
1、首先,我们声明一个名为PCI的类。在这个类中,我们声明了类属性:
logic [3:0] command; logic [31:0] address; logic [31:0] data, mem; logic [3:0] CycleType;
2、然后声明类构造函数new(),用于初始化类属性。如果不声明,当类被实例化时会调用隐式的new()函数。在本例中,函数new()将初始化为类中各个属性的默认值。2态变量初始化为0,4态变量初始化为x。
function new( );
command = 0;
address = 0;
CycleType = 4'hf;
data = 64'bz;
$display("PCI Init: data=%h command=%b addr=%h
CycleType=%b", data, command, address, CycleType);
endfunction
3、然后定义一个名为PCIWriteCycle的方法,这里是一个systemverilog function。在这个方法我们我们完成一些类属性的简单赋值,从设计的含义上就是随机发送不同的命令/地址/传输类型等信息。
task PCIWriteCycle (clk);
begin
command = $urandom;
address = $urandom;
CycleType = $urandom;
$display("PCI Write Cycle : clk=%b data=%h command=%b
addr=%h CycleType=%b", clk, data, command, address, CycleType);
end
endtask
4、在类定义之后,我们继续声明一个类的对象并示例化。注意:只有在调用new()之后才分配了实际的内存,PCI1(对象)就是一个指向这个内存空间的指针(或者是句柄,handle)。而如果不示例化,变量PCI1就是一个空指针“null”。
PCI PCI1; //defne variable PCI1 of type PCI PCI1 = new( ); //instantiate class – allocate memory
5、然后,我们使用对象句柄PCI1去调用类的方法PCIWriteCycle。
always @(posedge clock) begin //access class property using object handle PCI1 PCI1.data = $urandom; //Call Class method PCIWriteCycle PCI1.PCIWriteCycle(clock); end
仿真log:
PCI Init: data=zzzzzzzz command=0000 addr=00000000 CycleType=1111 PCI Write Cycle : clk=1 data=12153524 command=0001 addr=8484d609 CycleType=0011 PCI Write Cycle : clk=1 data=06b97b0d command=1101 addr=b2c28465 CycleType=0010 PCI Write Cycle : clk=1 data=00f3e301 command=1101 addr=3b23f176 CycleType=1101 $fnish called from fle "testbench.sv", line 52. $fnish at simulation time 60 V C S S i m u l a t i o n R e p o r t
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !