Altifigence Academy

15 / 37 · 概念

非阻塞赋值与同时状态更新

区分旧值与下一值,准确解读流水线及计数器 RTL。

右侧表达式依据旧状态求值

在时钟驱动的时序块中,<= 先计算右侧表达式,再在非阻塞非阻塞赋值 时序 RTL 中以 <= 表示的赋值。先计算右侧,再预约更新,使同一边沿的各寄存器能够依据旧状态计算。更新阶段写入结果。同一边沿更新多个寄存器寄存器 存储多位状态的电路。本课程中的同步寄存器在时钟边沿存储指定输入。了解更多时,这样可避免因代码行顺序而让新值连锁穿过多级。

SystemVerilog
always_ff @(posedge clk) begin
  if (rst) begin
    a <= 8'd0;
    b <= 8'd0;
  end else begin
    a <= d;
    b <= a;
  end
end
ak+1=dk,bk+1=aka_{k+1}=d_k,\qquad b_{k+1}=a_k

初始 a=b=0,输入依次为 5、9、2,则各边沿后的 (a,b) 为 (5,0)、(9,5)、(2,9)。若把第二行理解为读取刚更新的 a,就相当于删掉一级流水线流水线 用寄存器把计算划分为多个阶段,使多个输入能够重叠处理的结构。数据、valid 与控制信号必须在各级对齐。了解更多。

每列记录一个上升沿上升沿 时钟从 0 变为 1 的瞬间。它不同于表示整个 CLK=1 区间的电平。了解更多的观察结果。输入取自边沿前,名称带 after 的状态取自更新后。列的排列表示采样顺序,并非描绘物理传播延迟传播延迟 从输入变化到输出稳定为正确值所需的时间。逻辑表达式等价与时间特性是两回事。了解更多。初始 a=b=0。a 存储新的 d 时,b 存储的是旧 a,因此两行错开一级。

a 与 b 读取同一组旧状态
查看波形数据
波形数据:每个字符表示一个区间,点表示保持前一状态,p 表示一个时钟周期。
信号波形总线值
edge234E0 → E1 → E2
d2345 → 9 → 2
a after2345 → 9 → 2
b after2340 → 5 → 9

为什么改为阻塞赋值很危险

若在同一块中改为 a=d; b=a;,b 的计算可能使用该块中已经改变的 a。与其他时序块的调度交互还可能造成竞争。以“组合计算用阻塞赋值,状态存储用非阻塞赋值”为基本规则;只有能够解释事件语义时才采用例外。

避免多次给同一寄存器赋值

在同一过程中执行多次对 q 的非阻塞赋值,最后执行的赋值可能决定最终结果。不要用多个独立 if 隐藏优先级,应使用 if / else if / else 或显式下一状态变量表达功能。也应避免多个块驱动同一个寄存器。

审查 RTL 时,为每个寄存器各写一个下一状态表达式很有效。若得到两个表达式,或某个条件下没有定义,就应重新检查代码中的控制优先级。

自己试试

初始 a=1、b=4,在同一时钟块中执行 a<=b; b<=a;,一个边沿与两个边沿之后分别是什么状态?

阅读解释

一个边沿后 (a,b)=(4,1),两个边沿后为 (1,4)。各赋值读取同一组旧状态,因此发生交换。若写为 a=b; b=a;,按顺序执行后两者都可能变成旧 b,不是相同功能。

你的选择适用于此浏览器,可随时在页脚更改。