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

Verilog中非阻塞赋值为何导致进程重入?阻/非阻赋值执行差异问询

Verilog阻塞与非阻塞赋值生成时钟的执行差异分析

两段Verilog代码在实现振荡时钟时存在明显执行差异:

always @(clk) begin #10 clk <= ~clk;end       // 正常工作:进程重复进入,形成振荡器
always @(clk) begin #10 clk = ~clk;end        // 仅执行一次,无法形成振荡

下面针对你的疑问逐一解答:

1. 时间步内的事件评估是逐句执行的吗?

不是逐句执行,Verilog的时间步是分阶段处理事件队列的,核心队列包括:

  • 活跃事件队列:处理当前时间步触发的事件(比如always块敏感事件触发),队列内的语句按顺序执行,但阻塞赋值会立即更新变量。
  • 非阻塞赋值更新队列(NBA):存储非阻塞赋值的更新操作,必须等活跃队列处理完毕后才执行变量更新。
  • 未来事件队列:存储带延迟的时序控制事件(比如#10),到指定时间才会被移到活跃队列执行。

整个时间步的处理流程是:先清空活跃队列,再执行NBA队列的更新,最后处理监控类操作,之后进入下一个时间步。

2. 你的理解存在什么错误?

你之前认为两种赋值都能生成振荡,错误点在于忽略了赋值更新时机的核心差异:

  • 阻塞赋值在活跃队列阶段立即更新变量,同一时间步内的敏感事件检测已经完成,变量的变化无法触发同一个always块再次执行。
  • 非阻塞赋值的更新延迟到NBA阶段,这个阶段完成后会重新检测敏感事件,变量变化能触发always块进入下一轮执行,形成循环。

3. 为何非阻塞赋值的更新事件能在同一时间步触发敏感事件?

非阻塞赋值的更新发生在活跃队列处理完成后的NBA阶段。当NBA队列执行完clk的更新后,Verilog会重新检查所有敏感列表,always @(clk)会因为clk的跳变被触发,这个新的触发事件会被加入当前时间步的活跃队列,于是always块会立即再次执行,不需要等到下一个时间步,从而形成连续振荡。

4. 评估与更新事件如何进入层级事件队列?

  • 评估事件的入队逻辑:
    • 当clk发生跳变触发敏感列表时,always块的进程会被加入活跃事件队列等待执行。
    • 执行到#10这类延迟控制语句时,进程的剩余部分(赋值操作)会被加入未来事件队列,等到10个时间单位后,再被移到活跃队列执行。
  • 更新事件的入队逻辑:
    执行非阻塞赋值语句clk <= ~clk时,不会立即更新clk,而是把“将clk更新为~clk”的操作加入NBA队列。只有当活跃队列中的所有事件都处理完毕后,才会依次执行NBA队列中的所有更新操作,完成变量的赋值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 05:37:32