4. 时钟特性与不确定性
在 TimeQuest 中,create_clock 只定义了理想时钟的周期与波形,但真实时钟网络存在抖动、偏斜、相位偏移以及不同时钟域之间的相位关系。若只约束周期,STA 会把所有时钟边沿当作理想对齐,结果过于乐观。本节讨论三条用于描述时钟“非理想特性”的约束:set_clock_uncertainty、set_clock_latency 和 set_clock_groups,它们分别刻画时钟抖动/余量、时钟网络延迟以及时钟域之间的相位关系。
一、set_clock_uncertainty:为抖动与偏斜预留余量
set_clock_uncertainty 用于在时钟边沿上增加一段不确定区间,TimeQuest 在建立时间(setup)和保持时间(hold)分析中会把这部分时间从可用窗口中扣除。它通常用来建模 PLL 抖动、时钟树偏斜、以及板上时钟源抖动等无法精确建模的随机或系统性偏差。
基本语法为:
set_clock_uncertainty [-setup] [-hold] <uncertainty> [-from <clock>] [-to <clock>] [get_clocks <clock>]
若只写一个数值,则同时作用于 setup 和 hold。例如:
set_clock_uncertainty -setup 0.15 [get_clocks clk_100m]
set_clock_uncertainty -hold 0.08 [get_clocks clk_100m]
含义是:在 clk_100m 的建立分析中,从数据需求时间中扣除 0.15 ns;在保持分析中,从数据保持需求中扣除 0.08 ns。对 setup 而言,uncertainty 使需求时间提前,等效于压缩了数据路径的可用时间;对 hold 而言,它使保持需求推后,等效于要求数据保持更久。因此 uncertainty 越大,时序越难满足,但结果也更保守、更接近真实硬件。
当两个时钟之间存在确定的相位关系时,可以用 -from 和 -to 指定跨时钟域的 uncertainty。例如:
set_clock_uncertainty -from clk_100m -to clk_200m -setup 0.20
这表示从 clk_100m 发起到 clk_200m 捕获的路径,额外增加 0.20 ns 的建立不确定量。需要注意的是,uncertainty 是“人为添加的余量”,不是真实延迟,因此不能与 latency 混用;它只影响时序计算中的需求时间,不改变时钟边沿的实际位置。
二、set_clock_latency:描述时钟网络延迟
set_clock_latency 用于描述时钟从源点(如 PLL 输出或时钟输入引脚)到达寄存器时钟引脚所经历的延迟。在布局布线前,时钟树尚未生成,可以用它估算时钟网络延迟;在布局布线后,若使用真实时钟树,则通常由工具自动提取,不需要手动设置。
语法为:
set_clock_latency [-source] [-late] [-early] <latency> [get_clocks <clock>]
其中 -source 表示源延迟,即时钟源到时钟定义点之间的延迟;不加 -source 则表示网络延迟,即时钟定义点到寄存器时钟引脚之间的延迟。-late 和 -early 分别用于指定最大和最小延迟,常用于建模时钟树偏斜。
例如:
set_clock_latency -source -late 1.20 [get_clocks clk_100m]
set_clock_latency -source -early 0.80 [get_clocks clk_100m]
set_clock_latency -late 0.60 [get_clocks clk_100m]
set_clock_latency -early 0.40 [get_clocks clk_100m]
这组约束表示:时钟源到时钟定义点的延迟在 0.80~1.20 ns 之间,时钟定义点到寄存器时钟引脚的延迟在 0.40~0.60 ns 之间。TimeQuest 在 setup 分析中会使用 late latency(更晚到达),在 hold 分析中使用 early latency(更早到达),从而把时钟树偏斜纳入计算。若只写一个数值,则 late 和 early 相同,表示没有偏斜。
latency 与 uncertainty 的区别在于:latency 是真实存在的传播延迟,会同时影响发起时钟和捕获时钟的边沿位置;uncertainty 是额外预留的余量,只影响需求时间。两者叠加后,setup 的可用时间会进一步缩小。
三、set_clock_groups:声明时钟域之间的相位关系
set_clock_groups 用于告诉 TimeQuest 哪些时钟之间不需要做时序分析,或者哪些时钟之间是异步关系。它不改变时钟本身的特性,而是控制分析范围,避免对异步时钟域之间的路径产生无意义的时序报告。
常用形式有三种:
set_clock_groups -asynchronous -group {clk_100m} -group {clk_200m}
set_clock_groups -exclusive -group {clk_a} -group {clk_b}
set_clock_groups -logically_exclusive -group {clk_c} -group {clk_d}
-asynchronous 表示两组时钟之间异步,TimeQuest 会切断它们之间的时序路径,不做 setup/hold 分析。这适用于跨时钟域但已用同步器处理的路径。-exclusive 表示两组时钟在物理上不会同时存在,例如多路复用时钟,同一时刻只有一个时钟有效。-logically_exclusive 表示逻辑上互斥,通常用于同一时钟源经过不同分频或选择后的情况。
需要特别注意的是,set_clock_groups 只是“关闭分析”,并不等于“路径安全”。如果两个异步时钟域之间没有同步器,直接关闭分析会掩盖亚稳态风险。正确做法是:先确认跨时钟域路径已用两级触发器或其他同步结构处理,再用 -asynchronous 切断时序分析,最后用 set_false_path 或 set_max_delay 对同步器之间的路径做必要约束。
四、三条约束对时序分析的综合影响
下面这张图展示了三条约束在一条典型跨时钟域路径上的作用位置与影响方向。图中以 clk_100m 发起、clk_200m 捕获为例,标出了 latency、uncertainty 和 clock groups 分别作用于时钟网络的哪一段,以及它们对 setup/hold 窗口的压缩或切断效果。
从图中可以看出,latency 和 uncertainty 是“叠加压缩”关系:latency 描述真实延迟,uncertainty 在此基础上再预留余量,两者共同决定 setup/hold 的最终需求时间。而 clock groups 是“切断”关系,它直接跳过两组时钟之间的分析,不参与窗口计算。因此,前两者用于精确建模,后者用于控制分析范围,三者用途不同,不能互相替代。
五、实际约束示例与检查要点
假设一个设计中有 clk_100m 和 clk_200m 两个时钟,PLL 输出抖动约 0.12 ns,时钟树偏斜约 0.15 ns,跨时钟域路径已用两级触发器同步。合理的约束组合如下:
create_clock -name clk_100m -period 10.000 [get_ports clk_in]
create_clock -name clk_200m -period 5.000 [get_ports clk_in]
set_clock_uncertainty -setup 0.12 [get_clocks clk_100m]
set_clock_uncertainty -hold 0.06 [get_clocks clk_100m]
set_clock_uncertainty -setup 0.10 [get_clocks clk_200m]
set_clock_uncertainty -hold 0.05 [get_clocks clk_200m]
set_clock_latency -source -late 1.00 [get_clocks clk_100m]
set_clock_latency -source -early 0.70 [get_clocks clk_100m]
set_clock_latency -late 0.50 [get_clocks clk_100m]
set_clock_latency -early 0.35 [get_clocks clk_100m]
set_clock_groups -asynchronous -group {clk_100m} -group {clk_200m}
约束完成后,需要在 TimeQuest 中检查以下几点:第一,用 report_clock 确认每个时钟的 uncertainty 和 latency 已正确附加;第二,用 report_timing -setup 查看跨时钟域路径是否已被 clock groups 切断,若仍出现大量跨域路径,说明分组未生效;第三,用 report_timing -hold 确认 hold 分析中 early latency 和 hold uncertainty 已参与计算;第四,检查是否存在未约束的时钟或未分组的时钟域,避免遗漏。
set_clock_groups -asynchronous 只关闭时序分析,不保证跨时钟域路径的可靠性。若两个时钟域之间没有同步器,必须先用两级触发器或其他同步结构处理,再关闭分析。否则,STA 通过并不代表硬件安全。
总结来说,set_clock_uncertainty 负责为抖动和偏斜预留余量,set_clock_latency 负责描述时钟网络真实延迟,set_clock_groups 负责声明时钟域之间的分析关系。三者分别从“余量”“延迟”“关系”三个维度完善时钟模型,只有正确组合使用,TimeQuest 的时序签核结果才既不过于乐观,也不至于过度悲观。