4. SDC约束精讲(下):set_input_delay/set_output_delay、set_max_delay/set_min_delay、set_false_path、set_multicycle_path

好,咱们接着聊SDC约束的下半部分。上一章我们把时钟约束讲透了,这一章要啃的才是真正让新手头疼的——IO约束和路径约束。说实话,我当年刚入行时,最怕的就是set_input_delay和set_output_delay,总觉得这玩意儿玄学。后来踩过几次坑,才明白它其实没那么复杂。

4.1 set_input_delay / set_output_delay:芯片与外界握手

说白了,这两个约束就是告诉工具:芯片外面的信号,到底什么时候来,什么时候走。你想想看,芯片不是孤岛,它要和PCB上的其他器件通信。如果不告诉工具外部延迟,工具就会瞎优化。

4.1.1 set_input_delay 详解

这个约束描述的是:数据在时钟沿之后多久,才能稳定到达芯片的输入引脚。我习惯把它理解为「外部路径的延迟」。举个例子:

# 时钟周期为10ns,外部延迟为3ns
set_input_delay -clock clk -max 3.0 [get_ports data_in]
set_input_delay -clock clk -min 1.0 [get_ports data_in]

这里-max 3.0表示最坏情况下,数据在时钟沿后3ns才到。工具会据此检查内部寄存器能不能在剩下的7ns内完成捕获。

核心公式(记牢):

建立时间检查:T_clk - T_input_delay_max - T_setup > 0

保持时间检查:T_input_delay_min - T_hold > 0

我在项目中遇到过一个问题:有个客户给的输入延迟约束只有-max,没有-min。结果后仿时保持时间全挂。为什么?因为没有-min约束,工具默认min为0,但实际上外部器件输出保持时间很差,导致内部hold violation。嗯,这里要注意:max和min都要给,缺一不可。

4.1.2 set_output_delay 详解

这个反过来,描述的是数据从芯片输出后,到被外部器件捕获所需要的延迟。说白了,就是给外部留出多少时间窗口。

# 外部器件需要2ns的建立时间
set_output_delay -clock clk -max 2.5 [get_ports data_out]
set_output_delay -clock clk -min 0.5 [get_ports data_out]

这里-max 2.5意味着:内部数据必须在时钟沿前2.5ns就准备好输出。工具会检查内部路径能不能满足这个要求。

我的小技巧:做IO约束时,我习惯先画一张时序图。把时钟、数据、外部延迟都画出来,一目了然。别嫌麻烦,画图比硬算快多了。

4.2 set_max_delay / set_min_delay:给路径上紧箍咒

这两个约束,说白了就是给特定路径设定硬性延迟上限和下限。它们和时钟约束不同,时钟约束是自动推导的,而这两个是手动强加的。

4.2.1 set_max_delay 应用场景

我常用的场景有两个:

  • 异步时钟域之间的路径:两个异步时钟之间,工具默认不做时序检查。但如果你希望限制路径延迟(比如防止毛刺传播),可以用set_max_delay。
  • 组合逻辑路径:有些纯组合逻辑路径没有时钟,工具不会自动检查。这时候需要手动设一个最大延迟。
# 限制异步路径最大延迟为5ns
set_max_delay 5.0 -from [get_clocks clk_a] -to [get_clocks clk_b]

注意:set_max_delay会覆盖时钟约束!如果你对一条有时钟的路径用了set_max_delay,工具会忽略时钟周期,直接用这个值做检查。我曾经因为这个原因,把一条本应跑1GHz的路径约束成了100MHz,查了两天才发现是set_max_delay和时钟约束冲突了。

4.2.2 set_min_delay 应用场景

这个用得少一些,但关键时刻能救命。主要用来处理保持时间问题:

# 保证异步路径最小延迟为1ns
set_min_delay 1.0 -from [get_pins reg_a/Q] -to [get_pins reg_b/D]

为什么要设最小延迟?因为有些路径太短了,数据跑得太快,导致保持时间违例。加buffer又怕影响其他路径,这时候set_min_delay就派上用场了。

4.3 set_false_path:告诉工具「别管这条路」

这个约束,我愿称之为「STA工程师的免死金牌」。但用不好,就是「流片失败的催命符」。

set_false_path的意思是:这条路径不需要做时序检查。工具会直接跳过它。

# 跨时钟域同步路径,不需要检查
set_false_path -from [get_clocks clk_a] -to [get_clocks clk_b]

# 复位信号路径,不需要检查
set_false_path -to [get_ports rst_n]

# 测试模式下的路径
set_false_path -from [get_ports scan_enable]

我见过最惨的案例:有个同事把一条关键路径设成了false_path,结果芯片回来死活跑不到目标频率。查了两个月,才发现是false_path用错了。所以我的原则是:能用multicycle_path解决的,就别用false_path。

什么时候该用false_path?

  • 复位信号(异步复位)
  • 测试模式信号(scan_enable、test_mode等)
  • 已经做了同步处理的跨时钟域信号
  • 上电配置信号(只在初始化阶段有效)

4.4 set_multicycle_path:给路径多一个周期

这个约束比false_path温和得多。它告诉工具:这条路径不需要在一个周期内完成,可以多给几个周期。

# 数据需要2个周期才能稳定
set_multicycle_path 2 -setup -from [get_pins reg_a/Q] -to [get_pins reg_b/D]
set_multicycle_path 1 -hold -from [get_pins reg_a/Q] -to [get_pins reg_b/D]

这里有个坑:-hold的multicycle值默认比-setup小1。为什么?因为保持时间检查的是同一个时钟沿,而建立时间检查的是下一个时钟沿。如果你把setup改成2,hold默认还是1,不需要改。但如果你把setup改成3,hold默认变成2,这时候需要显式指定hold为1。

我记得有一次,一个设计里用了大量的multicycle_path,结果后仿时数据老是出错。查到最后发现是hold的multicycle没设对,导致保持时间检查放松了,数据被过早捕获。嗯,这个细节一定要记住。

我的经验:multicycle_path常用于以下场景:

  • 慢速外设接口(如SPI、I2C)
  • 内部大位宽数据通路(如DMA)
  • 流水线深度较大的计算单元

用之前,先确认数据是否真的需要多个周期。别为了省事乱用,否则后仿有你哭的。

4.5 知识体系总览

说了这么多,我画了一张图帮你理清思路。这四种约束,其实解决的是不同层面的问题:

SDC约束精讲(下)知识体系 时序约束四大金刚 IO约束 set_input_delay set_output_delay 路径约束 set_max_delay set_min_delay 例外约束 set_false_path set_multicycle_path 应用场景 芯片与PCB接口 跨时钟域处理 核心原则:先时钟,后IO,再例外

这张图把四种约束分成了三大类:IO约束管的是芯片和外界打交道;路径约束管的是内部特殊路径;例外约束管的是不需要或需要放宽检查的路径。你想想看,是不是这个理?

最后提醒一句:约束不是越多越好。我见过有人把整个设计都塞满了false_path和multicycle_path,结果工具跑得飞快,但流片回来全是bug。约束要精准,宁缺毋滥。每条约束都要问自己:我真的理解这条路径吗?

好了,这一章的内容就到这儿。四种约束的用法和坑都讲清楚了,剩下的就是多练。记住,纸上得来终觉浅,绝知此事要躬行。

可可精品资料库