当前位置:首页 > 编程笔记 > 正文
已解决

Verilog仿真文件中的阻塞和非阻塞赋值问题探讨

来自网友在路上 156856提问 提问时间:2023-09-27 21:03:02阅读次数: 56

最佳答案 问答题库568位专家为你答疑解惑

文章目录

  • 测试验证
    • RTL代码
    • 一、时钟初始值为1’b1
      • 1.1、时钟用“=”赋值,输入信号用“<=”赋值(correct)
      • 1.2、时钟和输入信号都用“<=”赋值(error)
      • 1.3、时钟和输入信号都用“=”赋值(error)
      • 1.4、时钟用“<=”赋值,输入信号用“=”赋值(error)
    • 二、时钟初始值为1’b0
      • 2.1、时钟用“=”赋值,输入信号用“<=”赋值(correct)
      • 2.2、时钟和输入信号都用“<=”赋值(error)
      • 2.3、时钟和输入信号都用“=”赋值(error)
      • 2.4、时钟用“<=”赋值,输入信号用“=”赋值(error)
  • 结论
  • 参考资料

在 RTL 代码中我们知道如果表达组合逻辑时使用“=”赋值,表达时序逻辑时使用“<=”赋值,如果我们不按照这种规则来设计往往会得到意想不到的答案。虽然说在 Testbench 中我们对赋值号的要求并不是很在意,使用“=”和“<=”赋值均可,都能够仿真出来结果,且最后不会被综合成实际的电路,不会影响功能。网络上的各种资料教程也各有不同的写法,难道在 Testbench 中随便使用“=”和“<=”赋值真的对测试没有任何影响吗?经过下面的测试验证我们得到了出乎意料的答案。

测试验证

RTL代码

首先编写被测试测RTL代码:一个简单的两输入 1bit 数据相与后通过寄存器输出。

//========================================================================
// 	module_name.v	:rtl_template.v
// 	Created on		:2023-9-27
// 	Author			:YprgDay
// 	Description		:用于Verilog仿真文件中的阻塞和非阻塞问题探讨
//========================================================================
module test
(//=========================< Port Name >==============================//inputinput 		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)	beginif(sys_rst_n == 1'b0)beginout <=	1'b0		;endelse	beginout <=	in1 & in2	;endend	endmodule

一、时钟初始值为1’b1

1.1、时钟用“=”赋值,输入信号用“<=”赋值(correct)

仿真代码:

`timescale 1ns/1nsmodule 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后一个时钟周期高。同时还测试了该情况下的“|”、“+”、“^”运算均正确。

在这里插入图片描述

1.2、时钟和输入信号都用“<=”赋值(error)

仿真代码:

`timescale 1ns/1nsmodule 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后一个时钟周期高。有错误,同时还测试了该情况下的“|”、“+”、“^”运算均错误。

在这里插入图片描述

1.3、时钟和输入信号都用“=”赋值(error)

仿真代码:

`timescale 1ns/1nsmodule 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后一个时钟周期高。有错误,同时还测试了该情况下的“|”、“+”、“^”运算均错误。

在这里插入图片描述

1.4、时钟用“<=”赋值,输入信号用“=”赋值(error)

仿真代码:

`timescale 1ns/1nsmodule 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同,但测试了该情况下的“|”、“+”、“^”运算均有错误。

在这里插入图片描述

二、时钟初始值为1’b0

2.1、时钟用“=”赋值,输入信号用“<=”赋值(correct)

仿真代码:

`timescale 1ns/1nsmodule 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后一个时钟周期高。同时还测试了该情况下的“|”、“+”、“^”运算均正确。

在这里插入图片描述

2.2、时钟和输入信号都用“<=”赋值(error)

仿真代码:

`timescale 1ns/1nsmodule 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后一个时钟周期高。有错误,同时还测试了该情况下的“|”、“+”、“^”运算均错误。

在这里插入图片描述

2.3、时钟和输入信号都用“=”赋值(error)

仿真代码:

`timescale 1ns/1nsmodule 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后一个时钟周期高。有错误,同时还测试了该情况下的“|”、“+”、“^”运算均错误。

在这里插入图片描述

2.4、时钟用“<=”赋值,输入信号用“=”赋值(error)

仿真代码:

`timescale 1ns/1nsmodule 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 beginsys_clk 	 = 1'b1;sys_rst_n 	<= 1'b0;in1 		<= 1'b0;in2 		<= 1'b0;#200sys_rst_n 	<= 1'b1;
end

参考资料

仿真文件中的阻塞和非阻塞

查看全文

99%的人还看了

猜你感兴趣

版权申明

本文"Verilog仿真文件中的阻塞和非阻塞赋值问题探讨":http://eshow365.cn/6-14863-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!