You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Verilog阻塞与非阻塞赋值中延迟控制的行为差异问询

Verilog延迟控制与阻塞/非阻塞赋值的输出差异解析

你在研究Verilog模拟器对#<delay>延迟控制的处理时,遇到两段代码输出差异的问题:

代码段(1)(非阻塞赋值版本)

module top ();
  reg a,b;
  initial begin
    $monitor("At time %d a=%b b=%b", $time,a,b);
    a = 1'b0;
    b = 1'b0;
    #10 a = 1'b1;
    #10 b = 1'b1;
    a <= #5 1'b0;
    b <= #5 1'b0;
  end
endmodule

代码段(2)(阻塞赋值版本)

module top ();
  reg a,b;
  initial begin
    $monitor("At time %d a=%b b=%b", $time,a,b);
    a = 1'b0;
    b = 1'b0;
    #10 a = 1'b1;
    #10 b = 1'b1;
    a = #5 1'b0;
    b = #5 1'b0;
  end
endmodule

输出差异

  • 代码(1)中,a和b均在t=25时被设为0;
  • 代码(2)中,a在t=25时设为0,b却要到t=30才变为0。

核心疑问

原本以为执行到a <= #5 1'b0;时,会先计算右侧值,等待5个时间单位后在非阻塞赋值(NBA)区域更新a,且要到t=25才开始处理b <= #5 1'b0;,就像阻塞赋值的情况一样。为何非阻塞赋值时,即便前一条语句有#5,模拟器仍会直接处理下一条?之前认为阻塞与非阻塞赋值仅在分层Verilog队列的调度区域不同,是否还有其他差异?


原因解析

要搞懂这个差异,关键是区分阻塞赋值中的延迟和非阻塞赋值中的延迟的本质:

  1. 阻塞赋值中的#<delay>:
    阻塞赋值(=)会直接暂停当前进程的执行。当执行a = #5 1'b0;时,当前initial进程立刻暂停5个时间单位,这段时间内不会执行任何后续语句。等5个时间单位到了(t=20+5=25),才完成a的赋值,之后才继续执行下一条b = #5 1'b0;,此时进程又暂停5个时间单位(到t=25+5=30),再完成b的赋值。这就是代码(2)中b在t=30才变0的原因。

  2. 非阻塞赋值中的#<delay>:
    非阻塞赋值(<=)不会暂停当前进程,而是把**“延迟5个时间单位后更新变量”这个动作打包,放到Verilog事件队列的非阻塞赋值更新区域**。当执行a <= #5 1'b0;时,模拟器会立即安排一个事件:在当前时间t=20的基础上加5,也就是t=25时,在NBA区域更新a为0。安排完这个事件后,当前进程不会暂停,立刻继续执行下一条b <= #5 1'b0;,同样安排一个t=25时更新b为0的事件。到t=25时,两个事件同时触发,所以a和b同时变为0。

  3. 除了调度区域的差异,阻塞和非阻塞赋值对延迟的处理逻辑完全不同:

    • 阻塞赋值的延迟是进程级暂停,会阻塞后续语句的执行;
    • 非阻塞赋值的延迟是事件调度,仅影响赋值动作的触发时间,不会阻塞当前进程的执行流程。

内容的提问来源于stack exchange,提问作者EE18

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 11:13:19