Verilog跨模块传值异常:memory输出到get_quantizer_output出现x态
异常行为成因及解决方案
核心成因
1. 模块实例化顺序不影响仿真调度优先级
Verilog是并发执行的硬件描述语言,代码中模块实例的书写顺序和仿真运行时的逻辑执行优先级没有任何关联,调整实例顺序的操作不会改变信号的更新先后。
2. 同步存储器的读延迟未对齐
绝大多数自定义memory采用同步读逻辑:输入地址后,需要等待至少1个时钟沿才会输出有效数据。如果下游get_quantizer_output模块在给出地址的同一个时钟沿就采样memory输出,拿到的必然是memory上电初始的x态,有效数据会延迟1个周期才出现。
3. Verilog分层事件队列调度顺序导致
Verilog仿真的事件队列分为多个阶段,同一时间步下:
- 活跃事件阶段会先执行所有阻塞赋值、连续赋值、下游模块的组合逻辑/时序逻辑采样
- 非阻塞赋值更新阶段才会更新用
<=赋值的信号值
如果你的memory的output_data是用非阻塞赋值输出,那么同一时钟沿下下游逻辑先执行时,memory的输出还未完成更新,拿到的是上一拍的x态,等到非阻塞赋值阶段完成后,才会打印出有效值,所以出现打印顺序颠倒的问题。
4. memory初始化时机错误
如果你的预存边界值是通过$readmemh/$readmemb加载的,若加载逻辑的执行时机晚于下游模块的第一次采样触发,第一次读操作拿到的就是未初始化的x态。
修复方向
- 对齐采样时序:如果是同步读memory,给下游计算逻辑加1拍的valid控制信号,等到memory输出稳定后再触发量化计算
- 统一信号赋值规则:如果需要同周期拿到memory输出,可以把memory改成异步读(组合逻辑输出);如果保留同步读,下游采样memory输出时统一用非阻塞赋值
<=,避免调度顺序混乱 - 调整初始化逻辑:把memory的固件加载逻辑放在
initial块最开头,保证仿真0时刻就完成所有边界值的写入 - 修正打印逻辑:用
$strobe代替$display打印信号值,$strobe会在当前时间步所有信号更新完成后才执行,不会出现打印值和实际值不一致的问题
内容的提问来源于stack exchange,提问作者Usman Sajid
相关产品推荐
相关产品推荐

