sv还引入了面向对象编程OOP特性,通过类区分不同的单元,每个类都可以封装自己的数据成员和提供对外的操作方法。
类是一种用户自定义的数据类型,其中包括数据(类的特性),运行在数据上的函数和任务。函数和任务叫做方法,两者都是类的成员。类允许动态的去创建、删除、赋值和访问通过对象的句柄。
以下的类有一个成员x和两个方法set,get。
class sv_class;
//class properties
int x;
//method-1
task set(int i);
x = i;
endtask
//method-2
function int get();
return x;
endfunction
endclass
声明一个类数据的变量时:
sv_class class_1;
此时class_1包含sv_class实例化的句柄(访问方法)
sv_class class_1 = new()
此时创建了对象。创建时,实例名=new();new()方法会返回一个句柄。
咱们来看一个简单示例,要调用类方法可以实例名.方法名。另外要注意的是,我们在类外并没有对类数据直接赋值,而是通过方法set对成员x进行赋值,可以保护数据
module argument_passing;
int x ;
int y ;
int z ;
//function to add two integers numbers
function automatic int sum(const ref int x, y);
x = x + y;
return x+y;
endfunction
initial begin
x = 20 ;
y = 30 ;
z = sum(x,y);
$display("-------------------------------------------------");
$display("\t Value of x = %0d", x);
$display("\t Value of y = %0d", y);
$display("\t Value of z = %0d", z);
$display("-------------------------------------------------");
end
endmodule
其输出结果是:
this关键字用来指向当前实例的性质和方法,说白了就是要对自身进行操作。当方法的参数名和成员名重复,编译器会困惑是谁??如下图所示,此时使用this可以解决这个问题。这个关键字使能使用在非静态的方法上。
class packet;
// class properties
bit [31:0] addr ;
bit [31:0] data ;
bit write ;
string pkt_type;
//constructor
function new(bit [31:0] addr, data, bit write, string pkt_type);
addr = addr ;
data = data ;
write = write;
pkt_type = pkt_type;
endfunction
// method to display class properties
function void display();
$display("==================================================");
$display("\t addr = %0h", addr);
$display("\t data = %0h", data);
$display("\t write = %0h", write);
$display("\t pkt_type = %0s", pkt_type);
$display("==================================================");
endfunction
endclass
module sv_constructor;
packet pkt;
initial begin
pkt = new(32'h10, 32'hFF, 1, "GOOD_PKT");
pkt.display();
end
endmodule
上面的例子想把addr = 32’h10,但是结果却是:
主要原因是new参数名和类的成员名重复,导致编译混乱,因此加上this:
其编译结果是:
new函数叫做类构造函数。调用new方法时,编译器会分配内存,并且返回类句柄的地址(类似指针)。
分配内存,会初始化赋值,二值逻辑为0,四值逻辑为x。
new操作没有返回值,每个类都有内建的new方法,当我们调用没有显式定义(即用户自己写new方法实现)的new方法时,将会调用默认的内建new方法。构造器可以用来初始化类的属性。如下图所示:
类成员可以用关键词static修饰,就成了静态成员,分为静态属性和静态方法。对于静态成员,多个实例会共享一份静态变量。注意,静态方法只能访问类的静态属性,访问非静态属性是不合法的,编译会报错,静态方法也不能用virtual修饰。声明结构如下:
static <data_type> <property_name>;
static task/function <method_name>;
class packet;
//class properties
byte packet_id;
//static property to keep track of number of pkt's created
static byte no_of_pkts_created;
//constructor
function new();
//incrementing pkt count on creating an object
no_of_pkts_created++;
packet_id = no_of_pkts_created;
endfunction
//method to display class prperties
function void display();
$display("--------------------------------------");
$display("\t packet_id = %0d",packet_id);
$display("--------------------------------------");
endfunction
endclass
module static_properties;
packet pkt[3];
initial begin
foreach(pkt[i]) begin
pkt[i] = new();
pkt[i].display();
end
end
endmodule
输出结果为:
静态方法访问类的非静态变量会报错。
另外,静态属性和静态方法,可以直接通过没有构造的句柄访问,看下面实例,pkt类实例数组都使用了new方法,而p却没有完成构造方法,但它依然可以访问静态成员。很好理解,静态成员已经分配好了内存空间,我当然可以找到它,自动变量由于地址未知,就无法访问
其输出结果时: