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

Modelsim仿真中Buffer的异常行为及原因咨询

Verilog Buffer模块仿真中buffer2输出差异的原因分析

我在Modelsim仿真Verilog编写的Buffer模块时,发现两种不同控制ena信号的方式下,buffer2的输出结果存在明显差异。以下是模块代码、测试平台代码,以及具体的原因分析:

1. Buffer模块代码

module buffer(
    input wire clk,
    input wire ena,
    output wire buffer,
    output wire buffer2
);
reg buffer_reg = 1'b0;
reg buffer_next = 1'b0;
reg buffer2_reg = 1'b0;

assign buffer = buffer_reg;
assign buffer2 = buffer2_reg;

always @(*) begin
    buffer_next = ena;
end

always @(posedge clk) begin
    buffer_reg <= buffer_next;
    buffer2_reg <= ena;
end
endmodule

2. 测试平台代码

`timescale 1ns / 1ns
module buffer_tb();

localparam CLK_CYCLE = 8;

reg clk;
reg ena;
wire buffer;
wire buffer2;

buffer dut(
    .clk(clk),
    .ena(ena),
    .buffer(buffer),
    .buffer2(buffer2)
);

// Clock generation
initial begin
    clk = 1'b0;
end

always #(CLK_CYCLE/2) clk = ~clk;

// Test sequence
initial begin
    // Initialize signals
    ena = 0;

    // change ena values based on the posedge clk
    @(posedge clk) ena = 1;
    @(posedge clk) ena = 0;
        
    repeat(5) @(posedge clk);
        
    @(posedge clk) ena = 1;
    @(posedge clk) ena = 0;
    
    
    repeat(2) #CLK_CYCLE;
    
    // change ena values based on the CLK_CYCLE
    #(CLK_CYCLE) ena = 1;
    #CLK_CYCLE ena = 0;
  
    repeat(5) #CLK_CYCLE;
  
    #CLK_CYCLE ena = 1;
    #CLK_CYCLE ena = 0;

    // Allow simulation to run for a while
    #50 $stop;   // Stop simulation
end
endmodule 

3. 差异原因解析

核心问题出在Verilog仿真的事件调度顺序,以及两种控制方式下ena信号变化与时钟上升沿的时间关系:

用@(posedge clk)控制ena的情况

当用@(posedge clk)触发ena赋值时,ena的更新发生在时钟上升沿的同一仿真时间步,但晚于时钟事件的触发:

  1. 时钟上升沿先触发always @(posedge clk)块执行;
  2. 此时ena还没完成更新,buffer2_reg采样到的是ena变化前的旧值;
  3. 时钟事件处理完毕后,ena的赋值才生效;
    所以buffer2的变化会比ena晚一个时钟周期,和buffer的行为一致(buffer是先通过组合逻辑锁存ena,再同步到寄存器)。

用#CLK_CYCLE控制ena的情况

CLK_CYCLE设为8ns,时钟周期正好是8ns(高低电平各4ns)。用#CLK_CYCLE延时赋值ena时:

  1. 假设初始时钟上升沿在0ns,下一个上升沿在8ns;
  2. #8ns的延时会让ena的变化恰好发生在时钟上升沿的同一时刻;
  3. 仿真事件调度中,ena的赋值事件优先级高于时钟上升沿的触发事件,会先执行;
  4. 因此always @(posedge clk)块执行时,会采样到已经更新后的ena新值;
    最终buffer2会和ena的变化同步,没有延迟,这就和第一种控制方式的表现产生了差异。

关键总结

两种控制方式的本质区别是ena变化与时钟上升沿的相对时序:

  • @(posedge clk)赋值:ena在时钟沿之后更新,寄存器采样旧值;
  • #CLK_CYCLE赋值:ena在时钟沿时刻先更新,寄存器采样新值;

这种差异是仿真事件调度规则导致的,实际硬件中如果ena是同步产生的,会和第一种情况一致;第二种情况属于仿真中人为制造的“零时间差”边界场景,硬件里几乎不会出现(信号变化不可能完全和时钟沿精准对齐)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 05:43:14