FPGA 时序约束:input_delay / output_delay / max_delay / min_delay
目录
- 0. 基础概念
- 1. set_input_delay
- 2. set_output_delay
- 3. set_max_delay / set_min_delay
- 4. -datapath_only 什么时候加
- 5. 决策速查表
0. 基础概念
三句话讲清本质
input_delay/output_delay不是设 FPGA 内部的延迟,是告诉工具外部世界的数据到达/出发时间- 工具拿
时钟周期T - 外部延迟 - 寄存器开销,反推出 FPGA 内部还能花多少时间 max_delay/min_delay不看时钟,直接管布线长度,用于异步信号和 CDC
约束影响布局
| 约束 | 影响布局吗 | 机制 |
|---|---|---|
create_clock | ✅ 强 | 周期是硬上限 |
input_delay/output_delay | ✅ 中~强 | 通过 setup/hold 方程间接驱动 |
set_max_delay/set_min_delay | ✅ 强 | 直接限走线长度 |
set_false_path | ⚠️ 放任 | 砍掉后工具可能放飞 |
1. set_input_delay
1.1 物理模型
外部器件 FPGA 内部 ┌────────────┐ ┌──────────────────┐ │ 寄存器 │ │ 寄存器 │ CLK ──────┼────────────┼────────────┼──────────────────┤ │ │ │ │ │ clk→Q ────┼── DATA ───┼── 组合逻辑 ──────┤ │ │ ↑ │ ↑ │ └────────────┘ ↑ └────────↑─────────┘ ↑ ↑ input_delay 内部路径 外部延迟 (工具要算的)set_input_delay= 数据从外部寄存器的时钟沿到FPGA 数据 pin的时间。
工具用这个值反推内部预算:
内部 setup 预算 = T - input_delay_max - Tsu 内部 hold 预算 = input_delay_min - Th1.2 物理系统与 PCB 延迟
50MHz 晶振 │ ┌─────┴─────┐ │ 时钟缓冲器 │ └──┬─────┬───┘ │ │ PCB_clk1 │ │ PCB_clk2 = 3ns │ │ = 2ns │ │ ┌────┴─┐ ┌─┴────────┐ │ FPGA │ │ ADC │ │ CLK │ │ CLK pin │ │ pin │ │ │ │ │ │ DOUT pin│ │ DATA │←┼──────────┘ │ pin │ PCB_data └──────┘ = 1.5ns已知参数:
时钟周期: T = 20ns (50MHz) ADC 参数: t_co_min = 2ns, t_co_max = 8ns (CLK↑→DOUT 有效) PCB 走线: PCB_clk1 = 3ns (晶振→FPGA) PCB_clk2 = 2ns (晶振→ADC) PCB_data = 1.5ns (ADC→FPGA) FPGA: Tsu = 0.4ns, Th = 0.2ns1.3 计算公式
input_delay_max = PCB_clk2 + t_co_max + PCB_data - PCB_clk1 = 2 + 8 + 1.5 - 3 = 8.5ns input_delay_min = PCB_clk2 + t_co_min + PCB_data - PCB_clk1 = 2 + 2 + 1.5 - 3 = 2.5ns为什么减 PCB_clk1?input_delay的含义是"FPGA 时钟 pin 收到沿之后,数据还要多久才到"。减 FPGA 侧的 PCB 延迟,就是把测量基准从晶振挪到 FPGA 时钟 pin。
1.4 时间轴推演:SETUP 分析(最慢路径)
t=0 晶振输出时钟沿 t=2 ADC 收到时钟沿 (PCB_clk2=2ns) ADC 开始输出数据, 最慢 t_co_max=8ns t=3 FPGA 收到时钟沿 (PCB_clk1=3ns) → 以此为 t=0 (相对时间) t=10 ADC DOUT 数据有效 (2+8=10ns, 绝对) t=11.5 FPGA 数据 pin 收到新数据 (10+1.5=11.5ns, 绝对) 相对时间: 11.5 - 3 = 8.5ns ← input_delay_max!时间轴 (以 FPGA CLK pin 为基准): 0 2 4 6 8 10 12 14 16 18 20ns ├─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┤ 基准: ┌──────────────────────────────┐ FPGA CLK pin(t=0): ──┘ └── 下一个沿 ↑ ↑ 采沿(0) 采沿(20) 外部数据到 pin: ├────── input_delay_max=8.5ns ───┤ ↓ │ t=8.5ns ← 数据到了 │ FPGA 内部能花的: │◄──── 内部预算 11.1ns ────►│ 20 - 8.5 - 0.4(Tsu) = 11.1nssetup 方程:8.5 + FPGA内部路径 < 20 - 0.4→ 内部路径 < 11.1ns。非常宽裕。
1.5 时间轴推演:HOLD 分析(最快路径)
t=0 晶振沿 t=2 ADC 收到沿 → t_co_min=2ns → 数据 t=4 有效 t=3 FPGA 收到沿 (相对 t=0) t=5.5 FPGA pin 收到数据 (4+1.5=5.5 绝对, 相对 5.5-3=2.5ns) hold 方程: 2.5 + FPGA_internal_path_min > 0.2(Th) → FPGA_internal_path_min > -2.3ns → 实际内部最短 ~0.5ns > -2.3ns → 自动满足 ✅1.6 极端例子:负的 input_delay_min
PCB_clk1(FPGA)=15ns, PCB_clk2(ADC)=2ns (ADC 紧贴晶振) PCB_data=1.5ns, t_co_min=2ns input_delay_min = 2+2+1.5-15 = -9.5ns ← 负数!含义:FPGA 时钟 pin 还在等沿 (15ns),数据 5.5ns 就到了——数据比时钟早到 9.5ns。
hold 要求: -9.5 + FPGA_internal_path_min > 0.2 → FPGA_internal_path_min > 9.7ns 工具必须把内部路径拉到至少 9.7ns! → 插 buffer/LUT 拖慢 → 否则新数据会砸掉上一笔的 hold1.7 max/min 总结
| 参数 | 算什么 | 管什么 | 设错了的后果 |
|---|---|---|---|
| max | PCB_clk2+t_co_max+PCB_data-PCB_clk1 | FPGA 内部 setup | 设太小→假违例;设太大→实际违例漏报 |
| min | PCB_clk2+t_co_min+PCB_data-PCB_clk1 | FPGA 内部 hold | 设太小→没问题(悲观);设太大→隐藏 hold 违例 |
工程原则:max 往大设,min 往小设。两头悲观,工具找真正的安全解。
2. set_output_delay
2.1 物理模型
FPGA 内部 外部器件 ┌──────────────────┐ ┌────────────┐ │ 寄存器 │ │ 寄存器 │ CLK ───┼──────────────────┼───────────┼────────────┤ │ │ │ │ │ clk→Q ── DATA ──┼───────────┼── 组合 ────┤ │ │ ↑ │ ↑ │ └──────────────────┘ ↑ └─────↑──────┘ ↑ ↑ FPGA内部 output_delay 路径 外部延迟set_output_delay= 数据从FPGA 输出 pin到下游器件寄存器 D 脚的时间(含 PCB + 下游 Tsu)。
2.2 等长 PCB(无时钟歪斜)
50MHz 晶振 │ ┌─────┴─────┐ │ 时钟缓冲器 │ └──┬─────┬───┘ │ │ PCB_clk1 │ │ PCB_clk2 = 3ns │ │ = 3ns ← 等长 │ │ ┌────┴─┐ ┌─┴────────┐ │ FPGA │ │ DAC │ │ │ │ │ │ DATA ├─┼──────────► │ pin │ PCB_data └──────┘ = 2.5nsT=20ns, FPGA Tco=0.3~0.6ns, DAC Tsu=1.5ns, Th=0.8ns output_delay_max = PCB_data + Tsu = 2.5 + 1.5 = 4.0ns output_delay_min = PCB_data - Th = 2.5 - 0.8 = 1.7ns2.3 时间轴推演:SETUP
t=0 晶振沿 t=3 FPGA 和 DAC 同时收到时钟 → 相对 t=0 FPGA: t=0 (相对) FPGA 时钟沿 t=0.6 (最慢) Tco → 数据到 FF Q t=0.6+X 数据到 FPGA 输出 pin (X=内部 routing+OBUF) 外部: 数据 t=0.6+X+2.5 到 DAC DIN pin DAC: t=0 (相对) DAC 收到沿 t=20 下一拍抓数据 Tsu=1.5ns → 数据必须在 t=18.5ns 前到 DAC pin setup 方程: 0.6 + X + 2.5 < 18.5 X < 15.4ns ← 内部预算 ✅ 等价: X < T - output_delay_max - Tco_max < 20 - 4.0 - 0.6 = 15.4ns2.4 不等长 PCB——歪斜修正
例 A: DAC 比 FPGA 远 例 B: DAC 比 FPGA 近 ───────────────────── ───────────────────── PCB_clk1 = 3ns PCB_clk1 = 5ns PCB_clk2 = 5ns PCB_clk2 = 2ns PCB_data = 2.5ns PCB_data = 2.5ns t_skew = 5-3 = +2ns t_skew = 2-5 = -3ns (DAC 晚到 2ns) (DAC 早到 3ns)推导歪斜修正:
DAC 晚到 → 抓取沿推迟 → 数据赶路时间变长 → 可以慢一点 → 外部预算缩小 → FPGA 内部预算放大。
output_delay_max = PCB_data + Tsu + PCB_clk1 - PCB_clk2 例 A: 2.5+1.5+3-5 = 2.0ns → 内部预算 = 20-2.0-0.6 = 17.4ns ← 宽裕 例 B: 2.5+1.5+5-2 = 7.0ns → 内部预算 = 20-7.0-0.6 = 12.4ns ← 紧张物理直觉:
| DAC 远(例 A) | DAC 近(例 B) | |
|---|---|---|
| 时钟歪斜 | DAC 晚 2ns | DAC 早 3ns |
| output_delay_max | 2.0ns(小) | 7.0ns(大) |
| FPGA 内部预算 | 17.4ns(宽裕) | 12.4ns(紧张) |
| 为什么 | DAC 晚抓,不着急 | DAC 早抓,得赶紧 |
2.5 output_delay_min
output_delay_min = PCB_data - Th + PCB_clk1 - PCB_clk2 例 A: 2.5-0.8+3-5 = -0.3ns ← 负数! 内部不能太快 例 B: 2.5-0.8+5-2 = 4.7ns ← 正数, 外部延迟已经够大, hold 自动满足当 min 为负数:数据可能比时钟早到达下游 pin → FPGA 内部最短路径必须大于 |min| → 工具插 buffer 拖慢。
2.6 完整公式总结
═══════════════════════════════════════════════════════════════ input_delay output_delay ═══════════════════════════════════════════════════════════════ 含义: 外部 pin 前的时间 外部 pin 后的时间 参考时钟: FPGA 时钟 pin FPGA 时钟 pin max: PCB_clk2 + t_co_max PCB_data_max + Tsu(下游) + PCB_data - PCB_clk1 + PCB_clk1 - PCB_clk2 min: PCB_clk2 + t_co_min PCB_data_min - Th(下游) + PCB_data - PCB_clk1 + PCB_clk1 - PCB_clk2 歪斜项: +(PCB_clk2 - PCB_clk1) +(PCB_clk1 - PCB_clk2) 外部器件钟晚→外部变大 下游钟晚→外部变小 →内部预算缩小 →内部预算放大 max 管: FPGA 内部 setup FPGA 内部 setup min 管: FPGA 内部 hold FPGA 内部 hold ═══════════════════════════════════════════════════════════════歪斜项记忆:谁钟晚到,谁的 delay 就小(因为可以慢)。
3. set_max_delay / set_min_delay
3.1 和 input/output delay 的本质区别
| input/output delay | max/min delay | |
|---|---|---|
| 参考时钟 | 必须有 | 不需要 |
| 分析方式 | 完整 setup/hold 方程 | 纯数据路径延迟 |
| 适用 | 同步/源同步接口 | 异步信号、CDC、伪路径 |
| 存在的 min | -min管 hold | -min管路径不能太短 |
3.2 使用场景
场景 1:异步输入,防偏斜
ADC 的 SCLK、DRDY、DOUT — 三根线,FPGA 100MHz 过采样。 没参考时钟 → 不用 input_delay → 用 max_delay 控偏斜。三根线不加约束,工具可能把 r_shift_reg[0] 放在 pin 旁,r_shift_reg[23] 放芯片对角:
偏斜 = 最慢 - 最快 = 8.7 - 0.5 = 8.2ns (不加约束) 偏斜 = 3.8 - 1.2 = 2.6ns (加 max+min 约束后)约束:
set_false_path -from [get_ports i_ads_sclk] set_false_path -from [get_ports i_ads_drdy] set_false_path -from [get_ports i_ads_dout] set_max_delay -from [get_ports i_ads_sclk] \ -to [get_cells -hier -filter {NAME =~ "*r_sclk_r0*"}] \ -datapath_only 5.000 set_max_delay -from [get_ports i_ads_drdy] \ -to [get_cells -hier -filter {NAME =~ "*r_drdy_r0*"}] \ -datapath_only 5.000 set_max_delay -from [get_ports i_ads_dout] \ -to [get_cells -hier -filter {NAME =~ "*r_shift_reg*"}] \ -datapath_only 5.000三根线同一上限 → 任意两根内部偏斜 ≤ 5ns → 板上物理先后关系被保留 → RTL 的组合逻辑w_sclk_pos && r_drdy_r0正常工作。
场景 2:CDC 格雷码总线,防偏斜
clk_a 域(写侧)→ 4 位格雷码 → clk_b 域(读侧) 格雷码相邻值只变 1 bit。 但 4 根线偏斜 > 一个 clk_b 周期 → 同一拍内多 bit 翻转 → 不是合法格雷码 → 解码后指针错。 约束:max_delay 控上限 + min_delay 控下限 → 把 4 根线挤进窄窗。不加约束:
gray[0] 路由: 0.5ns 加 max(4ns)+min(1ns) 后: gray[1] 路由: 1.2ns gray[0]: 1.2ns (插 buffer) gray[2] 路由: 3.8ns gray[1]: 1.5ns (插 buffer) gray[3] 路由: 8.7ns gray[2]: 3.2ns (换短路线) 偏斜: 8.2ns gray[3]: 3.8ns (移到 pin 旁) 偏斜: 2.6ns ← 压缩到 2.6ns所有 bit 在 1.2~3.8ns 之间到达,clk_b 周期 10ns,不可能采到多 bit 同时翻转。
约束:
set_false_path -from [get_cells -hier -filter {NAME =~ "*gray_a_reg*"}] set_max_delay -from [get_cells -hier -filter {NAME =~ "*gray_a_reg*"}] \ -to [get_cells -hier -filter {NAME =~ "*r_sync0*"}] \ -datapath_only 4.000 set_min_delay -from [get_cells -hier -filter {NAME =~ "*gray_a_reg*"}] \ -to [get_cells -hier -filter {NAME =~ "*r_sync0*"}] \ 1.000 set_property ASYNC_REG TRUE ...3.3 max 和 min 分别干什么
set_max_delay | set_min_delay | |
|---|---|---|
| 管什么 | 路径不能太慢 | 路径不能太快 |
| 违规后果 | 信号晚到 → 漏采 / 偏斜大 | 信号早到 → 多 bit 偏斜大 / glitch 穿透 |
| 工具解决 | 换更短路线、移近 pin | 插 buffer/LUT、拉长走线 |
| 单比特异步 | ✅ 用,防放飞 | ❌ 不需要 |
| 多比特异步 | ✅ 用 | ✅ 用 |
偏斜窗 = max - min。窗越窄,多根线到达越齐。
3.4 max/min 值怎么定
单比特:设一个合理上限(如 5ns),不设 min。目的是别让走线绕芯片一圈。
多比特:
手册规定外部最小间隔 = 2.2ns (如 SCLK↑→DRDY↑) 要保留内部先后顺序: 内部偏斜 < 外部最小间隔 工程放宽: < 半个 FPGA 时钟周期 (如 5ns,100MHz 下)CDC 格雷码: 偏斜 < 半个捕获时钟周期 clk_b=100MHz → 半周期=5ns → max=4ns, min=1ns → 窗宽=3ns < 5ns4.-datapath_only什么时候加
加不加的区别
设定set_max_delay 5.000。工具内部计算:
不加 -datapath_only: 加 -datapath_only: ════════════════ ════════════════ data_path: 1.2ns data_path: 1.2ns clock_skew: 3.8ns clock_skew: 忽略 Tsu: 0.4ns Tsu: 忽略 ────────────── ────────────── 总计: 5.4ns 总计: 1.2ns 结果: VIOLATED ❌ 结果: PASS ✅-datapath_only砍掉了时钟偏斜和 Tsu,只看纯数据路径长度。
判断
| 场景 | 加-datapath_only | 原因 |
|---|---|---|
| 异步输入 pin→寄存器 | ✅ 加 | 没有参考时钟,算 Tsu 没意义 |
| CDC 跨时钟域 | ✅ 加 | 两时钟异步,clock_skew 没物理意义 |
| 伪路径后补 max_delay | ✅ 加 | false_path 已经砍了时钟关系 |
| 同源时钟域覆盖默认约束 | ❌ 不加 | 需要完整 setup/hold,clock_skew 真实存在 |
判断标准:源和目标的时钟有没有已知的物理相位关系。有 → 不加。没有 → 加。
5. 决策速查表
拿到一个 I/O 信号,该用什么约束?
信号有合法的参考时钟进了 FPGA 吗? ├── 有 → input_delay / output_delay │ 参考时钟 + 手册算值 │ └── 没有 (异步) → 几根线? ├── 单根 → set_false_path 够了 │ pin→寄存器太远的话补 set_max_delay -datapath_only │ └── 多根且互有时序关系 → set_false_path + set_max_delay -datapath_only (控上限) + set_min_delay (控下限) + ASYNC_REG (标同步器)完整速查
| 场景 | 约束 |
|---|---|
| 源同步 (DCO+DATA) | create_clock+set_input_delay |
| 系统同步 (同源 CLK) | create_clock+set_input_delay |
| FPGA 输出给 DAC/SDRAM | create_clock+set_output_delay |
| ADC 异步过采样 (单根) | set_false_path |
| ADC 异步过采样 (多根) | set_false_path+set_max_delay -datapath_only+set_min_delay+ASYNC_REG |
| CDC 数据总线 | set_false_path+set_max_delay -datapath_only+set_min_delay+ASYNC_REG |
| CDC 单 bit 握手 | set_false_path+ASYNC_REG |
| 异步复位分发 (多模块) | set_false_path+set_max_delay -datapath_only+set_min_delay |
| 静态配置信号 | set_false_path |