打两拍就能“消灭”亚稳态吗?
从一张 74HC174 的示波器照片说起
记忆要点
- 所有触发器都有亚稳态特性。
- 触发器输出延迟大于 T 秒的概率,随着时间 T 的增长呈指数下降。
——《高速数字设计》第 3 章,3.11.4 节
先说结论:打两拍不能消灭亚稳态;它只是把出错概率按指数规律压低,压低到工程上可以接受的程度。 这个结论听起来像“正确的废话”,但如果你看过触发器在示波器上真正进入亚稳态时的表现,就会明白“打两拍”为什么是数字设计里性价比最高的一招,也会明白它为什么常常被误用。
一、亚稳态不是采错值,是迟迟不决
触发器在时钟沿采样时,数据必须满足 setup/hold 窗口。如果跳变正好落在窗口里,内部锁存节点就会被推到 0 和 1 之间的某个电平;它最终会倒向 0 或 1,但要多久才倒下,是一个随机变量。
这个随机变量的尾部很长:大多数情况下它很快稳定,但极小概率下会拖很久。书里的两句话把这件事说透了:
- 输出延迟大于 T 秒的概率,随 T 指数下降;
- 但指数下降意味着永远不为零。
所以工程上从不问“会不会发生”,只问“多久发生一次”(MTBF, Mean Time Between Failure)。
二、示波器上的证据:45 ns 和 50 小时
书中图 3.33 用 74HC174(CMOS)做了 30 分钟的点累计实验,横轴 10 ns/格:

- 数据和时钟几乎同时跳变,Q 输出在时钟沿之后没有干脆地爬上去,而是拖出一大片密集的“墨迹”;
- 最后一个区域里,时钟到输出的延迟被拉到了 45 ns;
- 书中记录,各区域的衰减常数约为 10(ns 量级);
- 更关键的是:再等 50 个小时(是 30 分钟的 100 多倍),才能在 55 ns 的区域里再凑到 4 个点。
也就是说,延迟从 45 ns 拉到 55 ns,概率又掉了一个数量级,但为了抓到这几个样本,需要多等两个数量级的时间。这就是“指数尾部”的直观含义:越晚越安全,但永远没有绝对安全。
图 3.34 换成 74F174,延迟明显更短,但“效果相同”。书中还特别提醒:74F174 的输出缓冲能力更小,Q 会先爬到一个中间平台,然后才决定变高还是变低。对于接在 Q 后面、对边沿敏感的电路,这种毛刺很容易使其触发。

