复位设计:异步断言同步释放、复位树与复位次序
更新时间:2026-09-06。本文是「集成电路大类 · 芯片设计」**进阶层(intermediate)**第十篇新正文(#12)。入门层 时钟与复位入门 讲了复位的概念,这一篇讲工程上怎么把复位做对。复位是芯片的「出生状态」:它在上电时把所有触发器置为已知值——没有可靠复位,上电后寄存器是随机态,状态机可能停在非法态(FSM 设计 的 default 也救不了初始态)、总线内容未知、X 态蔓延。复位 bug 典型特征是「仿真全过、上板偶发不起」,因为释放时刻与时钟沿的相位关系在真实硅片上是随机的。
本文要回答的问题
- 同步复位和异步复位各有什么坑?
- 「异步断言、同步释放」为什么是标准答案?电路怎么搭?
- 复位为什么也要像时钟树一样做树?
- 多个时钟域、PLL、RAM 的复位先后次序怎么排?
一、同步复位 vs 异步复位
同步复位(if(rst) ... else @(posedge clk)) | 异步复位(@(posedge clk or negedge rst_n)) | |
|---|---|---|
| 生效 | 要等时钟沿,时钟没跑就复位不了 | 立即生效,不依赖时钟——上电/时钟故障时也能复位 |
| 释放 | 同步于时钟,天然干净 | 释放时刻随机,可能违反 recovery/removal(复位释放离时钟沿太近,等价于复位场景的 setup/hold),部分触发器这拍进复位、那拍已退出 → 复位不同步 |
| 抗毛刺 | 好(毛刺不在沿上无效) | 差(复位线上的毛刺直接触发复位) |
| 综合 | 可能被综合进数据路径,省复位线 | 用触发器专用复位引脚,路径独立 |
两者各有死穴:同步复位在时钟尚未稳定(PLL 未锁定)时无法复位上电乱态;异步复位释放随机、会导致复位撤离不同步。
二、标准答案:异步断言、同步释放
结合两者优点的电路——复位按下(assert)走异步:rst_n 一旦拉低,所有触发器立刻复位,不需要时钟;复位释放(deassert)走同步:释放信号先经过本时钟域的两级触发器同步,再分发出去,保证所有触发器都在同一个时钟沿之后离开复位,recovery 时间充足。

// 复位同步器:异步断言、同步释放
always_ff @(posedge clk or negedge async_rst_n) begin
if (!async_rst_n) begin rst_sync1 <= 1'b0; rst_n <= 1'b0; end
else begin rst_sync1 <= 1'b1; rst_n <= rst_sync1; end
end三、复位树:像时钟树一样对待
复位信号扇出是全芯片级的(几万到几百万个触发器),一根线直连会有巨大的电容和延迟差异:远端触发器撤离复位比近端晚几纳秒,恰好跨过一个时钟沿,就出现「一半逻辑已工作、一半还在复位」。所以后端要做 reset tree:插多级缓冲、平衡各路径延迟(与 CTS 时钟树综合同理,见进阶 #25),让复位到达每个触发器的时间基本一致。前端要保证:① 复位信号上不挂组合逻辑(毛刺风险);② 不用数据信号当复位条件;③ 复位极性全芯片统一(惯例低有效 rst_n);④ 时序约束里对复位断言路径放宽、对释放路径做 recovery 时序检查。
四、多时钟域:每域一个复位同步器
每个时钟域用自己的时钟做「同步释放」——不能拿 A 域时钟同步的复位去复位 B 域触发器(那又成了跨域信号,释放时刻对 B 域时钟是随机的,CDC 问题重演,见 CDC 基础)。结构:全局异步复位源(POR 上电复位 + 软复位寄存器)分发到各域,各域内各放一个复位同步器,输出本域的 rst_n。这就是 RDC(Reset Domain Crossing)检查要查的东西,与 CDC 一样由 Spyglass 类工具静态签核(进阶 #38)。
五、复位次序:不是所有东西同时撤离
上电后各部件就绪时间不同,复位释放要按次序(reset sequencing):

要点:① PLL 锁定(lock)前时钟不稳定,核心逻辑不能释放复位——把 lock 纳入复位同步器的释放条件;② RAM/ROM 初始化(或加载固件)完成前,访问它的逻辑保持复位;③ 对外接口(UART/PCIe/网口)最后释放,防止未初始化时向对端发垃圾数据;④ 软复位(软件写复位寄存器)只复位本模块、不要误动 PLL 和存活域(always-on),低功耗域的复位隔离见进阶 #23/#24。
六、recovery/removal 与仿真抓不到的复位坑
复位也有自己的「建立/保持时间」,这是很多人没意识到的:
- recovery time(恢复时间):复位释放沿必须比下一个时钟沿早到的最小时间。等价于复位场景的建立时间——释放离时钟沿太近,这一拍触发器到底算「已退出」还是「还在复位」无法确定,可能亚稳。
- removal time(撤离时间):复位撤销沿必须比最近一个时钟沿晚到的最小时间。等价于保持时间——复位不能在时钟沿后太快撤,否则该沿应被复位的动作可能没生效。
「异步断言、同步释放」恰好同时治住两者:断言走异步清零端,不看时钟,不存在 setup 问题;释放经两级触发器与时钟对齐,recovery 天然满足。STA 里要对同步后的复位释放路径单独做 recovery/removal 检查(约束里通常 set_false_path 掉异步断言路径、保留释放路径的时序检查)。
仿真为什么常常抓不到复位 bug?因为复位释放沿和时钟沿的相位关系是随机的物理量,行为仿真里复位往往在整数时刻、和时钟沿离得远远的,永远不碰违例窗口;上板后温度、电压、时钟源不同,释放沿恰好压在 recovery 窗口才偶发。这类「仿真全绿、冷启动十次有一次不起」的问题,靠规范电路 + 约束 + RDC 静态检查兜底,而不是靠多跑仿真。
一张可以直接照着自查的复位 checklist:
- 全芯片复位极性、命名统一(惯例低有效
rst_n),异步复位全部进敏感列表且加negedge rst_n; - 每个时钟域有自己的复位同步器,不用 A 域同步出的复位去直接复位 B 域(过 RDC 检查);
- 复位线上是纯网络、不挂组合逻辑、不拿数据/状态当复位条件,扇出大由后端插缓冲建复位树;
- 复位释放纳入 PLL lock、RAM 初始化完成条件,次序为 POR→PLL→核心→对外 IO;
- 每个需要已知初值的寄存器(尤其 FSM 状态、有效/忙碌标志、指针、总线 grant)都真的被复位覆盖——lint 里查「未复位的寄存器」;
- 数据 RAM、流水线数据寄存器等可考虑不复位以省面积/功耗,但 FSM 和控制必须复位;
- 软复位只复位目标域,别误清 always-on、PLL 配置和正在进行的外部事务;
- 约束:异步断言路径 false path,释放路径保留 recovery/removal 检查。
相关与延伸
上一篇:多 bit CDC:异步 FIFO。下一篇进入时序收敛线:SDC 约束实战(#13)。入门铺垫:时钟与复位入门;CDC 配合见 CDC 基础;recovery/removal 时序概念见 STA;复位树后端实现见进阶 #35 CTS,RDC 签核见 #45,低功耗域复位见 #23 低功耗 RTL / #24 UPF。
总结
复位设计的标准答案是「异步断言、同步释放」:按下立即生效不依赖时钟,释放经本域两级触发器同步保证全芯片同沿撤离;多时钟域各用各的时钟做同步器(RDC 签核),后端做平衡复位树,释放次序按 POR→PLL 锁定→核心逻辑→对外接口排——复位 bug 上板才现,必须在设计和检查阶段一次做对。