在OOP中,你需要考虑测试平台的结构,以及各部分的功能。 事务是测试平台的焦点。
发生器(generator)创建事务并且将它们传给下一级;驱动器(driver)和设计对话,设计返回的事务将被监视器(monitor)捕获,记分板(scoreboard)会将捕获的结果和预期的结果进行比对。
类:封装了数据和操作这些数据的子程序。
在SV中,可以把类定义在program、module、package中。
编写代码时的约定:
a、类名使用大写字母开头,中间不使用下划线
b、常数使用大写字母定义
c、变量都使用小写字母
OOP术语:
类(class)--------包含变量和子程序的基本构建块
对象(object)---类的一个实例
句柄(handle)--指向对象的指针,一个OOP句柄指向一个对象的地址,但是它保存在一个只能指向单一数据类型的指针中
属性(property)-存储数据的变量。
方法(method)--任务或者函数中操作变量的程序性代码
原型(prototype)-程序的头,包括程序名、返回类型和参数列表。程序体包含了执行代码。
-----------------------------------------------
SV中的类在使用之前必须先例化,且SV句柄可以指向很多对象,当然一次只能指向一个!
例化的含义:当你调用new函数例化一个对象时,你是在为该对象申请一个新的内存来保存对象的变量
1.构造函数new() : 除了分配内存之外,还初始化变量。
注:new函数不能有返回值,因为构造函数总是返回一个指向类对象的句柄,其类型就是类本身!
trans tr ; //声明一个句柄,初始化为特殊值null
tr = new() ; //为一个trans对象分配空间,将变量初始化为默认值,二值--> 0 , 四值--> 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,crc使用默认值X
SV中调用哪个new函数取决于赋值操作符左边的句柄类型!
2.避免在声明一个句柄的时候调用构造函数,即new函数,否则会引起顺序问题。
若忘记使用automatic,构造函数new将在仿真开始时调用,而非进入块的时候!
new()与new[]区别:
new()用于创建一个对象,可以使用参数设置对象的数值
new[]用于建立一个含有多个元素的数组,只需要使用一个数值来设置数组的大小
3.声明一个句柄来创建一个对象,在仿真中,一个句柄可以指向多个对象:
eg:
Trans tr1 , te2 ; //声明两个句柄
tr1 = new() ; //为第一个类对象分配地址空间
tr2 = tr1 ; //复制,指向同一个地址,都指向第一个对象
tr1 = new() ; //为第二个Trans对象分配地址
**分辨对象不再被引用的方法是记住指向它的句柄的数量,当最后一个句柄再在引用对象了,SV就将释放该对象的空间
垃圾回收-----------一种自动释放不再被引用的对象的过程
Trans tr ; //声明两个句柄
tr = new() ; //分配一个新的Transaction
tr = new() ; //分配第二个,并且释放第一个
tr = null ; //解除分配第二个
SV中,不允许将一种类型的句柄指向另一种类型的对象
使用对象 :使用 “ . ”符号来引用变量和子程序
Transaction t;
t = new();
t.addr = 32'h42; //设置变量的值
t.display(); //调用一个子程序
严格的OOP规定,只能通过对象的公用方法访问对象的变量,如get() 和 put()
静态变量:关键字“ static ”,该变量将被这个类的所有实例(对象)所共享,并且其使用范围仅限这个类
静态变量的访问方法有二:a、句柄 + “ . ” b、类名 + “ : : ”
静态变量的初始化:保证在创建第一个对象前,就已经初始化了静态变量。 通常在声明的时候初始化 不能简单地在构造函数中初始化静态变量!