4、I/O接口时序:输入延迟约束与输出延迟约束
说到I/O接口时序,很多刚入行的朋友会觉得头疼。其实说白了,这就是芯片和外部器件之间的「握手协议」怎么在时序上体现出来。我做了这么多年芯片,发现大部分接口问题都出在约束没给对,或者给得太随意。
4.1 输入延迟约束(set_input_delay)
先聊聊输入延迟。你想想看,外部器件把数据发过来,数据从芯片的pad到内部寄存器,这中间是有延迟的。这个延迟怎么算?
我个人习惯这样理解:输入延迟 = 外部器件的时钟到输出延迟 + PCB走线延迟。说白了,就是数据相对于时钟到达芯片引脚的时间差。
核心公式:
set_input_delay -clock [get_clocks clk] -max 2.5 [get_ports data_in]
set_input_delay -clock [get_clocks clk] -min 1.0 [get_ports data_in]
这里有个坑,我踩过好几次。max和min分别对应最坏和最好情况。max值决定了建立时间能不能满足,min值决定了保持时间。我曾经在一个项目中只给了max没给min,结果流片回来发现保持时间违例,那叫一个惨。
注意:输入延迟的参考点是芯片的时钟引脚,不是内部时钟树。很多新手容易搞混,以为set_input_delay是相对于内部时钟的,其实不是。
4.2 输出延迟约束(set_output_delay)
输出延迟和输入延迟是对称的。芯片内部把数据送到输出pad,外部器件要正确采样。这时候我们需要告诉工具:外部器件需要多少建立时间和保持时间。
公式很简单:
set_output_delay -clock [get_clocks clk] -max 4.0 [get_ports data_out]
set_output_delay -clock [get_clocks clk] -min 1.5 [get_ports data_out]
这里的max对应外部器件的建立时间要求,min对应保持时间要求。我一般会留0.5ns的裕量,毕竟PCB走线、温度变化这些因素都会影响实际延迟。
我的经验:输出延迟的max值不要设得太紧。我曾经在一个DDR接口项目中,把输出延迟设得刚好满足外部器件的建立时间,结果量产时温度一高就出问题。后来我学乖了,至少留10%的裕量。
4.3 如何与外部器件握手
握手,说白了就是双方约定好什么时候发数据、什么时候收数据。常见的握手方式有同步和异步两种。
4.3.1 同步握手
同步握手最简单,双方用同一个时钟。这时候约束就是上面说的输入输出延迟。但要注意时钟偏斜——外部器件的时钟和芯片的时钟可能不是完全同步的。
我遇到过一个问题:外部ADC用100MHz时钟,芯片也用100MHz时钟,但两个时钟来自不同晶振。结果就是频率一样,相位一直在漂。这种情况必须用异步处理,或者加一个PLL同步。
4.3.2 异步握手
异步握手需要握手信号。比如用req/ack协议:芯片发请求,外部器件回应答。这时候时序约束要分两部分:
- 输出路径:约束req信号的输出延迟
- 输入路径:约束ack信号的输入延迟
但异步握手有个特点:不需要严格的建立保持时间,因为内部会做同步处理。不过同步器本身会引入两个周期的延迟,这个要在系统设计时考虑进去。
关键点总结:
- 输入延迟 = 外部器件Tco + PCB延迟
- 输出延迟 = 外部器件Tsetup + PCB延迟
- 同步握手用set_input_delay/set_output_delay
- 异步握手需要同步器,延迟多2个时钟周期
- 始终留裕量,别卡着极限值
4.4 实际项目中的避坑指南
嗯,这里我总结几个常见问题,都是我在项目中真实遇到过的:
- 问题1:只约束了max没约束min。结果保持时间违例,数据被错误采样。
- 问题2:输入延迟参考时钟选错了。应该用外部器件的时钟,不是芯片内部时钟。
- 问题3:输出延迟没考虑PCB走线长度。高速接口尤其要注意,1英寸走线大约有170ps延迟。
- 问题4:异步握手没加同步器。直接跨时钟域采样,导致亚稳态。
我曾经在一个项目中,因为没加同步器,芯片在高温下频繁死机。查了整整两周才发现是异步握手的问题。从那以后,我每个异步接口都强制加两级同步器,宁可多花点面积,也不冒风险。
小技巧:如果你不确定输入输出延迟该设多少,可以先按外部器件datasheet的典型值来设,然后做一次STA看看裕量。如果裕量太大,可以适当收紧;如果违例,就要检查是不是约束太紧了。
最后说一句:I/O时序约束不是一锤子买卖。随着PCB设计变化、温度变化、电压变化,实际延迟都会变。所以我的习惯是:第一次约束留20%裕量,等PCB回来实测后再微调。这样既不会过度约束,也不会漏掉问题。