3. 异步复位设计:实现方式、优缺点与亚稳态问题

异步复位,这名字听着就有点「不守规矩」的意思。确实,它不像同步复位那样跟着时钟走,而是随时都可能跳出来打断电路的工作。我在很多项目里都见过它,说白了,它是个双刃剑——用好了很顺手,用不好就埋雷。

3.1 异步复位的实现方式

实现起来其实很简单。就是把复位信号直接接到触发器的异步复位端(通常是CLR或RST引脚)。

// 异步复位D触发器
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        q <= 1'b0;
    else
        q <= d;
end

你看,敏感列表里既有时钟上升沿,又有复位下降沿。这就是异步复位的标志。只要rst_n拉低,不管时钟在干嘛,输出立刻清零。

我个人习惯在顶层模块里统一做异步复位,这样每个子模块的复位逻辑都很干净。不过要注意,这里的rst_n是低电平有效,我见过新手写成高电平有效然后到处取反,那叫一个乱。

3.2 异步复位的优点

为什么大家喜欢用异步复位?我总结了几点:

  • 响应快:复位信号不依赖时钟,来了就复位。时钟停了也能复位。
  • 电路简单:不需要额外的同步逻辑,代码写起来也清爽。
  • 面积小:大部分标准单元库里的触发器本身就带异步复位端,不用白不用。
  • 适合低功耗:时钟门控时,异步复位依然有效。

我记得有个项目,芯片上电后时钟要等PLL锁定才能稳定。那段时间如果用同步复位,电路状态根本不可控。异步复位就完美解决了这个问题——先复位住,等时钟稳了再释放。

3.3 异步复位的缺点

当然,没有银弹。异步复位也有它的麻烦:

  • 容易受毛刺干扰:复位路径上的任何毛刺都会导致误复位。我在一个项目中遇到过,复位信号走线太长,被隔壁的时钟串扰了,结果芯片时不时自己复位一下。
  • 时序分析复杂:复位信号的恢复时间和移除时间需要STA检查,很多人会忽略这一点。
  • 释放时的亚稳态问题:这是最要命的,我单独拿出来讲。

3.4 异步复位释放时的亚稳态问题

好,重点来了。为什么异步复位释放会有亚稳态?

你想想看,复位释放时,复位信号的变化可能正好落在时钟的建立时间窗口内。这时候触发器会进入亚稳态——输出既不是0也不是1,而是一个中间电平,还可能振荡。

为什么会这样?因为触发器的异步复位端和时钟端是两条独立的路径。复位释放时,如果复位信号的变化沿离时钟沿太近,触发器内部的锁存结构就不知道该听谁的。

核心问题:异步复位释放时,复位信号的变化沿与时钟沿的相对关系是随机的。这违反了触发器的恢复时间(Recovery Time)和移除时间(Removal Time)约束。

我曾经在一个高速ADC接口项目中吃过这个亏。复位释放后,采集到的第一笔数据总是错的,查了两天才发现是复位释放亚稳态导致的。从那以后,我对复位释放的同步处理就特别上心。

3.5 异步复位同步释放

怎么解决?业界标准做法是——异步复位同步释放。说白了就是:复位用异步的,释放用同步的。

看代码:

// 异步复位同步释放电路
module rst_sync (
    input  wire clk,
    input  wire rst_async_n,
    output wire rst_sync_n
);

reg rst_s1, rst_s2;

always @(posedge clk or negedge rst_async_n) begin
    if (!rst_async_n) begin
        rst_s1 <= 1'b0;
        rst_s2 <= 1'b0;
    end
    else begin
        rst_s1 <= 1'b1;
        rst_s2 <= rst_s1;
    end
end

assign rst_sync_n = rst_s2;

endmodule

这个电路的工作原理:

  • 复位时:rst_async_n拉低,两个寄存器立即清零,输出rst_sync_n也拉低。这是异步的,响应很快。
  • 释放时:rst_async_n拉高,第一个寄存器在下一个时钟沿变成1,第二个寄存器再等一个时钟沿变成1。这是同步的,给了两个时钟周期的缓冲。

我的建议:两级同步就够了。三级当然更安全,但多一级就多一个时钟周期的复位释放延迟。除非你的时钟频率特别高(比如超过1GHz),否则两级足够。

3.6 复位释放的时序分析

这里有个容易忽略的点:复位释放后,所有触发器并不是在同一时刻退出复位状态的。

为什么?因为复位树的延迟。复位信号从根节点到每个触发器的路径长度不同,有的长有的短。释放时,短的先释放,长的后释放。这个时间差如果控制不好,会导致电路状态混乱。

问题 原因 解决方法
复位释放亚稳态 复位释放沿与时钟沿冲突 异步复位同步释放
复位释放不同步 复位树延迟差异 复位树平衡 + 同步释放
复位毛刺误触发 复位路径受干扰 加滤波、加保护环

警告:千万不要在多个时钟域之间直接共用同一个异步复位信号。每个时钟域都应该有自己的复位同步器。我曾经见过有人图省事,一个复位信号直接拉到两个时钟域的触发器上,结果复位释放时两个域不同步,数据路径直接崩了。

3.7 知识体系图

下面这张图总结了异步复位设计的核心要点:

异步复位设计知识体系 实现方式 优缺点分析 亚稳态问题 直接连接异步复位端 敏感列表包含复位信号 优点:响应快、面积小 缺点:毛刺敏感、时序复杂 恢复/移除时间违规 释放沿与时钟沿冲突 解决方案:异步复位同步释放 两级寄存器同步 复位树平衡设计

嗯,这张图把异步复位的三个核心维度串起来了。你从实现方式出发,看到优缺点,再落到亚稳态问题,最后用同步释放来收尾。整个知识链是闭环的。

最后说一句,异步复位本身不是问题,问题在于释放时的处理。只要把同步释放做好了,异步复位其实是个很优雅的方案。我在多个量产芯片里都用这个方案,从来没出过复位相关的问题。

避坑指南:我曾经在一个项目中,复位同步器只做了一级。结果后仿真时发现复位释放后第一个时钟周期有不定态。改成两级后就稳了。所以,别省那一级寄存器,省出来的那点面积,不够你查一次bug的时间成本。

可可精品资料库