4、输入输出延迟约束:输入延迟、输出延迟、虚拟时钟的应用

好,咱们今天聊聊输入输出延迟约束。这块内容,说难不难,说简单也不简单。很多新手工程师容易在这上面栽跟头。我自己刚入行那会儿,就因为没搞懂 set_input_delay 和 set_output_delay 的本质,导致芯片回来后接口时序怎么都调不通。嗯,那滋味可不好受。

说白了,输入输出延迟约束就是告诉工具:芯片外面的世界是什么样的。你想想看,芯片不是孤立存在的,它要和 PCB 上的其他器件通信。外部器件的时钟相位、数据输出时间,这些信息工具都不知道。所以你得替它「翻译」一下。

4.1 输入延迟:芯片在「听」什么?

set_input_delay 描述的是数据从外部器件发出,到到达芯片输入引脚这段时间。注意,这个延迟是相对于时钟边沿的。

我习惯把输入延迟拆成两部分看:

  • 外部器件的时钟到输出延迟(Tco)
  • PCB 走线延迟(Tpcb)

公式很简单:input_delay = Tco + Tpcb。但实际项目中,你得拿到外部器件的 datasheet,找到它的输出时序参数。千万别拍脑袋乱填,我曾经见过有人随便写了个 2ns,结果综合出来的电路根本没法用。

核心要点:输入延迟约束的是数据相对于时钟的到达时间。工具会用它来检查芯片内部寄存器的建立时间和保持时间是否满足。

举个例子,假设外部器件在时钟上升沿后 3ns 才输出数据,PCB 走线又花了 1ns。那么输入延迟就是 4ns。约束写法如下:

# 相对于时钟 clk,数据在时钟沿后 4ns 到达
set_input_delay -clock clk -max 4.0 [get_ports data_in]

# 最小延迟(通常用于保持时间检查)
set_input_delay -clock clk -min 1.0 [get_ports data_in]

这里有个坑:-max 和 -min 分别对应建立时间和保持时间检查。最大值一般来自外部器件的最大 Tco,最小值来自最小 Tco。你想想看,如果外部器件输出数据有抖动,那最小延迟可能比最大值小很多。

注意:输入延迟的参考时钟,必须是芯片内部生成的时钟吗?不一定。如果外部器件使用不同的时钟源,你就得用虚拟时钟了。这个咱们后面讲。

4.2 输出延迟:芯片在「说」什么?

set_output_delay 正好反过来。它描述的是数据从芯片输出引脚,到被外部器件正确采样的这段时间。说白了,就是给外部器件留出足够的建立时间和保持时间。

输出延迟的计算公式:

  • 建立时间角度: output_delay = Tsetup_of_external_device + Tpcb
  • 保持时间角度: output_delay = Thold_of_external_device + Tpcb

我个人习惯把输出延迟理解为「外部器件对芯片的要求」。芯片内部的数据必须提前到达输出引脚,这样外部器件才能正确采样。

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

# 外部器件需要 1ns 的保持时间
set_output_delay -clock clk -min 1.5 [get_ports data_out]

这里要注意符号。输出延迟的 -max 对应的是外部器件的建立时间要求,-min 对应保持时间要求。千万别搞反了。我刚开始做的时候,就犯过这个错,结果时序报告里全是 violation,查了半天才发现是符号写反了。

小技巧:你可以把输出延迟想象成「芯片欠外部器件的债」。芯片必须提前还清(数据提前输出),外部器件才能按时收到。

4.3 虚拟时钟:没有时钟怎么办?

虚拟时钟是个好东西。它不驱动任何寄存器,纯粹作为一个参考点存在。什么时候用?

  • 外部器件使用独立的时钟源,和芯片内部时钟不同频或不同相。
  • 输入输出延迟需要参考一个不存在的时钟,比如 DDR 接口的双边沿采样。
  • 跨时钟域约束,需要定义一个虚拟时钟来模拟外部时序。

创建虚拟时钟很简单:

# 创建一个 100MHz 的虚拟时钟
create_clock -name vclk -period 10.0

# 然后输入延迟参考这个虚拟时钟
set_input_delay -clock vclk -max 4.0 [get_ports data_in]

虚拟时钟的名字可以随便起,但最好有意义。我习惯用 vclk_xxx 的格式,一看就知道是虚拟的。

为什么需要虚拟时钟?因为工具默认输入输出延迟是相对于芯片内部时钟的。如果外部时钟和内部时钟不同,你直接参考内部时钟,工具会认为它们同源,从而做错误的时序分析。虚拟时钟就是用来「解耦」的。

嗯,这里要特别提醒一下:虚拟时钟的周期和波形,必须和外部器件的实际时钟一致。否则你约束得再漂亮,也是白搭。我曾经遇到一个项目,外部器件是 50MHz 的,我虚拟时钟写成了 100MHz,结果时序分析全乱套了。排查了两天才发现这个低级错误。

4.4 实战中的常见陷阱

我总结几个实际项目中容易踩的坑:

  1. 忽略最小延迟:很多人只设 -max,不设 -min。工具默认 -min 为 0,这可能导致保持时间检查过于乐观。实际上外部器件的最小输出延迟可能很小,甚至为负值。
  2. 时钟抖动没考虑:输入输出延迟本身已经包含了外部器件的抖动,但如果你用虚拟时钟,别忘了在时钟约束里加上抖动。
  3. 多路复用接口:如果同一个引脚在不同模式下有不同的延迟,建议用 -add_delay 选项添加多组约束。
  4. 忘记约束双向口:双向口既要设输入延迟,也要设输出延迟。我见过有人只设了一边,结果另一边时序完全没检查。

避坑指南:我曾经在一个高速接口项目中,因为没设 -min 延迟,导致保持时间 violation 被忽略。流片回来后,接口在高温下频繁出错。从那以后,我每次都会把 -max 和 -min 都写上,哪怕 -min 是 0 也要显式声明。

4.5 知识体系结构图

下面这张图,帮你理清输入输出延迟约束的核心逻辑:

输入输出延迟约束知识体系 输入延迟 set_input_delay 输出延迟 set_output_delay 虚拟时钟 Virtual Clock 外部器件 Tco + PCB 走线 建立时间检查(-max) 保持时间检查(-min) 外部器件 Tsetup + PCB 建立时间要求(-max) 保持时间要求(-min) 独立时钟源场景 DDR 双边沿采样 跨时钟域约束 核心原则 输入输出延迟 = 外部器件时序参数 + PCB 走线延迟 虚拟时钟用于解耦内部时钟与外部时钟的依赖关系 常见陷阱:忽略 -min 延迟 | 时钟抖动未考虑 | 双向口只约束一边

这张图把三个核心概念的关系和子项都列出来了。你可以看到,输入延迟和输出延迟本质上是对称的,一个管「进来」,一个管「出去」。虚拟时钟则是它们的「辅助工具」,用来处理特殊情况。

我的建议:写约束文件时,先把外部器件的 datasheet 翻出来,把关键参数(Tco、Tsetup、Thold)列个表。然后对照着写 set_input_delay 和 set_output_delay。这样不容易漏,也不容易错。

好了,关于输入输出延迟约束,核心内容就这些。记住一句话:约束的本质是沟通——你在替芯片和外部世界「传话」。传对了,时序收敛;传错了,流片回来哭都来不及。

可可精品资料库