本文由知乎
赵俊军
授权转载,知乎主页为https://www.zhihu.com/people/zhao-jun-jun-19
本章节将介绍静态时序分析所执行的一部分检查,这些检查旨在详尽地验证待分析设计的时序。
-
两项主要的检查是建立时间和保持时间检查。一旦在触发器的时钟引脚上定义了时钟,便会自动推断出该触发器的建立时间和保持时间检查。时序检查通常会在多个条件下执行,包括最差情况的慢速条件和最佳情况的快速条件。通常,最差情况的慢速条件对于建立时间检查很关键,而最佳情况的快速条件对于保持时间检查很关键(尽管也可以在最差情况的慢速条件下执行保持时间检查)。
-
本章节中的示例假定网络延迟为零,这样做是为了简化说明,并且不会更改所介绍的概念。
8.1 建立时间检查
建立时间检查会验证触发器时钟和数据引脚之间的时序关系,从而满足建立时间要求。换句话说,建立时间检查会确保在触发器输入时钟之前,数据在触发器的输入端可用。在时钟的有效沿到达触发器之前,数据应在一定时间内保持稳定,即触发器的建立时间,该要求将确保数据可靠地被捕获到触发器中。图8-1显示了典型触发器的建立时间要求,建立时间检查将验证触发器的建立时间要求。
通常,有一个发起触发器(用于发起数据的触发器)和捕获触发器(用于捕获数据的触发器),这个捕获触发器的建立时间要求必须满足。建立时间检查将验证从发起触发器到捕获触发器的最长(或最大)路径,这两个触发器的时钟可以相同也可以不同。建立时间检查是从发起触发器中时钟的第一个有效沿到捕获触发器中时钟后面最接近的那个有效沿。建立时间检查将确保上一个时钟周期发起的数据准备好在一个周期后被捕获。
现在我们研究一个简单的示例,如图8-2所示,其中发起触发器和捕获触发器具有相同的时钟。时钟CLKM的第一个上升沿在Tlaunch时间后出现在发起触发器的时钟引脚上,由该时钟沿发起的数据出现在触发器UFF1的D引脚的所需时间为Tlaunch + Tck2q + Tdp。时钟CLKM的第二个上升沿(通常在一个周期后检查建立时间)出现在捕获触发器UFF1的时钟引脚上的时间为Tcycle + Tcapture。这两个时间之差必须大于触发器UFF1的建立时间要求,以确保触发器UFF1可靠地捕获数据。
建立时间检查可以用数学公式表示:
- Tlaunch + Tck2q + Tdp < Tcapture + Tcycle - Tsetup
其中Tlaunch是发起触发器UFF0的时钟树延迟,Tdp是组合逻辑数据路径的延迟,Tcycle是时钟周期,Tcapture是捕获触发器UFF1的时钟树延迟。
换句话说,数据到达捕获触发器D引脚所花费的总时间必须小于时钟传输到捕获触发器所花费的时间加上时钟周期再减去建立时间要求。
由于建立时间检查受到-max的约束,因此建立时间检查始终使用最长或最大的时序路径。出于同样的原因,通常在延迟最大的慢工艺角(slow corner)下执行建立时间检查。
8.1.1 触发器到触发器路径
以下是一份建立时间检查的路径报告:
该报告中显示发起触发器(由Startpoint指定)的实例名称为UFF0,由时钟CLKM的上升沿触发。捕获触发器(由Endpoint指定)为UFF1,也由时钟CLKM的上升沿触发。路径组(Path Group)显示它属于路径组CLKM。如上一章所述,设计中的所有路径都基于捕获触发器的时钟归类为路径组。路径类型(Path Type)显示此报告中的延迟均为最大路径延迟,表明这是建立时间检查。这是因为建立时间检查对应于通过逻辑的最大(或最长路径)延迟。注意,保持时间检查对应于通过逻辑的最小(或最短路径)延迟。
Incr列显示了指定端口或引脚的单元或网络延迟增量,Path列显示了数据实际到达和需要到达的路径累积延迟,这是用于此示例的时钟约束:
-
create_clock -name CLKM -period 10 -waveform {0 5} [get_ports CLKM]
-
set_clock_uncertainty -setup 0.3 [all_clocks]
-
set_clock_transition -rise 0.2 [all_clocks]
-
set_clock_transition -fall 0.15 [all_clocks]
数据发起路径需要0.26ns的延迟才能到达触发器UFF1的D引脚,这是捕获触发器输入端的到达时间。捕获边沿(建立时间检查时为一个周期)为10ns,为此时钟指定了0.3ns的时钟不确定度(clock uncertainty),因此,有效时钟周期由于不确定度而减少了0.3ns。时钟不确定度包括由于时钟源抖动引起的周期变化以及用于分析的任何其它时序裕量。从总的捕获路径中还要减去触发器的建立时间0.04ns(library setup time),得出数据需要到达的时间为9.66ns。由于数据实际到达时间为0.26ns,因此在此时序路径上有9.41ns的正裕量(slack)。请注意,所需到达时间和实际到达时间之差可能看起来是9.40ns,但是实际值是出现在报告中的9.41ns。之所以存在差异,是因为报表仅显示小数点后两位数字,而内部计算和存储的值比所报告的精度更高。
时序报告中的时钟网络延迟(clock network delay)是什么?为什么将其标记为理想(ideal)?时序报告中的这一行表明时钟树被认为是理想的,时钟路径中的任何缓冲器(buffer)都假定为零延迟。一旦构建了时钟树,就可以将时钟网络标记为“已传播”(propagated),从而使得时钟路径显示实际延迟值,如下一个示例时序报告中所示:0.11ns延迟是发起时钟上的时钟网络延迟,而0.12ns延迟是捕获触发器上的时钟网络延迟。
时序路径报告中可以选择包含扩展的时钟路径,即带有明确显示的时钟树。以下是一个例子:
请注意,上述路径报告中的UCKBUF0、UCKBUF1和UCKBUF2都是时钟缓冲器,提供了有关如何计算时钟树延迟的详细信息。
如何计算第一个时钟单元UCKBUF0的延迟呢?如前几章所述,单元延迟是根据单元的输入过渡时间和输出电容来计算的。因此,问题是在时钟树的第一个单元的输入处指定了多大的过渡时间,可以使用set_input_transition命令明确指定第一个时钟单元输入引脚上的过渡时间(或压摆)。
-
set_input_transition -rise 0.3 [get_ports CLKM]
-
set_input_transition -fall 0.45 [get_ports CLKM]
在上述的set_input_transition命令中,我们将输入上升过渡时间指定为了0.3ns,将下降过渡时间指定为了0.45ns。在没有该命令约束的情况下,将在时钟树的源端假设存在理想的压摆,这意味着上升和下降过渡时间均为0ns。
时序报告中的r和f字符表示时钟或数据信号的上升沿(和下降沿)。上一个时序路径报告中显示了一条从UFF0 / Q的下降沿开始到UFF1 / D的上升沿结束的路径。由于UFF1 / D可以为0或1,因此也可以有一条路径在UFF1 / D的下降沿结束。以下就是这样一条路径:
注意,触发器时钟引脚的边沿(称为有效边沿)保持不变。它只能是上升或下降有效沿,具体取决于触发器是由上升沿触发的还是由下降沿触发的。
什么是时钟源延迟(clock source latency)? 这也被称为插入延迟(insertion delay),是时钟从其源端传播到待分析设计的时钟定义点所花费的时间,如图8-3所示,这对应于设计之外的时钟树延迟。例如,如果该设计是较大模块的一部分,则时钟源延迟是指直到待分析设计时钟引脚为止的时钟树延迟。可以使用set_clock_latency命令明确指定此延迟。
-
set_clock_latency -source -rise 0.7 [get_clocks CLKM]
-
set_clock_latency -source -fall 0.65 [get_clocks CLKM]
在没有上述命令的情况下,将假定延迟为0,这是早期路径报告中使用的假设。请注意,源延迟不会影响设计内部的路径,并且它们具有相同的发起时钟和捕获时钟,这是因为发起时钟路径和捕获时钟路径都会加上一段相同的延迟。但是,这种延迟确实会影响经过待分析设计输入和输出的时序路径。
如果没有-source选项,则set_clock_latency命令将定义时钟网络延迟,这是从DUA中时钟定义点到触发器的时钟引脚的延迟。时钟网络延迟用于在建立时钟树之前(即在时钟树综合之前)对通过时钟路径的延迟进行建模。一旦建立了时钟树并标记为了“已传播”(propagated),便会忽略此时钟网络延迟约束。set_clock_latency命令也可用于对从主时钟到其衍生时钟的延迟进行建模,如7.3节所述。当时钟生成逻辑不是设计的一部分时,该命令也可用于建模片外时钟延迟。
8.1.2 输入到触发器路径
以下是一个通过输入端口到触发器的路径报告示例,图8-4给出了与输入路径有关的原理图和时钟波形。
首先要注意的是第一行中的input port clocked by VIRTUAL_CLKM。如7.9节中所述,该时钟可以被认为是驱动设计输入端口INA的虚拟触发器,该虚拟触发器的时钟为VIRTUAL_CLKM。此外,从该虚拟触发器的时钟引脚到输入端口INA的最大延迟指定为2.55ns,在报告中显示为input external delay。可以使用以下SDC命令指定这些参数:
-
create_clock -name VIRTUAL_CLKM -period 10 -waveform {0 5}
-
set_input_delay -clock VIRTUAL_CLKM -max 2.55 [get_ports INA]
请注意,虚拟时钟VIRTUAL_CLKM的定义没有与设计中任何引脚相关,这是因为它是在设计之外定义的(它是虚拟的)。输入延迟约束set_input_delay指定了相对于虚拟时钟的延迟。
输入路径从端口INA开始,如何计算连接到端口INA的第一个单元UINV1的延迟呢?一种方法是指定输入端口INA的驱动单元,该驱动单元用于确定驱动强度,从而确定端口INA上的压摆,然后用于计算单元UINV1的延迟。在输入端口INA上没有任何压摆约束的情况下,将假定端口上的过渡是理想的,即过渡时间为0ns。
- set_driving_cell -lib_cell BUFF -library lib0131wc [get_ports INA]
图8-4还展示了如何进行建立时间检查。数据必须到达UFF2 / D的时间为9.85ns,但是数据实际到达的时间为2.65ns,因此该报告显示该路径的正裕量为7.2ns。
具有实际时钟的输入路径
输入延迟也可以相对于实际时钟来指定,并不一定必须相对于虚拟时钟来指定。实际时钟可以是设计中的内部引脚或者输入端口上的时钟,图8-5描绘了一个示例,其中相对于输入端口CLKP上的时钟指定了端口CIN上的输入延迟约束。此延迟约束为:
- set_input_delay -clock CLKP -max 4.3 [get_ports CIN]
以下是与此约束相对应的输入路径时序报告:
请注意,起始点(Startpoint)与预期一致,将输入端口的延迟参考时钟指定为了CLKP。
8.1.3 触发器到输出路径
与上述输入端口约束类似,可以相对于虚拟时钟或设计中的内部时钟来约束输出端口,或者可以相对于实际的输入时钟端口或输出时钟端口来约束输出端口。以下是一个示例,相对于虚拟时钟约束了输出引脚ROUT,输出约束如下:
-
set_output_delay -clock VIRTUAL_CLKP -max 5.1 [get_ports ROUT]
-
set_load 0.02 [get_ports ROUT]
为了确定最后一个单元连接到输出端口的延迟,需要指定该端口上的负载,上面使用了set_load命令来指定输出负载。请注意,端口ROUT可能在DUA内部具有负载,而set_load约束指定的是额外的负载,即来自DUA外部的负载。在没有set_load命令约束的情况下,将假定外部负载的值为0(这可能不现实,因为该设计很可能会在其它设计中使用)。下图8-6显示了具有虚拟时钟的虚拟触发器的时序路径:
以下是通过该输出端口的时序路径报告:
注意,指定的输出延迟在报告中显示为output external delay,其作用类似于虚拟触发器所需的建立时间。
8.1.4 输入到输出路径
设计也可以具有从输入端口到输出端口的纯组合逻辑路径。可以像我们前面看到的输入和输出路径一样,对路径进行约束和时序分析。下图8-7显示了这种路径的一个示例,虚拟时钟同时用于指定输入和输出端口上的约束,以下是输入和输出延迟约束:
-
set_input_delay -clock VIRTUAL_CLKM -max 3.6 [get_ports INB]
-
set_output_delay -clock VIRTUAL_CLKM -max 5.8 [get_ports POUT]
以下是一个时序路径报告,它经过从输入INB到输出POUT的组合逻辑。请注意,任何内部时钟延迟(如果存在)都不会对该路径报告产生影响。
8.1.5 频率直方图
如果要绘制一个典型设计的建立时间裕量与路径数的频率直方图,则如图8-8所示。根据设计的状态(是否进行了优化) ,对于未优化的设计,零裕量(zero slack)线将更靠近右侧,而对于优化后的设计则更趋向于左侧。对于没有时序违例的设计(即没有路径的裕度为负),整个曲线将在零裕量线的右侧。
以下是以文本形式显示的直方图,通常可以由静态时序分析工具生成:
前两个索引表示裕量的范围,第三个索引是该裕量范围内的路径数,例如,有941条路径的裕量范围为410ps至415ps。直方图表明该设计没有时序违例的路径,即所有路径均具有正的裕量,而关键路径的裕量值在375ps至380ps之间。
难以满足时序要求的设计会使直方图的驼峰向左偏大,也就是说,许多路径的裕量值接近于零。通过观察频率直方图可以得出的另一结果是:可以进一步优化设计以实现零裕量的可能性,即时序收敛有多困难。如果违例路径的数量少并且负裕量值也很小,则设计相对比较容易满足所需的时序。但是,如果违例路径的数量很大并且负裕量值也很大,则这意味着设计将需要付出很大努力才能满足所需的时序。
8.2 保持时间检查
保持时间检查可确保正在变化的触发器输出值不会传递到捕获触发器、并在捕获触发器有机会捕获其原始值之前重写(overwrite)其输出。该检查基于触发器的保持时间要求,触发器的保持时间要求规定在时钟的有效沿之后的指定时间段内,被锁存的数据应保持稳定。图8-9给出了典型触发器的保持时间要求:
就像建立时间检查一样,是在发起触发器(发起数据的触发器)和捕获触发器(捕获数据的触发器以及必须满足其保持时间要求的触发器)之间进行保持时间检查的。这两个触发器的时钟可以相同也可以不同,保持时间检查从发起触发器时钟的一个有效沿到捕获触发器中相同的时钟沿。因此,保持时间检查与时钟周期无关,保持时间检查会在捕获触发器时钟的每个有效沿上执行。
现在我们来看一个简单的示例,如图8-10所示,其中发起触发器和捕获触发器具有相同的时钟。
考虑时钟CLKM的第二个上升沿。时钟上升沿发起的数据需要Tlaunch + Tck2q + Tdp时间到达捕获触发器UFF1的D引脚。时钟的同一边沿需要Tcapture时间才能到达捕获触发器的时钟引脚,目的是使捕获触发器在下一个时钟周期捕获来自发起触发器的数据。如果在同一时钟周期内捕获数据,则捕获触发器中的预期数据(来自上一个时钟周期)将被覆盖,因此保持时间检查旨在确保捕获触发器中的目标数据不会被覆盖。保持时间检查可验证这两个时间之差(捕获触发器的数据到达时间和时钟到达时间)必须大于捕获触发器的保持时间,这样触发器上的数据才不会被覆盖,并且捕获到可靠的数据。
保持时间检查可以用数学公式表示为:
- Tlaunch + Tck2q + Tdp > Tcapture + Thold
其中Tlaunch是发起触发器的时钟树延迟,Tdp是组合逻辑数据路径中的延迟,Tcapture是捕获触发器的时钟树延迟。换句话说,由时钟边沿发起的数据到达捕获触发器D引脚所需的总时间必须大于时钟同一边沿到达捕获触发器所需的时间加上保持时间。这样可以确保UFF1 / D保持稳定状态,直到触发器的时钟引脚UFF1 / CK时钟上升沿之后的保持时间为止。
保持时间检查对捕获触发器的数据路径施加了最小值(-min)约束,需要确定到捕获触发器D引脚的最快路径。这意味着将始终使用最短时序路径来进行保持时间检查,同样,通常在快速工艺角下进行保持时间检查。
即使设计中只有一个时钟,时钟树也会导致时钟在发起触发器和捕获触发器处的到达时间大不相同。为了确保可靠的数据捕获,捕获触发器的时钟沿必须在数据可改变之前到达。保持时间检查可确保(见图8-11):
-
当前数据发起时钟沿(Setup launch edge)的下一个(subsequent)时钟沿发起的数据不被当前数据捕获时钟沿(Setup receiving edge)所捕获。
-
当前数据发起时钟沿发起的数据不被当前数据捕获时钟沿的前一个(Preceding)时钟沿所捕获。
如果发起时钟和捕获时钟都属于同一时钟域,则这两个保持时间检查实质上是相同的。但是,当发起时钟和捕获时钟处于不同频率或处于不同时钟域时,以上两个保持时间检查就有可能是不同的。在这种情况下,最差的保持时间检查就是所要报告的检查。上图8-11说明了这两个保持时间检查。
UFF0是发起触发器,UFF1是捕获触发器。建立时间检查在这一个数据发起时钟沿(Setup launch edge)和这一个数据捕获时钟沿(Setup receiving edge)之间。下一个数据发起时钟沿(Subsequent launch edge)不得以太快的速度传播数据,因为这可能会导致这一个数据捕获时钟沿没有时间可靠地捕获这一个数据。此外,这一个数据发起时钟沿同样不得以太快的速度传播数据,因为这可能会导致前一个数据捕获时钟沿(Preceding receiving edge)没有时间可靠地捕获前一个数据。在上述各种情况中,最差情况的保持时间检查对应于最严格的保持时间检查。
稍后将在8.3节和8.8节中分别讨论更通用的时钟,例如用于多周期路径和多频率路径的时钟。讨论内容将涵盖建立时间检查和保持时间检查之间的关系,尤其是如何从建立时间检查中推断出保持时间检查。虽然建立时间违例会导致设计的工作频率降低,但保持时间违例会“杀死”(kill)设计,即设计在任何频率下都无法运行。因此,了解保持时间检查并解决任何违例行为非常重要。
8.2.1 触发器到触发器路径
本小节将基于图8-2中示例说明触发器到触发器的保持时间路径。以下是一份保持时间检查的路径报告,该示例来自8.1节中的建立时间检查路径。
注意,路径类型(Path Type)为最小值(min),表示使用了最短路径的单元延迟值,这对应于保持时间检查。库保持时间(library hold time)指定了触发器UFF1的保持时间。如前3.4节所述,触发器的保持时间也可以为负。请注意,发起和捕获路径都是从时钟CLKM的上升沿(触发器的有效沿)开始计算的。时序报告显示,新数据最早可以到达UFF1、同时又可以安全地捕获上一个时钟周期数据的时间为0.19ns。由于新数据的实际到达时间为0.33ns,因此报告显示正的保持时间裕量(slack)为0.14ns。
图8-12显示了时钟信号到达发起和捕获触发器时钟引脚的时间,以及数据在捕获触发器处的最早允许到达时间和实际到达时间。由于数据实际到达的时间晚于数据所需到达的时间(允许的最早到达时间),因此满足保持时间要求。
保持时间裕量计算
需要注意的一点是,为建立时间和保持时间的时序报告计算裕量值的方式有所不同。在建立时间报告中,会计算数据实际到达时间和数据需要到达时间,然后将需要到达时间减去实际到达时间,从而得到建立时间的裕量值。但是,在保持时间报告中,当我们把需要到达时间减去实际到达时间后,负的结果将转化为正的裕量值(表示满足保持时间要求),而正的结果将转化为负的裕量值(表示保持时间违例)。
8.2.2 输入到触发器路径
接下来介绍输入端口的保持时间检查。有关示例,请参见图8-4。使用虚拟时钟将输入端口上的最小延迟指定为:
- set_input_delay -clock VIRTUAL_CLKM -min 1.1 [get_ports INA]
以下是一份保持时间检查的路径报告:
input external delay中的值为输入延迟约束命令中的指定值。在0时刻的VIRTUAL_CLKM上升沿和CLKM上升沿之间进行保持时间检查。UFF2在不违反其保持时间的情况下捕获数据所需的到达时间为0.25ns,这表明数据应在0.25ns之后到达。由于数据实际上在1.2ns才到达,因此显示出0.95ns的正裕量。
8.2.3 触发器到输出路径
这小节将介绍输出端口上的保持时间检查。示例见图8-6,输出端口延迟约束为:
- set_output_delay -clock VIRTUAL_CLKP -min 2.5 [get_ports ROUT]
输出延迟也是相对于虚拟时钟指定的,这是另一份保持时间检查的路径报告:
请注意,output external delay中的值为输出延迟约束命令中的指定值。
具有实际时钟的触发器到输出路径
有一条输出端口保持时间检查的路径,如图8-13所示。请注意,最小输出延迟是相对于实际时钟指定的。
-
set_output_delay -clock CLKP -min 3.5 [get_ports QOUT]
-
set_load 0.55 [get_ports QOUT]
以下是保持时间报告:
保持时间检查是在时钟CLKP的上升沿(触发器的有效沿)处执行的。以上报告表明,这条触发器到输出的路径保持时间的正裕量为4.46ns。
8.2.4 输入到输出路径
这是对输入到输出路径的保持时间检查,如图8-7所示。端口的约束为:
-
set_load -pin_load 0.15 [get_ports POUT]
-
set_output_delay -clock VIRTUAL_CLKM -min 3.2 [get_ports POUT]
-
set_input_delay -clock VIRTUAL_CLKM -min 1.8 [get_ports INB]
-
set_input_transition 0.8 [get_ports INB]
输入端口和输出端口上的延迟约束是相对于虚拟时钟指定的,因此,保持时间检查是在该虚拟时钟的上升沿(有效沿)处执行的。