route_io.sv
在lab3中的router_io.sv中进行的接口的声明,指明了信号的输入和输出的方向,以及一些延时的时序信息。
interface router_io(input bit clock);
//声明信号
logic reset_n;
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;
//在时钟块中,声明仿真延迟的时序信息,以及信号的方向
//即是输入还是输出
clocking cb @(posedge clock);
default input #1 output #1;
output reset_n;
output din;
output frame_n;
output valid_n;
input dout;
input valido_n;
input busy_n;
input frameo_n;
endclocking
modport TB(clocking cb, output reset_n);
endinterface
test.sv
代码里有详细的注释
program automatic test(router_io.TB rtr_io);
int run_for_n_packets ; //测试n个数据包
bit [3:0] sa ; //源地址
bit [3:0] da ; //目标地址
logic [7:0] payload[$] ; //预期的数据包数据数组
//任务1:声明一个队列来存储采样的数据
logic [7:0] pkt2cmp_payload[$] ; //实际数据包数据数组
initial begin
$vcdpluson;
//任务2:发送2000个数据包,需要在任务中执行
run_for_n_packets = 2000;
reset(); //全局复位任务
repeat(run_for_n_packets) begin
gen(); //产生数据包
//任务3:同时执行发送和接收数据包线程
fork
send(); //发送数据包
recv(); //接收数据包
join
check(); //检查
end
end
//reset的任务
task reset();
rtr_io.reset_n = 1'b0;
rtr_io.frame_n <= '1;
rtr_io.valid_n <= '1;
##2 rtr_io.cb.reset_n <= 1'b1;
endtask:reset
//gen的任务
task gen();
//任务4:随机产生sa and da
sa = $urandom;
da = $urandom;
payload.delete(); //删除过去的数据
repeat($urandom_range(4,2))
payload.push_back($urandom);
endtask:gen
//send任务
task send();
send_addrs(); //发送数据
send_pad();
send_payload();
endtask: gen
//发送地址
task send_addrs;
rtr_io.cb.frame_n[sa] <= 1'b0; //一个数据包的开始
for(int i = 0; i < 4; i++) begin
rtr_io.cb.din[sa] <= da[i]; //da的每一位
@(rtr_io.cb); //等待时钟的上升沿
end
endtask
//发送pad
task send_pad();
rtr_io.cb.frame_n[sa] <= 1'b0;
rtr_io.cb.din[sa] <= 1'b1;
rtr_io.cb.valid_n[sa] <= 1'b1;
repeat(5) @(rtr_io.cb);
endtask
//发送payload
task send_payload();
foreach(payload[index])
for(int i=0; i<8; i++) begin
rtr_io.cb.din[sa] <= payload[index][i]; //发送每一位
rtr_io.cb.valid_n[sa] <= 1'b0; //驱动一个有效位
//下面语句当整个传输完成时,拉高frame_n[sa]
rtr_io.cb.frame_n[sa] <= ((i == 7) && (index == (payload.size()-1)));
@(rtr_io.cb);
end
endtask
//任务4:声明接收任务
task recv();
//调用任务get_payload来检索有效负载
get_payload();
endtask
task get_payload();
//删除pkt2cmp_payload的内容
pkt2cmp_payload.delete();
fork
begin: wd_timer_fork
fork: frameo_wd_timer
@(negedge rtr_io.cb.frameo_n[da]); //一个线程:等待下降沿
begin //另一个线程:检测超时
repeat(1000) @(rtr_io.cb);
$display("\n%m\n[ERROR]%t Frame signal timed out!\n", $realtime);
$finish;
end
join_any: frameo_wd_timer
disable fork;
end: wd_timer_fork
join
//任务继续,采样router的输出
//直到frame的被检测到,循环结束
forever begin
logic [7:0] datam;
for(int i = 0; i<8; i++) begin
if(!rtr_io.cb.valido_n[da]) //数据有效
datum[i++] = rtr_io.cb.dout[da];
if(rtr_io.cb.frameo_n[da]) //一个字节传输完成
if(i==8) begin //byte alligned
pkt2cmp_payload.push_back(datum);//加入队列
return; //done with payload
end
else begin
$display("\n%m\n[ERROR]%t Packet payload not byte aligned!\n", $realtime);
$finish;
end
@(rtr_io.cb);
end
pkt2cmp_payload.push_back(datum);
end
endtask
//compare function 比较payload[$]和pkt2cmp_payload[$]
//如果大小不匹配
//数据不匹配 使用==
function bit compare(ref string message);
if(payload.size() != pkt2cmp_payload.size()) begin
message = "Payload size Mismatch:\n";
message = { message, $sformatf("payload.size() = %0d, pkt2cmp_payload.size() = %0d\n", payload.size(), pkt2cmp_payload.size()) };
return (0);
end
if(payload == pkt2cmp_payload) ;
else begin
message = "Payload Content Mismatch:\n";
message = { message, $sformatf("Packet Sent: %p\nPkt Received: %p", payload, pkt2cmp_payload) };
return (0);
end
message = "Successfully Compared";
return(1);
endfunction: compare
task check();
string message;
static int pkts_checked = 0;
if (!compare(message)) begin
$display("\n%m\n[ERROR]%t Packet #%0d %s\n", $realtime, pkts_checked, message);
$finish;
end
$display("[NOTE]%t Packet #%0d %s", $realtime, pkts_checked++, message);
endtask: check
endprogram