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 做兜底约束,防止组合逻辑延迟过大导致亚稳态窗口过宽。
四、约束关系全景
下图把本节四类约束放在同一条“端口—路径—时钟”关系链上,帮助理解它们各自作用的位置与参照对象。
五、实操检查清单
完成 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 只应用于无时钟参照或异步场景,否则会掩盖真实的建立时间问题。