1、测试平台的构建
发生器(generator):创建事务并且将它们传给下一级
驱动器(drive):与设计进行会话
监视器(monitor):捕获设计返回的事务
计分板(scoreboard):将捕获的结果跟预期的结果进行对比
测试平台应该分成若干个块(block),然后定义它们相互之间如何通信。
2、OOP(Object-Oriented Program)
类(class)、对象(object)、句柄(object)、属性(property)、方法(method)、原型(prototype)
3、类定义的位置
类应当在program或者module外的package中定义,将临时变量在测试平台最内部的某处定义。
4、创建对象
方法:创建一个指向目标类对象的句柄,然后调用new()函数。
对象和句柄:句柄可以在不同的时间指向不同的对象
5、对象的接触分配
SV分辨对象不再被引用的最好办法就是记住指向它的句柄的数量,当最后一个句柄不再引用某个对象了,SV就释放该对象的空间。
6、使用对象
方法:用“.”操作符
7、静态变量和全局变量
每个对象都有自己的局部变量,这些变量不和任何其他对象共享。而使用静态变量就可以被所以对象所共享。
8、静态函数
没有创建类对象就可以执行,不允许读写非静态变量。调用静态函数:类名::方法名
9、类的方法
在类的作用域内定义的内部task或者function。SV会根据句柄的类型调用正确的display()方法。
10、将对象传递给方法
如果要在任务或者函数中修改句柄,则必须将该任务或函数声明为automatic,并且对象加ref
11、对象的复制
可以使用new操作符,但这样是简易复制(shallow copy),类似于原对象的一个影印本,原对象的值被盲目地抄写到目的对象中。如果类中包含一个指向另一个类的句柄,那么只有最高一级的对象被new操作符复制,下层的对象都不回被复制。更推荐的做法是编写自己的复制函数:为每个类构建复制函数,并在其中继续调用对象成员的复制函数。
12、公有和私有
在SV中,所以成员都是公有的,除非标记为local或者protected。应该尽量使用默认值,以保证对DUT行为的最大程度的控制
13、建立一个测试平台
图中的Generator、Agent、Drive、Monitor、Checker和Scoreboard都是类,被建模成事务处理器(transactor)。事务处理器由一个简单的循环构成,这个循环从前面的块接受事务对象,经过变换后送给后续块。
14、示例代码
package,包含类的定义
package class_package;
typedef class Statistics;
class Transaction;
Statistics stats; //对象成员
bit [31:0] addr,crc,data[8]; //默认公有
static int count = 0; //静态变量
int id;
function new(logic [31:0] a=3,d=5);
addr = a;
foreach (data[i])
data[i] = d;
id = count++;
stats = new(); // 调用对象成员的构造函数
endfunction:new
function Transaction copy; // 复制函数
copy = new();
copy.addr=addr;
copy.crc=crc;
copy.data=data;
copy.stats=stats.copy(); //调用对象成员的复制函数
endfunction
function void display();
$display("addr:%h",addr);
endfunction:display
static function void static_f();
$display("count:%h",count);
endfunction:static_f
endclass:Transaction
class Statistics;
time startT;
function new();
startT = 1;
endfunction:new
function Statistics copy(); //复制函数
copy=new();
copy.startT=startT;
endfunction
endclass:Statistics
endpackage
program:
import class_package::*;
//将对象传递给方法
function automatic void create(ref Transaction tr);
//在方法中改变了句柄,因此必须加ref
tr = new();
tr.addr = 42;
endfunction
program test;
initial begin
Transaction tr1,tr2,tr3,src,dst;
tr1 = new();
tr2 = new();
create(tr3); //将对象传递给方法
tr1.display();
tr2.display();
tr3.display();
$display("Second object id = %0d,count = %0d",tr2.id,Transaction::count);
Transaction::static_f();
//使用new复制对象
src = new();
src.stats.startT = 42;
dst = new src;
dst.stats.startT = 96;
$display("========= dst = new src ==========");
$display("shallow copy - src.stats.startT:%0d",src.stats.startT); //96 因为src和dst的stats都指向同一个对象
$display("shallow copy - dst.stats.startT:%0d",dst.stats.startT); //96
$display("shallow copy - src.id:%0d",src.id); // 3
$display("shallow copy - dst.id:%0d",dst.id); // 3
//使用copy函数复制对象
dst = src.copy;
dst.stats.startT = 48;
$display("========= dst = src.copy ==========");
$display("shallow copy - src.stats.startT:%0d",src.stats.startT); //96,没有被改成48
$display("shallow copy - dst.stats.startT:%0d",dst.stats.startT); //48
$display("shallow copy - src.id:%0d",src.id); // 3
$display("shallow copy - dst.id:%0d",dst.id); // 4
#50;
$display("End of test");
end
endprogram
输出:
# addr:00000003
# addr:00000003
# addr:0000002a
# Second object id = 1,count = 3
# count:00000003
# ========= dst = new src ==========
# shallow copy - src.stats.startT:96
# shallow copy - dst.stats.startT:96
# shallow copy - src.id:3
# shallow copy - dst.id:3
# ========= dst = src.copy ==========
# shallow copy - src.stats.startT:96
# shallow copy - dst.stats.startT:48
# shallow copy - src.id:3
# shallow copy - dst.id:4
# End of test