Skip to content
深入#时序分析#建立时间#保持时间#亚稳态#同步器#约束

时序分析:建立/保持时间与亚稳态 ​

1. 设计动机 ​

<>

两个触发器在同一个时钟域里传数据:发端 FF 在时钟沿把数据打出来,经过组合逻辑,到收端 FF 的 D 端。问题是——收端 FF 在自己的时钟沿采数据时,数据到了没有?稳了没有?

如果数据到得太晚,违反建立时间(Setup Time, tSU),收端采到半稳定数据,输出可能卡在 0/1 之间的"亚稳态",系统偶发跑飞。这就是数字系统"看波形没问题但偶发死机"的头号根因。本章讲清楚:怎么算裕量、怎么判违例、亚稳态怎么缓解。

本章是时序逻辑的"验收标准"。所有同步设计最终都要回答:在目标时钟频率下,建立时间够不够、保持时间够不够、跨时钟域会不会亚稳。

2. 原理与逻辑图 ​

2.1 同时钟域数据通路 ​

发端 Launch FF 在时钟沿把 Q 打出来,经过组合逻辑延迟,到达收端 Capture FF 的 D 端。收端 FF 在同一个时钟沿(下一拍)采样这个 D。

同时钟域数据通路:Launch FF → 组合逻辑 → Capture FF,标注 Tco / Tlogic / tSU / tH
同时钟域数据通路:Launch FF → 组合逻辑 → Capture FF,标注 Tco / Tlogic / tSU / tH

关键延迟:

  • TcoT_{co}:发端 FF 从时钟沿到 Q 输出的延迟(clk-out)。
  • TlogicT_{logic}:组合逻辑延迟。
  • TskewT_{skew}:时钟到达两个 FF 的时刻差(时钟树偏斜)。
  • tSUt_{SU}:收端 FF 要求数据比时钟沿提前稳定的时间。
  • tHt_H:收端 FF 要求数据比时钟沿之后继续保持的时间。

2.2 建立时间(Setup) ​

数据必须在捕获沿之前 tSUt_{SU} 时间就稳定。建立时间方程:

Tco+Tlogic+Tskew≤Tclk−tSUT_{co}+T_{logic}+T_{skew} \le T_{clk}-t_{SU}

左边是数据实际到达 D 的时刻(相对发端沿),右边是收端沿减去建立窗口。数据路径太慢 → 左边太大 → 建立违例(Setup Violation),表现为"频率跑不上去"。

2.3 保持时间(Hold) ​

数据在捕获沿之后还要保持 tHt_H 不能变。保持时间方程:

Tco+Tlogic,min≥tHT_{co}+T_{logic,min} \ge t_H

数据路径太快 → 还没等 tHt_H 过完,新数据就来了 → 保持违例(Hold Violation)。保持违例比建立违例更隐蔽——上电就错,跟频率无关。

3. 静态分析(时序余量) ​

以典型 28nm FPGA 参数(量级示意):Tco=0.3nsT_{co}=0.3\text{ns},Tlogic=2.0nsT_{logic}=2.0\text{ns},Tskew=0.1nsT_{skew}=0.1\text{ns},tSU=0.5nst_{SU}=0.5\text{ns},tH=0.2nst_H=0.2\text{ns}。

时钟周期建立余量 slack_setup判定
10ns (100MHz)10−0.3−2.0−0.1−0.5=7.110-0.3-2.0-0.1-0.5=7.1ns✓ 富余
5ns (200MHz)5−0.3−2.0−0.1−0.5=2.15-0.3-2.0-0.1-0.5=2.1ns✓
3ns (333MHz)3−0.3−2.0−0.1−0.5=0.13-0.3-2.0-0.1-0.5=0.1ns勉强
2.5ns (400MHz)2.5−0.3−2.0−0.1−0.5=−0.42.5-0.3-2.0-0.1-0.5=-0.4ns✗ 建立违例

保持余量:Tco,min+Tlogic,min−tHT_{co,min}+T_{logic,min}-t_H。只要数据路径最短延迟大于 tHt_H 就 OK,与时钟周期无关。

4. 动态分析(时序波形与亚稳态) ​

下面用波形画出建立/保持窗口:CLK 上升沿为中心,左边 tSUt_{SU}、右边 tHt_H 是"禁区",数据落在禁区外才安全。

