这一篇在干嘛?
工具不会读心术——你不在 SDC 文件里告诉它”我的时钟是 50MHz、外部数据延迟 2ns”,它就只能瞎猜或干脆不分析。这一篇讲安路 TD 软件的图形化约束工具 Timing Wizard:不用背 SDC 语法,点点界面就能生成
create_clock、set_input_delay等全部常用约束。同系列下一篇讲如何解读时序分析报告,建议先学完这篇再去看报告。
为什么要做时序约束
TD 软件对设计做静态时序分析(STA)时,需要知道三件事:时钟的频率与波形(算延迟预算 Budget)、外部信号何时到达/何时需要输出(算端口路径预算)、哪些路径不用分析(时序例外)。这些信息全部来自 SDC 约束文件。
给设计加时序约束有两种方式:
- 手动新建 SDC 文件,直接写 SDC 命令;
- 通过 Timing Wizard 图形界面设置,由工具自动生成 SDC 命令。
本篇只讲第二种。它的好处是:每个参数都有中文说明、带信号搜索框、实时预览生成的命令,写错参数时 Ok 按钮会置灰 preventing 你保存——对初学者非常友好。
启动前提:Flow 必须运行完 Syn Opt 阶段的 Optimize RTL,并执行 Open Run 操作之后,菜单 Tools → Timing Wizard 才会从置灰变为可点击。刚建完工程就去找这个菜单是找不到的。
常见坑:打开时的 Warning 弹窗
首次打开 Timing Wizard 会弹一个 Warning,提示”更改 Timing Wizard 不会导致重启运行 Optimize RTL stage”。意思是:你改了约束后不会自动重新综合,需要手动重跑 Flow 才能让新约束生效。点 Continue 进入界面即可;点 Cancel 则放弃打开。
Timing Wizard 主界面
主界面分上、下两个窗口,加最下面三个全局按钮:

上方是 SDC 命令设置窗口,左侧约束树分五组:
- Clocks:创建/定义时钟相关约束(本篇重点)。
- Inputs:输入延迟约束(
set_input_delay)。 - Outputs:输出延迟约束(
set_output_delay)。 - Exceptions:时序例外约束(max/min delay、多周期、伪路径)。
- Summary:汇总显示所有已创建的时钟和时序路径约束。
下方是 已生成 SDC 命令列表,包含用户自己建的命令和 IP 自动生成的命令(带”锁”图标的行来自 IP 自带 SDC,用户不可改)。列表表头含义:
| 表头 | 含义 |
|---|---|
| Position | SDC 命令编号 |
| Command | SDC 命令内容 |
| Source File | 命令所属的 SDC 文件 |
| Scoped Cell | 命令调用的 IP |
| Current Instance | IP 例化名 |
最底下是 Save / Apply / Cancel 三个全局按钮,对所有命令生效:
- Apply:对所有 SDC 命令做语法、依赖、冲突检查,通过后跳转到 Summary 界面。
- Save:先自动执行 Apply 的检查,检查不通过则 Save 置灰无法保存,错误位置可在 TD 主界面 Console 窗口查看。
- Cancel:放弃所有修改并退出。
几个对所有设置界面通用的操作,先记住能省很多事:
- 双击命令列表中任意一行,可将该命令”反标”回上方设置窗口,方便查看或修改参数;没做任何修改时 Ok 置灰。
- 列表工具栏 ”+” 恢复设置界面默认状态、新建命令;选中一行后点 ”-” 删除该命令。
- 每个设置界面都有 Reference 按钮,点开可查看对应 SDC 命令的参数说明和官方示例。
- 信号输入框右侧的 搜索(放大镜) 按钮可弹出信号查找窗,支持
get_ports、get_pins、get_nets等过滤方式,不用手敲层级名。
Clocks:时钟类约束
Clocks 分类下有 8 个设置界面,对应 8 条 SDC 命令。先给一张速查表,再逐个讲最常用的:
| 设置界面 | 生成的 SDC 命令 | 用途 |
|---|---|---|
| Create Clock | create_clock | 定义主时钟(必须掌握) |
| Create Generated Clock | create_generated_clock | 定义派生时钟(PLL 输出、分频时钟) |
| Rename Auto-Derived Clocks | rename_clock | 给硬核(HXT/PCIe/DDR 等)自动生成的时钟改名 |
| Derive Clocks | derive_clocks | 一条命令自动约束所有 PLL/分频 Clock Buffer 输出时钟 |
| Set Clock Latency | set_clock_latency | 设置时钟源/网络延迟 |
| Set Clock Uncertainty | set_clock_uncertainty | 给时钟加不确定度裕量 |
| Set Clock Groups | set_clock_groups | 声明时钟组互斥/异步,跨组路径不分析 |
| Set Clock Sense | set_clock_sense | 指定时钟从某网表节点停止传播 |
Create Clock:定义主时钟
这是最核心的约束——不定义主时钟,整个时序分析无从谈起。界面参数:
- Clock Name:主时钟名称,不可缺省。
- Source Objects:时钟来源管脚,一般是 FPGA 外部输入时钟管脚或硬核 IP 输出时钟管脚。此项留空则创建的是虚拟时钟(virtual clock,用于约束输入/输出端口但不驱动任何内部寄存器)。
- Add:勾选后可在已有时钟的同一管脚上追加新时钟;不勾选则新约束覆盖旧约束。
- Period:时钟周期,单位 ns,支持三位小数。
- Rise / Fall:第一个上升/下降沿时刻。Rise 缺省为 0.000,Fall 缺省为 Period/2,取值范围均为 0~Period。
例如板卡上有一颗 25MHz 晶振接到 clk_25m 管脚,设置后生成的命令为:
create_clock -name clk_25m -period 40.000 -waveform {0.000 20.000} [get_ports {clk_25m}]40.000ns 就是 25MHz 的周期,waveform 两个值分别是第一个上升沿和下降沿时刻。点击 Ok 后命令出现在下方列表:

Create Generated Clock:定义派生时钟
设计中经 PLL 倍频/分频、或寄存器二分频得到的时钟,要用派生时钟约束告诉工具它和主时钟的关系。生成的命令是 create_generated_clock,关键参数:
- Master Pin / Master Clock:驱动源点及其上的驱动时钟。同一个源点可能挂了多个时钟,必须指定跟随哪一个。
- Source Objects:派生时钟的约束对象节点。
- By Clock Frequency(与 By Clock Edges 互斥):用频率关系定义——分频填 Divide source clock frequency by,倍频填 Multiply source clock frequency by,配合 Duty Cycle(占空比 %)与 Invert waveform(波形反转)。
- By Clock Edges(与 By Clock Frequency 互斥):用边沿对应关系定义——Edge List 三个框分别指定新时钟的第一个上升沿、第一个下降沿、第二个上升沿对应驱动时钟的第几个边沿;Edge Shift List 指定每个沿的偏移(单位 ns,正右负左)。
手册里的例子:驱动时钟 demo_clk 10ns 周期,派生时钟按边沿关系取 2 分频,生成 demo_clk_gen,两者波形关系一目了然:

Rename Auto-Derived Clocks 与 Derive Clocks
Rename Auto-Derived Clocks:工程中 HXT、PCIe、DDR、PROCESSOR SYSTEM 等硬核的输出时钟由软件自动约束(Auto-Derived Clocks),这个界面可以把它们改成好记的名字(生成 rename_clock 命令)。注意:直接引用原时钟名的其他约束会因此失效,改名后要同步更新。界面分 ListView(平铺,方便搜索)和 TreeView(树形,方便看驱动级联关系)两种视图。
Derive Clocks:勾选 Drive clocks 并点 Ok,一条 derive_clocks 命令即可自动约束工程中所有 PLL 和带分频功能的 Clock Buffer(如 LCLK、DBUF)的输出时钟,频率相位严格按 PLL 设置参数生成。它会替换旧的 derive_pll_clocks 命令。若 PLL 有多路可选输入参考时钟:选择信号是常数时只选其中一路生成派生时钟;是变量时会对每一路分别生成各自的派生时钟。
竞赛建议:如果用了 PLL IP,直接在 SDC 里写
derive_clocks一条命令搞定所有派生时钟约束,比自己逐个create_generated_clock省事且不易错。
Latency / Uncertainty / Groups / Sense
Set Clock Latency(set_clock_latency):设置时钟的最大/最小延迟。勾选 Source 表示”源延迟”(时钟源点到时钟定义点的延迟),不勾选则是网络延迟(布线延迟,布线后会被实际值替代)。Source latency variation bound 可选 early/late 分别指定最小/最大源延迟;Operating condition 选 max/min 对应 slow/fast corner 分析。设置后,时序报告的 Launch Clock 路径里会出现对应延迟项:

