Verilog基础:阻塞/非阻塞赋值

Verilog基础:阻塞/非阻塞赋值


  • 对于具有一定软件基础的同学来说,赋值无非是将等号右边的数字赋给等号左边的变量。那么什么是阻塞/非阻塞赋值呢?在Verilog中,阻塞赋值和非阻塞赋值应用于截然不同的代码逻辑中。
  • 阻塞赋值用于组合逻辑(即无记忆数字逻辑电路,其任何时刻的输出仅取决于输入的组合),其在块内按顺序执行;而非阻塞赋值用于时序逻辑(任何一个时刻的输出状态由当时的输入信号和电路原来的状态共同决定),在块内并行执行。

  本文将站在电路角度上对阻塞与非阻塞赋值进行深入解读,希望大家能够知其然并知其所以然。本文将从综合区别/仿真时序/常见问题三部分进行介绍。


综合区别

   在我的理解中,阻塞和非阻塞是为了区分连线“wire”和D触发器的赋值。同样是赋值,在时序逻辑和组合逻辑中,其综合出来的电路结构是不同的。

  • &阻塞赋值‘=’,其综合结果是一根简单的导线,将上下级连接起来。最简单的阻塞赋值代码如下所示。
always @(*)begin
    b = a;
end

   对block进行综合,得到的就是简单的a与b的连线,而b可以是DFF/锁存器或连接线,其赋值将是每时每刻的。

Verilog基础:阻塞/非阻塞赋值_第1张图片

  • 非阻塞赋值则截然不同,将阻塞赋值代码进行简单修改,得到非阻塞赋值代码。
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        b <= 1'b0;
    else 
        b <= a;
end

   综合出来将会是下图这样一个DFF采样电路,上一级的值被一个边沿触发的D触发器采样并保持,只在边沿的瞬间赋值。
Verilog基础:阻塞/非阻塞赋值_第2张图片

  • 阻塞和非阻塞赋值取决于设计者希望赋值是边沿瞬间还是不间断的。

时序区别

   基于上述综合区别的理解,理解时序区别将变得简单。为什么阻塞赋值需要等block中前置的逻辑结束后才能执行,而非阻塞赋值可以同时执行?

always @(*)begin
    b[3:0] = a[3:0];
    c[3:0] = b[3:0];
end
  • 上述组合逻辑,实际电路将是一个串行的导线,从下图波形中也能看出,电路需要先将a值传递到b后,才能将b值传递给a,所以最后是c=a,这就是阻塞赋值的含义。
    Verilog基础:阻塞/非阻塞赋值_第3张图片
    更改为非阻塞赋值,代码如下。
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        b[3:0] <= 4'h0;
        c[3:0] <= 4'h0; //wechat bug!
    end
    else begin
        b[3:0] <= a[3:0];
        c[3:0] <= b[3:0];
    end
end
  • 综合后的电路为两个边沿触发的D触发器,采样发生在边沿,只与触发前瞬间的输入有关,所以波形看起来会慢上一拍

Verilog基础:阻塞/非阻塞赋值_第4张图片

常见问题

   在清楚区分阻塞和非阻塞逻辑后,入门阶段常会犯的一个错误——使用阻塞累加器,代码如下。


always @(*)begin
    a[3:0] = a[3:0] + 4'b1;
end
  • 这样的阻塞型累加器,会形成一个组合逻辑环路,累加在环路中不断运行,导致结果无法预测。因此,在进行类似电路设计时,应使用非阻塞赋值构成D触发器达到设计要求。




搜索关注我的微信公众号【IC墨鱼仔】,获取我的更多IC干货分享!
Verilog基础:阻塞/非阻塞赋值_第5张图片

你可能感兴趣的:(verilog经验之谈,fpga开发,芯片)