4、I/O约束实战:输入延迟(set_input_delay)、输出延迟(set_output_delay)的设置方法与常见误区
做芯片设计,最头疼的是什么?我猜很多人会说是时序收敛。而时序收敛的第一步,就是把I/O约束搞对。说白了,芯片内部怎么跑得快,那是后端和综合工具的事。但芯片跟外界怎么通信,全靠你这几条I/O约束。
今天咱们就聊聊 set_input_delay 和 set_output_delay。这两个命令,看着简单,用起来坑不少。我这些年踩过的雷,今天一次性给你讲清楚。
4.1 输入延迟:芯片在等数据,你得告诉它等多久
先问个问题:数据从片外送到芯片内部,中间经历了什么?
数据从上一级芯片(比如FPGA或者另一个ASIC)的时钟沿出发,经过PCB走线,再经过封装,最后到达你的芯片引脚。这个过程需要时间。这个时间,就是 输入延迟。
公式很简单:
set_input_delay -clock clk -max 2.5 [get_ports data_in]
set_input_delay -clock clk -min 1.0 [get_ports data_in]
这里 -max 是最大延迟,-min 是最小延迟。为什么要有两个?因为数据到达的时间不是固定的。温度变了、电压变了、PCB走线有偏差,都会导致延迟变化。
核心理解:输入延迟 = 外部时钟到芯片引脚的延迟 + 数据从外部器件到芯片引脚的延迟。这个值越大,留给芯片内部去采样数据的时间就越少。
4.2 输出延迟:芯片送数据出去,外部器件能接住吗?
输出延迟跟输入延迟是对称的。数据从芯片内部寄存器出发,经过输出路径,到达芯片引脚。然后呢?外部器件需要时间去采样这个数据。
输出延迟的定义是:
set_output_delay -clock clk -max 4.0 [get_ports data_out]
set_output_delay -clock clk -min 1.5 [get_ports data_out]
你想想看,外部器件采样数据,需要满足建立时间和保持时间。输出延迟其实就是告诉工具:外部器件需要多少时间准备。这个值越大,芯片内部留给数据从寄存器到引脚的时间就越少。
我的习惯:做输出约束时,我会先拿到外部器件的datasheet,找到它的建立时间和保持时间。然后加上PCB走线延迟,就是输出延迟的值。千万别拍脑袋随便填。
4.3 常见误区:我踩过的那些坑
做I/O约束这么多年,见过太多人在这里翻车。我挑几个典型的说说。
误区一:输入延迟和输出延迟搞反了
这个错误很基础,但确实有人犯。输入延迟是数据从外部到芯片引脚的时间,输出延迟是数据从芯片引脚到外部器件被采样的时间。方向别搞反了。
误区二:只设了max,没设min
我见过一个项目,只设了 -max,没设 -min。结果工具默认 -min 为0。流片回来,保持时间违例,芯片在某些条件下工作不稳定。嗯,这个教训挺深刻的。
警告:一定要同时设置 -max 和 -min。max用于检查建立时间,min用于检查保持时间。缺一个都不行。
误区三:忽略了时钟抖动和不确定性
有些同学设完输入延迟就完事了。但实际电路中,时钟是有抖动的。你需要在约束里加上 set_clock_uncertainty。我曾经在一个项目中,因为没加时钟不确定性,STA报告全绿,但实际测试就是有问题。后来加上0.2ns的uncertainty,问题就暴露出来了。
误区四:输出延迟设得太大
输出延迟设得太大,芯片内部时序会很难收敛。设得太小,外部器件可能采样不到数据。这个平衡怎么找?我的建议是:先按datasheet的典型值设,然后留10%-20%的余量。不要一上来就设最严苛的值。
4.4 实战案例:一个典型的DDR接口约束
咱们看一个实际例子。假设你有一个DDR接口,时钟频率200MHz,数据速率400Mbps。外部DDR颗粒的建立时间要求0.5ns,保持时间要求0.5ns,PCB走线延迟约0.3ns。
输入约束:
# 输入数据延迟
set_input_delay -clock clk_ddr -max 1.2 [get_ports ddr_dq]
set_input_delay -clock clk_ddr -min 0.6 [get_ports ddr_dq]
# 输入时钟延迟
set_input_delay -clock clk_ddr -max 0.8 [get_ports ddr_dqs] -clock_fall
set_input_delay -clock clk_ddr -min 0.4 [get_ports ddr_dqs] -clock_fall
输出约束:
# 输出数据延迟
set_output_delay -clock clk_ddr -max 1.0 [get_ports ddr_dq]
set_output_delay -clock clk_ddr -min 0.5 [get_ports ddr_dq]
# 输出时钟延迟
set_output_delay -clock clk_ddr -max 0.8 [get_ports ddr_dqs] -clock_fall
set_output_delay -clock clk_ddr -min 0.4 [get_ports ddr_dqs] -clock_fall
小技巧:对于DDR接口,数据是双沿采样的。记得用 -clock_fall 选项来处理下降沿。这个细节很多人会忘。
4.5 知识体系:一张图看懂I/O约束
下面这张图,是我自己总结的I/O约束核心逻辑。你看一遍就能明白整个流程。
4.6 总结:记住这几点就够了
好了,说了这么多,我帮你总结一下:
- 输入延迟:数据从外部到芯片的时间。设大了,内部时序难收敛;设小了,可能采不到数据。
- 输出延迟:数据从芯片到外部被采样的时间。设大了,内部时序难收敛;设小了,外部器件可能采不到。
- 必须同时设max和min:一个管建立时间,一个管保持时间。缺一不可。
- 别忘了时钟不确定性:加个
set_clock_uncertainty,让STA更真实。 - 参考datasheet:别自己瞎猜,外部器件的参数都在datasheet里写着。
做I/O约束,说白了就是跟外部器件打交道。你理解了外部器件的时序要求,约束自然就写对了。下次咱们聊聊虚拟时钟和生成时钟,那个坑更多。
可可精品资料库