这一篇在干嘛?

工具不会读心术——你不在 SDC 文件里告诉它”我的时钟是 50MHz、外部数据延迟 2ns”,它就只能瞎猜或干脆不分析。这一篇讲安路 TD 软件的图形化约束工具 Timing Wizard:不用背 SDC 语法,点点界面就能生成 create_clockset_input_delay 等全部常用约束。同系列下一篇讲如何解读时序分析报告,建议先学完这篇再去看报告。

为什么要做时序约束

Timing Wizard 主界面

Clocks:时钟类约束

Inputs / Outputs:端口延迟约束

Exceptions:时序例外约束

Summary:检查与保存

为什么要做时序约束

TD 软件对设计做静态时序分析(STA)时,需要知道三件事:时钟的频率与波形(算延迟预算 Budget)、外部信号何时到达/何时需要输出(算端口路径预算)、哪些路径不用分析(时序例外)。这些信息全部来自 SDC 约束文件

给设计加时序约束有两种方式:

  1. 手动新建 SDC 文件,直接写 SDC 命令;
  2. 通过 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 主界面

主界面分上、下两个窗口,加最下面三个全局按钮:

Timing Wizard 主界面:左侧约束分类树,右上为参数设置区,下方为已生成 SDC 命令列表

上方是 SDC 命令设置窗口,左侧约束树分五组:

  • Clocks:创建/定义时钟相关约束(本篇重点)。
  • Inputs:输入延迟约束(set_input_delay)。
  • Outputs:输出延迟约束(set_output_delay)。
  • Exceptions:时序例外约束(max/min delay、多周期、伪路径)。
  • Summary:汇总显示所有已创建的时钟和时序路径约束。

下方是 已生成 SDC 命令列表,包含用户自己建的命令和 IP 自动生成的命令(带”锁”图标的行来自 IP 自带 SDC,用户不可改)。列表表头含义:

表头含义
PositionSDC 命令编号
CommandSDC 命令内容
Source File命令所属的 SDC 文件
Scoped Cell命令调用的 IP
Current InstanceIP 例化名

最底下是 Save / Apply / Cancel 三个全局按钮,对所有命令生效:

  • Apply:对所有 SDC 命令做语法、依赖、冲突检查,通过后跳转到 Summary 界面。
  • Save:先自动执行 Apply 的检查,检查不通过则 Save 置灰无法保存,错误位置可在 TD 主界面 Console 窗口查看。
  • Cancel:放弃所有修改并退出。

几个对所有设置界面通用的操作,先记住能省很多事:

  • 双击命令列表中任意一行,可将该命令”反标”回上方设置窗口,方便查看或修改参数;没做任何修改时 Ok 置灰。
  • 列表工具栏 ”+” 恢复设置界面默认状态、新建命令;选中一行后点 ”-” 删除该命令。
  • 每个设置界面都有 Reference 按钮,点开可查看对应 SDC 命令的参数说明和官方示例。
  • 信号输入框右侧的 搜索(放大镜) 按钮可弹出信号查找窗,支持 get_portsget_pinsget_nets 等过滤方式,不用手敲层级名。

Clocks:时钟类约束

Clocks 分类下有 8 个设置界面,对应 8 条 SDC 命令。先给一张速查表,再逐个讲最常用的:

设置界面生成的 SDC 命令用途
Create Clockcreate_clock定义主时钟(必须掌握)
Create Generated Clockcreate_generated_clock定义派生时钟(PLL 输出、分频时钟)
Rename Auto-Derived Clocksrename_clock给硬核(HXT/PCIe/DDR 等)自动生成的时钟改名
Derive Clocksderive_clocks一条命令自动约束所有 PLL/分频 Clock Buffer 输出时钟
Set Clock Latencyset_clock_latency设置时钟源/网络延迟
Set Clock Uncertaintyset_clock_uncertainty给时钟加不确定度裕量
Set Clock Groupsset_clock_groups声明时钟组互斥/异步,跨组路径不分析
Set Clock Senseset_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_clock 约束设置示例:设置 clk_25m 后命令已加入下方列表

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,两者波形关系一目了然:

create_generated_clock 生成的 2 分频派生时钟波形示意图

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 Latencyset_clock_latency):设置时钟的最大/最小延迟。勾选 Source 表示”源延迟”(时钟源点到时钟定义点的延迟),不勾选则是网络延迟(布线延迟,布线后会被实际值替代)。Source latency variation bound 可选 early/late 分别指定最小/最大源延迟;Operating condition 选 max/min 对应 slow/fast corner 分析。设置后,时序报告的 Launch Clock 路径里会出现对应延迟项:

set_clock_latency 设置的 1ns Source Latency 出现在报告 Launch Clock 的 source latency 行

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

set_clock_uncertainty 设置的 1ns 在报告 Other 栏体现为 clock uncertainty 行

Set Clock Groupsset_clock_groups):声明时钟组之间互斥/异步,工具就不再分析跨时钟组的路径。与 set_false_path 的区别:false path 只禁止单方向(from → to),clock_groups 禁止双向。Exclusive 与 Async 目前效果相同。只指定一个组时,该组与其他所有时钟之间的路径都不分析。

Set Clock Senseset_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_input_delay 的 0.5ns 出现在报告 Data 栏 input 行

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:

set_max_delay 约束设置示例:signal_meta 到 signal_dst 最大延迟 2ns

两者都有 Datapath_only 选项:勾选后消除时钟 jitter/skew/pessimism 计算,仅考虑第一级触发器 Clock-to-Q 延迟、级间连线延迟和第二级触发器建立时间——跨时钟域打两拍同步器常这么约束。

Set Multicycle PathMultiplier 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 命令(含原有命令),并选择保存路径。保存路径分三种情况:

  1. 工程无 SDC 文件:新建 SDC 文件界面,默认文件名为工程名+编号,可自定义;默认勾选 Add this SDC File to the current project 加入工程。
  2. 工程已有单个 SDC 文件:默认存入该文件,不可更改。
  3. 工程已有多个 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 的单双向差异。