静态时序分析笔记
11 Aug 2024 11266字 38分 次 STA打赏作者 CC BY 4.0 (除特别声明或转载文章外)
1 前言
本文是《Static Timing Analysis for Nanometer Designs A Pravtical Approach》一书以及涉及到的概念的笔记。
2 基础概念
2.1 传播延迟(Propagation Delay)
通过设置输入/输出的上升/下降沿的阈值点来计算传播延迟。比如用以下四个变量来定义的点:
input_threshold_pct_fall :40.0; #输入上升沿阈值点 A
input_threshold_pct_rise :60.0; #输入下降沿阈值点 B
output_threshold_pct_fall :30.0; #输出上升沿阈值点 C
output_threshold_pct_rise :70.0; #输出下降沿阈值点 D
下图表明传播延迟是如何根据这四个点计算的:
- $T_f$:输出下降沿延迟
- $T_r$:输出上升沿延迟
2.2 转换率(Slew Rate)与转换时间(Transition Time)
转换率和转换时间互为倒数。
转换率通过以下四个上升/下降沿的阈值来计算:
slew_lower_threshold_pct_fall :30.0; #下降沿阈值低点 A
slew_upper_threshold_pct_fall :70.0; #下降沿阈值高点 B
slew_lower_threshold_pct_rise :30.0; #上升沿阈值低点 C
slew_upper_threshold_pct_rise :70.0; #上升沿阈值高点 D
下图表明转换时间根据这四个点的计算:
- $T_f$:下降沿转换时间
- $T_r$:上升沿转换时间
2.3 时钟延迟(clock latency)
指从时钟源到终点所花费的总时间。时钟源通常是定义时钟的节点,比如PLL的输出端口。终点通常是同步元件(例如触发器)的时钟引脚。
2.4 偏移(Skew)、抖动(Jitter)与不确定性(Uncertainty)
偏移是指2个或多个信号(data或clock)之间的时序之差的最大值。
抖动是指信号在两个不同周期之间存在的差值。时钟抖动实在时钟发生器内部产生的,和晶振或PLL内部电路有关。
Uncertainty = Skew + Jitter + Margin。
2.5 时序弧(Timing Arc)
分类:
- 单元弧(Cell Arc),每个单元都有多个时序弧
- 组合逻辑单元:单元每个输入到每个输出都有时序弧
- 时序逻辑单元:
- 时钟输入引脚到输出引脚,例如CK到Q,为时序单元内部路径的传输延迟(Delay Arc)
- 时钟输入引脚到其他引脚,例如CK到D,用于setup、hold分析(Timing Check Arc)
- 线弧(Net Arc)
- 一个单元的输出到下一个单元的输入之间的路径,引起传输延迟
每个时序弧都有时序极性(Timing Sense):
- 正单调(Positive Unate):输入的极性变化导致输出极性的变化相同或不变,例如与门,或门
- 负单调(Negative Unate):输入的极性变化导致输出极性的变化相反或不变,例如与非门,或非门
- 非单调(Non Unate):输入的极性变化决定不了输出极性变化,也要取决于其它输入状态,例如异或门
2.6 最大和最小时序路径
逻辑通过几条不同的路径传播到终点,每条路径的传播时间被称为路径延迟(Path Delay),这包括该路径上cell和net的总延迟。延迟最大的叫最大路径(Max Path/Late Path),延迟最小的路径叫最小路径(Min Path/Early Path)。
2.7 建立、保持时间相关概念和计算
2.7.1 基础概念
- 启动时钟(Lauch Clock):传输到源寄存器的时钟。
- 锁存时钟(Latch Clock):传输到目的寄存器的时钟。
- 启动沿(Lauch Edge):源寄存器(前级寄存器)数据变化的时钟边沿,也是静态时序分析的起点。
- 锁存沿(Latch Edge):目的寄存器(后级寄存器)数据锁存的时钟边沿,也是静态时序分析的终点。
- 数据到达路径(data arrival path):数据在两个寄存器间传输的实际路径。
- 数据需求路径(data required path):数据在两个寄存器传输的理论所需时间的计算路径。
- 数据到达时间(Data Arrival Time):数据在两个寄存器间传输的实际传播时间,计算方法见2.9.4。
- 数据要求时间(Data Required Time):包含数据建立要求时间和数据保持要求时间,计算方法见2.9.4。
2.7.2 时序路径
时序路径的形态:
- 从输入端口到内部时序单元的路径:in2reg
- 从时序单元到时序单元的内部路径:reg2reg
- 从内部时序单元到输出端口的路径:reg2out
- 从输入端口到输出端口的路径:in2out
时序路径分段:
- 源时钟路径(Source Clock Path):从时钟源点(通常是input port)到源寄存器的clock pin的路径。
- 目的时钟路径(Destination Clock Path):从时钟源点到目的寄存器的clock pin的路径。
- 数据路径(Data Path):指数据传播的路径。从时序单元的时钟引脚或数据输入端口开始,到时序单元的数据输入引脚或一个数据输出端口结束。
2.7.3 建立、保持时间
建立保持时间是寄存器固有特性参数,时间长短由器件本身决定。
- 建立时间(Setup):在锁存时钟沿之前,即将被采样数据需要提前保持稳定的时间。
- 保持时间(Hold):在锁存时钟沿之后,已被采样数据需要继续保持稳定的时间。
- 建立关系(Setup Relationship):两个相邻的寄存器,其后级寄存器(目的寄存器)每次锁存的数据应是前级寄存器(源寄存器)上一个时钟周期锁存过的数据。
- 保持关系(Hold Relationship):实际上是同一个edge,也就是说目的寄存器的数据保持时间可能遭到源寄存器同一个时钟沿所传输数据的“侵犯”。(这里可以换一个说法,根据建立关系,需要保证launch clock下一次发射的数据不会过早到来而“侵犯”到本次latch clock的数据锁存。)
2.7.4 余量计算
数据到达时间(Data Arrival Time):数据在两个寄存器间传输的实际传播时间。
Data Arrival Time = Launch Edge + Tclk1 + Tco + Tdata
数据要求时间(Data Required Time):包含数据建立要求时间和数据保持要求时间。
Data Required Time (Setup) = Latch Edge + Tclk2 – Tsu
Data Required Time (Hold) = Launch Edge + Tclk2 + Th
建立时间裕量(Setup Slack):数据建立要求时间与数据到达时间的差。
建立余量为正时(数据到达时间要早于建立数据需求时间),满足时序要求。
Setup Slack = Data Required Time (Setup) - Data Arrival Time
= Latch Edge + Tclk2 – Tsu - Launch Edge - Tclk1 - Tco - Tdata
= (Latch Edge - Launch Edge) - (Tclk1 - Tclk2) - Tsu - Tco - Tdata
= T - Tskew - Tsu - Tco - Tdata > 0
Tsu < T - Tskew - Tco - Tdata
保持时间裕量(Hold Slack):数据到达时间与数据保持要求时间的差。
保持余量为正时(下次数据到达时间要晚于保持数据需求时间),满足时序要求。由此可见,源寄存器与目的寄存器之间的数据传输延迟Tdata不能太短,延迟越短,slack越小。
Hold Slack = Data Arrival Time - Data Required Time (Hold)
= Launch Edge + Tclk1 + Tco + Tdata - Launch Edge - Tclk2 - Th
= (Launch Edge - Launch Edge) + (Tclk1 - Tclk2) + Tco + Tdata - Th
= Tskew + Tco + Tdata - Th > 0
Th < Tskew + Tco + Tdata
2.8 时钟域(Clock Domain)
由同一个时钟驱动的触发器所在的区域为一个时钟域。
如果两个时钟域之间没有数据路径,则这两个时钟域相互独立。相反如果有数据路径跨时钟域,则必须确定这条路径是真还是假。
例如,一个两倍频时钟驱动的触发器发起数据,再由一倍频时钟驱动的触发器捕获数据,就是真实路径(real path)。如果设计人员将时钟同步器明确放置在两个时钟域之间,即使好像存在从一个时钟域到另一个时钟域的时序路径,但数据没有被约束要在一个时钟周期内通过同步器传播,因此这样的路径被称为伪路径(false path),因为是由时钟同步器来确保数据正确地跨时钟域传播。可以使用set_false_path命令指定时钟域之间的伪路径。分辨出哪些跨时钟域路径是真实的,哪些是伪路径,是时序验证工作的重要组成部分,这使得设计人员可以专注于验证真实的时序路径。
还有一种伪路径的例子。比如通过二选一MUX选择时钟源,虽然只有一个时钟域,却有两个时钟,而这两个时钟是互斥的,因为一次只有一个时钟处于有效状态,因此这两个时钟之间不存在时序路径。
2.9 工作条件
工作条件定义为工艺(Process)、电压(Voltage)和温度(Temperature)的组合,简称PVT。逻辑单元的延迟和互连走线的延迟是根据特定的PVT计算的。
3 标准单元库
标准单元库包含时序信息、单元面积、功能等信息。
3.1 引脚电容
单元的每个输入和输出都可以在引脚(pin)上指定电容。在大多数情况下,仅为单元输入引脚指定电容,而不为输出引脚指定电容,即大多数单元库中的输出引脚电容为0。
pin(INP1) {
capacitance: 0.5;
rise_capacitance: 0.5;
rise_capacitance_range: (0.48,0.52);
fall_capacitance: 0.45;
fall_capacitance_range: (0.435,0.46);
...
}
电容单位通常为皮法拉(pF),一般在库文件的开头指定。
3.2 时序建模
逻辑单元的时序模型(timing model)旨在为设计中的各种单元实例(instance)提供准确的时序信息。通常会从单元的详细电路仿真中获得时序模型,用以对单元工作时的实际情况进行建模,且需要为逻辑单元的每个时序弧都建立一个时序模型。
分为线性延迟模型和非线性延迟模型。
3.2.1 线性时序模型(linear delay model)
使用input transition time和output load capacitance两个参数的线性函数表示cell delay和output transition time。计算形式如下:
cell delay = A + B*input transition time + C*output load capacitance
其中A、B、C为常数。 对于亚微米(submicron)技术,线性延迟模型在输入过渡时间和输出负载电容的范围内并不准确,因此,目前大多数单元库都使用更复杂的模型,例如非线性延迟模型。
3.2.2 非线性延迟模型(non-linear delay model)
非线性延迟模型通常是表格模型,被称为NLDM(Non-Linear Delay Model),用于延迟,输出压摆计算或其它时序检查。NLDM表格里提供了input transition time和output load capacitance的各种组合下的单元延迟。例如:
pin(OUT){
max_transition: 1.0;
timing(){
related_pin: "INP1";
timing_sense: negative_unate;
cell_rise(delay_template_3x3) {
index_1 ("0.1,0.3,0.7"); /* Input transition */
index_2 ("0.16,0.35,1.43"); /* Output capacitance */
valuse ( /*0.16 0.35 1.43 */ \
/* 0.1 */ "0.0513, 0.1537, 0.5280", \
/* 0.3 */ "0.1018, 0.2327, 0.6476", \
/* 0.7 */ "0.1334, 0.2973, 0.7252" );
}
cell_fall(delay_template_3x3){
index_1 ("0.1,0.3,0.7"); /* Input transition */
index_2 ("0.16,0.35,1.43"); /* Output capacitance */
valuse ( /*0.16 0.35 1.43 */ \
/* 0.1 */ "0.0617, 0.1537, 0.5280", \
/* 0.3 */ "0.0918, 0.2027, 0.5676", \
/* 0.7 */ "0.1034, 0.2273, 0.6452" );
}
}
}
上述反相器的NLDM描述了输出引脚OUT的延迟信息。根据该表格,输入下降沿的input transition time为0.3ns且output load capacitance为0.16ps时,反相器的上升沿的延迟为0.1018ns。
NLDM模型不仅可以用于计算单元延迟,还可以用来计算输出引脚的过渡时间(Output transation time),即上表中的cell_rise变成了rise_transition,cell_fall变成了fall_transition。
如果输入过渡时间和输出电容无法与表格条目中的值对应,可以利用二维插值的方法得到。
3.3 时序模型——组合单元
以二输入的与门为例,可知该单元的两个timing arc均为positive_unate,且有以下四种延迟:
- A to Z output rise
- A to Z output fall
- B to Z output rise
- B to Z output fall
因此NLDM将会有四个表格模型用于指定延迟。
3.4 时序模型——时序单元
以下图所示的时序单元为例,考虑以下时序弧:
对于同步输入,例如D或SI、SE,有以下时序弧:
- Setup检查时序弧(rise and fall)
- Hold检查时序弧(rise and fall)
对于异步输入,例如CDN,有以下时序弧:
- Setup检查时序弧(rise and fall)
- Hold检查时序弧(rise and fall)
对于触发器的同步输出,比如Q或QN,有以下时序弧:
- CK到输出的传播延迟时序弧(上升和下降)
3.4.1 同步检查:Setup/Hold
Setup/Hold同步时序检查是为了确保数据正常的通过时序单元传播。概念见2.9.3。
一个时序单元的同步引脚的Setup/Hold约束通常用二维表来描述:
pin(D){
direction: input;
...
timing(){
related_pin: "CK";
timing_type: "setup_rising";
rise_constraint ("setuphold_template_3x3") {
index_1("0.4,0.57,0.84"); /* Data transition */
index_2("0.4,0.57,0.84"); /* Clock transition */
values( /* 0.4 0.57 0.84 */ \
/* 0.4 */ "0.063, 0.093, 0.112", \
/* 0.57 */"0.526, 0.644, 0.824", \
/* 0.84 */"0.720, 0.839, 0.930");
}
fall_constraint ("setuphold_template_3x3") {
index_1("0.4,0.57,0.84"); /* Data transition */
index_2("0.4,0.57,0.84"); /* Clock transition */
values( /* 0.4 0.57 0.84 */ \
/* 0.4 */ "0.762, 0.895, 0.969", \
/* 0.57 */"0.804, 0.952, 0.166", \
/* 0.84 */"0.159, 0.170, 0.245");
}
}
timing(){
related_pin: "CK";
timing_type: "hold_rising";
rise_constraint ("setuphold_template_3x3") {
index_1("0.4,0.57,0.84"); /* Data transition */
index_2("0.4,0.57,0.84"); /* Clock transition */
values( /* 0.4 0.57 0.84 */ \
/* 0.4 */ "-0.220,-0.339,-0.584", \
/* 0.57 */"-0.247,-0.381,-0.729", \
/* 0.84 */"-0.398,-0.516,-0.864");
}
fall_constraint ("setuphold_template_3x3") {
index_1("0.4,0.57,0.84"); /* Data transition */
index_2("0.4,0.57,0.84"); /* Clock transition */
values( /* 0.4 0.57 0.84 */ \
/* 0.4 */ "-0.028,-0.397,-0.489", \
/* 0.57 */"-0.408,-0.527,-0.649", \
/* 0.84 */"-0.705,-0.839,-0.580");
}
}
}
上面是相对于CK的上升沿,一个时序单元输入引脚D上的Setup/Hold时间约束。二维数组的索引是D和CK上的transation time。
其中rise_constraint表和fall_constraint表针对的是constrained_pin;timing_type指定了单元是上升沿触发还是下降沿触发。
上述例子中的一些hold time是负值,这是可接受的。这通常发生在当数据路径从触发器的引脚到内部的锁存点比对应的时钟路径长。所以hold time为负,意味着触发器的数据引脚可以先于时钟引脚变化,并怡然满足保持时间检查。(我理解触发器内部CK和D的路径差又把这个负值补偿到正值了)。
触发器的建立时间也可以是负值。这代表在触发器的引脚上,数据可以在时钟引脚变化后变化,却依然满足setup时间检查。
但setup和hold时间不能同时为负值。为了让setup和hold time检查一致,两者的和必须为正。因为建立时间必须发生在保持时间之前,建立时间加保持时间的时间宽度就是信号必须保持稳定的区间。
对于触发器,在扫描数据输入(Scan Data Input)引脚有负的保持时间是很有帮助的,这给了时钟偏移一定灵活性,在扫描模式下就不需要为了修复保持时间为例而插入大量的Buffer。
3.4.2 异步检查:Recovery/Removal
异步引脚,比如异步清除(Clear)或异步置位(Set)引脚可以覆盖单元的任何同步行为。当有一个异步引脚有效时,输出是由异步引脚控制的。当异步引脚为无效,时钟的有效沿开始在数据输入端所存。异步的Recovery/Removal约束检查确保异步引脚在下一个有效时钟沿之前确定恢复到无效状态。
- Recovery time:异步引脚被设置为无效后们再下一个有效时钟沿之前需要保持稳定的最短时间
- Removal time:异步引脚可以被设置为无效前,在一个有效时钟沿之后需要保持有效的时间
除了同步和异步时序检查,还有一个检查来确保单元输入引脚的秒冲宽度满足最小要求。比如时钟引脚的脉冲宽度小于指定的最小值,时钟可能没有正确的所存数据。
3.4.3 传播延迟
时序单元的传播延迟时从时钟的有效沿到输出的上升或下降沿。这是非单调时序弧。下例时下降沿触发的触发器,从时钟引脚CKN到输出Q的传播延迟弧:
timing(){
related_pin: "CKN";
}
3.5 状态相关的时序模型
3.6 Black Box的接口时序模型
3.7 高级时序模型
3.8 功耗建模
3.9 单元库中的其它属性
面积规范,可以是该单元占据的真实的硅上面积,也可以是相对测量值:
area: 2.35
功能规范,指定了引脚或引脚组的功能:
pin(Z){
function: "IN1 & IN2";
...
}
SDF条件属性支持标准延迟格式SDF(Standard Delay Format)文件的生成以及在反标(backannotation)期间的条件匹配。就像when条件指定用于时序分析的状态相关模型的条件一样,SDF标注(annotation)时状态相关时序的相应条件由sdf_cond来表示。
3.10 特征化和工作条件
PVT。
4 互联寄生参数
5 延迟计算
6 串扰和噪声
7 配置STA环境
STA只处理同步电路。
7.1 指定时钟
要指定时钟,需要提供以下信息:
create_clock \
-name SYSCLK \ ;# 时钟名称,不指定则默认为端口名称
-period 20 \ ;# 时钟周期
- waveform {0 5} ;# 指定沿,可以指定多个沿,但指定的数量必须是偶数,从上升沿开始指定,不指定则默认为{0 period/2}
[get_port SCLK] ;# 指定时钟source
使用create_clock指定的时钟为Master Clock。
同样需要对时钟误差进行估计:
#======================================================================
# 设置时钟源的transation time,用于工具无法自动计算出PLL输出的transation time时;该约束只对理想时钟有作用,当时钟树构建完成则会被无视。
set_clock_transition -rise 0.1 [get_clocks CLK_CONFIG]
set_clock_transition -rise 0.12 [get_clocks CLK_CONFIG]
#======================================================================
# 设置时钟不确定性,使得设计更悲观,让电路更稳定
set_clock_uncertainty -setup 0.2 [get_clock CLK_CONFIG]
set_clock_uncertainty -hold 0.05 [get_clock CLK_CONFIG]
#======================================================================
# 跨时钟边界路径上的时钟间不确定性,用于穿过两个不同时钟域的路径上跨时钟域的不确定性约束
set_clock_uncertainty -from VIRTUAL_SYS_CLK -to SYS_CLK -setup 0.3
set_clock_uncertainty -from VIRTUAL_SYS_CLK -to SYS_CLK -hold 0.05
set_clock_uncertainty -from SYS_CLK -to CFG_CLK -setup 0.1
set_clock_uncertainty -from SYS_CLK -to CFG_CLK -hold 0.05
还有时钟延迟(Clock Latency)。有两种时钟延迟:网络延迟(Network Latency)和源延迟(Source Latency)。
- Network Latency:时钟定义点到触发器时钟引脚的延迟,是在时钟树综合之前对时钟树延迟的估计,一旦时钟树构建完成,Network Latency就可以忽略(假设使用了set_propagated_clock命令)
- Source Latency:时钟源头到时钟定义点的延迟,可以是片上(PLL到clock source)也可以是片外延迟,时钟树构建完成依然存在
#======================================================================
# 时钟延迟
#----------------------------------------------------------------------
# 网络延迟
set_clock_latency 1.8 -rise [get_clocks MAIN_CLK]
set_clock_latency 2.1 -fall [all_clocks]
#----------------------------------------------------------------------
# 源延迟
set_clock_latency 1.9 -source -min [get_clocks CFG_CLK]
set_clock_latency 1.3 -source -max [get_clocks CFG_CLK]
7.2 生成时钟
Generated Clock是从Master Clock派生出来的。例如二分频电路的输出端需要重新定义一个Generated Clock。
# Master Clock
create_clock -name CLKP 10 [get_pins UPLL0/CLKOUT]
# Generated Clock
create_generated_clock -name CLKPDIV2 -source UPLL0/CLKOUT -divide_by 2 [get_pins UFF0/Q]
把CLKPDIV2定义为一个Generated Clock,可以与Master Clock在同一个时钟域,不需要进行额外的约束。对于Master Clock,时钟的源头在Master Clock的定义点;对于Generated Clock,时钟的源头也在Master Clock而不是Generated Clock。这意味着在timing report里,时钟路径的起点永远都是Master Clock的定义点。因此定义为Generated Clock的优势是能够自动把源延迟计算进来。
下面的例子是生成时钟的频率比源时钟高:
# Master Clock
create_clock -period 10 -waveform {0 5} [get_ports PCLK]
# Generated Clock
create_generated_clock -name PCLK×2 -source [get_ports PCLK] -multiply_by 2 [get_pins UCLKMULTREG/Q]
7.2.1 MUX上的时钟
当MUX的输入端都有时钟时,没必要在输出端定义时钟。
如果Sel是常量,输出会自动得到正确传播的时钟。
如果Sel没有被约束,STA会使两个时钟都经过MUX传播。在这种情况下,STA可能会报告两个时钟之间的路径,这显然是不存在的(在设计的其他地方没有两个时钟之间的路径),这就需要设置False Path或指定两个时钟之间的互斥关系,进而避免报告不正确路径。
如果Sel不是静态的,在期间工作时可以改变,则需要对MUX的输入进行时钟门控检查没确保MUX输入端的时钟会按照MUX的Sel安全地切换。详见第十章。
7.2.2 时钟门控单元输出端上的主时钟
7.3
8 时序验证
9 接口分析
[img12]: