【Verilog 基础】阻塞赋值和非阻塞赋值的区别

目录

 

阻塞赋值

非阻塞赋值

实际工程仿真

阻塞赋值仿真

编写Verilog代码

编写测试文件代码

综合看RTL图

进行实际仿真

非阻塞赋值仿真

编写Verilog代码

编写测试文件代码

综合看RTL图

实际仿真图

总结


阻塞赋值

阻塞赋值的赋值号用 “=” 表示,对应的电路结构往往于触发闫妮没有关系,只与输入电平的变化有关系。它的操作可以认为是只有一个步骤的操作,即计算赋值号右边的语句并更新赋值号左边的语句,此时不允许有来自任何其他Verilog语句的干扰,直到现行的赋值完成,才允许下一条的赋值语句的执行。

串行块也就是begin end,各条阻塞赋值语句将以它们在顺序块中的排列次序依次执行。

非阻塞赋值

非阻塞赋值的赋值号用 “<=” 表示,对应的电路结构往往与触发沿有关系,只有在触发沿的时刻才能进行非阻塞赋值。

它的操作可以看作为两个步骤的过程:在赋值结束时刻,更新赋值号左边的语句。

在计算非阻塞语句赋值号右边的语句更新赋值号左边的语句期间,允许其他的Verilog语句同时进行操作。

非阻塞左槽只能用于对寄存器类型变量(reg)进行赋值,因此只能用于 “initial” 和 "always" 块中,不允许用于连续赋值 “assign” 。

实际工程仿真

阻塞赋值仿真

编写Verilog代码

首先是阻塞赋值仿真(blocking),利用 “=” 进行赋值,表示阻塞赋值。

module	blocking
(			
	input	wire			clk,
	input	wire			rst_n,
	input	wire	[1:0]	in,
	output	reg		[1:0]	out

);

reg		[1:0]	in_reg;

always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		in_reg = 2'b0;
		out    = 2'b0;
	end
	else begin
		in_reg = in;
		out    = in_reg;
	end
end
endmodule

编写测试文件代码

`timescale 1ns / 1ns

module tb_blocking();
	
	reg				clk;
	reg				rst_n;
	reg		[1:0]	in;

	wire	[1:0]	out;

	initial	begin
		clk = 1'b1;
		rst_n <= 1'b0;
		in <= 2'b0;
		#20
		rst_n <= 1'b1;
	end
	always #10 clk = ~clk;
	always #10 in <= {$random} % 4;


blocking tb_blocking(
	.clk(clk),
	.rst_n(rst_n),
	.in(in),
	.out(out)
	);
endmodule

综合看RTL图

可以看到只有一个寄存器,因此在实际的仿真图显示的应该是in_reg和out信号应该同时变化,并且两路信号都延时in信号一拍。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBATGluZXN0LTU=,size_20,color_FFFFFF,t_70,g_se,x_16

进行实际仿真

与预想的一致

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBATGluZXN0LTU=,size_20,color_FFFFFF,t_70,g_se,x_16

非阻塞赋值仿真

编写Verilog代码

如下:只需要将阻塞赋值的代码将 “=” 改成 “

module	blocking
(			
	input	wire			clk,
	input	wire			rst_n,
	input	wire	[1:0]	in,
	output	reg		[1:0]	out

);

reg		[1:0]	in_reg;

always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		in_reg <= 2'b0;
		out	   <= 2'b0;
	end
	else begin
		in_reg <= in;
		out    <= in_reg;
	end
end
endmodule

编写测试文件代码

和阻塞赋值的测试文件一样

`timescale 1ns / 1ns

module tb_blocking();
	
	reg				clk;
	reg				rst_n;
	reg		[1:0]	in;

	wire	[1:0]	out;

	initial	begin
		clk = 1'b1;
		rst_n <= 1'b0;
		in <= 2'b0;
		#20
		rst_n <= 1'b1;
	end
	always #10 clk = ~clk;
	always #10 in <= {$random} % 4;


blocking tb_blocking(
	.clk(clk),
	.rst_n(rst_n),
	.in(in),
	.out(out)
	);
endmodule

综合看RTL图

可以看到有两个寄存器,从in信号赋值给in_reg信号中有一个寄存器,再从in_reg信号赋值给out信号中也有一个寄存器,因此在实际的仿真图显示的应该是in_reg信号相对于in信号延时一拍,而out信号相对于in_reg延时一拍,也就是相对于in信号延时两拍。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBATGluZXN0LTU=,size_20,color_FFFFFF,t_70,g_se,x_16

实际仿真图

与观察RTL图后设想的一致。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBATGluZXN0LTU=,size_20,color_FFFFFF,t_70,g_se,x_16

总结

阻塞赋值和非阻塞赋值在实际使用上不能随意乱用,否则可能会出现难以预估的后果,根据官方给出的建议,在编写组合逻辑电路时,使用阻塞赋值;在编写时序逻辑时,使用非阻塞赋值。

猜你喜欢

转载自blog.csdn.net/m0_61298445/article/details/123622639