时序约束入门:什么是SDC?
各位同学,今天咱们聊聊时序约束的起点——SDC。
我记得刚入行那会儿,听到“SDC”三个字母,第一反应是“又是个高大上的术语”。后来才发现,这东西说白了就是个约束文件。全称叫 Synopsys Design Constraints,是 Synopsys 公司提出来的一套标准格式。现在几乎所有主流工具都认它,包括 Cadence 的 Genus、Innovus,还有我们常用的 PrimeTime。
你想想看,一个芯片里成千上万个寄存器,工具怎么知道哪个信号该什么时候到?全靠 SDC 告诉它。没有 SDC,工具就像蒙着眼睛走路,时序乱成一锅粥。
SDC 到底长什么样?
SDC 文件其实就是一堆命令的集合。每条命令告诉工具一件事。比如:
# 创建一个时钟
create_clock -name clk -period 10 [get_ports clk_in]
# 设置输入延迟
set_input_delay -clock clk -max 5 [get_ports data_in]
# 设置输出延迟
set_output_delay -clock clk -max 4 [get_ports data_out]
嗯,看着挺简单对吧?但实际项目里,SDC 文件动辄几百行。我见过最夸张的一个项目,SDC 文件写了三千多行,光时钟定义就占了三分之一。
创建时钟——create_clock
时钟是时序分析的基石。没有时钟,所有路径都没法算延迟。
create_clock 的基本语法是这样的:
create_clock -name <时钟名> -period <周期> [<源对象>]
举个例子:
create_clock -name sys_clk -period 10 [get_ports clk_pad]
这条命令的意思是:在端口 clk_pad 上创建一个名为 sys_clk 的时钟,周期是 10ns,也就是 100MHz。
这里有个坑,我踩过。如果你不指定 -name,工具会自动用端口名作为时钟名。但有时候端口名和内部时钟名冲突,查起来特别费劲。所以我个人习惯,每个时钟都显式指定 -name,哪怕名字和端口一样。
-waveform 参数指定上升沿和下降沿的位置。比如 50% 占空比的 10ns 时钟,波形参数是 {0 5}。
设置输入延迟——set_input_delay
输入延迟描述的是:外部信号从芯片外部到达芯片引脚,需要多长时间。这个时间包括 PCB 走线延迟、外部器件的输出延迟等等。
语法:
set_input_delay -clock <时钟名> -max <最大延迟> [get_ports <端口列表>]
举个例子:
set_input_delay -clock sys_clk -max 3.5 [get_ports {addr bus data_in}]
这条命令告诉工具:addr、bus、data_in 这三个输入端口,相对于 sys_clk 的上升沿,最大延迟是 3.5ns。
为什么要分 -max 和 -min?
因为芯片工作在不同的电压温度下,延迟会变化。高温低压时延迟最大,低温高压时延迟最小。STA 工具会同时检查这两种情况,确保芯片在所有条件下都能正常工作。
-max 没设 -min,结果 hold 检查全红了。后来花了整整两天才排查出来。所以记住:-max 和 -min 都要设,缺一不可。
设置输出延迟——set_output_delay
输出延迟和输入延迟是对称的。它描述的是:芯片内部信号从寄存器输出到芯片引脚,再到外部器件接收,需要预留多少时间。
语法:
set_output_delay -clock <时钟名> -max <最大延迟> [get_ports <端口列表>]
举个例子:
set_output_delay -clock sys_clk -max 4.2 [get_ports {data_out valid}]
这条命令的意思是:data_out 和 valid 这两个输出端口,相对于 sys_clk 的上升沿,外部需要 4.2ns 的建立时间裕量。
你可能会问:为什么输出延迟是“外部需要的时间”?
因为 STA 工具会这样算:时钟周期 - 输出延迟 = 内部路径允许的最大延迟。如果输出延迟设得太大,内部路径就得很短,布局布线压力就大。反过来,设得太小,外部器件可能采不到数据。
所以这个值怎么定?我一般会跟 PCB 工程师一起商量。看看外部器件的 datasheet,算算 PCB 走线延迟,再留点余量。通常 0.5ns 到 1ns 的余量是合理的。
知识体系总览
下面这张图,是我自己画的 SDC 时序约束的核心逻辑。你看一眼就能明白整个框架:
实际项目中的经验
说了这么多理论,聊聊实战吧。
我记得有个项目,芯片要跑 200MHz,我一开始只设了 create_clock -period 5,觉得万事大吉。结果综合出来的网表,setup 时序一塌糊涂,关键路径延迟到了 6ns 多。
后来排查发现,问题出在输入端口上。外部芯片的输出延迟是 2ns,PCB 走线还有 0.5ns,但我根本没设 set_input_delay。工具默认输入延迟为 0,等于把外部延迟全算到内部路径上,自然过不了。
加了 set_input_delay -max 2.5 之后,内部路径的可用时间从 5ns 变成了 2.5ns,综合工具才知道要优化哪些路径。最终布局布线后,时序全收敛了。
所以我的建议是:SDC 文件不要等到布局布线阶段才写。从 RTL 综合阶段就开始写,哪怕只是粗略的约束,也能帮工具提前发现问题。
- SDC 是时序约束的标准格式,所有主流工具都支持
create_clock定义时钟,是时序分析的起点set_input_delay描述外部输入路径的延迟set_output_delay描述外部输出路径的延迟-max和-min都要设,分别对应 setup 和 hold 检查
好了,这一章的内容就到这儿。SDC 看起来简单,但实际项目里坑不少。下一章咱们聊聊更复杂的时钟约束——生成时钟和时钟分组。到时候我会分享一个我踩过的“时钟没分组导致时序爆炸”的案例。