TB1 接口的使用
1.1 在已有代码的基础上使用 intf.ck 的方式来做数据驱动,并且再观察波形,查看驱动的数据与时钟上升沿的延迟是多少。
使用intf.ck方式做驱动。
如图,延迟时间为在clocking中设置的1ns。
1.2 已有代码会使得有效数据之间保持固定的一个空闲周期,使用 idle_cycles 变量, 来灵活控制有效数据之间的空闲周期。 通过这个方法,在 tb 的 initial 块中我们通过方法 set_idle. cycles()使得三个 channel initiator 的空闲周期变为0,1,2。
TB2 仿真的结束
//burst_test核心代码段
fork
begin
repeat(500) chnl0_init.chnl_write(chnl0_gen.get_data());
chnl0_init.chnl_idle();
end
begin
repeat(500) chnl1_init.chnl_write(chnl1_gen.get_data());
chnl1_init.chnl_idle();
end
begin
repeat(500) chnl2_init.chnl_write(chnl2_gen.get_data());
chnl2_init.chnl_idle();
end
join
fork
wait(chnl0_init.intf.ch_margin == 'h20);
wait(chnl1_init.intf.ch_margin == 'h20);
wait(chnl2_init.intf.ch_margin == 'h20);
join
//fifo_full_test核心代码段
fork: fork_all_run
forever chnl0_init.chnl_write(chnl0_gen.get_data());
forever chnl1_init.chnl_write(chnl1_gen.get_data());
forever chnl2_init.chnl_write(chnl2_gen.get_data());
join_none
$display("fifo_full_test: 3 initiators running now");
$display("fifo_full_test: waiting 3 channel fifos to be full");
fork
wait(chnl0_init.intf.ch_ready == 0);
wait(chnl1_init.intf.ch_ready == 0);
wait(chnl2_init.intf.ch_ready == 0);
join
$display("fifo_full_test: 3 channel fifos have reached full");
$display("fifo_full_test: stop 3 initiators running");
disable fork_all_run;
$display("fifo_full_test: set and ensure all agents' initiator are idle state");
fork
chnl0_init.chnl_idle();
chnl1_init.chnl_idle();
chnl2_init.chnl_idle();
join
$display("fifo_full_test waiting DUT transfering all of data");
fork
wait(chnl0_init.intf.ch_margin == 'h20);
wait(chnl1_init.intf.ch_margin == 'h20);
wait(chnl2_init.intf.ch_margin == 'h20);
join
$display("fifo_full_test: 3 channel fifos have transferred all data");
TB3 类的例化和类的成员
3.1 在 iniital 块中分别例化 3 个已经声明过的 chnl_initiator 和 3 个chnl_generator。
3.2 通过调用 chnl_iniaitor 中的方法来完成接口的传递。
3.3 调用已经定义过的三个 test 任务来展开测试了。
initial begin
// USER TODO 3.1
// instantiate the components chn0/1/2_init chnl0/1/2_gen
chnl0_init = new("chn0_init");
chnl1_init = new("chn1_init");
chnl2_init = new("chn2_init");
chnl0_gen = new(0);
chnl1_gen = new(1);
chnl2_gen = new(2);
// USER TODO 3.2
// assign the interface handle to each chnl_initiator objects
chn0_init.set_interface(chnl0_if);
chn1_init.set_interface(chnl1_if);
chn2_init.set_interface(chnl2_if);
// USER TODO 3.3
// START TESTs
basic_test();
burst_test();
fifo_full_test();
$display("*****************all of tests have been finished********************");
$finish();
end
3.4 观察 chnl_generator 在例化 chnl_trans t 时, 有没有不恰当的地方, 如果有请指出来现有的代码会造成什么样的潜在问题呢?
class chnl_generator;
chnl_trans trans[$];
int num;
int id;
chnl_trans t;
function new(int n);
this.id = n;
this.num = 0;
t = new(); //位置1
endfunction
function chnl_trans get_trans();
// t = new(); //位置2
t.data = 'h00C0_0000 + (this.id<<16) + this.num;
t.id = this.id;
t.num = this.num;
this.num++;
this.trans.push_back(t);
return t;
endfunction
endclass
位置1的例化只会创建一个对象,对于后面的多次调用同一个通道的get_trans()时变会覆盖前一次的数据,直至到最后一个数据;而位置2的例化可以调用一次创建一个对象,更符合数据的保存使用。
TB4 包的定义和类的继承
4.1 在 module tb4 中要声明类的句柄, 首先应该从 chnl_pkg 中引入其中定义的类。
4.2 参考之前已经实现的 burst_test() 和 fifo_full_test()任务, 以及已经实现的chnl_basic_test, 按照同样的要求来实现两个新的类 chnl_burst_test 和 chnl_fifof_full_test。
4.3 例化三个测试环境。 在 4.2 中继承了三个 chnl_root_test 的子类, 并在 import package之后, 创建了对应的句柄。 现在要例化三个 test, 即创建对应的对象, 并将句柄指向这些对象。
4.4 将每个通道的接口, 赋值给对应的 chnl_initiator。并运行测试。
4.5 代码部分
class chnl_burst_test extends chnl_root_test;
//USER TODO
function new(int ntrans = 500, string name = "chnl_burst_test");
super.new(ntrans, name);
foreach (agent[i]) begin
this.agent[i].init.set_idle_cycles(0);
end
$display("%s configured objects", this.name);
endfunction
endclass: chnl_burst_test
class chnl_fifo_full_test extends chnl_root_test;
// USER TODO
function new(int ntrans = 1_000_000, string name = "chnl_fifo_full_test");
super.new(ntrans, name);
foreach (agent[i]) begin
this.agent[i].init.set_idle_cycles($urandom_range(1,3));
end
$display("%s configured objects", this.name);
endfunction
task run();
$display("%s started testing DUT", this.name);
fork:fork_all_run
agent[0].run();
agent[1].run();
agent[2].run();
join_none
$display("%s: 3 agents are running now", this.name);
$display("%s: waiting 3 channel fifos to be full", this.name);
fork
wait(agent[0].vif.ch_margin == 0);
wait(agent[1].vif.ch_margin == 0);
wait(agent[2].vif.ch_margin == 0);
join
$display("%s: 3 channel fifos have reached full", this.name);
$display("%s: stop 3 agents running", this.name);
disable fork_all_run;
$display("%s: set and ensure all agents' initiator are idle state", this.name);
fork
agent[0].init.chnl_idle();
agent[1].init.chnl_idle();
agent[2].init.chnl_idle();
join
$display("%s waiting DUT transfering all of data", this.name);
fork
wait(agent[0].vif.ch_margin == 'h20);
wait(agent[1].vif.ch_margin == 'h20);
wait(agent[2].vif.ch_margin == 'h20);
join
$display("%s: 3 channel fifos have transferred all data", this.name);
$display("%s finished testing DUT", this.name);
endtask
endclass: chnl_fifo_full_test
4.6 仿真结果