写了个spi module,怎么测都不过,没办法,回头来做行为仿真。
学习写testbench使用的是下面的文档,来自某FPGA制造商文档:
/Files/pied/verilog_testbench_primer.pdf
区别与verilog HDL代码,主要留意以下内容:
1,语言本身支持的特征和可综合的代码是两回事,不是所有verilog语言都可以转化为硬件的。
2,testbench作为top module,不需要任何输入和输出。
3,在testbench module中将要测试的模块例化为dut(名字可以任起),input要是reg类型,output要是wire类型,inout是reg。
4,initial和always是同时执行的,只是initial只执行一次。
5,通过在initial里面添加语句,对 dut进行各种输入设置,以达到测试dut的目的。
6,必要时在测试的module,或者是testbench的代码中添加$display($time,"<value of BufferPort :%h>", BufferPort); 来查看变量值。
下面是给俺的SPI module写的testbench,参考上面的pdf写的:
module controller();
reg rst_l;
reg clk_100;
reg sdi;
reg sck;
reg cs;
reg TransFlag;
reg [ 0: 7] trsData;
wire [ 0: 7] rcvData;
wire TransEndFlag;
wire ReceiveFlag;
wire sdo;
reg [ 4: 0] i;
reg [ 4: 0] counter;
spi dut( .rst(rst_l),
.clk(clk_100),
.sdi(sdi),
.sdo(sdo),
.sck(sck),
.cs(cs),
.trsData(trsData),
.rcvData(rcvData),
.TransFlag(TransFlag),
.TransEndFlag(TransEndFlag),
.ReceiveFlag(ReceiveFlag)
);
// test 'read'&'read' from reg 0x0000 of ad9865
always # 5 clk_100 = ~clk_100;
initial begin
$display($ time, " It's my first test bench! ");
clk_100 = 1 ' b0;
counter = 3 ' b000;
$display($ time, " coming out of reset! ");
// initiate spi input
sck = 1 ' b0;
cs = 1 ' b1;
sdi = 1 ' b0;
rst_l = 1 ' b0;
# 20 rst_l = 1 ' b1;
// send parametes set
TransFlag = 1 ' b1;
trsData = 8 ' b0101_0101;
// begin send test
cs = 1 ' b0;
wait (TransEndFlag == 1 ' b1);
$display($ time, " send processing is finished! ");
TransFlag = 1 ' b0;
cs = 1 ' b1;
// begin receive test
cs = 1 ' b0;
for (i = 8; i != 0; i=i- 1) sdi = 1;
wait (ReceiveFlag == 1 ' b1);
cs = 1;
$display($ time, " the data received :%h ", rcvData);
end
always @( posedge clk_100) begin
if(sdo == 1)
$display($ time, " posedge_ of sdo comes :%h ", sdo);
if(counter == 11) begin
sck =~sck;
counter = 3 ' b000;
end
else begin
counter = counter + 1 ' b1;
end
end
endmodule
reg rst_l;
reg clk_100;
reg sdi;
reg sck;
reg cs;
reg TransFlag;
reg [ 0: 7] trsData;
wire [ 0: 7] rcvData;
wire TransEndFlag;
wire ReceiveFlag;
wire sdo;
reg [ 4: 0] i;
reg [ 4: 0] counter;
spi dut( .rst(rst_l),
.clk(clk_100),
.sdi(sdi),
.sdo(sdo),
.sck(sck),
.cs(cs),
.trsData(trsData),
.rcvData(rcvData),
.TransFlag(TransFlag),
.TransEndFlag(TransEndFlag),
.ReceiveFlag(ReceiveFlag)
);
// test 'read'&'read' from reg 0x0000 of ad9865
always # 5 clk_100 = ~clk_100;
initial begin
$display($ time, " It's my first test bench! ");
clk_100 = 1 ' b0;
counter = 3 ' b000;
$display($ time, " coming out of reset! ");
// initiate spi input
sck = 1 ' b0;
cs = 1 ' b1;
sdi = 1 ' b0;
rst_l = 1 ' b0;
# 20 rst_l = 1 ' b1;
// send parametes set
TransFlag = 1 ' b1;
trsData = 8 ' b0101_0101;
// begin send test
cs = 1 ' b0;
wait (TransEndFlag == 1 ' b1);
$display($ time, " send processing is finished! ");
TransFlag = 1 ' b0;
cs = 1 ' b1;
// begin receive test
cs = 1 ' b0;
for (i = 8; i != 0; i=i- 1) sdi = 1;
wait (ReceiveFlag == 1 ' b1);
cs = 1;
$display($ time, " the data received :%h ", rcvData);
end
always @( posedge clk_100) begin
if(sdo == 1)
$display($ time, " posedge_ of sdo comes :%h ", sdo);
if(counter == 11) begin
sck =~sck;
counter = 3 ' b000;
end
else begin
counter = counter + 1 ' b1;
end
end
endmodule
再三检查SPI的逻辑,最后发现,我给的sck是clk的十分之一,而SPI module里面用的给端口采样的频率也是clk的十分之一,所以老是采样不成功;把sck改更小后问题解决。