Set Clock Uncertainty(set_clock_uncertainty):给时钟加”不确定度”,即人为压缩时序裕量,为时钟抖动等留余量。Object 支持单/多节点;Uncertainty type 可选 setup/hold、setup、hold。时序报告的 Other 栏会单列 clock uncertainty 一行(软件默认也会加一份 default uncertainty):

Set Clock Groups(set_clock_groups):声明时钟组之间互斥/异步,工具就不再分析跨时钟组的路径。与 set_false_path 的区别:false path 只禁止单方向(from → to),clock_groups 禁止双向。Exclusive 与 Async 目前效果相同。只指定一个组时,该组与其他所有时钟之间的路径都不分析。
Set Clock Sense(set_clock_sense):指定时钟从某网表对象开始停止传播(stop propagation)。被停止的路径会进入时序报告的 Ignored Report 分类。
Inputs / Outputs:端口延迟约束
芯片管脚之外的延迟工具管不着,所以要靠 set_input_delay / set_output_delay 把”外部世界”的时序也告诉工具。
Set Input Delay:定义外部信号到达 FPGA 输入端口所需的延迟。主要参数:
- Clock:该延迟对应的采样时钟。
- Target:约束的输入管脚,支持多个。
- Reference:参考点(pin 或 port),工具会考虑参考点处的 Source/Network Latency。
- Delay Value:延迟值,ns,三位小数。
- Max/Min:max 用于 Setup 检查,min 用于 Hold 检查,默认 max/min 同值。
- Slow/Fast:指定分析 corner(slow=慢角点,fast=快角点),默认两者都分析。
- Clock Fall:以时钟下降沿为参考。
- Add Delay:同一端口用不同 Clock Edge/Reference 约束多次时,取各 Delay 之和;不勾选则后者覆盖前者。
设置 input delay 后,工具会据此调整采样寄存器的布线延迟、平衡时钟树;报告中 Data 路径的第一行就是它:

Set Output Delay:定义从 FPGA 输出端口到外部寄存器所需的延迟,参数与 Set Input Delay 一一对应(Target 换成输出管脚)。它让工具在分析时考虑输出管脚延迟,从报告中可判断输出数据能否满足外部电路的采样时序。
常见坑:延迟值乱填导致时序不收敛
官方手册特别强调:输入/输出延迟必须根据实际外部电路情况正确设置,随意填大数值会挤占内部布线预算,容易造成本来没问题的设计时序不收敛。EG4S20 竞赛板上如果外设是同步接口,去查外设芯片手册的 tCO/tSU;如果是低速异步信号(按键、LED),管脚上适当给个宽松值或声明为伪路径即可。
Exceptions:时序例外约束
四条命令解决”默认分析规则不适合某些路径”的问题:
| 命令 | 作用 |
|---|---|
set_max_delay | 指定路径允许的最大延迟(覆盖默认的时钟周期预算) |
set_min_delay | 指定路径允许的最小延迟 |
set_multicycle_path | 允许数据用多个时钟周期到达 |
set_false_path | 声明伪路径,完全不分析 |
四个界面的 From / Through / To 结构一致:
- From:路径起点,须为 input port 或寄存器时钟输入端口。对象为 clock 管脚时约束所有被该时钟驱动的路径;为 input port 时约束以它为起点的路径;为 cell 时约束该 cell 内所有寄存器。
- Through:路径必须依次经过的中间点(可多个,用 +/- 增删)。
- To:路径终点,须为寄存器非时钟输入端口或 output port。
- From/To 下拉可切换 rise/fall(默认,
-from/-to)、rise(-rise_from/-rise_to)、fall(-fall_from/-fall_to),后两者对象仅支持 clocks。
Set Max/Min Delay 的 Delay value 直接改写路径预算。例如对跨时钟寄存器对约束最大延迟 2ns,路径的 Budget 就从默认时钟周期变成 2.000ns:

