首先编写被测试测RTL代码:一个简单的两输入 1bit 数据相与后通过寄存器输出。
//========================================================================
// module_name.v :rtl_template.v
// Created on :2023-9-27
// Author :YprgDay
// Description :用于Verilog仿真文件中的阻塞和非阻塞问题探讨
//========================================================================
module test
(
//=========================< Port Name >==============================
//input
input wire sys_clk ,
input wire sys_rst_n ,
input wire in1 ,
input wire in2 ,
//output
output reg out
);
//=========================< Always block >===========================
//sequential logic
//block description:用于两输入的与
always @(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0)begin
out <= 1'b0 ;
end
else begin
out <= in1 & in2 ;
end
end
endmodule
仿真代码:
`timescale 1ns/1ns
module tb_test();
reg sys_clk;
reg sys_rst_n;
reg in1;
reg in2;
wire out;
//初始化
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
in1 <= 1'b0;
in2 <= 1'b0;
#200
sys_rst_n <= 1'b1;
end
//产生 50Mhz 的时钟
always #10 sys_clk = ~sys_clk;
always #10 in1 <= {$random};
always #10 in2 <= {$random};
//------------------------test_isnt------------------------
test test_inst(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.in1 (in1 ), //input in1
.in2 (in2 ), //input in2
.out (out ) //output out
);
endmodule
仿真波形效果:
仿真结果同 RTL 逻辑代码实现的功能一致。
此处是220ns后两个时钟周期高,340ns后一个时钟周期高。同时还测试了该情况下的“|”、“+”、“^”运算均正确。
仿真代码:
`timescale 1ns/1ns
module tb_test();
reg sys_clk;
reg sys_rst_n;
reg in1;
reg in2;
wire out;
//初始化
initial begin
sys_clk <= 1'b1;
sys_rst_n <= 1'b0;
in1 <= 1'b0;
in2 <= 1'b0;
#200
sys_rst_n <= 1'b1;
end
//产生 50Mhz 的时钟
always #10 sys_clk <= ~sys_clk;
always #10 in1 <= {$random};
always #10 in2 <= {$random};
//------------------------test_isnt------------------------
test test_inst(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.in1 (in1 ), //input in1
.in2 (in2 ), //input in2
.out (out ) //output out
);
endmodule
仿真波形效果:
与1.1中相比。此处是200ns后一个时钟周期高,320ns后一个时钟周期高。有错误,同时还测试了该情况下的“|”、“+”、“^”运算均错误。
仿真代码:
`timescale 1ns/1ns
module tb_test();
reg sys_clk;
reg sys_rst_n;
reg in1;
reg in2;
wire out;
//初始化
initial begin
sys_clk = 1'b1;
sys_rst_n = 1'b0;
in1 = 1'b0;
in2 = 1'b0;
#200
sys_rst_n = 1'b1;
end
//产生 50Mhz 的时钟
always #10 sys_clk = ~sys_clk;
always #10 in1 = {$random};
always #10 in2 = {$random};
//------------------------test_isnt------------------------
test test_inst(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.in1 (in1 ), //input in1
.in2 (in2 ), //input in2
.out (out ) //output out
);
endmodule
仿真波形效果:
与1.1中相比。此处是200ns后一个时钟周期高,320ns后一个时钟周期高。有错误,同时还测试了该情况下的“|”、“+”、“^”运算均错误。
仿真代码:
`timescale 1ns/1ns
module tb_test();
reg sys_clk;
reg sys_rst_n;
reg in1;
reg in2;
wire out;
//初始化
initial begin
sys_clk <= 1'b1;
sys_rst_n = 1'b0;
in1 = 1'b0;
in2 = 1'b0;
#200
sys_rst_n = 1'b1;
end
//产生 50Mhz 的时钟
always #10 sys_clk = ~sys_clk;
always #10 in1 <= {$random};
always #10 in2 <= {$random};
//------------------------test_isnt------------------------
test test_inst(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.in1 (in1 ), //input in1
.in2 (in2 ), //input in2
.out (out ) //output out
);
endmodule
仿真波形效果:
与1.1中相比。此处是220ns后两个时钟周期高,340ns后一个时钟周期高,和1.1同,但测试了该情况下的“|”、“+”、“^”运算均有错误。
仿真代码:
`timescale 1ns/1ns
module tb_test();
reg sys_clk;
reg sys_rst_n;
reg in1;
reg in2;
wire out;
//初始化
initial begin
sys_clk = 1'b0;
sys_rst_n <= 1'b0;
in1 <= 1'b0;
in2 <= 1'b0;
#200
sys_rst_n <= 1'b1;
end
//产生 50Mhz 的时钟
always #10 sys_clk = ~sys_clk;
always #10 in1 <= {$random};
always #10 in2 <= {$random};
//------------------------test_isnt------------------------
test test_inst(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.in1 (in1 ), //input in1
.in2 (in2 ), //input in2
.out (out ) //output out
);
endmodule
仿真波形效果:
仿真结果同 RTL 逻辑代码实现的功能一致。
此处是210ns后1个时钟周期高,330ns后一个时钟周期高。同时还测试了该情况下的“|”、“+”、“^”运算均正确。
仿真代码:
`timescale 1ns/1ns
module tb_test();
reg sys_clk;
reg sys_rst_n;
reg in1;
reg in2;
wire out;
//初始化
initial begin
sys_clk <= 1'b0;
sys_rst_n <= 1'b0;
in1 <= 1'b0;
in2 <= 1'b0;
#200
sys_rst_n <= 1'b1;
end
//产生 50Mhz 的时钟
always #10 sys_clk <= ~sys_clk;
always #10 in1 <= {$random};
always #10 in2 <= {$random};
//------------------------test_isnt------------------------
test test_inst(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.in1 (in1 ), //input in1
.in2 (in2 ), //input in2
.out (out ) //output out
);
endmodule
仿真波形效果:
与2.1中相比。此处是210ns后两个时钟周期高,330ns后一个时钟周期高。有错误,同时还测试了该情况下的“|”、“+”、“^”运算均错误。
仿真代码:
`timescale 1ns/1ns
module tb_test();
reg sys_clk;
reg sys_rst_n;
reg in1;
reg in2;
wire out;
//初始化
initial begin
sys_clk = 1'b0;
sys_rst_n = 1'b0;
in1 = 1'b0;
in2 = 1'b0;
#200
sys_rst_n = 1'b1;
end
//产生 50Mhz 的时钟
always #10 sys_clk = ~sys_clk;
always #10 in1 = {$random};
always #10 in2 = {$random};
//------------------------test_isnt------------------------
test test_inst(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.in1 (in1 ), //input in1
.in2 (in2 ), //input in2
.out (out ) //output out
);
endmodule
仿真波形效果:
与2.1中相比。此处是210ns后两个时钟周期高,330ns后一个时钟周期高。有错误,同时还测试了该情况下的“|”、“+”、“^”运算均错误。
仿真代码:
`timescale 1ns/1ns
module tb_test();
reg sys_clk;
reg sys_rst_n;
reg in1;
reg in2;
wire out;
//初始化
initial begin
sys_clk <= 1'b0;
sys_rst_n = 1'b0;
in1 = 1'b0;
in2 = 1'b0;
#200
sys_rst_n = 1'b1;
end
//产生 50Mhz 的时钟
always #10 sys_clk = ~sys_clk;
always #10 in1 = {$random};
always #10 in2 = {$random};
//------------------------test_isnt------------------------
test test_inst(
.sys_clk (sys_clk ), //input sys_clk
.sys_rst_n (sys_rst_n ), //input sys_rst_n
.in1 (in1 ), //input in1
.in2 (in2 ), //input in2
.out (out ) //output out
);
endmodule
仿真波形效果:
与2.1中相比。此处是210ns后两个时钟周期高,330ns后一个时钟周期高。有错误,同时还测试了该情况下的“|”、“+”、“^”运算均错误。
时钟初始值为1’b1或时钟初始值为1’b0的情况下,时钟用“=”赋值,输入信号用“<=”赋值不发生错误,其他情况均有错误出现。
所以推荐在写 Testbench 的时候时钟用“=”赋值,输入信号用“<=”赋值才能够避免这种情况,这种问题的根源其实是产生的数据没有同步时钟的原因,导致产生一些错乱,这种情况在 System Verilog 中就不会差生,这也是 System Verilog 更适合作为仿真验证语言的原因之一。至于时钟的初始值是 0 还是 1 对仿真的正确性影响不大,但是推荐大家把时钟的初始值幅值为 1,方便数据的变化都是在时钟的上升沿进行,和我们的 RTL 代码更接近。
推荐书写方式:
//==========================< Reset block >============================
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
in1 <= 1'b0;
in2 <= 1'b0;
#200
sys_rst_n <= 1'b1;
end
仿真文件中的阻塞和非阻塞