4. 异步复位同步释放:经典的双级同步器结构,如何解决异步复位释放的亚稳态问题

复位信号在数字电路里,就像给系统按了个“重启键”。但麻烦的是,复位信号往往是异步的——它随时可能来,也随时可能走。尤其是复位释放的那一刻,如果刚好撞上时钟沿,那可就热闹了。

我早年做第一个项目时,就吃过这个亏。当时复位释放没处理好,芯片上电后有一半的寄存器状态是乱的,查了整整三天才定位到问题。从那以后,我对复位同步这件事就格外上心。

4.1 问题本质:复位释放为什么危险?

先想清楚一个问题:复位有效时,所有寄存器都被强制清零,这时候无所谓同步不同步。但复位释放的瞬间,寄存器要从“被强制”状态回到“正常采样”状态。如果这个释放沿刚好落在时钟的建立/保持窗口内,寄存器输出就会进入亚稳态。

说白了,亚稳态就是寄存器“卡在中间”——既不是0也不是1,输出电平在两者之间来回振荡。更可怕的是,这个不稳定状态会沿着组合逻辑传播,把整个系统都带偏。

核心矛盾:复位释放是异步事件,而时钟是同步的。异步事件进入同步域,必须经过同步处理。

4.2 经典解法:双级同步器结构

解决这个问题,业界最成熟的做法就是“异步复位同步释放”。名字听着绕口,其实逻辑很简单:

  • 复位有效时:直接异步清零,不经过同步器,保证复位速度
  • 复位释放时:用两级触发器同步,让释放沿对齐到时钟域

我画了个结构图,你看一眼就明白了:

异步复位同步释放——双级同步器结构 rst_n clk D Q FF1 异步复位 时钟 D Q FF2 rst_sync_n 复位有效时:rst_n 直接异步清零 FF1 和 FF2 复位释放时:经过两级时钟同步后输出 rst_sync_n

4.3 为什么两级就够了?

你可能会问:一级同步器不行吗?为什么非要两级?

嗯,这里有个关键点。一级同步器确实能降低亚稳态概率,但还不够。亚稳态的衰减需要时间,一级触发器只能提供一个时钟周期的“等待窗口”。如果这个周期不够长,亚稳态还没完全稳定就传出去了。

两级同步器相当于给了两个时钟周期的缓冲。第一级可能进入亚稳态,但第二级采样时,第一级的输出已经基本稳定了。就算第一级还在振荡,第二级采到“中间值”的概率也极低。

经验数据:对于典型的工艺和频率,两级同步器可以把亚稳态的MTBF(平均无故障时间)做到几百年甚至上千年。一级同步器可能只有几毫秒。差距就是这么大。

4.4 代码实现:Verilog示例

直接上代码,这是我项目里常用的模板:

module rst_sync (
    input  wire clk,
    input  wire rst_n,       // 异步复位输入
    output wire rst_sync_n   // 同步后的复位输出
);

reg rst_n_ff1, rst_n_ff2;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        rst_n_ff1 <= 1'b0;
        rst_n_ff2 <= 1'b0;
    end else begin
        rst_n_ff1 <= 1'b1;
        rst_n_ff2 <= rst_n_ff1;
    end
end

assign rst_sync_n = rst_n_ff2;

endmodule

注意看:复位有效时,两个触发器都被异步清零,输出立即为0。复位释放后,rst_n_ff1先变1,下一个时钟沿rst_n_ff2才变1。这个“延迟两个周期”的特性,就是同步释放的精髓。

我曾经踩过的坑:千万别把同步后的复位信号再拿去异步复位其他寄存器!同步后的rst_sync_n应该作为全局复位信号,但所有使用它的寄存器,复位端必须接这个同步后的信号,而不是原始的rst_n。否则就白同步了。

4.5 时序约束:别忘了告诉工具

代码写完了,还得给综合工具交代清楚。异步复位信号不需要做setup/hold检查,但同步器内部的路径需要约束。

约束对象 约束类型 说明
rst_n 到 FF1 的复位端 set_false_path 异步路径,不做时序检查
FF1 Q 到 FF2 D 正常时序路径 需要满足setup/hold,但可以放宽
FF2 Q 到下游逻辑 正常时序路径 按常规约束处理

我个人习惯在SDC里这样写:

# 异步复位信号设为false path
set_false_path -from [get_ports rst_n] -to [get_pins rst_sync_inst/rst_n_ff1/C]

# 同步器内部路径可以放宽
set_max_delay -from [get_pins rst_sync_inst/rst_n_ff1/Q] \
              -to [get_pins rst_sync_inst/rst_n_ff2/D] 10.0

4.6 多比特复位同步:小心!

如果系统里有多个复位域,每个复位域都需要独立的同步器。千万别图省事,用一个同步器输出分给多个域。

为什么?因为不同域的时钟可能不同频、不同相。一个同步器输出只能保证跟它自己的时钟域对齐。分给其他时钟域,又变成异步信号了。

黄金法则:每个时钟域配一个独立的复位同步器。同步器的输出只给本时钟域的寄存器使用。

4.7 小结

异步复位同步释放,说白了就是“复位快,释放慢”。复位时走异步路径,保证速度;释放时走同步路径,保证稳定。两级触发器给了亚稳态足够的衰减时间,让系统从复位状态平稳过渡到正常工作状态。

这个结构我用了十几年,从FPGA到ASIC,从低速到GHz级,从来没出过问题。只要你记住:每个时钟域一个同步器,同步后的复位只给本域用,时序约束别漏掉——基本就稳了。

可可精品资料库