我错了。不立flag,不定期更新~
前面几次推送已经给出了FIFO的RTL综合设计和SV写法的ref模型
带选通信号的同步FIFO(重发)
带选通信号的同步FIFO(可综合RTL设计)
本次的Testbench就是基于这两次的代码,进行验证。
Testbench的常见组成模块如下,由复位、产生、发送、接收、计分板比对几个模块组成。
本次验证代码就是通过给上述两个FIFO发送相同的信号与指令内容,通过把两个FIFO的输出发送到check task中进行比对,确定RTL写法与时序是否正确,看其是否可以实现正确的功能。
首先要连接DUT模块和TB模块,那么使用interface接口进行连接。
一般来说,我们在接口中使用时钟块去同步TB中的信号,确定端口方向。
代码语言:javascript复制`timescale 1ns / 100ps
//******************************************************************
// Author:SJTU_chen
// Date: 2019/10/26
// Version: v1.0
// Module Name: fifo-interface
// Project Name: SystemVerilog Lab1
//*******************************************************************
interface fifo_io(input bit clock);
logic reset_n,valid_in,valid_out,valid_out1,ready_in,ready_in1;
logic [63:0] data_in;
logic [1:0] wstrb;
logic [31:0] data_out,data_out1;
clocking cb @(posedge clock);
default input #1ns output #1ns;
output reset_n;
output valid_in;
output data_in;
output wstrb;
input valid_out,valid_out1;
input data_out,data_out1;
input ready_in,ready_in1;
endclocking: cb
modport TB(clocking cb, output reset_n);
endinterface:fifo_io
在顶层模块中把其连接起来,部分代码如下:
代码语言:javascript复制
`timescale 1ns / 100ps
//******************************************************************
// Author:SJTU_chen
// Date: 2019/10/26
// Version: v1.0
// Module Name: fifo-testbench_top
// Project Name: SystemVerilog Lab1
//*******************************************************************
module fifo_test_top();
parameter simulation_cycle = 10;
bit SystemClock = 0;
fifo_io top_io(SystemClock);
test t(top_io);
fifo_dut fifo_dut_inst(
.clock(top_io.clock),
.reset_n(top_io.reset_n),
.valid_in(top_io.valid_in),
.wstrb(top_io.wstrb),
.data_in(top_io.data_in),
.valid_out(top_io.valid_out),
.ready_in(top_io.ready_in),
.data_out(top_io.data_out)
);
fifo_ref fifo_ref_inst(
.clock(top_io.clock),
.reset_n(top_io.reset_n),
.valid_in(top_io.valid_in),
.wstrb(top_io.wstrb),
.data_in(top_io.data_in),
.valid_out(top_io.valid_out1),
.ready_in(top_io.ready_in1),
.data_out(top_io.data_out1)
);
always begin
#(simulation_cycle/2) SystemClock = ~SystemClock;
end
endmodule
接下来就是编写TB模块了,如上图所示:
首先我们编写的是复位reset task模块:
代码语言:javascript复制 //task reset
task reset();
fi_io.reset_n = 1'b0;
fi_io.cb.wstrb <= '0;
fi_io.cb.valid_in <= '1;
fi_io.cb.data_in <= '0;
repeat(2) @fi_io.cb;
fi_io.cb.reset_n <= 1'b1;
repeat(15) @fi_io.cb;
endtask: reset
上述代码请仔细看,有点儿意思,很多同学的写法不是这样的,这个在Soc设计方法学课程中会讲到~
接下来就是gen task
代码语言:javascript复制//task gen
task gen();
send_data.delete();
wstrb_quene.delete();
repeat(120)
begin
wstrb_quene.push_back({$urandom});
send_data.push_back({$urandom,$urandom});
end
endtask: gen
发送 send task:
代码语言:javascript复制 task send();
send_payload();
endtask:send
task send_payload();
// static int count = 0;
static int pkts_checked = 0;
while(send_data.size() != 0)
begin
if (pkts_checked < 80)
begin
fi_io.cb.data_in <= send_data.pop_front();
fi_io.cb.wstrb <= wstrb_quene.pop_front();
fi_io.cb.valid_in <= $urandom;
// count ;
end
else begin
fi_io.cb.data_in <= send_data.pop_front();
fi_io.cb.wstrb <= 2'b11;
fi_io.cb.valid_in <= 1'b1;
// count ;
end
end
endtask:send_payload
接收 task
代码语言:javascript复制 //task recv_dut
task recv_dut();
get_payload_fromdut();
endtask: recv_dut
//task recv_ref
task recv_ref();
get_payload_fromref();
endtask: recv_ref
比对模块部分代码:
代码语言:javascript复制 function void check();
string message;
static int pkts_checked = 0;
if (!compare(message)) begin
$display("n%mn[ERROR]%t Packet #
%sn", $realtime, pkts_checked , message);
$finish;
end
$display("[NOTE]%t Packet #
%s", $realtime, pkts_checked , message);
endfunction: check
通过以上比对,我们就可以看出dut设计是否正确,请注意,前提条件是保证我们设计的ref模型是没问题的。
最终的仿真截图如下:
下次,我们讲讲怎么使用面向对象的结构去验证~