时钟组与时钟特性:set_clock_groups的精髓

时钟组这个概念,说白了就是告诉工具哪些时钟之间不用分析。我刚开始做STA那会儿,总觉得把所有时钟都分析一遍才放心,结果跑出来的时序报告又臭又长,真正的问题反而被淹没了。后来才明白,合理的时钟分组,是STA效率的关键。

核心思想:时钟组就是给时钟「划圈子」——同一个圈子里的时钟要互相检查,不同圈子里的时钟各玩各的。

set_clock_groups 的三种模式

这个命令有三种常用模式,我一个个说。

1. 异步时钟组(-asynchronous)

两个时钟之间没有固定的相位关系,比如来自不同PLL的时钟。你想想看,它们之间传递数据时,谁快谁慢根本说不准,强行分析只会产生一堆假路径。

# 两个异步时钟,互不关心
set_clock_groups -asynchronous -group {clk_a} -group {clk_b}

我在项目中遇到过这样的情况:一个芯片里有CPU核和USB控制器,它们的时钟源完全不同。如果不设异步组,工具会去分析CPU到USB的跨时钟路径,结果全是违例,但实际功能上这些路径有同步器处理,根本不需要关心。

我的习惯:所有来自不同晶振或不同PLL的时钟,一律设为异步组。省心,也省运行时间。

2. 互斥时钟组(-logically_exclusive)

互斥时钟,说白了就是「同一时刻只有一个能干活」。比如芯片有正常模式和测试模式,用的时钟不同,但不会同时出现。

# 功能时钟和测试时钟互斥
set_clock_groups -logically_exclusive -group {func_clk} -group {test_clk}

嗯,这里要注意:互斥时钟在物理上可能连到同一个触发器,但因为MUX选择,同一时刻只有一个有效。工具不需要分析它们之间的路径。

3. 物理互斥组(-physically_exclusive)

这个更狠——两个时钟在物理上就不可能同时存在。比如同一个PLL输出的不同分频时钟,你选了2分频就不能选4分频。

# 同一个PLL的不同分频模式
set_clock_groups -physically_exclusive -group {pll_div2} -group {pll_div4}

我曾经踩过的坑:把物理互斥和逻辑互斥搞混了。物理互斥的时钟连MUX都没有,纯粹是配置不同。如果误用逻辑互斥,工具可能会漏掉一些真正的时序路径。

时钟延迟:别小看这根线

时钟从源头到触发器,中间要经过缓冲器、走线,这些都会引入延迟。我见过新手直接设0延迟,结果流片回来芯片跑不起来。

# 设置时钟源延迟
set_clock_latency -source 2.0 [get_clocks clk_sys]

# 设置时钟网络延迟
set_clock_latency 1.5 [get_clocks clk_sys]

实际项目中,时钟树综合(CTS)之前,我们会给一个预估的延迟值。CTS之后再用真实值替换。我个人习惯在前期设一个偏大的值,给自己留点余量。

时钟抖动:真实世界的「手抖」

时钟抖动,就是时钟边沿在时间轴上的随机摆动。PLL不可能完美,温度电压变化也会影响。说白了,你期望时钟在10ns时跳变,它可能在9.98ns或10.02ns才跳。

抖动类型 来源 影响
周期抖动 PLL噪声、电源噪声 影响建立时间
长周期抖动 温度变化、老化 影响保持时间
# 设置时钟抖动
set_clock_uncertainty -setup 0.2 [get_clocks clk_sys]
set_clock_uncertainty -hold 0.1 [get_clocks clk_sys]

我的经验:抖动值不要拍脑袋。查一下PLL的数据手册,一般会给出典型值和最大值。我通常取典型值的1.5倍作为设计余量。

时钟不确定性:把「不确定」变成「确定」

时钟不确定性(clock uncertainty)是个大箩筐,除了抖动,还包括:

  • 时钟树的不匹配
  • 工艺偏差
  • 电压温度变化
  • 串扰影响

你想想看,这些因素都会让时钟边沿偏离理想位置。我们用一个总的uncertainty值把它们包进去。

# 综合的时钟不确定性设置
set_clock_uncertainty -setup 0.3 [all_clocks]
set_clock_uncertainty -hold 0.15 [all_clocks]

注意:建立时间和保持时间的uncertainty通常不同。建立时间要留更多余量,因为数据路径延迟变化更大。保持时间相对稳定,但也不能忽略。

知识体系总览

下面这张图,是我自己总结的时钟组与时钟特性的核心逻辑。你看一眼就能明白它们之间的关系。

时钟组与时钟特性知识体系 set_clock_groups ├─ -asynchronous:异步时钟 不同源时钟,无固定相位关系 ├─ -logically_exclusive:逻辑互斥 同一时刻只有一个有效(如功能/测试) └─ -physically_exclusive:物理互斥 物理上不可能同时存在 时钟特性参数 ├─ 时钟延迟 (Clock Latency) 源延迟 + 网络延迟 ├─ 时钟抖动 (Clock Jitter) 周期抖动 / 长周期抖动 └─ 时钟不确定性 (Clock Uncertainty) 抖动 + 不匹配 + 工艺偏差 + 串扰 共同作用于 核心原则 合理分组减少假路径,准确设置特性保证时序收敛 实践建议 1. 不同PLL时钟 → 异步组 2. 功能/测试时钟 → 逻辑互斥组 3. 抖动值参考数据手册 4. uncertainty留20%余量

避坑指南

最后,我把自己这些年踩过的坑总结一下:

  • 别把所有时钟都设成异步——我曾经图省事,把同源时钟也设成异步,结果漏掉了真正的跨时钟路径问题,后端修时序修到崩溃。
  • 互斥时钟要确认硬件设计——有个项目,设计文档说功能时钟和测试时钟互斥,但实际电路里有个MUX没做好隔离,结果两个时钟同时有效,时序分析全错了。
  • 抖动和不确定性别混用——有些工具里,set_clock_uncertainty已经包含了抖动。如果你再单独设抖动,相当于重复计算,时序会变得过于悲观。

一句话总结:时钟组帮你「划清界限」,时钟特性帮你「精准建模」。两者配合好了,STA才能又快又准。

可可精品资料库