静态时序分析笔记
11 Aug 2024 21389字 72分 次 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 互联寄生参数
在数字设计中,线(Wire)把标准单元或块(Block)的引脚连接起来,称为信号线(Net)。一条Net通常只有一个Drive,但可以有多个Load。在物理实现后,Net再芯片的多个金属层上移动,每个金属层的电阻值和电容值可能不同。对于等效的电气表示,通常将网络划分为多个段(segment),每个段均由等效的寄生参数表示。我们也将段称为互连走线(interconnect trace)。
4.1 互连RLC
类似PCB多层板,互连电阻R来自金属层和过孔中的互连走线,可以将其视为单元的输出引脚与扇出单元的输入引脚之间的电阻。
互连电容C也来自金属走线,包括接地电容以及相邻信号路径之间的电容。
互连电感L是由于电流环路而产生的,通常电感效应在芯片内可以忽略不计,仅在封装和板级分析中考虑。
互连走线的任一部分的RC被理想的表示为1个分布式RC树,如下图。
![img35][img35]
RC树的总电阻和电容分别为$R_t$和$R_c$,计算方法为: \(R_t = R_p × L\) \(C_t = C_p × L\)
其中$R_p$和$C_p$是该段走线的单位长度的互连电阻电容,$L$为走线长度。$R_p$和$C_p$的值通常从各种配置后提取的寄生参数中获得,且由ASIC代工厂提供。
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 时钟门控单元输出端上的主时钟
下图例子中时钟SYS_CLK被一个触发器的输出端门控。因为触发器的输出端不是静态的,处理这种情况的一个方法是在与门单元的输出端定义一个Generate Clock。
create_clock 0.1 [get_ports SYS_CLK]
create_generated_clock -name CORE_CLK -divide_by 1 -source SYS_CLK [get_pins UAND1/Z]
下图例子中,两个时钟输入进一个与门单元,如果与门单元的输入都是时钟,那就可以安全的在与 门单元的输出定义一个新的主时钟,因为很可能该单元的输出和任一输入时钟都没有相位关系。
create_clock -name SYS_CLK -period 4 -waveform { 0 2 } [get_pins UFFSYS/Q]
create_clock -name CORE_CLK -period 12 -waveform { 0 4 } [get_pins UFFCORE/Q]
create_clock -name MAIN_CLK -period 12 -waveform { 0 2 } [get_pins UAND2/Z]
在内部引脚创建时钟会影响路径延迟的计算,要求设计者手动计算源延迟。例如下图例子,生成了一个二分频时钟和两个有相位差的时钟。
create_clock 2 [get_ports DCLK] ;#时钟是DCLK, 周期为2ns, 上升沿在Ons, 下降沿在lns。
create_generated_clock -name DCLKDIV2 -edges {2 4 6} -source DCLK [get_pins UBUF2/Z] ;#生成时钟DCLKDIV2定义在缓冲器的输出端。它的波形是上升沿在源时钟的沿2,下降沿在源时钟的沿4,下一个上升沿在源时钟的沿6。
create_generated_clock -name PH0CLK -edges {3 4 7} -source DCLK [get_pins UANDO/Z] ;#生成时钟PH0CLK是用源时钟的沿3,4,7组成。
create_generated_clock -name PH1CLK -edges {1 2 5} -source DCLK [get_pins UANDl/Z] ;#生成时钟PH1CLK定义在与门单元的输出端,是用源时钟的沿1,2和5组成。
下图的例子可以使用-edge_shift配合-edge使用,使相应的沿偏移,形成新的generated波形。它指定了沿列表中每个沿的偏移量(以时间为单位)。
create_clock -period 10 -waveform { 0 5 } [get_ports DCLK]
create_generated_clock -name DCLKDIV2 -source DCLK -edges { 1 3 5 } [get_pins DIVCLKREG/Q] ;#创建一个二分频时钟。
create_generated_clock -name DDIV2 -source DCLK -edges { 1 1 5 } -edge_shift { 0 5 0 } [get_pins DCLKDIV/Q] ;#创建一个二分频时钟,但是占空比和源时钟的50%不同。
沿列表中的沿排列必须是非降序排列,但是同一沿可以使用两次,进而实现时钟脉冲独立于源时钟的占空比。上面例子中的-edge_shift选项指明将源时钟的沿1移动Ons得到第1个沿,将源时钟的沿1移动5ns得到第2个沿,将源时钟的沿5移动Ons得到第3个沿。
7.2.3 使用invert选项生成时钟
下列例子使用invert选项来生成时钟。
create_clock -period 10 [get_ports CLK]
create_generated_clock -name NCLKDIV2 -divide_by 2 -invert - source CLK [get_pins UINVQ/Z]
7.2.4 生成时钟的延迟
生成时钟也可以被指定时钟延迟。同样包括两种时钟延迟:网络延迟(Network Latency)和源延迟(Source Latency)。一个生成时钟的总延迟包含以下三部分。
一个生成时钟可以以生成时钟作为它的源;一个生成时钟只能有一个源。
7.2.5 典型的生成时钟的场景
下图是一个典型的ASIC中时钟分配的场景。晶振(Oscillator)位于芯片外部,生成一个低频时钟(典型值为10~50MHz),该时钟被芯片上的PLL当作参考时钟生成一个高频低抖动(Low-Jitter)的时钟(典型值为200~800MHz)。这个PLL时钟输入到一个时钟分频逻辑,然后生成ASIC所需要的各种时钟。
在时钟分配的一些分支上,可以存在时钟门控单元(Clock Gate Cell),用来关闭设计中不活跃的时钟,节省功耗。PLL也可以在输出端连接一个MUX做Bypass。
在参考时钟进入芯片输入引进的地方会为参考时钟定义一个主时钟。第二个主时钟定义在PLL的输出端。PLL输出端的时钟和参考时钟没有相位关系,所以是两个主时钟,而不是主时钟和生成时钟。通常情况下,所有时钟分频器逻辑产生的时钟都被指定为是PLL输出端主时钟的生成时钟。
7.3 输入延迟
STA不能检查没有约束的路径上的任何时序,所以任何路径都应该被约束,才能被分析。也有例外,可以不约束不关心的逻辑的相关输入。
下图展示了DUA的一条输入路径。
在Launch Edge时刻开始,外部逻辑所用的延迟为$Tclk2q+Tcomb1$,所以延迟约束在输入引脚INP1定义了外部延迟。在这个例子里,指定的延迟是相对于时钟CLKA的。
set Tclk2q 0.2
set Tcomb1 0.6
set_input_delay -clock CLKA -max [expr Tclk2q + Tcomb1] [get_ports INP1]
以上约束指定了在输入INP1的外部延迟是0.8ns,该延迟是相对于时钟CLKA的。如果CLKA的周期为2ns,引脚INP1的逻辑在设计内部可用的传播时间为2-0.8=1.2ns。这就意味着Tcomb2+Tsetup必须小于1.2ns,这样触发器UFF1才可以可靠的捕获外部寄存器UFF0发射出来的数据。
以上为指定外部延迟的最大值,如果同时考虑最大和最小延迟,则参考如下电路图和约束。
create_clock -period 15 -waveform {5 12} [get_ports CLKP]
set_input_delay -clock CLKP -max 6.7 [get_ports INPA]
set_input_delay -clock CLKP -min 3.0 [get_ports INPA]
INPA的最大最小延迟分别对应着最坏情况(最大时序工艺角下的最长路径)和最佳情况(最小时序工艺角下的最短路径)。Tclk2q的最大和最小延迟分别为1.1ns和0.8ns,组合逻辑延迟Tcomb1最大和最小延迟为5.6ns和2.2ns,因此CLKP到INPA的最大和最小延迟为6.7ns和3ns。在INPA上的波形可以看出数据到达设计输入并且期望保持稳定的时间窗口。因此,考虑到外部延迟,设计内部的可用建立时间的最小值是15ns-6.7ns,最大值是15ns-3ns。
还有一些其他例子:
set_input_delay -clock CLKP 6.7 [get_ports INPA] ;# 没有指定-max或-min,则0.5ns会应用在最大和最小延迟上
set_input_delay -clock CLKN -clock_fall 6.7 [get_ports INPB] ;# 默认情况下外部延迟是针对CLKP的上升沿指定的,如果是针对时钟下降沿,则需要使用-clock_fall选项
7.4 输出延迟
先看只指定最大延迟的例子。
Tcomb1和Tcomb2是经过组合逻辑的延迟,时钟CLKQ的周期定义了从触发器UFF0到UFF1的总可用时间。外部逻辑的延迟是Tcomb2+Tsetup,指定为输出延迟约束的一部分。数据必须及时到达外部触发器UFF1,以满足建立时间要求。
set Tcomb2 3.9
set Tsetup 1.1
set_output_delay -clock CLKQ -max [expr Tcomb2 + Tsetup] [get_ports OUTB]
下面是有最大和最小延迟的例子。最大路径延迟为7.4ns,最小延迟路径为-0.2ns。
set Tcomb2_max 7
set Tcomb2_min 0
set Tsetup 0.4
set Tsetup 0.2
set Delay_max [expr Tcomb2_max + Tsetup] ;# 7+0.4=7.4
set Delay_min [expr Tcomb2_min - Thold] ;# 0-0.2=-0.2
输出约束如下:
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]
下列是结合输入延迟约束的列子,该模块有两个输入一个输出。
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]
7.5 时序路径组
设计中的时序路径可以被当做路径的集合。每条路径都有起点和终点。STA中的路径是依据有效起点和终点来记录的。有效起点包括输入端口、同步器件(FF、MEM)的时钟引脚。有效终点包括输出端口、同步器件的数据输入引脚。因此一条有效的时序路径可以是:
- 输入端口到输出端口
- 从输入端口到触发器或存储器的输入
- 从触发器或存储器的时钟引脚到触发器或存储器的输入
- 从触发器或存储器的时钟引脚到输出端口
参考2.7.2。
时序路径可以根据路径终点相关的时钟被分为不同的路径组(Path Group),所以每个时钟都有一组和它相关的路径。也会有默认路径组,它包括了所有异步路径。
7.6 外部属性建模
之前的约束足够约束芯片内部的所有路径并进行时序分析,但还不够得到IO引脚的精确时序,因此需要以下命令精确建模设计的环境。
7.6.1 驱动能力建模
命令set_drive和set_driving_cell是用来对外部资源的驱动能力建模,如果没有这些约束,默认所有的输入假设拥有无限的驱动力,意味着输入引脚的转换时间为0。
set_drive在DUA的输入引脚明确指定了驱动电阻的值,阻值越小,驱动能力越强。
set_drive 100 UCLK ;#给输入UCLK指定驱动电阻为100
set_drive -rise 3 [all_inputs] ;# 给所有input pin指定上升沿驱动
set_drive -fall 2 [all_inputs] ;# 给所有input pin指定下降沿驱动
驱动能力是用来计算在第一个单元上的转换时间,以及计算存在任何RC互联参数情况下从输入端口到第一个单元的延迟,计算公式如下:
延迟值 = (驱动强度 * 网络负载) + 互连线延迟
这个命令已经逐渐过时,不推荐使用,建议使用set_driving_cell命令或set_input_transition命令。
set_driving_cell提供了描述端口驱动能力的更保守和精确的方法,被用来指定一个单元来驱动输入端口。它同样也被用来计算在第一个单元上的转换时间,以及计算存在任何RC互联参数情况下从输入端口到第一个单元的延迟。
set_driving_cell -lib_cell INV3 -library slow [get_ports INPB] ;#输入INPB是由库文件slow中的INV3单元驱动
set_driving_cell -lib_cell INV2 -library tech13g [all_inputs] ;#所有输入是由库文件tech13g中的INV2单元驱动
set_driving_cell -lib_cell BUFFD4 -library tech90gwc [get_ports {testmode[3]}] ;#输入testmode[3]是由库文件tech90gwc中的BUFFD4单元驱动
该约束需要注意的一点是,由于输入端口上的电容性负载而导致驱动单元的增量延迟被视作为输入上的附加延迟被包括在内。作为上述方法的替代方法,set_input_transition约束提供了一种在输入端口表示过渡时间的便捷方法,并且可以指定参考时钟。
set_input_transition 0.85 [get_ports INPC]
set_input_transition 0.6 [all_inputs]
set_input_transition 0.25 [get_ports SD_DIN*]
总之,设计人员需要指定输入端的压摆值来确定输入路径中第一个单元的延迟。在没有该约束的情况下,将假设为理想过渡值0,这显然是不现实的。
7.6.2 电容负载建模
set_load可以指定输出端口的电容性负载,有-pin_load和-wire_load两种。
在输出端口设置了电容性负载,以此对输出端口驱动的外部负载建模。默认情况下下电容性负载为0。该负载可以被指定为明确的电容值,或是一个单元的输入引脚电容。
set_load 5 [get_ports OUTX] ;#在输出端口OUTX指定5pF引脚负载
set_load 25 [all_outputs] ;#在所有输出端口指定25pF引脚负载
set_load -pin_load 0.007 [get_ports {shift_write[31]}] ;#在指定输出端口指定7fF引脚负载,不指定-pin_load或-wire_load则默认为-pin_load
指定输出负载影响驱动输出的单元的延迟,没有该约束是不现实的。
set_load也可以用来指定设计内部线的负载:
set_load 0.25 [get_nets UCNT5/NET6]
原书里说的不是很清楚,具体可以看这篇blog:SDC命令详解:使用set_load命令进行约束。
7.7 规则设计检查
STA中两个常用的设计规则是最大转换时间(Max Transition)和最大电容(Max Capcitance)。这些规则会检查设计内所有端口和引脚都满足指定的转换时间和电容范围。这些范围可以用如下指令指定:
set_max_transition 0.6 IOBANK ;#在IOBANK设定极限为600ps
set_max_capacitance 0.5 [current_design];#在当前设计中设定所有线的最大电容为0.5pF。
作为STA的一部分,任何违反这些设计规则的违例都会以裕量的形式被报告出来。
网络上的电容是通过将所有引脚电容加上任何IO负载再加上网络上的任何互连电容的总和计算得出的。
Total cap on net N1 = Pin cap of UBUF1/A + Pin cap of UOR2/B + Load cap specified on output port + wire/routing cap
= 0.05 + 0.03 + 0.05 + 0.02
= 0.17pF
Total cap in net N2 = Pin cap of UBUF2/A + wire/routing cap from input to buffer
= 0.03 + 0.04
= 0.07pF
Transition time on pin UBUF2/A = drive of 2 * total cap on net N2
= 2 * 0.07
= 0.14ns
Transition time on output port = drive resistance of UBUF2/Z * total cap on net N1
= 1 * 0.17
= 0.17ns
也可以为设计指定其他的设计规则检查,例如set_max_fanout、set_max_area等,但这些检查是为了约束综合而不是STA。
7.8 虚拟时钟
虚拟时钟(virtual clock)是存在的时钟,但与设计中的任何引脚或端口均不相关。在STA中仅用作参考,以指定相对于时钟的输入延迟和输出延迟。
上图所示的电路中,DUT的输入端口ROW_IN的驱动时钟是CLK_SAD,无法用DUT内部的时钟做约束,输出端口STATE_O存在同样问题,为了处理这种情况,可以在不指定源端口或引脚的情况下来定义虚拟时钟。
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]
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]
输入路径的时序关系如下图:
输出路径的时序关系如下图:
-min选项在set_input_delay和set_output_delay约束中指定时,可用于检查最小时序路径。使用虚拟时钟只是约束输入和输出(IO)的一种方法,设计人员还可以选择其它方法来约束IO。
7.9 完善时序分析
用于约束分析的四个常用命令是:
- set_case_analysis :在单元的引脚或输入端口上指定常量值
- set_disable_timing :中断单元的时序弧
- set_false_path :指定实际不存在的路径,这意味着在STA中不需要检查这些路径
- set_multicycle_path :指定可能花费超过一个时钟周期的路径
后面讨论set_false_path和set_multicycle_path约束。
set_case_analysis通常通过指定单元引脚或输入端口上的常量来指定无效信号,例如在nominal mode下将DFT逻辑的test引脚设为0,这样除了不必报告任何不相关的路径之外,还有助于减少分析空间。
set_case_analysis 0 TEST
set_case_analysis 0 [get_ports {testmode[0]}]
可以在设计中的任何引脚上指定set_case_analysis,这个命令的另一个常见应用是可以在多个时钟上运行的设计,并且时钟的适当选择由多路复用器控制。
set_case_analysis 1 UCORE/UMUX0/CLK_SEL[0]
每个单元都有从其输入到输出的时序弧,并且时序路径可能会通过这些时序弧中的其中一个。在某些情况下,单元中的一条路径可能无法发生。比如,时钟连接到多路复用器的选择端,而多路复用器的输出是数据路径的一部分。在这种情况下,中断多路复用器选择引脚和输出引脚之间的时序弧可能很有用。
set_disable_timing -from S -to Z [get_cells UMUX0]
这样从选择端到输出端的时序弧不存在了,需要分析的时序路径相应的减少了。类似用法的另一个示例是取消触发器的最小时钟脉冲宽度检查。
使用set_disable_timing命令需要格外小心,因为它会删除通过指定引脚的所有时序路径。在可能的情况下,最好使用set_false_path和set_case_analysis命令。
7.10 点对点约束
使用命令set_min_delay和set_max_delay来约束点对点路径,这将引脚到引脚之间的路径延迟限制在了命令指定值内。该约束将覆盖所有默认的单周期时序路径以及此类路径的任何多周期路径约束。set_max_delay约束了指定路径的最大延迟,而set_min_delay约束了指定路径的最小延迟。
set_max_delay 5.0 -to UFF0/D
set_max_delay 0.6 -from UFF2/Q -to UFF3/D
set_max_delay 0.45 -from UMUX0/Z -through UAND1/A -to UOR0/Z
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]
set_min_delay 0.4 -from [get_clocks SYS_CLK] -to [get_clocks CFG_CLK]
如果路径上有多个时序约束,例如时钟频率约束、set_max_delay和set_min_delay,则最严格的那个约束是始终用于检查的约束。多个时序约束可能是先应用某些全局(global)约束,然后再应用某些局部(local)约束。
7.11 路径分割
路径分割(path segmentation)是指将时序路径分解为可以进行时序分析的较小路径。
时序路径具有起点和终点,可以使用set_input_delay和set_output_delay命令在时序路径上创建其它起点和终点。通常在单元的输出引脚上指定set_input_delay来定义新起点,而通常在单元的输入引脚上指定set_output_delay来定义新终点。这些约束定义了新的时序路径,它是原始时序路径的子集。
考虑上图所示的路径。为SYSCLK定义时钟后,待分析的时序路径即为从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到UFF1/D的原始时序路径被分段,并分别在UAND2/Z和UAND6/A处创建内部起点和内部终点。现在,时序报告将明确显示此新路径。请注意,还会自动创建另外两条时序路径,一条从UFF0/CK到UAND2/Z,另一条从UAND6/A到UFF1/D。因此,原始的时序路径已被分为了三个部分,每个部分分别进行时序分析。
set_disable_timing、set_max_delay和set_min_delay命令也会对时序路径进行分段。
8 时序验证
9 接口分析
[img35]: [img36]: [img37]: [img38]: [img39]: [img40]: