SVA断言仿真停止时机疑问:Cadence工具行为与标准探讨
SVA断言失败与Action Block执行的状态问题解析
核心问题1:断言失败到Action Block执行期间仿真状态是否真会变化?
是的,确实存在状态变化的可能。
按照SystemVerilog IEEE 1800标准的调度周期顺序:
- Preponed Region:采样并发断言所需的信号值
- 经过Active、Inactive、Nonblocking Update等Region后,进入Observed Region执行断言检查,判定是否失败
- 随后进入Reactive Region执行断言失败后的Action Block
关键在于,Reactive Region中可能存在多个待执行的进程——比如其他断言的Action Block、用户显式标记为reactive的进程,甚至工具自身的后台操作。这些进程如果在当前断言的Action Block之前执行,就可能修改仿真信号的状态。另外,如果Action Block中包含#0或其他显式延迟语句,还会跨调度周期,状态变化的概率会更高。
核心问题2:Action Block中使用$sampled能否缓解状态变化问题?
完全可以。
$sampled()函数的作用是返回并发断言在Preponed Region采样到的原始信号值,也就是断言失败判定时所基于的状态值,不受后续任何状态修改的影响。在Action Block中用$sampled(sig)代替直接引用信号sig,就能精准获取断言失败时的真实状态。
示例代码:
assert property (@(posedge clk) valid |-> ready) else begin $error("Assertion failed! Current values: valid=%b, ready=%b | Sampled values (failure state): valid=%b, ready=%b", valid, ready, $sampled(valid), $sampled(ready)); end
关于标准规定的疑惑
SystemVerilog IEEE 1800标准并没有强制要求Action Block必须在断言失败时的状态下执行。标准只明确了断言检查在Observed Region完成,Action Block在Reactive Region执行,但没有限制Reactive Region内的进程执行顺序,也没有禁止其他进程在Action Block之前修改仿真状态。因此,厂商提到的状态变化场景是符合标准的。
如何查看断言失败时的状态?
有几种实用方法:
- 用
$sampled打印采样值:这是最便捷的方式,直接在Action Block中输出$sampled获取的信号值,就能得到断言判定时的原始状态。 - 触发波形快照:在Cadence工具中,可以在Action Block里调用
$fsdbDumpvars生成当前周期的波形快照,结合$sampled的值定位失败状态。比如:assert property (@(posedge clk) a |-> b) else begin $fsdbDumpvars(0, top_dut, 1); // 生成快照 $error("Failure at %0t: sampled a=%b, b=%b", $time, $sampled(a), $sampled(b)); end - 配置工具在Observed Region停止:如果需要直接查看断言失败瞬间的状态,可以按照厂商建议配置仿真工具在Observed Region立即停止。同时可以通过工具的回调机制,在停止前自动执行打印操作,兼顾状态查看和报错信息输出。
内容的提问来源于stack exchange,提问作者nachum
相关产品推荐
相关产品推荐

