Verilog阻塞与非阻塞赋值详解

105 篇文章 14 订阅
本文介绍了Verilog中阻塞赋值(=)和非阻塞赋值(<=)的区别,阻塞赋值顺序执行,适用于组合逻辑,非阻塞赋值并行执行,适合时序电路描述。在时序模块中应使用非阻塞赋值,而在组合逻辑描述时使用阻塞赋值,避免在同一always块内混合使用。
摘要由CSDN通过智能技术生成

基本概念

        关于阻塞赋值(=)和非阻塞赋值(<=), 阻塞赋值(=)是顺序敏感的,非阻塞赋值(<=)是顺序独立的。阻塞赋值按它们在程序块中列出的顺序顺序执行。当它们被执行时,它们会立即对抽象 reg 的内容产生影响,阻塞必须在执行下一个赋值之前执行。非阻塞赋值在对左侧抽象 reg 进行赋值之前,评估程序块中每个语句右侧的表达式,并同时执行。
                                                顺序敏感和顺序独立示例

// Blocking assignment executes sequentially .
initial begin
a=#12 1;
b=#3  0;
c=#2  3;

// Non-blocking assignment executes in parallel.
initial begin
d <=#12 1;
e <=#3  0;
f <=#2  3;
end

        阻塞赋值是顺序敏感,而非阻塞赋值是顺序独立的。从两份代码所仿真的时序图所示,abc是顺序执行的,而非阻塞赋值def则是同时执行。这也意味着,如果改变阻塞赋值语句顺序,那么会得到不同的结果。如下面2段代码改变阻塞赋值顺序综合出结果不同,前面代码综合出1个DFF,而第二段代码综合出2个DFF。

always @(posedge clk) 
begin
  rega = data;
  regb = rega;
end
always @(posedge clk) 
begin
  regb = rega;
  rega = data;
end

而对于非阻塞赋值,仅改变语句的顺序并不会改变结果,如下面2段代码综合出的结果是一样的。

reg qa,qb,qc;
always @(posedge clk) 
begin
    qa <= a;
    qb <= qa;
    qc <= qb;
end
reg qa,qb,qc;
always @(posedge clk) 
begin
    qc <= qb;
    qb <= qa;
    qa <= a;
end

为什么always块组合逻辑使用阻塞赋值?

always @(a or b or c or d)     
          begin
               t1 = a & b;
               t2 = c | d;
               out = t1 & t2;
          end
always @(a or b or c or d or t1 or t2)   
       begin
            t1 <= a & b;
            t2 <= c | d;
            out <= t1 & t2;
       end

        上面2段代码综合出的结果都是一致的,区别就是当使用非阻塞赋值时,敏感列表需要加上t1t2。对于具有阻塞分配的 always 块,always 块的敏感列表包含组合电路的所有输入 abc 和 d。每次输入改变时,总是阻塞,因此输出结果,必须重新评估。此时 always 块中的语句是按顺序执行的,输入的最新值用于确定 t1 和 t2,最后使用新的 t1 和 t2 计算出。

        在具有非阻塞赋值的 always 块中,语句是同时执行的。因此,当敏感列表中信号改变触发always块执行时,out 将使用 t1 和 t2 的旧值,因为它们的新值尚不可用。为确保在组合电路中具有相同的行为,除了电路的输入信号之外,还应将电路的内部信号 t1 和 t2 放入敏感列表中。每次更新 t1 和 t2 的值时,这将重新触发(重新进入)always 块,使输出最终能够计算其新值。然而,这个模型相对复杂并且可能会造成混淆,所以always模块组合电路的描述应该使用阻塞赋值。

为什么always模块描述时序使用非阻塞?

always @(posedge clk)     
          begin
               t1 = a & b;
               t2 = t1 & c;
               out = t1 & t2;
          end
always @(posedge clk)   
       begin
            t1 <= a & b;
            t2 <= t1 & c;
            out <= t1 & t2;
       end


        对于具有阻塞赋值的always块,在clk的每一个上升沿,三个赋值顺序执行。因此,t1 使用 clk 的上升沿处的 a 和 b 的值更新,然后 t2clk上升沿使用 t1 的新值和c的值更新自己的值。最后,使用 t1 和 t2 的新值评估 out。可以看出,t1t2只是用于临时存储,方便对复杂表达式进行分区;它们不代表真正的硬件寄存器输出,甚至可能被优化掉。值得注意的是,组合电路已经优化为 out = t1&t2 = (a&b)&(t1&c) = (a&b)&(a&b&c) = a&b&c = t1&c = t2。

        对于具有非阻塞赋值的 always 块,在clk的每个上升沿处,同时执行三个赋值:(1)t1 在 clk 的上升沿处由 和 b 的值更新(2)同时t2使用旧t1的值(其新值此时不可用)和 在 clk 的上升沿更新值,以及(3)同时使用 t1的旧值和t2的旧值(它们的新值此时不可用)更新 out

        如图所示,阻塞和非阻塞分配描述了完全不同的时序电路。根据阻塞和非阻塞分配的行为,它们分别表示一个和三个触发器。也就是说,当 t1 和 t2 使用阻塞赋值来描述时,它们是组合输出而不是时序输出。因此,该模型可能会非常混乱,所以时序的always模块仅使用非阻塞赋值。

总结:

本文主要介绍阻塞赋值和非阻塞赋值的基本概念和运行机理,以及分析不同always块应该使用阻塞还是非阻塞,在记住相关规则的情况下,能理解原因也是非常重要的。亦安以Clifford E. Cummings的论文中关于阻塞和非阻塞所描述的原则结束本篇文章:

  1. 在时序的模块中使用非阻塞赋值。

  2. 当使用always块来描述组合逻辑时,使用阻塞赋值。

  3. 当在同一个always块中描述时序和组合逻辑时,使用非阻塞赋值。

  4. 在同一个always块中不要混合使用阻塞和非阻塞赋值。

摘自“亦安的数字小站”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值