3. 时序约束入门:创建时钟、生成时钟、输入延迟与输出延迟约束

时序约束,说白了就是给芯片设计定规矩。没有规矩,STA工具就不知道该怎么分析你的电路。我刚开始做后端时,觉得约束是前端的事,后来发现——后端工程师不懂约束,就像开车不看仪表盘,迟早要翻车。

这一章,我们聊聊最基础的四个约束:创建时钟、生成时钟、输入延迟、输出延迟。掌握了这些,你就能让STA工具听懂你的设计意图。

3.1 创建时钟(create_clock)

时钟是时序分析的基准。没有时钟,STA就没法算路径延迟。创建时钟的语法很简单:

create_clock -name clk -period 10 [get_ports clk_in]

这条命令的意思是:在端口 clk_in 上创建一个名为 clk 的时钟,周期是10ns(也就是100MHz)。

嗯,这里有几个坑要注意:

  • 时钟名要唯一。我见过有人把两个时钟都叫"clk",结果STA报错说时钟重复定义。
  • 周期单位是ns。默认是ns,但有些工具可以设成ps。建议统一用ns,省得换算出错。
  • 占空比默认50%。如果你需要非50%的占空比,可以加 -waveform 参数。

实际案例:我在一个项目中,前端给的时钟周期是10ns,但实际PLL输出有抖动。我加了 -jitter 0.2 来模拟时钟抖动,结果发现一条关键路径的slack从正变负。后来调整了时钟不确定性,才让时序收敛。

3.2 生成时钟(generate_clock)

生成时钟,是从已有时钟分频或倍频出来的时钟。比如PLL输出、分频器输出,都属于生成时钟。

create_generated_clock -name clk_div2 -source [get_clocks clk] -divide_by 2 [get_pins u_div/clk_out]

这条命令的意思是:从 clk 时钟分频2倍,得到 clk_div2 时钟,输出在 u_div/clk_out 这个pin上。

我个人习惯,生成时钟一定要指定 -master_clock 或 -source。否则工具可能找不到源时钟,导致分析出错。

避坑指南:我曾经遇到一个bug——生成时钟的源时钟是虚拟时钟(virtual clock),结果STA报了一堆unconstrained path。后来发现,生成时钟的源时钟必须是真实存在的时钟,不能是虚拟的。

生成时钟的常用参数:

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

3.3 输入延迟(set_input_delay)

输入延迟,描述的是外部信号到达芯片输入端口的时间。说白了,就是数据从外部芯片出来,经过PCB走线,再到我们芯片输入端口,花了多长时间。

set_input_delay -clock clk -max 2.5 [get_ports data_in]

这条命令的意思是:data_in 这个端口,相对于 clk 时钟,最大输入延迟是2.5ns。

你想想看,为什么要有 -max 和 -min?因为芯片工作在不同PVT条件下,延迟会变化。 -max 对应最差情况(慢工艺、高温、低压), -min 对应最好情况(快工艺、低温、高压)。

注意:输入延迟的值,通常由系统级仿真或PCB设计给出。不要自己瞎猜。我曾经见过有人随便填了个1ns,结果流片回来芯片根本没法跟外部器件通信。

输入延迟的常见写法:

  • 单沿采样:只用一个时钟沿采样数据
  • 双沿采样:DDR接口,上下沿都采样
  • 虚拟时钟:如果外部时钟和内部时钟不同源,需要先创建虚拟时钟

3.4 输出延迟(set_output_delay)

输出延迟,描述的是数据从芯片输出端口,到外部器件接收,需要多长时间。跟输入延迟是对称的。

set_output_delay -clock clk -max 3.0 [get_ports data_out]

这条命令的意思是:data_out 这个端口,相对于 clk 时钟,最大输出延迟是3.0ns。

输出延迟的约束逻辑,其实是在告诉STA工具:芯片内部的数据,必须在时钟沿之前提前准备好,留出足够的时间给外部走线和器件。

经验之谈:我建议输出延迟的 -max 值,至少留0.5ns的余量。因为PCB走线长度、连接器阻抗,都会引入额外的延迟。留点余量,总比流片回来发现IO时序违例要好。

3.5 知识体系总览

下面这张图,是我画的一个时序约束知识框架。你可以看到,四个约束分别对应芯片的四个边界:

时序约束知识体系 芯片内部 时序路径分析 输入延迟 set_input_delay 输出延迟 set_output_delay 创建时钟 create_clock 生成时钟 create_generated_clock 四个约束分别对应芯片的四个边界:时钟输入、时钟生成、数据输入、数据输出

这张图想表达的是:创建时钟和生成时钟,定义了芯片内部的时序基准;输入延迟和输出延迟,定义了芯片与外部世界的接口时序。四个约束缺一不可。

3.6 实战小贴士

最后,分享几个我在项目中积累的经验:

  • 先写时钟,再写IO延迟。顺序很重要,因为IO延迟依赖于时钟定义。
  • 用report_timing检查。写完约束后,跑一下report_timing,看看有没有unconstrained path。
  • 虚拟时钟别乱用。虚拟时钟只用于IO延迟,不要用在内部路径上。
  • 多跟前端沟通。约束值不是后端自己定的,需要前端提供系统级时序信息。

我的习惯:每次写完约束,我都会在SDC文件开头加一段注释,写明时钟来源、频率、IO延迟的依据。这样三个月后自己回来看,也能快速想起来当初为什么这么设。

好了,时序约束入门就聊到这里。记住一句话:约束写得好,时序收敛早。下一章我们聊聊更进阶的约束——多周期路径和伪路径,那才是真正考验后端工程师功底的地方。

可可精品资料库