这一点常被忽略:亚稳态的危害不只是“值可能错”,还包括在错误的时间产生一个像边沿的东西。后者对计数器、状态机、中断控制器往往更致命。
三、打两拍:把一次赌博变成两次
两级同步器的结构简单到不能再简单:
异步输入 ──► [FF1] ──► [FF2] ──► 同步后的信号 ──► 后续逻辑
↑ ↑
可能亚稳态 再采样(只它允许扇出)
书里的说法是:
将两个(或多个)触发器串联,用同一个时钟驱动。N 个触发器发生错误的概率是 P^N,其中 P 是一个触发器发生亚稳态错误的概率。标准的方法是采用至少两个触发器(有时采用 3 个)进行同步串联。
P^N 是一个工程近似(严格说,这是条件概率的连乘,第二级自身也有亚稳态窗口),但它抓住了本质:
- FF1 可以进入亚稳态,但它的输出被“隔离”了,不参与任何组合逻辑;
- 从 FF1 的时钟沿到 FF2 的下一个采样沿,中间有将近一个完整时钟周期让 FF1 衰减;
- FF2 采样时,FF1 已经以极高概率稳定;即使 FF2 自己偶尔进入亚稳态,那也是“FF1 一个周期后仍未稳定”这一小概率事件再次发生的条件概率;
- 只有 FF2 的输出允许进入后续逻辑。
所以打两拍的本质是:把“可能出错”的那段时间,挪到一个没人看的角落里,并用指数规律把概率压下去。
四、把“缓解”量化:MTBF
工程上不靠感觉,靠下面这个式子:
MTBF ≈ e^(t_r / τ) / (T_W · f_clk · f_data)
| 符号 | 含义 | 怎么影响 |
|---|---|---|
t_r |
留给第一级解析的时间(约一个周期减去第二级 setup 和第一级 t_pd) | 指数项,最敏感 |
τ |
触发器亚稳态时间常数(工艺相关) | 越小越好 |
T_W |
亚稳态窗口宽度 | 越小越好 |
f_clk |
时钟频率 | 越高越糟 |
f_data |
异步数据翻转率 | 越高越糟 |
举个示意性的例子(数值仅用于说明量级):设 T_W = 0.1 ns、τ = 0.2 ns、f_clk = 100 MHz、f_data = 1 MHz。
- 只打一拍,
t_r ≈ 0.2 ns:MTBF ≈ e^1 / 10^4 ≈ 0.27 ms,几乎一直在出错; - 打两拍,
t_r ≈ 10 ns:MTBF ≈ e^50 / 10^4 ≈ 5×10^17 s,约百亿年。
同样的电路,只多加一个触发器,MTBF 从“毫秒级”变成“百亿年级”。 这就是为什么几乎每个跨时钟域的单比特信号后面都跟着两级触发器。
但也别被这个数字冲昏头:t_r 只要少一点,指数项就掉得很快。高频、低压、慢工艺角下,两拍可能不够,需要三拍。
五、书中另外四条建议,今天依然好用
3.11.4 节一共给了五条建议,打两拍只是第二条。其余几条放到今天的 FPGA/ASIC 流程里,依然一一对应:
| 书中建议 | 背后的道理 | 现代对应做法 |
|---|---|---|
| 1. 采样快速触发器,可能有较窄的亚稳态时间窗 | 窗口窄、再生快 | 选高带宽工艺;用库里的同步专用单元 |
| 2. 两个或多个触发器串联,同一时钟驱动 | 错误概率 P^N | 两级/三级同步器,ASYNC_REG |
| 3. 使用能克服亚稳态的触发器 | 内部低电压、速度快、K 值大,再生能力强 | 同步器专用 cell,而不是随便拿个普通 DFF |
| 4. 尽量降低采样频率 | 周期变长,t_r 变大;失效率比指数下降还快 |
降频、分频后采样、使能采样 |
| 5. 输入边沿要快 | 慢变信号会在禁区里停留更久,亚稳态性能反而变差 | 加缓冲/施密特整形,别让慢沿直接进同步器 |
第 5 条尤其反直觉:“信号很慢”不等于“安全”。一个缓慢爬升的边沿会让触发器在阈值附近徘徊很久,反而更容易被采到中间电平。所以跨时钟域信号最好有干净、快速的边沿。
六、工程落地:打两拍的正确姿势
结构人人会画,坑几乎都在细节里:
- 两级必须同域、同钟、物理相邻,中间不能插任何组合逻辑。
- 只有第二级输出可以扇出;第一级输出必须视为同步器私有,禁止被其他逻辑读取。综合工具若把第一级输出优化出去,同步器就名存实亡。
- 时序约束要写对:
- 源端到 FF1:
set_false_path或set_max_delay -datapath_only; - FF1 到 FF2:正常同步路径,不能设 false path。
- 源端到 FF1:
- FPGA 加
ASYNC_REG = "TRUE",让工具把两级放进同一 slice、优化布局,提高 MTBF:
(* ASYNC_REG = "TRUE" *) reg sync0, sync1;
always @(posedge clk) begin
sync0 <= async_in; // 第一级:允许亚稳态
sync1 <= sync0; // 第二级:输出才可用
end
wire synced = sync1; // 只用这一级
- 复位也要同步:异步复位、同步释放(reset synchronizer)。否则复位释放本身就是一次跨时钟域。
- 注意 latency:同步后信号晚 2 个周期,握手和状态机要按这个延迟设计。
七、打两拍解决不了的事
这是最容易翻车的地方:
- 多比特总线不能“每位打两拍”。各位的亚稳态衰减时间和走线延迟都不同,可能这一拍 bit0 是新值、bit1 还是旧值,拼出一笔从未存在过的数据。正确做法是异步 FIFO(Gray 码指针)、握手协议、或让数据保持足够久。
- 快变数据不能只靠同步器。同步器只保证“采到的电平是稳定的”,不保证“采到的是你要的那一笔”。采样定理和丢码问题它管不了。
- 窄脉冲会丢。如果异步脉冲比一个时钟周期还窄,两级同步器可能根本看不到它,需要脉冲展宽或握手。
- 高频下两拍不够。按 MTBF 反算,该三拍就三拍,别省那一个触发器。
- 亚稳态不会被“消除”。所有触发器都有亚稳态特性,这是物理,不是设计缺陷。
八、结语
回到最初的问题:打两拍能缓解亚稳态吗?
能,而且是最标准、最便宜、最有效的缓解手段。它把第一级可能出现的亚稳态“关”在一个周期里,让第二级去承担采样,再通过 P^N 的指数规律把失效概率压到可接受。
但它不是消灭,也不是万能:
单比特、异步、事件型信号 → 两级(必要时三级)同步器 + 正确约束 + 只用第二级输出。
多比特数据 → 异步 FIFO / Gray 码 / 握手,别指望“每位打两拍”。
书里那张 74HC174 的照片之所以经典,是因为它把“指数尾部”画成了肉眼可见的墨迹:45 ns 时还在挣扎,55 ns 时几乎绝迹,但为了证明它绝迹,你得等 50 个小时。 数字设计做的,就是接受这个尾部永远存在,然后用两个触发器把它推到我们这辈子都遇不到的地方。

浙公网安备 33010602011771号