两者都有 Datapath_only 选项:勾选后消除时钟 jitter/skew/pessimism 计算,仅考虑第一级触发器 Clock-to-Q 延迟、级间连线延迟和第二级触发器建立时间——跨时钟域打两拍同步器常这么约束。
Set Multicycle Path 的 Multiplier Value 指定周期数:勾选 Setup 时把 Capture Clock 沿向后推 N 个周期;勾选 Hold 时把 Capture Clock 沿向前推 N 个周期。start/end 指定参考哪个时钟周期:setup 用 end(Capture Clock),hold 用 start(Launch Clock)。典型用法:大延迟组合逻辑路径约束 -setup 2 后,通常要配套 -hold 1,否则 hold 检查反而出问题。
Set False Path 的 setup/hold 选项决定约束作用于哪类检查(默认两者都不再分析该路径)。记住:false path 只禁 from→to 单方向,双向都要禁需再写一条反向命令。
Summary:检查与保存
所有约束设置完,点全局 Apply(或任意界面的 Save),工具做语法/依赖/冲突检查后跳到 Summary 界面——这里汇总了所有已生成的 SDC 命令(含原有命令),并选择保存路径。保存路径分三种情况:
- 工程无 SDC 文件:新建 SDC 文件界面,默认文件名为工程名+编号,可自定义;默认勾选 Add this SDC File to the current project 加入工程。
- 工程已有单个 SDC 文件:默认存入该文件,不可更改。
- 工程已有多个 SDC 文件:默认存到列表第一个文件;本次新建的命令可通过 Browse 换目标文件,但修改已有命令只会存回它原来所在的文件。
保存后 SDC 文件生效。但注意开头 Warning 的提示——改约束不会自动重跑 Flow,要重新运行并 Open Run 后,新约束才体现在新的时序报告里。
通关标准:
- 不看教程独立完成:create_clock 定义板载主时钟 → derive_clocks 约束 PLL 输出 → input/output delay 覆盖全部用到的端口 → Apply 检查通过 → Save 保存。
- 能说出虚拟时钟与主时钟的区别(Source Objects 留空 = 虚拟时钟,只用于端口约束)。
- 能解释 set_clock_groups 与 set_false_path 的单双向差异。
自测 1:为什么 Timing Wizard 菜单是灰的点不了?
Flow 还没运行完 Syn Opt 阶段的 Optimize RTL,或没执行 Open Run。先跑 Flow,再打开。
自测 2:create_clock 里 Rise/Fall 留空,生成的波形是什么样?
Rise 默认 0.000、Fall 默认 Period/2,即 50% 占空比的标准方波。例如 Period=40 时 waveform 为 {0.000 20.000}。
自测 3:PLL 输出的 100MHz 时钟需要用 create_clock 定义吗?
不需要。它属于派生时钟,应在 SDC 中用 derive_clocks 自动约束,或用 create_generated_clock 手动描述其与主时钟的倍/分频关系。直接对 PLL 输出 create_clock 反而会割裂它与主时钟的关系。
自测 4:两个异步时钟 clk_25m 和 clk_27m 之间的路径反复报违例,最合适的约束是?
set_clock_groups -async -group {clk_25m} -group {clk_27m}(前提是跨域逻辑已用同步器正确处理)。它双向禁止两时钟组间分析,比写两条方向相反的 set_false_path 简洁。
自测 5:点了 Save 却是灰的,去哪找错误?
Save 置灰说明 SDC 命令检查未通过。到 TD 主界面的 Console 窗口查看错误位置与原因,回到 Timing Wizard 对应界面修改。