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

Verilog寄存器行为异常求助:uut_1输出为何与write_flag同步更新?

问题解析:Verilog寄存器时序与仿真事件逻辑

你遇到的问题核心是对Verilog仿真中同一时间点的事件执行顺序理解不到位,再加上阻塞、非阻塞赋值的行为差异导致的。

1. 为什么uut_1的寄存器和write_flag同步更新?

看测试平台initial块里这段代码:

@(posedge clk)
d_in = 1;
write_flag_a = 1;
  • @(posedge clk)等时钟上升沿一到,仿真就进入同一个时间步。
  • 你用的是阻塞赋值(=),这种赋值会立刻把变量改成新值,在这个时间步里马上生效。
  • 而你的设计模块reg_behve里的always @(posedge clk)块,也是在这个时钟上升沿触发执行的。这时候write_flag_a和d_in已经是新值了,所以寄存器d_out_r会直接在当前这个时钟沿就更新,看起来和write_flag_a同步变高。

2. 为什么uut_2的寄存器是延迟一个周期更新?

再看write_flag_b的生成代码:

always @(posedge clk) begin
    write_flag_b <= write_flag_a;
end
  • 这里用的是非阻塞赋值(<=),这种赋值不会立刻改变量值,而是把更新动作放到一个专门的队列里,要等当前时间步里所有阻塞赋值、触发的always块都跑完,才会更新变量。
  • 当write_flag_a在某个时钟沿被设为1时,write_flag_b要等这个时间步结束后才会变成1。所以下一个时钟沿到来时,write_flag_b才生效,设计里的寄存器这时候才会捕获d_in的值,表现为延迟一个周期更新,这才是你原本预期的寄存器行为。

怎么让uut_1也符合预期时序?

有两种简单方法:

  • 方法一:把测试平台里的阻塞赋值改成非阻塞赋值:
    @(posedge clk)
    d_in <= 1;
    write_flag_a <= 1;
    
    这样变量更新会被延迟到当前时间步结束后,设计模块的always块在当前时钟沿看到的还是旧值,下一个时钟沿才会触发寄存器更新。
  • 方法二:提前一个时钟周期设置信号,确保时钟沿到来时信号已经稳定:
    d_in = 1;
    write_flag_a = 1;
    @(posedge clk)
    

关键要点记一下

  • 阻塞赋值(=):立刻改值,同一时间步里先执行的赋值会影响后续代码,适合组合逻辑。
  • 非阻塞赋值(<=):不立刻改值,延迟到当前时间步所有事件完成后再更新,适合时序电路的寄存器赋值,能避免仿真里的竞争问题。
  • 时钟边沿触发的always块,是在时钟沿所在的时间步执行的,这时候同一时间步的阻塞赋值已经完成,非阻塞赋值还没生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 00:47:32