SDC 约束实战:create_clock、IO delay、false path 与 multicycle
更新时间:2026-09-06。本文是「集成电路大类 · 芯片设计」进阶层(intermediate)第十一篇新正文(#13)。入门层 静态时序分析 STA 讲了 setup/hold 的原理,但 STA 工具(PrimeSpace/Tempus)和综合工具本身不知道你的时钟多快、IO 信号什么时候到——这些全靠 SDC 约束文件告诉它。约束是 STA 的输入前提:怎么读报告见 STA 报告解读(#14),怎么根据报告收敛见 时序收敛手法(#15)。异步时钟与 false path 的设计依据见 CDC 基础(#10)。
本文要回答的问题
- 一个芯片的 SDC 文件按什么顺序写?
- generated clock 为什么不能再 create_clock?
- false path / clock groups / multicycle 各用在什么场景,写错的后果是什么?
- 怎么知道约束没有漏?
一、时钟约束:一切时序的基准
# 1. 主时钟:挂在输入端口或 PLL 输出引脚上
create_clock -name clk_100 -period 10.0 \
-waveform {0 5} [get_ports clk_in] # 100MHz,上升沿 0ns、下降沿 5ns
# 2. 派生时钟:PLL 倍频/分频,用 -source 指源时钟,工具自动推相位关系
create_generated_clock -name clk_400 -source [get_pins pll/clk_out] \
-multiply_by 4 [get_pins pll/CLKOUT] # 不要对 PLL 输出再 create_clock!
# 3. 不确定性与延迟(余量)
set_clock_uncertainty -setup 0.30 [all_clocks] # jitter + 工程余量
set_clock_uncertainty -hold 0.10 [all_clocks]
set_clock_latency 1.2 [get_clocks clk_100] # 网络延迟(CTS 前用,CTS 后工具自动算 propagated)
set_propagated_clock [all_clocks] # CTS 后用实际时钟树延迟最常见错误:PLL/分频器输出再 create_clock 一个新时钟——工具会认为它与源时钟异步,两者间路径全被当跨域处理(可能正好你不想切的真实路径被放过)。派生时钟必须 create_generated_clock,工具才知道相位关系、能正确做同步时序分析。
二、IO 约束:把芯片当黑盒
芯片内部触发器到引脚之间还有板级走线、对端芯片的时序要求,用 input/output delay 描述「数据相对时钟沿提前/滞后多久到达芯片边界」:
# 输入:数据在 launch 沿之后 2.0ns 才到达本芯片输入端口(板级延迟)
set_input_delay -clock clk_100 -max 2.0 [get_ports {data_in[*]}]
set_input_delay -clock clk_100 -min 0.5 [get_ports {data_in[*]}]
# 输出:要求数据在 capture 沿之前 1.5ns 就稳定在端口(给对端留余量)
set_output_delay -clock clk_100 -max 1.5 [get_ports {data_out[*]}]
set_output_delay -clock clk_100 -min -0.5 [get_ports {data_out[*]}]由此工具能分析四类路径:reg→reg(芯片内部)、input→reg、reg→output、input→output(穿芯片)。漏约束 IO,工具默认边界延迟为 0,等于默许输入无限晚到、输出无限晚出——签核全绿,上板对端采不到数据。
三、切伪路径:false_path 与 clock_groups
不是所有路径都需要在一个周期内稳定(回顾 CDC 基础):
# 异步时钟域之间:成组声明,域间所有路径不做时序分析
set_clock_groups -asynchronous \
-group {clk_100} -group {clk_50} -group {clk_uart}
# 个别伪路径:静态配置(上电写一次不变)、复位、测试信号
set_false_path -from [get_ports rst_n]
set_false_path -from [get_cells cfg_regs[*]] -to [all_registers]
set_false_path -from [get_pins u_slow/valid_out] -to [get_pins u_fast/data_in]铁律:false path 只能切「设计上保证不需要时序」的路径——跨异步域(有同步器)、静态不变信号、复位。把没过时序的关键路径标 false path 等于签核时闭眼,是流片事故高发原因;CDC 路径应由 CDC 工具 确认同步器存在后再切,且优先用 set_clock_groups(按域批量、不遗漏)而不是一条条 false path。
四、多周期路径:数据本来就 N 拍才用一次
有些路径数据每个时钟都传,但接收逻辑隔 N 拍才采样一次(如使能信号每 4 拍有效一次的配置通路、慢到快的固定分频接口)。按 1 周期约束太苛刻、逼工具过度优化,用 multicycle 放宽:
# setup:接收端 4 个周期后才采,给数据路径 4 拍
set_multicycle_path 4 -setup -from [get_clocks clk_a] -to [get_clocks clk_b]
# hold 必须跟着调!setup 改 N 后默认 hold 检查沿也移动了,通常要回退 N-1
set_multicycle_path 3 -hold -from [get_clocks clk_a] -to [get_clocks clk_b]新手最大的坑:只写 setup 不写 hold——hold 的检查沿默认随 setup 移动,会导致 hold 检查在错误的沿上,要么大量假违例、要么放过真 hold 问题。multicycle 必须成对写、并在设计评审中证明「数据确实 N 拍不变」。
五、兜底与验证
set_max_delay/set_min_delay:不属于任何时钟的路径(如纯组合异步接口、某些 IO)直接给延迟上下限;- 约束验证比写约束更重要:每次跑 STA 先
check_timing(报告未约束端口/单元、无时钟寄存器、生成时钟问题),看 unconstrained paths 报告——存在漏约束路径则整个签核结果不可信; - SDC 要进版本管理、随 RTL 一起评审:新时钟域、新 IO、新 CDC 必须同步改约束,约束与 RTL 不一致是流片前最常见也最致命的脱节之一。
相关与延伸
下一篇:STA 报告解读:slack、launch/capture 与 CPPR(#14);收敛手法见 时序收敛基本手法(#15)。入门铺垫:STA 概念、逻辑综合;异步约束依据见 CDC 基础、复位 recovery 约束见 复位设计;CTS 后 propagated clock 见进阶 #35,物理签核见 #36。
总结
SDC 是写给工具的时钟说明书:create_clock 定基准、generated_clock 管 PLL 派生(别再 create_clock)、input/output_delay 封 IO 边界、clock_groups/false_path 只切设计上证明过的异步与静态路径、multicycle 成对写 setup+hold;最后 check_timing 和漏约束报告必须清零——假约束比没约束更危险。