1. 时序基础概念:建立时间、保持时间、时钟抖动、时钟偏斜

做FPGA设计的朋友,时序分析是绕不开的一道坎。我记得刚入行那会儿,总觉得时序约束是件麻烦事,能省则省。结果呢?板子调了三天三夜,最后发现是保持时间违例。从那以后,我再也不敢小看这些基础概念了。

今天咱们就聊聊时序分析的四个基石:建立时间、保持时间、时钟抖动、时钟偏斜。说白了,搞懂这四个东西,你就能看懂大部分时序报告了。

1.1 建立时间(Setup Time)

建立时间是什么?简单说,就是时钟有效沿到来之前,数据必须提前稳定下来的最短时间。你想想看,寄存器要采样数据,总得给它一点时间把数据"看清楚"吧?

定义:在时钟有效沿到来之前,数据输入端必须保持稳定的最小时间窗口。

我在项目中遇到过这样一个案例:一个100MHz的设计,综合后时序报告显示建立时间违例了0.3ns。查了半天,发现是一级组合逻辑太深了。解决办法?插入一级流水线,把长路径打断。嗯,就是这么简单粗暴。

建立时间的计算公式:

T_setup_slack = T_clk - T_co - T_logic - T_net - T_setup

其中:

  • T_clk:时钟周期
  • T_co:寄存器时钟到输出的延迟
  • T_logic:组合逻辑延迟
  • T_net:布线延迟
  • T_setup:寄存器本身的建立时间要求

这个公式你得记住。每次做时序分析,我第一件事就是看这个slack是正是负。正数说明没问题,负数嘛...就得想办法了。

1.2 保持时间(Hold Time)

保持时间和建立时间正好相反。它指的是时钟有效沿到来之后,数据还必须保持稳定的最短时间。为什么要这样?因为寄存器采样完成后,还需要一点时间来锁存数据。

注意:保持时间违例比建立时间违例更难处理。建立时间慢了可以加流水线,保持时间快了...你只能加延迟。

我曾经调试过一个SDRAM接口,时序报告显示保持时间违例。我当时的反应是:"怎么会?频率才133MHz啊!"后来发现是时钟偏斜太大,导致数据到达时间比时钟早了太多。解决办法是在数据路径上插入一些buffer,人为增加延迟。

保持时间的检查公式:

T_hold_slack = T_co_min + T_logic_min + T_net_min - T_hold

这里用的是最小值,因为保持时间检查的是"最快路径"。你想想看,数据跑得太快,反而会出问题。

1.3 时钟抖动(Clock Jitter)

时钟抖动,说白了就是时钟边沿的位置在不停地晃动。理想情况下,时钟边沿应该精确地每隔10ns出现一次(100MHz)。但实际中,每个边沿都会有点偏差,可能早到0.1ns,也可能晚到0.1ns。

小技巧:在做时序分析时,我习惯把时钟抖动分成两部分:周期抖动和长期抖动。周期抖动影响相邻两个时钟周期,长期抖动影响多个周期。对于建立时间分析,我们关心的是周期抖动。

时钟抖动的来源主要有:

  • PLL的相位噪声
  • 电源噪声
  • 温度变化
  • 电路本身的噪声

我记得有一次,一个设计在实验室跑得好好的,到了现场就时不时出错。查了三天,最后发现是现场的电源质量太差,导致PLL输出时钟抖动超标。从那以后,我设计时都会留出至少0.2ns的抖动余量。

1.4 时钟偏斜(Clock Skew)

时钟偏斜,指的是同一个时钟信号到达不同寄存器的时间差。为什么会有这个差异?因为时钟走线有长度,有负载,有RC延迟。

时钟偏斜分为两种:

  • 正偏斜:目标寄存器的时钟晚于源寄存器。这其实对建立时间有利,因为数据有更多时间到达。
  • 负偏斜:目标寄存器的时钟早于源寄存器。这对保持时间不利,因为数据可能还没到,时钟就来了。

关键点:时钟偏斜不是越小越好。有时候,我们会有意引入正偏斜来帮助建立时间收敛。但要注意,正偏斜会恶化保持时间。

我做过一个项目,时钟树综合后偏斜有0.5ns。当时年轻,觉得偏斜太大,花了两周时间优化到0.1ns。结果呢?建立时间反而更难收敛了。为什么?因为我把正偏斜也优化掉了。后来我学乖了,只优化负偏斜,保留正偏斜。

1.5 四个概念的关系

这四个概念不是孤立的。它们共同决定了你的设计能不能稳定工作。我画了一张图,帮你理清它们之间的关系:

时序基础概念关系图 建立时间 Setup Time 保持时间 Hold Time 时钟抖动 Clock Jitter 时钟偏斜 Clock Skew 互补关系 影响 影响 正偏斜有利 负偏斜不利 四个概念共同决定时序收敛,缺一不可

从这张图你可以看到:

  • 建立时间和保持时间是互补的,一个要求数据早到,一个要求数据晚走
  • 时钟抖动同时影响建立时间和保持时间,因为它让时钟边沿不确定
  • 时钟偏斜对建立时间和保持时间的影响是相反的

1.6 实际设计中的考量

说了这么多理论,咱们来点实际的。在做时序约束时,我一般会这样处理:

  1. 先看建立时间:这是最常见的违例。如果slack是负的,先检查路径长度,考虑插入流水线。
  2. 再看保持时间:如果保持时间违例,检查时钟偏斜。有时候加几个buffer就能解决。
  3. 留出抖动余量:我习惯在时序约束中加上0.2-0.3ns的抖动余量。别问我为什么,吃过亏就知道了。
  4. 控制时钟偏斜:尽量让时钟偏斜在0.2ns以内。如果做不到,至少保证负偏斜不要太大。

个人经验:在做跨时钟域设计时,时钟抖动和偏斜的影响会被放大。我建议使用异步FIFO或者双寄存器同步器来处理跨时钟域信号。别问我怎么知道的,有一次跨时钟域没处理好,整个系统在高温下就挂了。

嗯,时序基础概念就聊到这儿。这些概念看起来简单,但真正用好它们,需要大量的实践。下次你看到时序报告时,不妨先看看是建立时间还是保持时间出了问题,然后再对症下药。

专注资料整理