3. 时钟约束实战
在 TimeQuest 中,所有时序分析都建立在“时钟”这一基准之上。没有时钟约束,时序引擎就不知道寄存器何时被触发,也就无法计算建立时间、保持时间是否满足。本节围绕 create_clock 这一条核心 SDC 命令展开,讲清主时钟、虚拟时钟、生成时钟三类时钟的定义方式,以及波形、周期、占空比、相位这几个参数如何落到命令上。
一、create_clock 的基本语法与参数含义
TimeQuest 读取的 SDC 命令格式如下:
create_clock -name <时钟名> -period <周期> \
[-waveform {<上升沿> <下降沿>} ] \
[-add] [<目标引脚或端口>]
其中 -period 是必选参数,单位默认纳秒(ns)。-waveform 用两个时间点描述第一个时钟周期内上升沿和下降沿的位置,默认值为 {0, period/2},即 50% 占空比、0° 相位。-name 给时钟起名,便于后续 set_input_delay、set_clock_groups 引用。-add 用于在同一目标上叠加多个时钟,例如同一引脚既有时钟又有数据复用。
需要特别强调:-waveform 的两个数值是“相对时间零点”的绝对位置,不是相对上升沿的偏移。例如周期 10ns、占空比 40%、上升沿在 2ns,应写为 -waveform {2 6},而不是 {0 4}。相位设置正是通过移动这两个时间点实现的。
二、主时钟:约束外部输入时钟
主时钟是时序分析的源头,通常定义在 FPGA 的时钟输入引脚上。假设板级晶振为 50MHz,从 clk_in 引脚进入 FPGA,则:
create_clock -name sys_clk -period 20.000 \
-waveform {0 10} [get_ports clk_in]
这条命令告诉 TimeQuest:clk_in 上有一个 20ns 周期、50% 占空比、0° 相位的时钟,命名为 sys_clk。之后所有由它驱动的寄存器都会以 20ns 为周期参与分析。
如果外部时钟经过 PLL 或 MMCM 倍频,主时钟仍应定义在输入引脚上,而不是 PLL 输出端。PLL 输出由生成时钟自动派生,这样 TimeQuest 才能正确计算输入抖动、时钟不确定性等参数。
三、虚拟时钟:约束纯外部器件
虚拟时钟没有物理引脚,它用于描述 FPGA 之外的器件时钟,典型场景是外部 ADC、DAC 或存储器与 FPGA 之间的接口。例如外部 ADC 使用 100MHz 时钟,但该时钟不进入 FPGA,只用于驱动 ADC 的输出寄存器:
create_clock -name adc_clk -period 10.000 -waveform {0 5}
注意这里没有 get_ports 目标,这就是虚拟时钟的标志。定义后,配合 set_input_delay -clock adc_clk 即可描述 ADC 数据到达 FPGA 引脚的时间关系。虚拟时钟的价值在于:它让 TimeQuest 知道“数据是由哪个时钟发出的”,从而正确建立跨时钟域或纯输入路径的时序模型。
四、生成时钟:描述分频、倍频与相移
生成时钟由主时钟派生,常见于 PLL 输出、时钟分频器、时钟使能电路。TimeQuest 对 PLL 输出通常能自动推导,但对手写分频逻辑必须显式约束。例如从 sys_clk 二分频得到 10MHz 时钟:
create_generated_clock -name div_clk \
-source [get_ports clk_in] \
-divide_by 2 [get_pins clk_div|q]
若为三分频,则用 -divide_by 3;若为倍频,用 -multiply_by 2;若需要相移,可加 -phase 90(单位度)或直接用 -edges 指定边沿位置。生成时钟的关键是 -source 必须指向主时钟的源,这样 TimeQuest 才能沿时钟树向上追溯,计算公共路径上的抖动与延迟。
五、波形、周期、占空比与相位的组合设置
这四个参数最终都体现在 -period 和 -waveform 上。设周期为 T,上升沿位置为 R,下降沿位置为 F,则:
- 占空比 = (F − R) / T × 100%
- 相位(以度为单位)= R / T × 360°
例如要定义 125MHz、占空比 60%、上升沿滞后 1ns 的时钟:T = 8ns,F − R = 4.8ns,R = 1ns,F = 5.8ns,命令为:
create_clock -name clk_125m -period 8.000 \
-waveform {1 5.8} [get_ports clk_in]
若占空比不是 50%,TimeQuest 会分别用上升沿和下降沿建立两套分析模型,这对 DDR 接口、双边沿采样电路尤为重要。相位设置则直接影响建立/保持关系的松紧:上升沿后移,相当于给数据路径更多建立时间,但压缩了保持时间。
六、三类时钟的关系与约束检查
下图给出主时钟、虚拟时钟、生成时钟在 TimeQuest 中的派生关系与典型约束位置,便于对照理解。
七、约束后的检查与常见错误
写完约束后,应在 TimeQuest 中执行 Report Clocks 或 Report SDC,确认三类时钟都被正确识别。常见问题包括:
- 主时钟定义在 PLL 输出端:导致输入路径无约束,应改到输入引脚。
- 虚拟时钟误加 get_ports:TimeQuest 会报“找不到目标”,虚拟时钟必须无目标。
- 生成时钟 -source 指向错误:应指向主时钟的源引脚或端口,而非生成时钟自身。
- 波形时间点超出周期:如周期 10ns 却写
{0 12},会导致边沿错乱。 - 占空比与相位混淆:占空比改变 F−R,相位改变 R 的起点,两者独立设置。
Report Clocks,确认周期、波形、目标三项与预期一致,再继续添加 I/O 约束。这样能把错误定位在单条命令上,避免后期排查困难。掌握这三类时钟的定义方法后,后续的 set_input_delay、set_output_delay、set_false_path 等约束才有可靠的时钟基准。实际工程中,主时钟通常只有一两个,虚拟时钟用于外部接口,生成时钟由 PLL 自动推导或对手写分频显式声明,三者配合构成完整的时钟约束体系。