为何always块内将driver_a置0后未触发,无法更新driver_b的值?
为什么
always块内修改driver_a为0后没有再次触发执行? 你遇到的问题核心是对Verilog的事件调度模型和敏感列表触发规则的误解,我们一步步拆解原因和执行流程:
先明确代码的合法前提
首先假设driver_a和driver_b都是reg类型——这是代码能正常运行的必要条件,如果是wire类型,always块内的阻塞赋值是非法的,仿真器会直接报错或忽略赋值操作,那自然不会有后续触发。
详细仿真时序分析
我们按仿真时间线一步步看代码执行逻辑:
仿真时间0:
initial块执行driver_a = 0; driver_b = 0;,两个寄存器初始化为0,无敏感信号变化,仿真时间推进到2。仿真时间2:
initial块执行driver_a = 8'h8;,driver_a从0变为8'h8,这个值变化触发always @(driver_a)块第一次执行:- 执行
driver_b = driver_a;→driver_b立即变成8'h8(阻塞赋值即时生效); - 执行
driver_a = 0;→driver_a从8'h8变为0,这个值变化会生成一个新的值变化事件,被加入仿真器的事件队列。
- 执行
- 第一次
always块执行完毕后,仿真器检查事件队列,发现driver_a的新变化事件,于是再次触发always块执行:- 执行
driver_b = driver_a;→driver_b立即从8'h8变为0; - 执行
driver_a = 0;→driver_a值保持0,无变化,不会生成新事件。
- 执行
- 事件队列清空,仿真时间推进到4。
仿真时间4:
重复时间2的流程:initial块把driver_a设为8'hf,触发always块,driver_b先变为8'hf,然后立即变为0,driver_a被置0后无后续事件。
为什么你的波形看起来不符合预期?
你提到波形中driver_b没有更新为0,大概率是因为:
- 波形工具默认只显示每个时间步的最终值:在时间2的delta cycles内,
driver_b先变为8'h8,然后立即变为0,中间的8'h8持续时间为0,波形工具只会显示最终的0值,你可能误以为driver_b停留在8'h8; - 如果确实看到
driver_b停留在8'h8,那大概率是driver_a被定义为wire类型,导致always块内的driver_a = 0;赋值非法,driver_a实际没有变成0,自然不会触发第二次always块。
验证逻辑的小技巧
你可以在always块中加入打印语句,直观看到执行过程:
always @(driver_a) begin $display("[%0t] driver_a changed to %h, driver_b set to %h", $time, driver_a, driver_a); driver_b = driver_a; $display("[%0t] Setting driver_a to 0", $time); driver_a = 0; end
运行后会看到类似输出,证明always块确实被触发了两次:
[2] driver_a changed to 08, driver_b set to 08 [2] Setting driver_a to 0 [2] driver_a changed to 00, driver_b set to 00 [2] Setting driver_a to 0 [4] driver_a changed to 0f, driver_b set to 0f [4] Setting driver_a to 0 [4] driver_a changed to 00, driver_b set to 00 [4] Setting driver_a to 0
总结
你的核心误解是以为always块内修改敏感信号不会触发自己,但实际上这是会发生的——只是因为事件在同一个时间步的delta cycles内完成,波形工具不会显示极短的中间值,导致你误以为没有触发。只要代码合法(driver_a是reg类型),driver_b最终会被更新为0。
内容的提问来源于stack exchange,提问作者TheSprintingEngineer
相关产品推荐
相关产品推荐

