TB1 接口的使用
interface chnl_intf(input clk, input rstn);
logic [31:0] ch_data;
logic ch_valid;
logic ch_ready;
logic [ 5:0] ch_margin;
clocking drv_ck @(posedge clk);
default input #1ns output #1ns;
output ch_data, ch_valid;
input ch_ready, ch_margin;
endclocking
endinterface
module chnl_initiator(chnl_intf intf);
string name;
int idle_cycles = 1;
function automatic void set_idle_cycles(int n);
idle_cycles = n;
endfunction
function automatic void set_name(string s);
name = s;
endfunction
task automatic chnl_write(input logic[31:0] data);
@(posedge intf.clk);
// USER TODO 1.1
// Please use the clocking drv_ck of chnl_intf to drive data
intf.drv_ck.ch_valid <= 1;
intf.drv_ck.ch_data <= data;
wait(intf.ch_ready === 'b1);
$display("%t channel initiator [%s] sent data %x", $time, name, data);
repeat(idle_cycles)
// USER TODO 1.2
// Apply variable idle_cycles and decide how many idle cycles to be
// inserted between two sequential data
chnl_idle();
endtask
task automatic chnl_idle();
@(posedge intf.clk);
// USER TODO 1.1
// Please use the clocking drv_ck of chnl_intf to drive data
intf.drv_ck.ch_valid <= 0;
intf.drv_ck.ch_data <= 0;
endtask
endmodule
module chnl_generator;
int chnl_arr[$];
int num;
int id;
function automatic void initialize(int n);
id = n;
num = 0;
endfunction
function automatic int get_data();
int data;
data = 'h00C0_0000 + (id<<16) + num;
num++;
chnl_arr.push_back(data);
return data;
endfunction
endmodule
module tb1;
logic clk;
logic rstn;
logic [31:0] mcdt_data;
logic mcdt_val;
logic [ 1:0] mcdt_id;
mcdt dut(
.clk_i (clk )
,.rstn_i (rstn )
,.ch0_data_i (chnl0_if.ch_data )
,.ch0_valid_i (chnl0_if.ch_valid )
,.ch0_ready_o (chnl0_if.ch_ready )
,.ch0_margin_o(chnl0_if.ch_margin )
,.ch1_data_i (chnl1_if.ch_data )
,.ch1_valid_i (chnl1_if.ch_valid )
,.ch1_ready_o (chnl1_if.ch_ready )
,.ch1_margin_o(chnl1_if.ch_margin )
,.ch2_data_i (chnl2_if.ch_data )
,.ch2_valid_i (chnl2_if.ch_valid )
,.ch2_ready_o (chnl2_if.ch_ready )
,.ch2_margin_o(chnl2_if.ch_margin )
,.mcdt_data_o (mcdt_data )
,.mcdt_val_o (mcdt_val )
,.mcdt_id_o (mcdt_id )
);
// clock generation
initial begin
clk <= 0;
forever begin
#5 clk <= !clk;
end
end
// reset trigger
initial begin
#10 rstn <= 0;
repeat(10) @(posedge clk);
rstn <= 1;
end
initial begin
// verification component initializationi
chnl0_gen.initialize(0);
chnl1_gen.initialize(1);
chnl2_gen.initialize(2);
chnl0_init.set_name("chnl0_init");
chnl1_init.set_name("chnl1_init");
chnl2_init.set_name("chnl2_init");
chnl0_init.set_idle_cycles(0);
chnl1_init.set_idle_cycles(0);
chnl2_init.set_idle_cycles(0);
end
initial begin
@(posedge rstn);
repeat(5) @(posedge clk);
repeat(100) begin
chnl0_init.chnl_write(chnl0_gen.get_data());
end
chnl0_init.chnl_idle();
end
initial begin
@(posedge rstn);
repeat(5) @(posedge clk);
repeat(100) begin
chnl1_init.chnl_write(chnl1_gen.get_data());
end
chnl1_init.chnl_idle();
end
initial begin
@(posedge rstn);
repeat(5) @(posedge clk);
repeat(100) begin
chnl2_init.chnl_write(chnl2_gen.get_data());
end
chnl2_init.chnl_idle();
end
chnl_intf chnl0_if(.*);
chnl_intf chnl1_if(.*);
chnl_intf chnl2_if(.*);
chnl_initiator chnl0_init(chnl0_if);
chnl_initiator chnl1_init(chnl1_if);
chnl_initiator chnl2_init(chnl2_if);
chnl_generator chnl0_gen();
chnl_generator chnl1_gen();
chnl_generator chnl2_gen();
endmodule
TB2 task basic_test; task burst_test; task fifo_full_test
`timescale 1ns/1ps
interface chnl_intf(input clk, input rstn);
logic [31:0] ch_data;
logic ch_valid;
logic ch_ready;
logic [ 5:0] ch_margin;
clocking drv_ck @(posedge clk);
default input #1ns output #1ns;
output ch_data, ch_valid;
input ch_ready, ch_margin;
endclocking
endinterface
module chnl_initiator(chnl_intf intf);
string name;
int idle_cycles = 1;
function automatic void set_idle_cycles(int n);
idle_cycles = n;
endfunction
function automatic void set_name(string s);
name = s;
endfunction
task automatic chnl_write(input logic[31:0] data);
@(posedge intf.clk);
// USER TODO 1.1
// Please use the clocking drv_ck of chnl_intf to drive data
intf.drv_ck.ch_valid <= 1;
intf.drv_ck.ch_data <= data;
wait(intf.ch_ready === 'b1);
$display("%t channel initiator [%s] sent data %x", $time, name, data);
// USER TODO 1.2
// Apply variable idle_cycles and decide how many idle cycles to be
// inserted between two sequential data
repeat(idle_cycles)
chnl_idle();
endtask
task automatic chnl_idle();
@(posedge intf.clk);
// USER TODO 1.1
// Please use the clocking drv_ck of chnl_intf to drive data
intf.drv_ck.ch_valid <= 0;
intf.drv_ck.ch_data <= 0;
endtask
endmodule
module chnl_generator;
int chnl_arr[$];
int num;
int id;
function automatic void initialize(int n);
id = n;
num = 0;
endfunction
function automatic int get_data();
int data;
data = 'h00C0_0000 + (id<<16) + num;
num++;
chnl_arr.push_back(data);
return data;
endfunction
endmodule
module tb2;
logic clk;
logic rstn;
logic [31:0] mcdt_data;
logic mcdt_val;
logic [ 1:0] mcdt_id;
mcdt dut(
.clk_i (clk )
,.rstn_i (rstn )
,.ch0_data_i (chnl0_if.ch_data )
,.ch0_valid_i (chnl0_if.ch_valid )
,.ch0_ready_o (chnl0_if.ch_ready )
,.ch0_margin_o(chnl0_if.ch_margin )
,.ch1_data_i (chnl1_if.ch_data )
,.ch1_valid_i (chnl1_if.ch_valid )
,.ch1_ready_o (chnl1_if.ch_ready )
,.ch1_margin_o(chnl1_if.ch_margin )
,.ch2_data_i (chnl2_if.ch_data )
,.ch2_valid_i (chnl2_if.ch_valid )
,.ch2_ready_o (chnl2_if.ch_ready )
,.ch2_margin_o(chnl2_if.ch_margin )
,.mcdt_data_o (mcdt_data )
,.mcdt_val_o (mcdt_val )
,.mcdt_id_o (mcdt_id )
);
// clock generation
initial begin
clk <= 0;
forever begin
#5 clk <= !clk;
end
end
// reset trigger
initial begin
#10 rstn <= 0;
repeat(10) @(posedge clk);
rstn <= 1;
end
initial begin
basic_test();
burst_test();
fifo_full_test();
$display("*****************all of tests have been finished********************");
$finish();
end
// each channel send data with idle_cycles inside [1:3]
// each channel send out 200 data
// then to finish the test
task automatic basic_test();
// verification component initializationi
chnl0_gen.initialize(0);
chnl1_gen.initialize(1);
chnl2_gen.initialize(2);
chnl0_init.set_name("chnl0_init");
chnl1_init.set_name("chnl1_init");
chnl2_init.set_name("chnl2_init");
chnl0_init.set_idle_cycles($urandom_range(1, 3));
chnl1_init.set_idle_cycles($urandom_range(1, 3));
chnl2_init.set_idle_cycles($urandom_range(1, 3));
$display("basic_test initialized components");
wait (rstn === 1'b1);
repeat(5) @(posedge clk);
$display("basic_test started testing DUT");
// Please check the SV book for fork-join basic knowledge
// and get understood it is for parallel thread running
fork
repeat(100) chnl0_init.chnl_write(chnl0_gen.get_data());
repeat(100) chnl1_init.chnl_write(chnl1_gen.get_data());
repeat(100) chnl2_init.chnl_write(chnl2_gen.get_data());
join
$display("basic_test finished testing DUT");
endtask
// USER TODO 2.1
// each channel send data with idle_cycles == 0
// each channel send out 500 data
// then to finish the test
task automatic burst_test();
chnl0_gen.initialize(0);
chnl1_gen.initialize(1);
chnl2_gen.initialize(2);
chnl0_init.set_name("chnl0_init");
chnl1_init.set_name("chnl1_init");
chnl2_init.set_name("chnl2_init");
chnl0_init.set_idle_cycles(0);
chnl1_init.set_idle_cycles(0);
chnl2_init.set_idle_cycles(0);
$display("basic_test initialized components");
wait (rstn === 1'b1);
repeat(5) @(posedge clk);
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
$display("basic_test finished testing DUT");
endtask
// USER TODO 2.2
// The test should be immediately finished when all of channels
// have been reached fifo full state, but not all reaching
// fifo full at the same time
task automatic fifo_full_test();
chnl0_gen.initialize(0);
chnl1_gen.initialize(1);
chnl2_gen.initialize(2);
chnl0_init.set_name("chnl0_init");
chnl1_init.set_name("chnl1_init");
chnl2_init.set_name("chnl2_init");
chnl0_init.set_idle_cycles(0);
chnl1_init.set_idle_cycles(0);
chnl2_init.set_idle_cycles(0);
$display("fifo_full_test initialized components");
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_margin == 0);
wait(chnl1_init.intf.ch_margin == 0);
wait(chnl2_init.intf.ch_margin == 0);
join
$display("fifo_full_test : fifo have get all data");
$display("fifo_full_test: stop 3 initiators running");
disable all_run;
$display("fifo_full_test: have stoped 3 initiators running");
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");
$display("fifo_full_test :fifo have sent all data to arbiter");
endtask
chnl_intf chnl0_if(.*);
chnl_intf chnl1_if(.*);
chnl_intf chnl2_if(.*);
chnl_initiator chnl0_init(chnl0_if);
chnl_initiator chnl1_init(chnl1_if);
chnl_initiator chnl2_init(chnl2_if);
chnl_generator chnl0_gen();
chnl_generator chnl1_gen();
chnl_generator chnl2_gen();
endmodule
TB3 chnl_trans 用来封装chnl_generator 产生的数据 共有三个类 chnl_trans chnl_initiator chnl_generator
`timescale 1ns/1ps
interface chnl_intf(input clk, input rstn);
logic [31:0] ch_data;
logic ch_valid;
logic ch_ready;
logic [ 5:0] ch_margin;
clocking drv_ck @(posedge clk);
default input #1ns output #1ns;
output ch_data, ch_valid;
input ch_ready, ch_margin;
endclocking
endinterface
class chnl_trans;
int data;
int id;
int num;
endclass
class chnl_initiator;
local string name;
local int idle_cycles;
virtual chnl_intf intf;
function new(string name = "chnl_initiator");
this.name = name;
this.idle_cycles = 1;
endfunction
function void set_idle_cycles(int n);
this.idle_cycles = n;
endfunction
function void set_name(string s);
this.name = s;
endfunction
function void set_interface(virtual chnl_intf intf);
if(intf == null)
$error("interface handle is NULL, please check if target interface has been intantiated");
else
this.intf = intf;
endfunction
task chnl_write(input chnl_trans t);
@(posedge intf.clk);
// USER TODO 1.1
// Please use the clocking drv_ck of chnl_intf to drive data
intf.ch_valid <= 1;
intf.ch_data <= t.data;
wait(intf.ch_ready === 'b1);
$display("%t channel initiator [%s] sent data %x", $time, name, t.data);
repeat(idle_cycles)
// USER TODO 1.2
// Apply variable idle_cycles and decide how many idle cycles to be
// inserted between two sequential data
chnl_idle();
endtask
task chnl_idle();
@(posedge intf.clk);
// USER TODO 1.1
// Please use the clocking drv_ck of chnl_intf to drive data
intf.drv_ck.ch_valid <= 0;
intf.drv_ck.ch_data <= 0;
endtask
endclass
// USER TODO 3.4
// check if the object use is correct?
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();
endfunction
function chnl_trans get_trans();
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
module tb3;
logic clk;
logic rstn;
logic [31:0] mcdt_data;
logic mcdt_val;
logic [ 1:0] mcdt_id;
mcdt dut(
.clk_i (clk )
,.rstn_i (rstn )
,.ch0_data_i (chnl0_if.ch_data )
,.ch0_valid_i (chnl0_if.ch_valid )
,.ch0_ready_o (chnl0_if.ch_ready )
,.ch0_margin_o(chnl0_if.ch_margin )
,.ch1_data_i (chnl1_if.ch_data )
,.ch1_valid_i (chnl1_if.ch_valid )
,.ch1_ready_o (chnl1_if.ch_ready )
,.ch1_margin_o(chnl1_if.ch_margin )
,.ch2_data_i (chnl2_if.ch_data )
,.ch2_valid_i (chnl2_if.ch_valid )
,.ch2_ready_o (chnl2_if.ch_ready )
,.ch2_margin_o(chnl2_if.ch_margin )
,.mcdt_data_o (mcdt_data )
,.mcdt_val_o (mcdt_val )
,.mcdt_id_o (mcdt_id )
);
// clock generation
initial begin
clk <= 0;
forever begin
#5 clk <= !clk;
end
end
// reset trigger
initial begin
#10 rstn <= 0;
repeat(10) @(posedge clk);
rstn <= 1;
end
chnl_intf chnl0_if(.*);
chnl_intf chnl1_if(.*);
chnl_intf chnl2_if(.*);
chnl_initiator chnl0_init;
chnl_initiator chnl1_init;
chnl_initiator chnl2_init;
chnl_generator chnl0_gen;
chnl_generator chnl1_gen;
chnl_generator chnl2_gen;
initial begin
// USER TODO 3.1
// instantiate the components chn0/1/2_init chnl0/1/2_gen
chnl0_init = new("chnl0_init");
chnl1_init = new("chnl1_init");
chnl2_init = new("chnl2_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
chnl0_init.set_interface(chnl0_if);
chnl1_init.set_interface(chnl1_if);
chnl2_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
// each channel send data with idle_cycles inside [1:3]
// each channel send out 200 data
// then to finish the test
task automatic basic_test();
chnl0_init.set_idle_cycles($urandom_range(1, 3));
chnl1_init.set_idle_cycles($urandom_range(1, 3));
chnl2_init.set_idle_cycles($urandom_range(1, 3));
$display("basic_test initialized components");
wait (rstn === 1'b1);
repeat(5) @(posedge clk);
$display("basic_test started testing DUT");
// Please check the SV book for fork-join basic knowledge
// and get understood it is for parallel thread running
fork
repeat(100) chnl0_init.chnl_write(chnl0_gen.get_trans());
repeat(100) chnl1_init.chnl_write(chnl1_gen.get_trans());
repeat(100) chnl2_init.chnl_write(chnl2_gen.get_trans());
join
$display("basic_test finished testing DUT");
endtask
// USER TODO 2.1
// each channel send data with idle_cycles == 0
// each channel send out 500 data
// then to finish the test
task automatic burst_test();
chnl0_init.set_idle_cycles(0);
chnl1_init.set_idle_cycles(0);
chnl2_init.set_idle_cycles(0);
$display("basic_test initialized components");
wait (rstn === 1'b1);
repeat(5) @(posedge clk);
fork
begin
repeat(500) chnl0_init.chnl_write(chnl0_gen.get_trans());
chnl0_init.chnl_idle();
end
begin
repeat(500) chnl1_init.chnl_write(chnl1_gen.get_trans());
chnl1_init.chnl_idle();
end
begin
repeat(500) chnl2_init.chnl_write(chnl2_gen.get_trans());
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
$display("basic_test finished testing DUT");
endtask
// USER TODO 2.2
// The test should be immediately finished when all of channels
// have been reached fifo full state, but not all reaching
// fifo full at the same time
task automatic fifo_full_test();
chnl0_init.set_idle_cycles(0);
chnl1_init.set_idle_cycles(0);
chnl2_init.set_idle_cycles(0);
$display("fifo_full_test initialized components");
fork: all_run
forever chnl0_init.chnl_write(chnl0_gen.get_trans());
forever chnl1_init.chnl_write(chnl1_gen.get_trans());
forever chnl2_init.chnl_write(chnl2_gen.get_trans());
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_margin == 0);
wait(chnl1_init.intf.ch_margin == 0);
wait(chnl2_init.intf.ch_margin == 0);
join
$display("fifo_full_test : fifo have get all data");
$display("fifo_full_test: stop 3 initiators running");
disable all_run;
$display("fifo_full_test: have stoped 3 initiators running");
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");
$display("fifo_full_test :fifo have sent all data to arbiter");
endtask
endmodule
TB4 chnl_trans 用来封装chnl_generator 产生的数据
共有类 :chnl_trans chnl_initiator chnl_generator chnl_agent chnl_root_test chnl_basic_test chnl_burst_test chnl_fifo_full_test
所有类放在一个package里, chnl_initiator和chnl_generator在chnl_agent里例化
`timescale 1ns/1ps
interface chnl_intf(input clk, input rstn);
logic [31:0] ch_data;
logic ch_valid;
logic ch_ready;
logic [ 5:0] ch_margin;
clocking drv_ck @(posedge clk);
default input #1ns output #1ns;
output ch_data, ch_valid;
input ch_ready, ch_margin;
endclocking
endinterface
package chnl_pkg;
class chnl_trans;
int data;
int id;
int num;
endclass: chnl_trans
class chnl_initiator;
local string name;
local int idle_cycles;
local virtual chnl_intf intf;
function new(string name = "chnl_initiator");
this.name = name;
this.idle_cycles = 1;
endfunction
function void set_idle_cycles(int n);
this.idle_cycles = n;
endfunction
function void set_name(string s);
this.name = s;
endfunction
function void set_interface(virtual chnl_intf intf);
if(intf == null)
$error("interface handle is NULL, please check if target interface has been intantiated");
else
this.intf = intf;
endfunction
task chnl_write(input chnl_trans t);
@(posedge intf.clk);
// USER TODO 1.1
// Please use the clocking drv_ck of chnl_intf to drive data
intf.drv_ck.ch_valid <= 1;
intf.drv_ck.ch_data <= t.data;
wait(intf.ch_ready === 'b1);
$display("%t channel initiator [%s] sent data %x", $time, name, t.data);
// USER TODO 1.2
// Apply variable idle_cycles and decide how many idle cycles to be
// inserted between two sequential data
repeat (this.idle_cycles)
chnl_idle();
endtask
task chnl_idle();
@(posedge intf.clk);
// USER TODO 1.1
// Please use the clocking drv_ck of chnl_intf to drive data
intf.drv_ck.ch_valid <= 0;
intf.drv_ck.ch_data <= 0;
endtask
endclass: chnl_initiator
class chnl_generator;
chnl_trans trans[$];
int num;
int id;
function new(int n);
this.id = n;
this.num = 0;
endfunction
function chnl_trans get_trans();
chnl_trans t = new();
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: chnl_generator
class chnl_agent;
chnl_generator gen;
chnl_initiator init;
local int ntrans;
virtual chnl_intf vif;
function new(string name = "chnl_agent", int id = 0, int ntrans = 1);
this.gen = new(id);
this.init = new(name);
this.ntrans = ntrans;
endfunction
function void set_ntrans(int n);
this.ntrans = n;
endfunction
function void set_interface(virtual chnl_intf vif);
this.vif = vif;
init.set_interface(vif);
endfunction
task run();
repeat(this.ntrans) this.init.chnl_write(this.gen.get_trans());
this.init.chnl_idle(); // set idle after all data sent out
endtask
endclass: chnl_agent
class chnl_root_test;
chnl_agent agent[3];
protected string name;
function new(int ntrans = 100, string name = "chnl_root_test");
foreach(agent[i]) begin
this.agent[i] = new($sformatf("chnl_agent%0d",i), i, ntrans);
end
this.name = name;
$display("%s instantiate objects", this.name);
endfunction
task run();
$display("%s started testing DUT", this.name);
fork
agent[0].run();
agent[1].run();
agent[2].run();
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
function void set_interface(virtual chnl_intf ch0_vif, virtual chnl_intf ch1_vif, virtual chnl_intf ch2_vif);
agent[0].set_interface(ch0_vif);
agent[1].set_interface(ch1_vif);
agent[2].set_interface(ch2_vif);
endfunction
endclass
// each channel send data with idle_cycles inside [1:3]
// each channel send out 200 data
// then to finish the test
class chnl_basic_test extends chnl_root_test;
function new(int ntrans = 200, string name = "chnl_basic_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
endclass: chnl_basic_test
// USER TODO 4.2
// Refer to chnl_basic_test, and extend another 2 tests
// chnl_burst_test, chnl_fifo_full_test
// each channel send data with idle_cycles == 0
// each channel send out 500 data
// then to finish the test
class chnl_burst_test extends chnl_root_test;
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
// USER TODO 4.2
// The test should be immediately finished when all of channels
// have been reached fifo full state, but not all reaching
// fifo full at the same time
class chnl_fifo_full_test extends chnl_root_test;
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(0);
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 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 been 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
endpackage: chnl_pkg
module tb4;
logic clk;
logic rstn;
logic [31:0] mcdt_data;
logic mcdt_val;
logic [ 1:0] mcdt_id;
mcdt dut(
.clk_i (clk )
,.rstn_i (rstn )
,.ch0_data_i (chnl0_if.ch_data )
,.ch0_valid_i (chnl0_if.ch_valid )
,.ch0_ready_o (chnl0_if.ch_ready )
,.ch0_margin_o(chnl0_if.ch_margin )
,.ch1_data_i (chnl1_if.ch_data )
,.ch1_valid_i (chnl1_if.ch_valid )
,.ch1_ready_o (chnl1_if.ch_ready )
,.ch1_margin_o(chnl1_if.ch_margin )
,.ch2_data_i (chnl2_if.ch_data )
,.ch2_valid_i (chnl2_if.ch_valid )
,.ch2_ready_o (chnl2_if.ch_ready )
,.ch2_margin_o(chnl2_if.ch_margin )
,.mcdt_data_o (mcdt_data )
,.mcdt_val_o (mcdt_val )
,.mcdt_id_o (mcdt_id )
);
// clock generation
initial begin
clk <= 0;
forever begin
#5 clk <= !clk;
end
end
// reset trigger
initial begin
#10 rstn <= 0;
repeat(10) @(posedge clk);
rstn <= 1;
end
import chnl_pkg::*;
// USER TODO 4.1
// import defined class from chnl_pkg
chnl_intf chnl0_if(.*);
chnl_intf chnl1_if(.*);
chnl_intf chnl2_if(.*);
chnl_basic_test basic_test;
chnl_burst_test burst_test;
chnl_fifo_full_test fifo_full_test;
initial begin
// USER TODO 4.3
// Instantiate the three test environment
basic_test = new();
burst_test = new();
fifo_full_test = new();
// USER TODO 4.4
// assign the interface handle to each chnl_initiator objects
basic_test.set_interface(chnl0_if, chnl1_if, chnl2_if);
burst_test.set_interface(chnl0_if, chnl1_if, chnl2_if);
fifo_full_test.set_interface(chnl0_if, chnl1_if, chnl2_if);
// USER TODO 4.5
// START TESTs
basic_test.run();
burst_test.run();
fifo_full_test.run();
$display("*****************all of tests have been finished********************");
$finish();
end
endmodule