亚稳态波形:数据恰好在建立/保持窗口内翻转,收端输出既不是干净 0 也不是干净 1,在中间电平停留不确定时间后才落到某一态。

Q 在亚稳电平(~0.5V)徘徊了好几拍,第 7 拍后才落到 1——这就是亚稳态:时间不确定、电平非法。

5. 时序约束与亚稳态分析 ​

5.1 时序约束(Timing Constraints) ​

  • 创建时钟:告诉工具主时钟频率 TclkT_{clk},工具据此算建立/保持裕量。
  • 输入延迟/输出延迟:告诉工具外部数据相对时钟的到达/要求时刻。
  • 多周期路径:某些路径不需要每个周期都稳定(如使能每隔几拍才有效),放宽约束。
  • 伪路径(false path):不会真发生的路径(如异步输入),工具不该查它的建立保持。

5.2 亚稳态与 MTBF ​

触发器采样异步输入时,若数据落在建立/保持窗口内,输出可能进入亚稳态。亚稳态持续时间不确定,概率上平均无故障时间 MTBF:

MTBF=etmeta/τT0⋅fclk⋅fdataMTBF = \frac{e^{t_{meta}/\tau}}{T_0 \cdot f_{clk}\cdot f_{data}}

时钟越快、异步事件越多,MTBF 越短。唯一硬件缓解办法:同步器——用两级(或多级)触发器打拍,第一级可能亚稳,但等它稳定后再进第二级,第二级输出几乎一定合法。

5.3 跨时钟域(CDC) ​

  • 单 bit 异步信号:过两级同步器。
  • 多 bit 总线跨时钟域:不能逐位同步(各位到达时刻不一致会拼出错值),必须用握手或异步 FIFO。
  • 控制信号跨域:同步器;数据总线跨域:异步 FIFO。
<>

第一级 FF 采样到异步数据时可能进入亚稳态,但亚稳态不是永久的——它会在时间常数 τ\tau 内指数级收敛到某个合法电平。两级同步器让第二级在下一个时钟沿才采样第一级输出,此时第一级大概率已经收敛。级数越多,留给收敛的时间越多,MTBF 指数提升。代价是延迟增加 1~2 拍。

6. 元件取值与工程权衡 ​

  • 建立裕量要留多少:一般要求 slack_setup > 0.2ns(工艺/电压/温度变化),不要卡 0.01ns 上线。
  • 同步器级数:2 级是默认;时钟频率 > 200MHz 或异步率高时用 3 级。
  • 跨域宽度:单 bit 用同步器;多 bit 别逐位同步,用 FIFO/握手。
  • 时钟偏斜 skew:时钟树设计决定最高频率,skew 越大可用周期越小,高速设计看时序报告 slack。

7. 完整设计示例 ​

<>
  1. 需求:50MHz 时钟(周期 20ns),数据路径 Tco=0.5ns,Tlogic=8ns,Tskew=0.2ns,tSU=0.5ns。
  2. 算建立裕量:slack = 20 − 0.5 − 8 − 0.2 − 0.5 = 10.8ns,非常富余。
  3. 若跑 200MHz(周期 5ns):slack = 5 − 0.5 − 8 − 0.2 − 0.5 = −4.2ns,建立违例,必须缩短组合逻辑(流水线、插寄存器)。
  4. 保持检查:最短数据路径 Tcomin=0.3ns,Tlogicmin=0.5ns,tH=0.2ns;0.3+0.5−0.2=0.6ns>0,保持 OK。
  5. 异步按键:按键直接进 D 会亚稳,必须过两级同步器。
  6. 结论:50MHz 下设计满足建立保持,按键加同步器后可上线。

8. 仿真与实验 ​

在 Logisim / FPGA 仿真器中:

  • 搭 Launch FF → 若干门延迟 → Capture FF,用仿真器观察数据到达 D 的时刻 vs 时钟沿。
  • 故意缩短时钟周期,观察 Capture FF 输出不定(亚稳)。
  • 在异步输入后加两级同步器,对比加之前/之后输出是否稳定。
  • 用 FPGA 时序分析工具(如 Quartus/Vivado 的 Timing Analyzer)看 slack 报告,确认所有路径正裕量。

扩展与变种电路 ​

扩展1:两级触发器同步器 2-FF Synchronizer ​

异步单 bit 输入(按键、跨时钟域信号)过两级触发器,把亚稳风险降到可接受。

