接上文--STA 静态时序分析 第七章——STA环境的配置(1)
目录
7.5 输出路径的约束
例子A
下图中展示了待分析设计的输出路径例子。Tc1、Tc2分别是组合逻辑延时。
CLKQ的周期,决定了UFF0与UFF1之间有多少的可用时间。外部逻辑的延时为Tc2+Tsetup,需要被指定为外部延时。请注意,外部延时是依据捕获时钟来指定的。数据必须及时到达外部寄存器UFF1,从而满足建立时间的要求。
set Tc2 3.9
set Tsetup 1.1
set_output_delay -clock CLKQ -max [expr Tc2 + Tsetup] \
[get_ports OUTB]
这里指定了最大的外部延时,值为5ns。最小外部延时同样也可以用类似的方法指定。
例子B
下图的例子展示了,既有最小延时、也有最大延时的情况。最大路径延时为7.4ns,最小路径延时为-0.2ns。以上两个延时分别对应于max的Tc2+Tsetup,min的Tc2-Thold因此代码:
create_clock -period 20 -waveform {0 15} [get_ports CLKQ]
set_output_delay -clock CLKQ -min -0.2 [get_ports OUTC]
set_output_delay -clock CLKQ -max 7.4 [get_ports OUTC]
图中的波形展示了OUTC的数据需要保持稳定才能被外部的捕获寄存器捕捉到。这也就说明,数据输出端口必须在稳定区域开始前就准备好,并且需要保持稳定直到稳定区域结束。这转化为对逻辑时序的要求,即DUA内部输出端口OUTC的时序要求。
例子C
在下面的这个例子中,模块有两个输入DATAIN和MCLK,一个输出DATAOUT。下图中也有波形。
create_clock -period 100 -waveform {5 55} [get_ports MCLK]
set_input_delay 25 -max -clock MCLK [get_ports DATAIN]
set_input_delay 5 -min -clock MCLK [get_ports DATAIN]
set_output_delay 20 -max -clock MCLK [get_ports DATAOUT]
set_output_delay -5 -min -clock MCLK [get_ports DATAOUT]
对于代码解释:首先创建了周期100,边沿在5 55处的时钟。然后设置了输入延时最大为25ns,最小为5ns。设置输出延时最大为20ns,最小为5ns。
7.6 时序路径组
每个路径都有起点和终点。静态时序分析中,路径是根据有效的起始点和终点进行计时的。有效的起始点有:输入端口以及同步时序器件(寄存器、内存)的时钟引脚。有效的终点有:输出端口以及同步时序器件的数据输入引脚。因此一个有效的时序路径可以是:
- 从输入端口到输出端口;
- 从输入端口到触发器或存储器的数据输入引脚;
- 从触发器或存储器的时钟引脚到触发器或存储器的数据输入引脚;
- 从触发器的时钟引脚到输出端口;
- 从存储器的时钟引脚到输出端口
上图中有效的时序路径有:
- 输入端口A到UFFA的D输入端口
- 输入端口A到输出端口Z
- UFFA的时钟引脚CLK到UFFB的D输入端口
- UFFB的时钟引脚CLK到输出引脚Z
时序路径根据这条路径的终点,分类到不同的时序路径组中。因此,每个时钟都有一套与之相关联的路径。这里也存在一条默认路径(default path group),包含了所有的异步时序路径。在下图中的不同组为:
- 时钟A组:由输入端口A到UFFA的D引脚。
- 时钟B组:由UFFA的时钟引脚,到UFFB的D引脚。
- 默认组:输入端口A到输出引脚Z的路径以及UFFB的时钟引脚到输出端口Z。
对于每条路径的分析以及报告通常是分开的。
7.7 外部因素的建模
虽然使用 create_clock、set_input_delay 和 set_output_delay 足以约束设计中所有路径以执行时序分析,但这些方法不足以获得模块 I/O 引脚的准确时序。接下来的因素也需要,以此来模拟设计所处的环境。对于输入引脚,我们需要指定压摆,这可以使用:
- set_drive(不推荐)
- set_driving_cell
- set_input_transition
对于输出引脚,我们只需要指定由它所看到的负载电容的大小:
- set_load
7.7.1对于驱动能力建模
前两个指令用于指定驱动模块输入引脚的外部源头的驱动能力。如果没有这些指令,完全按照默认设置,所有的输入都有无穷大的驱动能力。理想情况也就暗示着输入引脚上的转换时间为0.set_drive显式地指出了在待分析设计的输入引脚上的驱动电阻值。值越小,驱动能力越强。如果电阻为0,意味着无穷大的驱动能力。
set_drive 100 UCLK
# Specifies a drive resistance of 100 on input UCLK.
# Rise drive is different from fall drive:
set_drive -rise 3 [all_inputs]
set_drive -fall 2 [all_inputs]
输入引脚的驱动,用来计算在第一个单元上的过渡时间。同时,也用于计算输入端口,到一个单元的延时(即使存在RC互连)
set_driving_cell则是描述端口驱动能力的更简单的方法。
set_driving_cell -lib_cell INV3 \
-library slow [get_ports INPB]
# The input INPB is driven by an INV3 cell
# from library slow.
set_driving_cell -lib_cell INV2 \
-library tech13g [all_inputs]
# Specifies that the cell INV2 from a library tech13g is
# the driving cell for all inputs.
set_driving_cell -lib_cell BUFFD4 -library tech90gwc \
[get_ports {testmode[3]}]
# The input testmode[3] is driven by a BUFFD4 cell
# from library tech90gwc.
lib-cell代表标准单元库,其他的注释都有解释。
使用set_driving_cell的一个注意点在于由于输入端口上的电容性负载而导致驱动单元的增量延迟被视作为输入上的附加延迟被包括在内。
作为上述方法的一种替代方法,set_input_transition可以在输入引脚更方便地指定压摆。参考时钟可以有选择性的指出。对于下面的图,如下有代码:
set_input_transition 0.85 [get_ports INPC]
# Specifies an input transition of 850ps on port INPC.
set_input_transition 0.6 [all_inputs]
# Specifies a transition of 600ps on all input ports.
set_input_transition 0.25 [get_ports SD_DIN*]
# Specifies a transition of 250ps on all ports with
# pattern SD_DIN*.
# Min and max values can optionally be specified using
# the -min and -max options.
get_ports SD_DIN*该命令将所有匹配模式SD_DIN*
的端口的输入转换时间设置为0.25纳秒(或250皮秒)。星号(*)是一个通配符,匹配任何字符序列,意味着此设置会应用于任何名称以SD_DIN
开头的端口。set_input_transition -min 0.2 -max 0.5 [get_ports CLK]
会为端口CLK
设置一个最小转换时间为0.2纳秒,最大转换时间为0.5纳秒,作为使用min max的示例。
总的来说,压摆值是需要的,因为我们要用它计算延时。如果不指定,就认为是理想情况,过渡时间为0,显然不现实。
7.7.2 容性负载的建模
set_load指令,相当于在输出端口放置了一个电容。默认情况下,电容的值为0。这个负载可以显式地指定为一个电容值,或者是单元输入引脚上的电容。
set_load 5 [get_ports OUTX]
# Places a 5pF load on output port OUTX.
set_load 25 [all_outputs]
# Sets 25pF load capacitance on all outputs.
set_load -pin_load 0.007 [get_ports {shift_write[31]}]
# Place 7fF pin load on the specified output port.
# A load on the net connected to the port can be
# specified using the -wire_load option.
# If neither -pin_load nor -wire_load option is used,
# the default is the -pin_load option.
前两行代码容易理解,单位都是pF。最后一行明确指出连接到该端口的引脚电容。如果是一个网络的负载,可以用-wire_load。
可以用set_load来指定一个内部网络的负载。
set_load 0.25 [get_nets UCNT5/NET6]
# Sets the net capacitance to be 0.25pF.
7.8 设计规则检查
两个最常用的设计规则:最大转换时间&最大电容。这些规则将会检查设计中的所有端口和引脚,是否满足过渡时间和电容的规定约束。这些规则可以使用以下命令指定:
- set_max_transition
- set_max_capacitance
作为STA的一部分,任何违背上述规则的行为,都会以裕度(slack)的形式来报告。
set_max_transition 0.6 IOBANK
# Sets a limit of 600ps on IOBANK.
set_max_capacitance 0.5 [current_design]
# Max capacitance is set to 0.5pf on all nets in
# current design.
上面的代码展示了可以接受的最大转换时间以及对于现在设计的最大电容值。
网络电容的计算方法:引脚电容和+IO负载电容+网络的互连电容。下图是一个例子:
Total cap on net N1 = pin cap of UBUF1:pin/A + pin cap of UOR2:pin/B + load cap specified on output port OUTP + wire/routing cap = 0.05 + 0.03 + 0.07 + 0.02 = 0.17pF
Total cap on net N2 = pin cap of UBUF2/A + wire/routing cap from input to buffer = 0.04 + 0.03 = 0.07pF
过渡时间的计算是延时计算的一部分。
Transition time on pin UBUF2/A = drive of 21 * total cap on net N2 = 2 * 0.07 = 0.14ns = 140ps
Transition time on output port OUTP = drive resistance of UBUF2/Z * total cap of net N1 = 1 * 0.17 = 0.17ns = 170ps
这里也有其他的设计准则,比如说set_max_fanout(设置引脚最大的引脚数)、set_max_area(设置面积)。然而这些准则不适用于STA。
7.9 虚拟时钟
这是一种存在的时钟,但是与设计中的任何引脚以及端口没有关联。在下图中的例子中,待分析设计的时钟是CLK_CORE,但是驱动着输入端口ROW_IN的时钟却是CLK_SAD。在这种情况下,如何指定输入端ROW_IN的IO约束呢?这个问题在输出端口STATE_O也同样存在。
这样的情况,我们可以定义虚拟时钟。上图中,我们对于CLK_SAD和CLK_CFG定义虚拟时钟。
create_clock -name VIRTUAL_CLK_SAD -period 10 -waveform {2 8}
create_clock -name VIRTUAL_CLK_CFG -period 8 \
-waveform {0 4}
create_clock -period 10 [get_ports CLK_CORE]
在定义了这些虚拟时钟之后,就可以指定和这个虚拟时钟有关的IO约束。
set_input_delay -clock VIRTUAL_CLK_SAD -max 2.7 \
[get_ports ROW_IN]
set_output_delay -clock VIRTUAL_CLK_CFG -max 4.5 \
[get_ports STATE_O]
下图展示了输入路径上的时序关系。这将待分析设计的输入路径延时约束到5.3ns或更小。
下图展示了输出路径上的时序关系。这可以将待分析设计的输出路径延时约束到3.5ns或更小。
min选项当在set_input_delay 和 set_output_delay中出现的时候,是用来验证最小时序路径的。虚拟时钟只是用来约束输入输出的一种方法。一个设计者也可以选择用别的方法约束输入和输出。
7.10 时序分析的完善
常用的四个指令 :
- set_case_analysis:对于单元的输入引脚,或者模块的输入端口,设置一个恒定的值。
- set_disable_timing:打破一个单元的某个时序弧。
- set_false_path:设置单元的伪路径,也就是说这个路径在STA时候不会进行分析。
- set_multicycle_path:指定一条路径,他所需要的时间可能多于一个时钟周期。
7.10.1 指定不活跃的信号
在一个设计中,部分信号在某些特定的模式下是一个恒定值。指定不活跃的信号对于STA很有用。这可以减少分析的范围,也可以减少一些不关联路径的报告。可以使用如下指令:
- set_case_analysis 0 TEST
- set_case_analysis 0 [get_ports {testmode[3]}]
- set_case_analysis 0 [get_ports {testmode[2]}]
- set_case_analysis 0 [get_ports {testmode[1]}]
- set_case_analysis 0 [get_ports {testmode[0]}]
如果一个设计有很多的功能模式,并且只分析其中一个分析,可以使用以上指令指定需要分析的模式。
- set_case_analysis 1 func_mode[0]
- set_case_analysis 0 func_mode[1]
- set_case_analysis 1 func_mode[2]
case analysis可以用于设计中的任何引脚,这个命令的另一常见应用是可以在多个时钟上运行的设计,并且时钟的适当选择由多路复用器控制。为了使STA分析更容易并减少CPU运行时间,对每个选择的时钟分别进行分析是十分有用的。下图给出了一个多路复用器选择不同时钟的示例。
- set_case_analysis 1 UCORE/UMUX0/CLK_SEL[0]
- set_case_analysis 1 UCORE/UMUX1/CLK_SEL[1]
- set_case_analysis 0 UCORE/UMUX2/CLK_SEL[2]
在左图中,PLLdiv8的有关时序路径,没有被分析,因为他被挡住了,没有被选择。其他的分析也是同理的。
7.10.2 打破时序弧
每个单元都有从输入到输出的时序弧,一条时序路径可能穿过其中的时序弧。一些情况下,穿过单元的某条路径可能无法实现。例如可能有这样一种情况,其中时钟连接到MUX的选择端,而MUX的输出是数据路径的一部分。在这种情况下,中断MUX选择引脚和输出引脚之间的时序弧可能很有用。下图中例子,经过MUX选择信号的路径不是一条有效的数据路径。这时候我们就可以用指令去中断。
set_disable_timing -from S -to Z [get_cells UMUX0]
这样我们可以分析更少的路径。类似用法的另一个示例是取消触发器的最小时钟脉冲宽度检查。
使用这个指令要谨慎,因为这打破了指定的引脚间的所有时序弧。可能的话,更建议用 set_false_path 和 the set_case_analysis。
7.11 点对点指定
点对点路径可以通过使用 set_min_delay 和 set_max_delay 规范来进行约束。这些约束限制了从引脚(from-pin)到目标引脚(to-pin)之间的路径延迟,具体值由约束中指定。该约束会覆盖任何默认的单周期时序路径以及任何多周期路径约束。set_max_delay 约束指定了指定路径的最大延迟,而 set_min_delay 约束则指定了指定路径的最小延迟。
set_max_delay 5.0 -to UFF0/D
# All paths to D-pin of flip-flop should take 5ns max.
set_max_delay 0.6 -from UFF2/Q -to UFF3/D
# All paths between the two flip-flops should take a
# max of 600ps.
set_max_delay 0.45 -from UMUX0/Z -through UAND1/A -to UOR0/Z
# Sets max delay for the specified paths.
set_min_delay 0.15 -from {UAND0/A UXOR1/B} -to {UMUX2/SEL}
使用非标准的内部引脚的时候,会强制这些引脚成为路径的起点和终点,并且会在这些点处将路径进行分段。
同样我们也可以相似的指定,从一个时钟到另一个时钟的点对点约束。
set_max_delay 1.2 -from [get_clocks SYS_CLK] \
-to [get_clocks CFG_CLK]
# All paths between these two clock domains are restricted
# to a max of 1200ps.
set_min_delay 0.4 -from [get_clocks SYS_CLK] \
-to [get_clocks CFG_CLK]
# The min delay between any path between the two
# clock domains is specified as 400ps.
第一行代码表示从SYS_CLK时钟域到CFG_CLK时钟域的延迟最大不能超过1.2ns。第二条代码意思也是类似的,表示的都是从一个时钟域到另一个时钟域的延时。
如果对于一条时序路径有多个时序约束,比如最大、最小延迟,时钟频率等,总是会检查最严格的约束。多个约束可能是由于最开始全局约束,后来再应用某些局部约束导致的。
7.12 路径的分段
将一条时序路径分割为更短的可以进行时序分析的路径,称为路径的分割(segmentation)。
一条时序路径有他的起点与终点。通过使用 set_input_delay 和 set_output_delay 进行指定,可以在时序路径上创建额外的起点和终点。set_input_delay 定义一个起点,通常指定在单元的输出引脚上,而 set_output_delay 定义一个新的终点,通常指定在单元的输入引脚上。这些指定,定义了一个新的时序路径,它是原始时序路径的一个子集。
一旦下图中的SYS_CLK的时钟确定了,UFF0/CK 到 UFF1/D的时序路径就可以进行分析。如果某人只关心 UAND2/Z 到 UAND6/A 的时序路径,可以使用以下的代码。
set STARTPOINT [get_pins UAND2/Z]
set ENDPOINT [get_pins UAND6/A]
set_input_delay 0 $STARTPOINT
set_output_delay 0 $ENDPOINT
这导致在原有的路径中创建了新的起点和终点,从而将原有的路径分割开来。 要注意,此时也创建了另外的两条新的路径,分别为UFF0/CK 到 UAND2/Z 以及 UAND6/A 到 UFF1/D。所以其实是将原有的路径分为了三段。set_disable_timing, set_max_delay 和 set_min_delay 这些指令也会导致时序路径的分割。
部分内容翻译自“Static Timing Analysis for Nanometer Designs A Practical Approach” 欢迎指正!