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

SystemVerilog零延迟连续赋值在信号上升沿取值异常问题

核心原因:Verilog仿真事件调度的竞争问题

你遇到的是Verilog/SystemVerilog仿真调度规则导致的典型零延迟竞争,和逻辑写法本身对错无关:

  1. 同一个仿真时间戳下,所有零延迟的事件都会被归入活跃事件队列,仿真器对这个队列里的事件执行顺序没有强制规范,可以乱序调度。这些事件包括:
    • always块中非阻塞赋值(<=)对寄存器(i/was_enabled/buff)的更新事件
    • 所有assign连续赋值对线网的求值更新事件
    • testbench中@(posedge rdy)被信号跳变唤醒后,后续语句的执行事件
  2. 你遇到断言失败的执行顺序是这样的:
    • 最后一次移位完成后,非阻塞赋值把i更新为7,首先触发rdy的连续赋值,rdy从0跳变为1
    • 这个上升沿立刻唤醒了testbench里阻塞等待的进程,断言语句马上开始执行
    • 此时out_data对应的连续赋值求值事件还在活跃队列里没有被调度执行,你读到的自然是更新前的旧值0
  3. 加#0延迟能通过的本质:#0会把后续断言的执行事件挪到优先级更低的非活跃事件队列,必须等当前时间戳下所有活跃事件(包括out_data的赋值更新)全部执行完,才会跑断言,自然能读到正确值。
  4. 你把out_data的判断条件直接展开也解决不了问题——两个连续赋值的求值事件同属活跃队列,只要testbench的唤醒事件排在out_data求值前面,一样会读到旧值。

你在波形里看到rdy和out_data同时跳变,是因为波形查看器默认展示同一个时间戳下所有事件执行完成后的最终值,不会显示同一时间点内事件调度的先后顺序,所以肉眼看不出中间的执行差。


关于边沿后加小延迟的实践规范

在testbench的@(posedge signal)等待语句后加远小于时钟周期的小延迟(比如几皮秒、几百皮秒,只要不超过时钟周期的1/10都可以),等所有组合逻辑、寄存器值稳定后再做校验,是行业内通用的标准写法,完全属于良好实践,可以从根源上规避这类零延迟调度竞争问题。
需要注意两个边界:

  • 这种小延迟只能写在testbench校验/激励逻辑里,绝对不能写到可综合的RTL设计代码中,否则会导致综合前后仿真行为不一致,属于明确的不良设计。
  • 延迟值不能设得太大,避免跨到下一个时钟边沿,读到下一周期的错误值。

另外你自己也提到的assign _clk = en | clk;组合逻辑产生时钟的写法确实要修正,这种写法不仅容易产生时钟毛刺,本身也会额外增加仿真调度的竞争概率,正式实现时要么把en作为逻辑使能接入时序always块的判断条件,要么调用标准的时钟门控单元,不要直接用组合逻辑拼时钟。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 08:24:15