文章目录
前言
怎样才能位总线事务创建于给可以注入错误并带有可变延时的复杂的类呢?
第一种方法:将所有东西放入一个大的、不分层的类,创建和理解简单,开发和调试费时。
第二种方法:合成,一个模块例化另一个模块,搭建层次化的测试平台。
第三种方法:**和原始类很相像的类,增加了一些新的变量和方法,继承!**允许从一个现存的类得到一个新的类并共享其变量和子程序。提供了可重用性。
1. 继承简介
1.1 事务基类
事务基类 含有一些变量和子程序;
变量包含:源地址、目的地址、八个数据字和校验错误用的CRC变量。
子程序包含:用于显示内容和计算CRC的子程序。
class Transaction;
rand bit [31:0] src, dst,data[8]; // 随机变量
bit [31:0] crc; // 计算得到的CRC值
virtual function void calc_crc;
crc = src^dst^data.xor;
endfunction
virtual function void display(input string prefix = "");
$display("%s TR: src=%h, dst=%h, crc=%h", prefix,src,dst,crc);
endfunction
endclass
1.2 Transaction 类的扩展
class badtr extends Transaction;
rand bit bad_crc;
virtual function void calc_crc;
super.calc_crc(); // 计算正确的CRC
if(bad_crc) crc = ~crc; //产生错误的CRC位
endfunction
virtual function void display(input string prefix = "");
$write("%s badTR: src=%h, dst=%h, crc=%h", prefix,src,dst,crc);
super.display();
endfunction
endclass
扩展类可以直接方位基类和其本身的所有变量,例如bad_crc。
SV不允许用类似 super.super.new 的方式进行多层调用,因为这种调用跨越了不同的层次,跨越了不同的边界,自然也违反了封装的规则。
virtual需要加在基类的任务和函数,除了new函数。因为new函数在对象创建时调用,所以无法扩展。
1.3 扩展类的构造函数
类的变量称为属性(property);
任务或者函数称为方法(method);
如果你的基类构造函数有参数,那么扩展类必须有一个构造函数而且必须在其构造函数的第一个调用基类的构造函数。
class Base1;
int var;
function new(input int var); //带有参数的构造函数
this.var = var;
endfunction
endclass
class extended extends Base1;
function new(input int var); // 需要参数
super.new(var); // 必须是new函数的第一个行
..
endfunction
endclass
1.4 OOP规则
OOP的规则:指向基类(Transaction)的句柄也可以用来指向派生类(Badtr)的对象,因为句柄tr 可以引用变量src、dst、crc、data以及函数cala_crc,所以不做修改直接将Badtr对象送入driver。
在调用tr.calc_crc时,是调用父类还是子类的方法,因为calc_crc 在父类声明了虚方法,SV查看tr中的对象类型,如果tr是transaction类型,则选择父类的方法,如果tr是 Badtr类性,则选择派生类的方法。
generator 只能使用 transaction对象,无法使用扩展对象Badtr。 解决办法是:将tr的创建和初始化分开。
1.5 蓝图blueprint模式
OOP一种非常有用的技术。生产标记,并不需要预先知道每个可能的标记形状。
先构建一个对象的蓝图(建材金属模),然后修改他的约束,甚至使用一个扩展对象替换它。然后当你随机化这个蓝图的时候,它就会 具有你想赋予的随机值。接着复制这个对象,并将拷贝值发送给下游的事务处理器。
将声明和构造分开;
将蓝图对像的构建和随机化分开:
class generator;
mailbox gen2drv;
transaction blueprint;
function new(input mailbox gen2drv);
this.gen2drv = gen2drv;
blueprint = new();
endfucntion
task run;
transaction tr;
forever begin
assert(blueprint.randomize());
tr = blueprint.copy(); 复制对象,以便传送
mbx.put(tr);
end
endtask
endclass
2. environment 类
例化测试平台的所有元素,创建build、运行Run、收尾Wrap-up。
2. 1 使用扩展的Transaction类
为了注入错误,你需要将蓝图对象从transaction对象变成Badtr。在环境的创建和运行阶段完成。
在测试平台中增加扩展了的事务
program automatic test;
Environment env;
initial begin
env = new();
env.build(); //创建generator等
begin
Badtr bad = new(); // 以bad对象取代蓝图
env.gen.blueprint = bad;
end
env.run();
env.wrap_up();
end
endprogram
2. 2 使用扩展类 改变 随机约束
class childclass extends transaction
constraint c_childclass