SystemVerilog带层次引用的非阻塞赋值未实现单周期延迟咨询
问题根因与解决方案
这个现象既不是层次引用非阻塞赋值的特殊行为规则,也不是QuestaSim 2019.4的仿真bug,核心问题是没有正确使用clocking块的非阻塞采样机制,导致采样时机刚好命中DUT信号在当前时钟沿的更新完成点,最终表现得和连续赋值的行为完全一致。
时序逻辑的匹配验证
结合你给出的波形,可以完全对应到整个仿真调度的实际执行流程:
- 你定义的空clocking块没有显式声明任何输入、输出信号,仅作为时钟事件的触发标记存在,它的触发时机和直接写
@(posedge clk iff !rst)没有区别,不会自动启用clocking块默认的提前一个时间步的无竞争采样延迟。 - 你在always块里直接通过层次路径读
cache.cntrl.LinkState,这个读操作发生在always块被触发的瞬时。由于IEEE 1800标准没有强制规定同一时间戳、同一调度阶段的事件执行顺序,仿真器可以按照内部实现逻辑安排事件先后:只要DUT内部LinkState的非阻塞赋值更新(即NBA阶段操作)先完成,你的always块才对RHS的LinkState值完成求值,就会采样到当前时钟沿刚更新完成的新值,而非你预期的上一个周期的旧值。 - 你内部的两个延迟寄存器逻辑本身是完全正常的:
LinkState_d1和LinkState_d2都是cov模块内部的变量,在同一个always块的RHS求值阶段,LinkState_d2读到的是LinkState_d1尚未被当前非阻塞赋值更新的旧值,所以天然会比LinkState_d1再晚一个周期更新——这和你观察到的LinkState_d2正常延迟的波形完全吻合。
修正方案
按照SystemVerilog的标准用法,把需要采样的DUT信号显式声明为clocking块的输入,利用clocking块默认的#1step提前采样机制,从根源上避免和当前时钟沿的DUT信号更新产生竞争:
module cov import cachePkg::*; ( input logic clk, input logic rst ); // 显式声明层次信号为clocking块输入,自动启用#1step无竞争采样 clocking cclk @(posedge clk iff !rst); input LinkState = cache.cntrl.LinkState; endclocking logic [1:0] LinkState_d1, LinkState_d2; always @(cclk) begin // 直接读取clocking块已经提前采样稳定的信号值,不要直接读层次路径 LinkState_d1 <= cclk.LinkState; LinkState_d2 <= LinkState_d1; end endmodule
修改完成后,LinkState_d1会采样上一个时钟沿已经稳定的LinkState值,天然比DUT的LinkState信号晚一个周期更新,完全符合最初的延迟预期。
补充说明:如果不使用clocking块的采样机制,直接在同一时钟域的always块里读取其他模块层次的非阻塞赋值输出,非常容易因为仿真器的调度顺序差异,出现采样值和预期延迟不一致的问题,这也是验证环境开发中非常典型的采样竞争场景。
内容的提问来源于stack exchange,提问作者Melandru's Square
相关产品推荐
相关产品推荐

