第三节:约束类型详解——时钟、输入、输出、例外路径
这一节,我们来聊聊 LINCS 框架的基石——四种核心约束类型。
在我刚开始做时序约束的时候,总觉得只要把时钟周期设对就行了。
结果呢?跑到后端实现,时序一片红。后来我才明白,时钟约束只是开始。
输入延退、输出延迟、例外路径,每一个都是“暗坑”。
我把它们叫做“四件套”。你只要把这四种约束吃透,绝大部份的时序问题都能提前发现。
3.1 时钟约束 (Clock Constraints)
时钟是芯片的心跳。所有的时序路径,都绕着时钟转。
我个人习惯用 SDC(Synopsys Design Constraints)来描述时钟。工具能看懂,团队也能看懂。
最基本的时钟定义:
create_clock -name sys_clk -period 10 [get_ports clk_in]
这里的 -period 10 代表时钟周期是 10ns,也就是 100MHz。
但实际项目中,时钟往往会有 jitter 和 skew。我建议你加上 -waveform 参数来明确定义占空比,尤其是处理 DDR 接口时。
时钟约束的核心参数:
- 周期 (Period):这是最基本的,决定了芯片能跑多快。
- 波形 (Waveform):定义上升沿和下降沿的时间。
- 时钟组 (Clock Groups):异步时钟域的分离。
- 生成时钟 (Generated Clocks):如 PLL 分频或倍频后的时钟。
举个例子,异步时钟域的约束:
set_clock_groups -asynchronous -group [get_clocks clk_a] -group [get_clocks clk_b]
如果在两个异步时钟域之间有路径,工具默认会去分析。但这样做既费时间又没意义。你想想看,异步信号本来就有亚稳态风险,用 set_clock_groups 告诉工具“别管这段”,能省下大量运行时间。
小技巧:我习惯在约束文件开头,先把所有时钟定义好,再处理输入输出延迟。顺序乱了,排查起来特别累。
3.2 输入延迟 (Input Delay)
输入延迟描述了数据从外部芯片到达当前芯片内部寄存器的路径时间。
标准写法:
set_input_delay -clock sys_clk -max 2.5 [get_ports data_in]
这里 -max 2.5 表示最坏情况下的输入延迟是 2.5ns。
你可能会问:“为什么还有 -min?”
因为芯片的工作温度、电压会变。不同条件下,路径延迟不一样。
我曾经遇到过一个项目,只约束了输入延迟的最大值,没管最小值。结果在快速工艺角下,数据保持时间 (hold) 直接违规。最终只能 ECO 修复,多折腾了两周。
输入延迟的两种模式:
| 模式 | 应用场景 | 典型值 |
|---|---|---|
| 系统同步 | 外部芯片与当前芯片共用时钟源 | 1.0 ns ~ 3.0 ns |
| 源同步 | 数据与时钟从同一芯片输出 | 0.5 ns ~ 1.5 ns |
我个人习惯在 IP 集成时,特别留意输入延迟的推导。很多时候,IP 手册里给的数值是理论值,你最好加上 20% 的裕量。
3.3 输出延迟 (Output Delay)
输出延迟可以看作是输入延迟的“镜像”。它定义了从内部寄存器到外部芯片的路径时间。
标准写法:
set_output_delay -clock sys_clk -max 3.0 [get_ports data_out]
这里面的 -max 对外部建立时间负责,-min 对外部保持时间负责。
嗯,这里要注意。输出延迟的数值通常比输入延迟大一点,因为 PCB 走线和外部芯片的建立时间需求会累加进来。
输入/输出延迟的“黄金法则”:
- 输入延迟 = 外部芯片输出延迟 + PCB 走线延迟
- 输出延迟 = 外部芯片建立时间 + PCB 走线延迟
记得我在做板级调试时,发现芯片明明时序报告是绿的,但 FPGA 和 ASIC 通信就是出错。后来查了半天,是输出延迟设得太理想了,没考虑 PCB 上走线的实际时延。从那以后,我每次出约束都会多问一句:“PCB 那边预估的走线延迟是多少?”
3.4 例外路径 (Exceptions)
例外路径是时序约束里最灵活、也最容易出错的部分。
常用的三种例外:
- False Path (伪路径):工具不做时序检查。
- Multicycle Path (多周期路径):数据不是在单个时钟沿采样,可以在 N 个周期后采样。
- Max/Min Delay (最大/最小延迟):手动指定路径延迟范围。
具体示例:
set_false_path -from [get_clocks rst_clk] -to [get_clocks sys_clk]
set_multicycle_path 2 -setup -from [get_pins reg_a/Q] -to [get_pins reg_b/D]
set_max_delay 5.0 -from [get_ports start] -to [get_pins end_reg/D]
我见过一些设计师,遇到时序违例就喜欢用 set_false_path“一刀切”。这种做法很危险。你想想看,如果一条路径真的不能假,闩锁结果会直接导致芯片功能错误。
我曾经接手过一个老项目,里面被前任工程师加了几十条 false path。最后查芯片功能异常,才发现其中一条路径根本不能设成 false。原因很简单:当时他赶时间,没仔细分析那条路径的功能相关性。
例外路径的黄金原则:
| 类型 | 什么时候用 | 绝对不要用 |
|---|---|---|
| False Path | 异步复位、测试模式、跨时钟域 | 功能正常的数据路径 |
| Multicycle | 除法器、慢速外设、状态机读取 | 高速流水线数据路径 |
| Max/Min Delay | 异步握手信号、接口时序微调 | 标准时钟沿采样的数据路径 |
3.5 四类约束的关系
为了让你更直观地理解这四种约束之间的关系,我画了一张图。
总结一下这张图想表达的意思:
- 时钟约束是根基,所有路径分析都依赖它。
- 输入/输出延迟是桥梁,连接着芯片内部与外部世界。
- 例外路径是“手术刀”,用来处理那些特殊的、不按标准时序走的路径。
做时序约束的时候,我习惯先从时钟开始,再逐步增加输入输出延迟,最后才加例外路径。别一上来就狂加例外,容易把自己的思路搞乱。
避坑指南:如果你发现自己一个工程里例外路径超过时钟定义的两倍以上,那就要警惕了。大概率是设计本身出了问题,而不是约束的问题。