4、时钟定义与约束:create_clock、create_generated_clock、时钟分组、时钟延迟与不确定性

时钟,说白了就是芯片的「心跳」。

我做了十几年后端,见过太多因为时钟没定义好,导致整个芯片时序崩盘的案例。你想想看,心跳都不对,人还能跑得动吗?

这一节,咱们就把时钟定义与约束的四个核心点掰开揉碎讲清楚。

4.1 create_clock:定义主时钟

create_clock 是所有时序约束的起点。没有它,STA 工具根本不知道你的设计要跑多快。

我个人习惯,在项目一开始就把所有主时钟定义好。别等到综合完了再补,那时候容易漏。

基本语法:

create_clock -name clk_sys -period 10.0 [get_ports clk_in]

这条命令的意思是:在端口 clk_in 上定义一个名为 clk_sys 的时钟,周期 10ns(即 100MHz)。

这里有几个坑,我踩过:

  • 时钟源必须是端口或 pin——别直接定义在 net 上,工具会报 warning。
  • 周期单位是 ns——默认是 ns,别写成 ps,否则频率直接差 1000 倍。
  • 占空比默认 50%——如果你需要非 50% 的占空比,用 -waveform 参数指定上升沿和下降沿时间。

小技巧: 我习惯在 create_clock 时加上 -comment 参数,写上这个时钟的用途。比如 -comment "DDR PHY 参考时钟"。等过几个月回来看约束文件,你会感谢自己的。

4.2 create_generated_clock:定义衍生时钟

芯片里很少有只有一个时钟的情况。PLL 分频、倍频、门控……这些衍生时钟怎么定义?用 create_generated_clock。

举个例子,我有一个 100MHz 的主时钟,经过一个二分频器,得到 50MHz 的时钟:

create_generated_clock -name clk_div2 -source [get_ports clk_in] \
  -divide_by 2 [get_pins u_divider/clk_out]

这里要注意:-source 指向的是主时钟的源端,而不是衍生时钟的输入端。很多人搞反了。

我曾经在一个项目里,把 -source 指向了分频器的输入 pin,结果工具报了一堆莫名其妙的时序违例。查了两天才发现是这里写错了。

警告: 对于多级分频或倍频,一定要保证 -source 指向的是最原始的时钟源。否则工具无法正确计算相位关系。

常用的参数还有:

参数 说明 示例
-divide_by 分频系数 -divide_by 2
-multiply_by 倍频系数 -multiply_by 4
-invert 反相时钟 -invert
-edges 自定义边沿关系 -edges {1 3 5}

4.3 时钟分组:set_clock_groups

芯片里时钟多了,它们之间可能有关系,也可能没关系。没关系的话,就别让工具去分析跨时钟域路径,否则浪费时间还容易报假违例。

set_clock_groups 就是干这个的。

set_clock_groups -asynchronous -group {clk_a clk_b} -group {clk_c}

这条命令告诉工具:clk_a 和 clk_b 是同一组的,它们之间要分析时序;clk_c 是另一组,跟前面两组是异步关系,不用分析。

嗯,这里要注意:

  • 异步分组要谨慎——如果你把有真实数据交互的时钟分到不同组,工具会漏掉真正的时序路径。
  • 物理互斥——如果两个时钟永远不会同时存在(比如 MUX 选择),用 -logically_exclusive 或 -physically_exclusive。

我的经验: 在项目初期,我倾向于把所有时钟都放在一个组里,先跑一遍 STA 看看有哪些跨时钟路径。然后再根据实际情况分组。这样不容易漏掉关键路径。

4.4 时钟延迟与不确定性

时钟延迟(clock latency)和不确定性(clock uncertainty),这两个概念容易混淆。我简单解释一下:

  • 时钟延迟:时钟信号从源端到寄存器时钟 pin 的传播时间。包括网络延迟和器件延迟。
  • 时钟不确定性:时钟抖动、时钟偏斜、以及各种余量的总和。说白了,就是给时序分析留点「安全垫」。

定义时钟延迟:

set_clock_latency -source 0.5 [get_clocks clk_sys]
set_clock_latency 0.3 [get_clocks clk_sys]

第一行是源端延迟(比如 PLL 输出到芯片 pin 的延迟),第二行是网络延迟(从 pin 到寄存器的延迟)。

定义时钟不确定性:

set_clock_uncertainty -setup 0.2 [get_clocks clk_sys]
set_clock_uncertainty -hold 0.05 [get_clocks clk_sys]

setup 和 hold 的不确定性通常不一样。setup 留的余量更大,因为 setup 对工艺、电压、温度更敏感。

注意: 时钟不确定性不是越大越好。设得太大,工具会过度悲观,导致面积和功耗增加。设得太小,又可能漏掉真正的时序问题。我一般根据工艺节点和经验值来设——比如 28nm 工艺,setup uncertainty 设 0.15~0.25ns,hold 设 0.05~0.1ns。

知识体系总览

下面这张图,把时钟定义与约束的核心逻辑串起来了:

时钟定义与约束知识体系 create_clock 定义主时钟源 create_generated_clock 定义分频/倍频/反相时钟 set_clock_groups 时钟分组与异步处理 延迟与不确定性 set_clock_latency/uncertainty STA 时序分析引擎 基于完整时钟约束进行路径分析 时序报告 · 违例路径 · 修复建议

从这张图可以看出来,create_clock 和 create_generated_clock 是基础,set_clock_groups 和延迟/不确定性是进阶。四者缺一不可。

最后说一句:时钟约束做得好,后端工作少烦恼。这句话是我自己总结的,你品,你细品。


可可精品资料库