前言:
非阻塞赋值也会有延一拍的现象。
module blocking
(
input wire sys_clk , //系统时钟50Mh
input wire sys_rst_n , //全局复位
input wire [1:0] in , //输入信号
output reg [1:0] out //输出信号
);
reg [1:0] in_reg;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)begin
in_reg = 2'b0;
out = 2'b0;
end
else begin
in_reg = in;
out = in_reg;
end
endmodule
阻塞赋值
此时只有out 一个寄存器
仿真图:
分析:
首先中间变量in_reg赋值为in前一时刻的值,所以会比输入信号in延迟一拍,而中间变量in_reg和输出信号out却没有延迟一拍的关系了,而是在同一时刻同时变化的,因为我们使用的是阻塞赋值,也就是说只要赋值号右边的表达式的值有变化, 赋值号左边的表达式的值也将立刻变化,所以我们最终看到的结果是中间变量in_reg和输出信号out是同时变化的。
module non_blocking
(
input wire sys_clk e ,//系统时钟50Mh
input wire sys_rst_n ,//全局复位
input wire [1:0] in ,//输入按键
output reg [1:0] out //输出控制led灯
);
reg [1:0] in_reg;
//in_reg:给输入信号打一拍
//out:输出控制一个LED灯
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
in_reg <= 2'b0;
out <= 2'b0;
end
else begin
in_reg <= in;
out <= in_reg;
end
endmodule
根据上面RTL代码综合出的RTL视图所示,我们可以看到综合出的结果有两组寄存器,这是和使用阻塞赋值所综合的RTL视图所不同的
仿真:
分析:
我们发现输入信号in和中间变量in_reg是延迟一拍的关系,而中间变量in_reg和输出信号out也是延迟一拍的关系,也就是输入信号in 和输出信号out一共是延迟两拍的关系。
首先中间变量in_reg赋值为in前一时刻的值,所以会比输入信号in延迟一拍,,所以会比输入信号in延迟一拍,这是和阻塞赋值过程相同的,但是接下来就不一样了,因为我们使用的是非阻塞赋值,也就是说只要赋值号右边的表达式的值有变化 ,赋值号左边的表达式的值也不会立刻变化,需要等待下一次时钟沿到来时一起变化,所以我们最终看到的结果是输出信号out相对于输入信号是打了两拍的关系。
总结:
计算赋值号右手边的信号时,所有的变量值均是触发沿到来前的值,更新的赋值号左手边的信号作为触发沿后的值,并且保持到下一个触发沿到来时候,等待更新。这样,就可以使得在同一个块中非阻塞赋值语句不必要求出现的顺序,都是在全部进行赋值号右手边的信号计算后同时更新赋值号左手边的信号的值。非阻塞赋值可以简单的认为是赋予下一状态的值
延一拍有两种情况:
1、时序逻辑中
2、非阻塞赋值,更新的永远是<=右侧变量前一时刻的值。