4、时序约束入门:create_clock、set_input_delay、set_output_delay、set_max_delay

时序约束,说白了就是给芯片设计定规矩。

没有规矩,不成方圆。你想想看,工具不知道时钟周期是多少,不知道数据什么时候来、什么时候走,它怎么帮你优化?我刚开始做数字芯片那会儿,就吃过这个亏——约束没写全,结果后仿一堆violation,改得我头皮发麻。

今天咱们就聊聊最基础的四个约束命令。掌握了它们,你就能应付绝大多数场景了。

4.1 create_clock:给芯片一个心跳

时钟是数字电路的脉搏。没有时钟,所有寄存器都成了摆设。

create_clock 就是告诉工具:嘿,这个端口上有个时钟,周期是多少,占空比怎样。

create_clock -name clk_sys -period 10 [get_ports clk]

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

我个人习惯,-name 一定要写。为什么?因为有时候端口名和时钟名不一样,后续约束里引用时钟名会更方便。比如你有个PLL输出,端口名叫 pll_out,但你想叫它 clk_pll,那就用 -name 指定。

小技巧: 如果时钟有抖动(jitter),可以用 -jitter 选项。我在一个高速接口项目中,时钟抖动达到了50ps,不加这个约束,时序分析结果偏乐观,差点翻车。

多时钟域设计里,你可能会遇到多个时钟。比如一个芯片有CPU时钟、总线时钟、外设时钟。每个都要单独定义:

create_clock -name clk_cpu -period 5 [get_ports clk_cpu_in]
create_clock -name clk_bus -period 10 [get_ports clk_bus_in]
create_clock -name clk_periph -period 20 [get_ports clk_periph_in]

嗯,这里要注意:不同时钟域之间的路径,工具默认会做跨时钟域分析。如果你没加 set_false_path 或 set_clock_groups,可能会报一堆你根本不需要关心的violation。

4.2 set_input_delay:数据什么时候到?

光有时钟还不够。数据从芯片外部进来,它相对于时钟是什么时候到达的?这就是 set_input_delay 要干的事。

set_input_delay -clock clk_sys -max 2.5 [get_ports data_in]
set_input_delay -clock clk_sys -min 1.0 [get_ports data_in]

这条命令的意思是:数据 data_in 相对于时钟 clk_sys 的上升沿,最大延迟2.5ns,最小延迟1.0ns。

为什么要分最大和最小?因为PVT(工艺、电压、温度)变化会导致延迟有波动。最大延迟对应最差情况(slow corner),最小延迟对应最好情况(fast corner)。

核心理解: set_input_delay 描述的是外部器件发送数据的时间点。它等于外部器件的 Tco(时钟到输出延迟)加上 PCB 走线延迟。

我曾经在一个项目中,只写了 -max 没写 -min。结果工具在hold分析时用了默认值0,导致hold timing过于乐观。流片回来,低温下数据采样出错。嗯,从那以后我再也不敢偷懒了。

实际项目中,input delay 怎么算?我给你个公式:

set_input_delay -max = Tco_max + Tpcb_max - Tclk_skew
set_input_delay -min = Tco_min + Tpcb_min - Tclk_skew

其中 Tco 是外部器件的时钟到输出延迟,Tpcb 是PCB走线延迟,Tclk_skew 是时钟到达芯片和外部器件的偏差。

4.3 set_output_delay:数据什么时候被取走?

有进就有出。set_output_delay 描述的是芯片输出数据时,下游器件需要多长的建立时间和保持时间。

set_output_delay -clock clk_sys -max 3.0 [get_ports data_out]
set_output_delay -clock clk_sys -min 0.5 [get_ports data_out]

这条命令的意思是:下游器件要求数据在时钟沿之前3.0ns稳定(setup),在时钟沿之后0.5ns保持稳定(hold)。

你想想看,这其实是在帮下游器件做约束。工具会保证芯片内部路径的延迟,加上输出buffer延迟,再加上PCB走线延迟,最终到达下游器件时,能满足它的时序要求。

注意: set_output_delay 的值通常是负的?不对!很多人搞混。实际上,output delay 是「从时钟沿往回收」的时间。如果下游器件要求建立时间2ns,那 output delay 就是2ns。工具会保证芯片内部路径延迟 + 输出延迟 ≤ 时钟周期 - 2ns。

我建议你画个时序图来理解。时钟沿在中间,左边是setup窗口,右边是hold窗口。output delay 就是从时钟沿往左画一段,表示数据必须在这之前就稳定。

4.4 set_max_delay:给路径设个上限

set_max_delay 是个「万能胶」约束。它不依赖时钟,直接给某条路径设定最大延迟。

set_max_delay 5.0 -from [get_ports rst_n] -to [get_pins reg_a/D]

这条命令的意思是:从复位端口 rst_n 到寄存器 reg_a 的数据输入引脚,最大延迟不能超过5ns。

什么时候用这个?我总结了几种场景:

  • 异步信号约束: 比如复位释放、异步中断,它们没有时钟关系,但你又不想让它太慢。
  • 组合逻辑路径: 有些纯组合逻辑路径,没有寄存器,没法用时钟约束。
  • 跨时钟域路径: 虽然用了同步器,但你还是想限制一下延迟,防止毛刺太长。
避坑指南: 我曾经在一个项目中,对异步复位用了 set_max_delay 5ns。结果工具为了满足这个约束,把复位树的buffer加得很大,面积暴涨。后来我改成10ns,完全没问题。所以,set_max_delay 的值别拍脑袋定,要结合实际物理延迟来估算。

另外,set_max_delay 和 set_min_delay 经常成对出现。一个设上限,一个设下限,把路径延迟框在一个范围内。

set_max_delay 8.0 -from [get_ports data_in] -to [get_ports data_out]
set_min_delay 2.0 -from [get_ports data_in] -to [get_ports data_out]

这样,从输入到输出的纯组合路径,延迟就被限制在2~8ns之间。

知识体系总览

下面这张图,帮你理清这四个约束的关系:

时序约束四大金刚 数字芯片 内部逻辑 + 寄存器 时钟树 + 数据路径 外部器件 / 接口 发送数据到芯片 下游器件 / 接口 从芯片接收数据 数据 数据 create_clock set_input_delay set_output_delay set_max_delay 时钟是基准,输入/输出延迟描述接口时序,max_delay补充特殊路径

这张图你看懂了吗?create_clock 是基准,set_input_delay 和 set_output_delay 描述芯片与外部交互的时序窗口,set_max_delay 则用来约束那些没有时钟关系的特殊路径。

这四个命令,是时序约束的基石。你写SDC文件时,80%的内容都离不开它们。我个人建议,刚开始学的时候,先拿一个小模块练手,把每个约束的效果都跑一遍时序报告看看。实践出真知,光看文档是不够的。

好了,今天就聊到这儿。记住:约束写得好,后仿没烦恼;约束写不好,流片两行泪。

一句话总结: create_clock 定节奏,set_input_delay 管输入,set_output_delay 管输出,set_max_delay 补漏洞。四者配合,时序无忧。

可可精品资料库