4. 输入输出延迟与组合逻辑约束

在综合流程中,Design Compiler 只能看到模块内部的逻辑,模块外部(上游驱动、下游负载、PCB 走线、板级时钟)的时序环境必须由设计者显式描述。描述外部时序环境的核心手段就是 set_input_delay 与 set_output_delay;而当路径两端都不在同一个时钟域、或路径本身是纯组合逻辑时,则需要 set_max_delay / set_min_delay 来直接约束路径延迟。本节围绕这四类约束展开,重点讲清“约束值怎么算、虚拟时钟怎么用、组合路径怎么限”。

一、I/O 延迟的本质:把外部世界折算到端口

综合工具在端口处做时序检查时,需要知道数据相对于时钟到达(或离开)端口的时间。这个时间由外部器件决定,工具无法推导,因此用 set_input_delay 告诉工具:“数据在时钟沿之后 X ns 才到达输入端口”;用 set_output_delay 告诉工具:“数据必须在时钟沿之前 Y ns 就稳定在输出端口”。

关键约定:延迟值以时钟沿为参照,正号表示“沿之后到达/沿之前要求”。对输入延迟,值等于“上游器件 Tco + 板级走线延迟”;对输出延迟,值等于“下游器件 Tsetup + 板级走线延迟”。这两个值都是相对同一个参考时钟沿测量的,因此必须配合 -clock 使用。

# 输入延迟:上游 Tco=2.0ns,走线=0.5ns,参考时钟 clk
set_input_delay -clock clk -max 2.5 [get_ports data_in*]
set_input_delay -clock clk -min 0.3 [get_ports data_in*]

# 输出延迟:下游 Tsetup=1.5ns,走线=0.4ns
set_output_delay -clock clk -max 1.9 [get_ports data_out*]
set_output_delay -clock clk -min 0.2 [get_ports data_out*]

注意 -max 与 -min 必须成对给出:-max 用于建立时间检查(数据最晚到达),-min 用于保持时间检查(数据最早到达)。只给 -max 会导致保持时间无约束,综合结果可能在硅后出现 hold 违例。

二、虚拟时钟:当外部没有真实时钟时

很多接口的外部器件时钟与内部时钟并不同源,甚至外部根本没有可用的时钟端口。此时若强行用内部时钟做参考,约束值会失去物理意义。虚拟时钟(virtual clock)正是为此设计:它不绑定任何端口,只提供一个“时间参照系”。

create_clock -name vclk -period 10 -waveform {0 5}
set_input_delay  -clock vclk -max 3.0 [get_ports rx_data]
set_output_delay -clock vclk -max 2.0 [get_ports tx_data]

虚拟时钟的周期应与外部器件的实际工作周期一致。若外部是 100MHz,则 -period 10;若外部是 125MHz,则 -period 8。虚拟时钟不参与时钟树综合,也不产生时钟延迟,它只影响 I/O 端口的时序检查基准。

虚拟时钟最常见的两个场景:一是源同步接口(数据与选通信号一起传输),二是异步接口(外部时钟与内部时钟无固定相位关系)。前者用虚拟时钟描述选通沿,后者用虚拟时钟把异步路径“隔离”成可约束的检查。

三、组合路径与异步接口:set_max_delay / set_min_delay

当一条路径的起点和终点不在同一个时钟域,或者路径两端都是组合逻辑(没有触发器),默认的建立/保持检查无法正确覆盖它。此时应使用 set_max_delay 限制路径的最大延迟,用 set_min_delay 限制最小延迟。

# 组合路径:从输入端口经纯组合逻辑到输出端口,要求 ≤ 4ns
set_max_delay 4.0 -from [get_ports a] -to [get_ports y]
set_min_delay 0.5 -from [get_ports a] -to [get_ports y]

# 异步接口:跨时钟域路径,限制最大延迟
set_max_delay 6.0 -from [get_clocks clk_a] -to [get_clocks clk_b]
set_min_delay 1.0 -from [get_clocks clk_a] -to [get_clocks clk_b]

使用 set_max_delay 时要注意:它会覆盖默认的时钟周期约束,因此值必须根据实际接口协议计算,不能随意填一个“看起来安全”的数。对异步接口,通常还会配合 set_clock_groups -asynchronous 或 set_false_path 来关闭默认的跨时钟检查,再用 set_max_delay 做兜底约束,防止组合逻辑延迟过大导致亚稳态窗口过宽。

四、约束关系全景

下图把本节四类约束放在同一条“端口—路径—时钟”关系链上,帮助理解它们各自作用的位置与参照对象。

上游器件 Tco + 走线 下游器件 Tsetup + 走线 Design Compiler 综合模块 组合逻辑 时序逻辑 in out set_input_delay -clock clk -max/-min set_output_delay -clock clk -max/-min 虚拟时钟 vclk create_clock -name vclk set_max_delay / set_min_delay 组合路径 · 异步接口 · 跨时钟域 参考时钟 clk create_clock -period 10 I/O 延迟描述外部环境 · 虚拟时钟提供参照 · max/min 约束组合与异步路径

五、实操检查清单

完成 I/O 约束后,建议按以下顺序自查,避免常见遗漏:

  • 参考时钟是否存在:-clock 指定的时钟必须已由 create_clock 或 create_generated_clock 定义,否则约束会被忽略或报错。
  • max/min 是否成对:每个端口或路径的 -max 与 -min 都应给出,保持时间检查不可省略。
  • 虚拟时钟周期是否匹配外部器件:周期填错会导致约束值整体偏移,综合结果偏乐观或偏悲观。
  • 组合路径是否被覆盖:纯组合路径若没有 set_max_delay,工具可能不检查或按默认值处理,需显式约束。
  • 异步接口是否双重保护:先用 set_clock_groups -asynchronous 关闭默认检查,再用 set_max_delay 限制组合延迟。
不要用 set_max_delay 去“修复”本应有时钟周期的同步路径。同步路径的时序由时钟周期决定,set_max_delay 只应用于无时钟参照或异步场景,否则会掩盖真实的建立时间问题。