package rt_test_pkg;
class rt_packet;
rand bit[3:0] src;
rand bit[3:0] dst;
rand bit[7:0] data[];
constraint pkt_cstr {
src inside {[0:15]};
dst inside {[0:15]};
soft data.size() inside {[0:31]};
};
function new();
endfunction
function void set_members(bit[3:0] src, bit[3:0] dst, bit[7:0] data[]);
this.src = src;
this.dst = dst;
this.data = data;
endfunction
function string sprint();
sprint = {sprint,$sformatf("src =%0d,\n",src)};
sprint = {sprint,$sformatf("dst =%0d,\n",dst)};
sprint = {sprint,$sformatf("data len =%0d,\n",data.size())};
foreach(data[i])
sprint = {sprint,$sformatf("data[%d] ='h%0x,\n",i,data[i])};
endfunction
function bit compare(rt_packet p);
if(this.dst==p.dst && this.data==p.data) begin
compare = 1;
end
else begin
compare = 0;
end
endfunction
endclass
class rt_stimulator;
virtual rt_io io;
mailbox #(rt_packet) pkts;
mailbox #(rt_packet) ch_pkts[16];
int src_chal_status[int];
function new();
foreach(ch_pkts[i])
ch_pkts[i] = new(1);
endfunction
task distribute_pkt();
rt_packet p;
forever begin
pkts.get(p);
ch_pkts[p.src].put(p);
end
endtask
task drive_reset_proc();
forever begin
@(negedge io.rstn);
io.din <= 0;
io.frame_n <= '1;
io.valid_n <= '1;
end
endtask
task drive_a_chal_proc(rt_packet p);
for(int i = 0;i<4;i++) begin
@(posedge io.clk);
io.din[p.src] <= p.dst[i];
io.valid_n[p.src] <= 1'b0;
io.frame_n[p.src] <= 1'b0;
end
for(int i = 0;i<5;i++) begin
@(posedge io.clk);
io.din[p.src] <= 1'b1;
io.valid_n[p.src] <= 1'b1;
io.frame_n[p.src] <= 1'b0;
end
foreach(p.data[id]) begin
for(int i = 0;i<8;i++) begin
@(posedge io.clk);
io.din[p.src] <= p.data[id][i];
io.valid_n[p.src] <= 1'b0;
if(id == p.data.size()-1 && i == 7)
io.frame_n[p.src] <= 1'b1;
else
io.frame_n[p.src] <= 1'b0;
end
end
@(posedge io.clk);
io.din[0] <= 1'b0;
io.valid_n[p.src] <= 1'b1;
io.frame_n[p.src] <= 1'b1;
$display("@%0t [stimulaor] finished \n%s",$time,p.sprint());
endtask
task wait_src_chanl_avail(rt_packet p);
if(!src_chal_status.exists(p.src))
src_chal_status[p.src] = p.dst;
else if(src_chal_status[p.src] >= 0)
wait(src_chal_status[p.src] == -1);
endtask
function void set_src_chanl_avail(rt_packet p);
src_chal_status[p.src] = -1;
endfunction
task drive_chanl_proc();
@(negedge io.rstn);
repeat(10) @(posedge io.clk);
foreach(ch_pkts[i]) begin
automatic int id = i;
automatic rt_packet p;
fork
forever begin
ch_pkts[id].get(p);
drive_a_chal_proc(p);
end
join_none
end
endtask
task run();
fork
drive_reset_proc();
distribute_pkt();
drive_chanl_proc();
join_none
endtask
endclass
class rt_monitor;
virtual rt_io io;
rt_packet in_pkts[16][$];
rt_packet out_pkts[16][$];
task automatic moni_chal_in(bit[3:0] id);
rt_packet pkt;
forever begin
pkt = new();
pkt.src = id;
@(negedge io.frame_n[id]);
for(int i=0;i<4;i++) begin
@(posedge io.clk);
pkt.dst[i] = io.din[id];
end
repeat(5) @(negedge io.clk);
do
begin
pkt.data = new[pkt.data.size+1] (pkt.data);
for(int i=0;i<8;i++) begin
@(negedge io.clk);
pkt.data[pkt.data.size-1][i] = io.din[id];
end
end
while(!io.frame_n[id]);
in_pkts[id].push_back(pkt);
$display("@%0t [monitor-in ]%d train finished\n%s ", $time, id, pkt.sprint());
end
endtask
task automatic moni_chal_out(bit[3:0] id);
rt_packet pkt;
forever begin
pkt = new();
pkt.src = 0;
pkt.dst = id;
@(negedge io.frameo_n[id]);
do
begin
pkt.data = new[pkt.data.size+1](pkt.data);
for(int i=0;i<8;i++) begin
@(negedge io.clk iff !io.valido_n[id]);
pkt.data[pkt.data.size-1][i] = io.dout[id];
end
end
while(io.frameo_n[id] == 0);
out_pkts[id].push_back(pkt);
$display("@%0t [monitor-out]%d train finished\n%s",$time,id,pkt.sprint());
end
endtask
task moni_chanl();
foreach(in_pkts[i]) begin
automatic int chanl_id = i;
fork
moni_chal_in(chanl_id);
moni_chal_out(chanl_id);
join_none
end
endtask
task run();
fork
moni_chanl();
join_none
endtask
endclass
class rt_generator;
mailbox #(rt_packet) pkts;
function new();
pkts = new();
endfunction
task put_pkt(input rt_packet p);
pkts.put(p);
endtask
task get_pkt(output rt_packet p);
pkts.get(p);
endtask
function void gen_pkt(int src = -1, int dst = -1);
endfunction
task run();
endtask
endclass
class check;
int unsigned compared_counter;
int unsigned error_counter;
rt_packet expct_out_pkts[16][$];
rt_monitor moni;
function new();
compared_counter = 0;
error_counter = 0;
endfunction
task do_routing(bit[3:0] id);
rt_packet pkt;
forever begin
wait(moni.in_pkts[id].size() > 0);
pkt = moni.in_pkts[id].pop_front();
expct_out_pkts[pkt.dst].push_back(pkt);
end
endtask
task do_compare(bit[3:0] id);
rt_packet exp_pkt,act_pkt;
forever begin
wait(moni.out_pkts[id].size()>0 && expct_out_pkts[id].size()>0);
exp_pkt = expct_out_pkts[id].pop_front();
act_pkt = moni.out_pkts[id].pop_front();
if(exp_pkt.compare(act_pkt)) begin
$display("[check] chanl-%d compare successed with data= \n%s\n",id,act_pkt.sprint());
end
else begin
error_counter++;
$display("[check] chanl-%d compare failure with expct/actual= \n%s\n%s \n",id,exp_pkt.sprint(),act_pkt.sprint());
end
compared_counter++;
end
endtask
function void report(string name);
$display("[report]");
$display("TOTAL COMPARED %d times",compared_counter);
if(error_counter == 0) begin
$display("TEST %s PASSED!",name);
end
else begin
$display("TEST %s FAILED!",name);
$display("TOTAL ERROE %d times",error_counter);
end
endfunction
function bit check_data_buffer();
check_data_buffer = 1;
foreach(expct_out_pkts[id]) begin
if(expct_out_pkts[id].size() != 0) begin
$display("expct_out_pkts[%d] still has %d data",id,expct_out_pkts[id].size());
end
end
foreach(moni.out_pkts[id]) begin
if(moni.out_pkts[id].size() != 0) begin
$display("moni.out_pkts[%d] still has %d data",id,moni.out_pkts[id].size());
end
end
endfunction
task run();
foreach(expct_out_pkts[i]) begin
automatic int chanl_id = i;
fork
do_routing(chanl_id);
do_compare(chanl_id);
join_none
end
endtask
endclass
class rt_env;
rt_generator gen;
rt_stimulator stim;
rt_monitor monitor;
check chk;
function new(virtual rt_io io);
stim = new();
gen = new();
monitor = new();
chk = new();
stim.io = io;
monitor.io = io;
chk.moni = monitor;
stim.pkts = gen.pkts;
endfunction
function void report(string name);
chk.report(name);
endfunction
task run();
rt_packet p;
fork
stim.run();
gen.run();
monitor.run();
chk.run();
join_none
endtask
endclass
class rt_base_test;
rt_env env;
bit gen_trans_done = 0;
int unsigned wait_trans_time_us = 20;
string name;
function new(virtual rt_io io,string name = "rt_base_test");
env = new(io);
this.name = name;
endfunction
function void set_gen_trans_done(bit done);
gen_trans_done = done;
endfunction
task report(string name);
wait(gen_trans_done == 1);
#(wait_trans_time_us * 1us);
env.report(name);
$finish();
endtask
task run();
$display("%s is start",name);
fork
env.run();
report(name);
join_none
endtask
endclass
class rt_single_chanl_test extends rt_base_test;
function new(virtual rt_io io,string name = "rt_single_chanl_test");
super.new(io,name);
endfunction
task run();
rt_packet p;
super.run();
p = new();
p.randomize();
env.gen.put_pkt(p);
set_gen_trans_done(1);
endtask
endclass
class rt_two_chanl_test extends rt_base_test;
function new(virtual rt_io io,string name = "rt_two_chanl_test");
super.new(io,name);
endfunction
endclass
class rt_two_ch_same_chout_test extends rt_two_chanl_test;
function new(virtual rt_io io,string name = "rt_two_ch_same_chout_test");
super.new(io,name);
endfunction
endclass
class rt_multi_chanl_test extends rt_base_test;
rand bit[0:3] p_count;
constraint cstr_p_count {p_count inside {[1:16]};};
function new(virtual rt_io io,string name = "rt_multi_chanl_test");
super.new(io,name);
endfunction
task run();
rt_packet p;
super.run();
randomize(p_count);
$display("p num = %d",p_count);
for(int i = 0;i<p_count;i++) begin
p = new();
p.randomize();
env.gen.put_pkt(p);
end
set_gen_trans_done(1);
endtask
endclass
class rt_full_chanl_test extends rt_multi_chanl_test;
function new(virtual rt_io io,string name = "rt_full_chanl_test");
super.new(io,name);
endfunction
endclass
endpackage
interface rt_io;
logic clk;
logic rstn;
logic[15:0] din;
logic[15:0] frame_n;
logic[15:0] valid_n;
logic[15:0] dout;
logic[15:0] valido_n;
logic[15:0] busy_n;
logic[15:0] frameo_n;
endinterface
module tb1;
import rt_test_pkg::*;
var bit clk,rstn;
initial begin
forever #5 clk = ~clk;
end
initial begin
#5 rstn <= 1;
#10 rstn <= 0;
#10 rstn <= 1;
end
rt_io io();
assign io.clk = clk;
assign io.rstn = rstn;
router dut(
.reset_n(io.rstn),
.clock(io.clk),
.frame_n(io.frame_n),
.valid_n(io.valid_n),
.din(io.din),
.dout(io.dout),
.busy_n(io.busy_n),
.valido_n(io.valido_n),
.frameo_n(io.frameo_n)
);
rt_single_chanl_test single_chanl_test;
rt_multi_chanl_test multi_chanl_test;
rt_base_test tests[string];
initial begin:instance_inital_proc
string name;
single_chanl_test = new(io);
multi_chanl_test = new(io);
name = "multi_chanl_test";
case(name)
"single_chanl_test":single_chanl_test.run();
"multi_chanl_test":multi_chanl_test.run();
default:$fatal("error test name %d is invalid, please specify a valid name",name);
endcase
end
endmodule