3、时序约束入门:SDC约束文件介绍、时钟定义、生成时钟、输入延迟与输出延迟
各位同学,今天我们来聊聊时序约束。说实话,我刚入行那会儿,觉得时序约束就是个麻烦事——不就是把时钟频率写上去吗?后来被现实狠狠教育了一顿。有一次我设计的模块,综合后时序报告一片飘红,折腾了两周才发现是时钟定义少了个参数。从那以后,我对SDC文件再也不敢马虎了。
3.1 SDC约束文件是什么?
SDC,全称Synopsys Design Constraints。说白了,它就是一份给EDA工具看的“设计说明书”。你告诉工具:我的时钟长什么样,数据什么时候来,什么时候走。工具才能帮你算时序。
我个人习惯把SDC文件放在项目根目录的constraints/文件夹下。一个典型的SDC文件,大概长这样:
# 时钟定义
create_clock -name clk_sys -period 10.0 [get_ports clk]
# 输入延迟
set_input_delay -clock clk_sys -max 2.5 [get_ports data_in]
# 输出延迟
set_output_delay -clock clk_sys -max 3.0 [get_ports data_out]
嗯,看着简单吧?但实际项目中,SDC文件动辄几百行。我见过最夸张的一个项目,SDC文件有2000多行,光时钟就定义了30多个。
核心要点:SDC文件是时序分析的“法律条文”。工具会一字不差地执行你的约束。写错了,时序分析就错了。
3.2 时钟定义:create_clock
时钟是时序分析的“心跳”。没有时钟,STA就没法做。create_clock命令的基本语法:
create_clock -name <时钟名> -period <周期(ns)> [<时钟源>]
举个例子:
create_clock -name clk_100m -period 10.0 [get_ports clk_in]
这里我定义了一个叫clk_100m的时钟,周期10ns,也就是100MHz。时钟源是端口clk_in。
你可能会问:如果时钟有占空比要求呢?比如不是50%?可以用-waveform参数:
create_clock -name clk_60_40 -period 10.0 -waveform {0.0 6.0} [get_ports clk_in]
这个时钟高电平6ns,低电平4ns,占空比60%。
我的经验:时钟命名要规范。我习惯用“clk_频率_用途”的格式,比如clk_100m_core、clk_50m_io。这样看SDC文件时一目了然。
3.3 生成时钟:create_generated_clock
实际设计中,很多时钟不是直接从端口进来的。它们可能是PLL分频、倍频后的产物。这时候就要用create_generated_clock。
语法:
create_generated_clock -name <生成时钟名> -source <源时钟> -divide_by <分频系数> [<目标引脚>]
看个例子:
create_generated_clock -name clk_50m -source [get_ports clk_in] -divide_by 2 [get_pins pll/clk_out]
这里我把100MHz的输入时钟二分频,得到50MHz的生成时钟。
倍频呢?用-multiply_by:
create_generated_clock -name clk_200m -source [get_ports clk_in] -multiply_by 2 [get_pins pll/clk_out]
还有一种情况:时钟相位偏移。比如DDR接口需要90度相移的时钟:
create_generated_clock -name clk_ddr_90 -source [get_ports clk_in] -phase 90 [get_pins dll/clk_out]
注意:生成时钟的-source一定要指定到源时钟的定义点,而不是随便一个节点。我曾经犯过这个错,把-source指向了PLL的输出,结果时序分析全乱了。
3.4 输入延迟与输出延迟
芯片不是孤立存在的。它要和外部器件通信。输入延迟和输出延迟,就是描述这种“芯片外部”的时序关系。
3.4.1 输入延迟
输入延迟,指的是数据从外部到达芯片输入端口所花费的时间。公式很简单:
输入延迟 = 外部器件时钟到输出的延迟 + PCB走线延迟
SDC中这样写:
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]
-max用于建立时间检查,-min用于保持时间检查。为什么要有两个值?因为外部器件的延迟有波动,温度、电压都会影响。
避坑指南:我曾经在一个项目中,只设了-max没设-min。结果保持时间违例了,工具没报出来。后来流片回来,芯片在低温下工作不稳定。查了两个月才发现是保持时间问题。所以,max和min都要设。
3.4.2 输出延迟
输出延迟,描述的是数据从芯片输出到外部器件被采样的时间。公式:
输出延迟 = PCB走线延迟 + 外部器件建立时间
SDC写法:
set_output_delay -clock clk_sys -max 3.0 [get_ports data_out]
set_output_delay -clock clk_sys -min 1.5 [get_ports data_out]
这里-max对应外部器件的建立时间要求,-min对应保持时间要求。
3.4.3 一个完整的例子
假设我们有一个SPI接口,主控芯片输出时钟和数据给从设备。约束可以这样写:
# 时钟定义
create_clock -name clk_spi -period 20.0 [get_ports spi_clk]
# 输入延迟(从设备返回的数据)
set_input_delay -clock clk_spi -max 5.0 [get_ports spi_miso]
set_input_delay -clock clk_spi -min 2.0 [get_ports spi_miso]
# 输出延迟(发送给从设备的数据)
set_output_delay -clock clk_spi -max 4.0 [get_ports spi_mosi]
set_output_delay -clock clk_spi -min 1.0 [get_ports spi_mosi]
你想想看,这些延迟值怎么来的?不是拍脑袋定的。要查外部器件的数据手册,看它的时序参数,再结合PCB走线长度估算。我一般会留10%-20%的余量。
3.5 本章知识体系
下面这张图,帮你理清本章的核心逻辑:
这张图把本章四个核心知识点串起来了。你仔细看,SDC文件的核心就两件事:定义时钟、定义延迟。时钟定义好了,延迟设对了,时序分析才能跑出靠谱的结果。
个人建议:刚开始写SDC文件时,不要追求一步到位。先定义好时钟,跑一遍时序分析,看看有没有问题。再加输入输出延迟,逐步完善。我每次都是这样迭代着来的。
好了,这一章的内容就到这里。记住:SDC文件是时序分析的基石。写错了,后面所有工作都是白费。下一章我们会深入讨论时序路径和时序报告怎么看,到时候你会更理解为什么SDC文件这么重要。
可可精品资料库