一、回调
如何创建一个可以不做任何更改就能在所有测试中使用的验证环境?
要做到这一点的关键就是测试平台必须提供一个“钩子”,以便测试程序在不修改原始类的情况下注入新的代码。
驱动器的作用:
- 注入错误
- 放弃事务
- 延迟事务
- 将本事务跟其他事务同步
- 将事务放进记分板
- 收集功能覆盖数据
与其试图预测所有可能的错误、延迟或者事务流程中的干扰,不如使用回调的方法,这时驱动器仅需要回调一个在顶层测试中定义的子程序。这种回调子程序可以在每个测试中做不同的定义,这样测试就可以使用回调来为驱动器增加新的功能而不用编辑Driver类。
二、创建一个回调任务
一个回调任务应该在顶层测试中创建,在环境中的最低级即驱动器中调用。
回调基类
virtual class Driver_cbs; //驱动器回调
virtual task pre_tx(ref Transaction tr, ref bit drop); //默认情况下回调不做任何动作
endtask
virtual task post_tx(ref Transaction tr); //默认情况下回调不做任何动作
endtask
endclass
使用回调的驱动器类
class Driver;
Driver_cbs cbs[$]
task run();
bit drop;
Transaction tr;
forever begin
drop = 0;
agt2drv.get(tr);
foreach(cbs[i]) cbs[i].pre_tx(tr,drop);
if(!drop) continue;
transmit(tr);
foreach(cbs[i]) cbs[i].post_tx(tr,drop);
end
endtask
endclass
三、使用回调来注入干扰
回调可以用来注入干扰,例如引起一个错误或延迟。回调也可以用来向记分板发送数据或者收集功能覆盖率数据。
使用回调进行错误注入
class Driver_cbs_drop extends Driver_cbs;
virtual task pre_tx(ref Transaction tr, ref bit drop);
//每100个事务中随机丢弃一个
drop = ($urandom_range(0,99) == 0);
endtask
endclass
program automatic test;
Environment env;
initial begin
env.new();
env.gen_cfg();
env.build();
begin //创建错误注入的回调任务
Driver_cbs_drop dcd = new();
env.drv.cbs.push_back(dcd); //放入驱动器队列
end
env.run();
env.wrap_up();
end
endprogram
四、记分板
记分板的设计取决于待测设计DUT。
使用原子事务的简单记分板
/*
这个记分板,它将事务存储在一个期望值队列中,
第一个方法用来保存一个期望的事务,
第二个方法尝试找出与测试平台接收到的实际事务相匹配的期望事务,
可能会得到0个匹配,1个匹配或者多个匹配。
*/
class Scoreboard;
Transaction scb[$]; //保存期望的事务的队列
function void save_expect(input Transaction tr);
scb.push_bask(tr);
endfunction
function void compare_actual(input Transaction tr);
int q[$];
q = scb.find_index(x) with (x.src == tr.src);
case(q.size())
0: $display("No match found");
1: scb.delete(q[0]);
default:
$display("Error,multiple matches found!");
endcase
endfunction : compare_actual
endclass : Scoreborad
五、与使用回调的记分板进行连接
记分板使用回调
class Driver_cbs_scoreboard extends Driver_cbs;
Scoreboard scb;
virtual task pre_tx(ref Transaction tr, ref bit drop);
scb.save_expect(tr); //将事务放入记分板
endtask
function new(input Scoreboard scb)
this.scb = scb;
endfunction
endclass
program automatic test;
Environment env;
initial begin
env.new();
env.gen_cfg();
env.build();
begin //创建scb回调
Driver_cbs_scoreboard dcs = new(env.scb);
env.drv.cbs.push_back(dcs); //放入驱动器队列
end
env.run();
env.wrap_up();
end
endprogram
应该总是为记分板和功能覆盖使用回调。事务监测器可以使用一个回调来比较接受到的事务和期待的事务,监视器回调也非常适合用来收集DUT实际发送事务的功能覆盖数据。
六、使用回调来调试事务处理器
如果一个使用回调的事务处理器没有按照预期工作,可以使用另外一个回调来调试它,可以通过增加一个显示事务内容的回调。