FPGA学习篇之阻塞赋值与非阻塞赋值
前言
学习Verilog时区分阻塞赋值与非阻塞赋值一直是个绕不过去的坎,小白在刚接触这两个概念时也是一头雾水,一般在组合逻辑中使用阻塞赋值,在时序逻辑中使用非阻塞赋值,这与组合逻辑和时序逻辑的特性有关。有时仿真代码时与我们预想的时序不太一样,可能就是没区分阻塞赋值与非阻塞赋值的使用,只有写过大量的代码才能真正理解这两者的区别,从而设计出符合我们意愿的代码。
一、阻塞赋值(=)
要理解阻塞赋值与非阻塞赋值,首先要区分它们(小白经常将它们的名字搞混)。在Verilog中阻塞赋值用“=”来表示,在过程块中,阻塞赋值是顺序执行的,只有执行完前一条语句才会执行下一条,执行前一条语句时,下一条语句等待执行,也就是被“阻塞”了。阻塞赋值的执行过程可以归纳为一个步骤:计算表达式右边的值并立即更新给表达式左边的变量,在这个过程中不允许有其他verilog语句的干扰。同时要注意阻塞赋值往往应用于组合逻辑电路中,其对应的电路结构往往与电平触发有关。
module blocking(
input clk_100m,
input rst_n,
input [7:0] in2,
output reg [7:0] out2
);
// 阻塞赋值
reg [7:0] reg_in2;
always @(posedge clk_100m or negedge rst_n) begin
if(!rst_n) begin
reg_in2 = 8'b0;
out2 = 8'b0;
end
else begin
reg_in2 = in2;
out2 = reg_in2;
end
end
endmodule
图中reg_in2延迟in2一拍,是因为只有时钟的上升沿到来时才会将in2锁存进reg_in2,由于采用的阻塞赋值,out2的值直接跟随reg_in2,也就是reg_in2改变会立刻更新out2。
二、非阻塞赋值(<=)
在Verilog中非阻塞赋值用“<=”来表示,非阻塞赋值往往应用于时序逻辑电路中,其对应的电路结构往往与边沿触发有关。非阻塞赋值语句的执行过程是并行的,在时序逻辑电路的代码块中,所有的非阻塞赋值表达式同时执行,代码也就没有先后顺序之分。非阻塞赋值语句的执行可以分为两个步骤:首先是赋值开始时刻计算表达式右边的值 ,第二是在赋值结束时刻将表达式右边的值更新给左边的变量。其次要注意非阻塞赋值只能对reg型变量进程操作,不能对wire型变量进行赋值。也就是非阻塞赋值能用在initial 和always块中,不能再assign语句中使用。
module non_blocking(
input clk_100m,
input rst_n,
input [7:0] in1,
output reg [7:0] out1
);
// 非阻塞赋值
reg [7:0] reg_in1;
always @(posedge clk_100m or negedge rst_n) begin
if(!rst_n) begin
reg_in1 <= 8'b0;
out1 <= 8'b0;
end
else begin
reg_in1 <= in1;
out1 <= reg_in1;
end
end
endmodule
图中reg_in1延迟in1一拍,是因为只有时钟的上升沿到来时才会将in1锁存进reg_in1,由于采用的非阻塞赋值,reg_in1要等到时钟的上升沿到来才会把前一时刻的值锁存进out1,所以out1会延迟reg_in1一拍。
总结
要充分理解阻塞赋值与非阻塞赋值的区别与应用场合,才能在今后设计出符合要求的电路。