两级同步器:异步输入先过 FF1(可能亚稳),等一拍稳定后再过 FF2,输出合法
两级同步器:异步输入先过 FF1(可能亚稳),等一拍稳定后再过 FF2,输出合法
<>
  • 异步输入不满足建立/保持,FF1 可能亚稳。
  • 但 FF1 的输出在下一个时钟沿时大概率已收敛,FF2 采到的是合法电平。
  • 延迟 = 2 个时钟周期;MTBF 随级数指数提升。
  • 仅适用单 bit 控制信号;多 bit 总线不能逐位同步。

设计要点:同步器两级必须是同一时钟域、同一组 FF,中间不要插组合逻辑。取值/对比:2 级 vs 3 级——高速/高异步率用 3 级。适用:按键、UART RX、跨域使能;不适用:多 bit 数据总线(用 FIFO)。

<>
  • 现象:跨时钟域后总线偶尔拼出错值,比如应该传 1000 却采到 0111。
  • 原因:各位经过同步器的延迟略有差异,且数据本身各位到达时刻不同,逐位同步会拼出中间态。
  • 解决:多 bit 跨域用异步 FIFO 或握手协议(req/ack),不能逐位过同步器。

扩展2:复位同步器(异步置位、同步释放)Reset Synchronizer ​

复位释放沿本身也可能违反建立时间,必须"异步生效、同步释放"。

复位同步器:/RST 异步强制两 FF 清零,释放时经 CLK 打拍后才同步释放内部复位
复位同步器:/RST 异步强制两 FF 清零,释放时经 CLK 打拍后才同步释放内部复位
<>
  • 复位有效时:/RST 异步直接清两个 FF,内部复位立刻生效(不等时钟)。
  • 复位释放时:/RST 先撤,但 FF1.D=1 要等下一个时钟沿才打入,再下一个沿 FF2 才输出 1——释放被延迟 2 拍,对齐到时钟沿。
  • 这样释放沿不违反建立时间,避免复位释放导致亚稳。

设计要点:复位树异步生效、同步释放是通用做法。取值/对比:全异步复位 vs 异步置位同步释放——前者释放沿可能亚稳,后者安全。适用:FPGA/MCU 复位设计;不适用:极慢/慢边沿复位源(还要先整形)。

<>
  • 现象:上电后系统偶发跑飞,复位释放时刻不确定。
  • 原因:RC 慢边沿在复位阈值附近徘徊很久,正好被时钟沿采样到亚稳区。
  • 解决:复位源(上电 POR、按键、看门狗)先经施密特整形,再进复位同步器。

9. 常见坑与故障现象 ​

<>
  • 异步输入不过同步器:按键、外部总线直接进数据端,偶发亚稳导致状态机跑飞。异步单 bit 必过两级同步器。
  • 保持违例没查:只看建立时间 slack,忘了保持。保持违例上电就错、跟频率无关,最难查。时序报告必须同时看 setup 和 hold。
  • 多 bit 跨域逐位同步:拼出错值。多 bit 用异步 FIFO/握手。
  • 复位直接全局异步释放:释放沿亚稳。要异步置位、同步释放。

10. 自测题 ​

建立时间 slack = −0.3ns 意味着什么?怎么解决?

数据路径太慢,在当前时钟频率下数据到达 Capture FF 的 D 端时已经晚于建立窗口,FF 可能采样错误。解决:降低时钟频率(加大周期)、缩短数据路径(插入流水线寄存器、简化组合逻辑)、或换更快的工艺/FF。

为什么保持违例比建立违例更难查?

建立违例跟频率有关,降频就消失、容易复现;保持违例是数据路径太快,上电就错、跟频率无关,即使降频也错。而且它通常只在某些极端条件(最佳工艺角)出现,仿真和常温测试可能发现不了。

一个 8 位数据总线从慢时钟域传到快时钟域,能给每一位各加一个两级同步器吗?

不能。各位同步器延迟略有差异,且数据本身各位变化时刻不同,逐位同步会拼出中间错值(比如该传 1000 采成 0111)。多 bit 跨时钟域必须用异步 FIFO 或 req/ack 握手,保证整组数据同时有效。

11. 参考资料 ​

  • sources/notes/metastability-clockreset.md
  • AMD/Xilinx 复位设计与时序约束应用文档