写了个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改更小后问题解决。