介绍芯片中反相器、与门、寄存器、选择器、全加器、IO缓冲器等多种基本单元、以及复杂IP的时序信息、面积功能等内容,并通过标准延迟格式(Standard Delay Format, SDF)描述。
注意本文中所有SDF的数值均为非真实数值。
1. 引脚电容
一般在单元的输入引脚处指定电容,单位一般为皮法pF,SDF描述如下
# 输入引脚INP1的电容值
pin(INP1){
capacitance: 0.5;
rise_capacitance: 0.5;
rise_capacitance_range: (0.48,0.52);
fall_capacitance: 0.5;
fall_capacitance_range: (0.48,0.52);
...
}
SDF中可指定单个值0.5pF,也可指定上升沿和下降沿跳变时的电容值,也可以指定一个范围。
2. 时序模型
时序模型用于提供各单元的时序信息,通常会从单元的详细电路仿真中获得时序模型。
常常使用非线性的时序模型,即表格模型。
2.1. 组合逻辑单元
首先介绍过渡时间和单元延迟的概念。
● 过渡时间: 指从阈值电压的起始点到终止点所需的时间。压摆率(Slew rate)是过渡时间的倒数。
例如
#下降沿的阈值点,即下降沿的终止点和起始点
slew_lower_threshold_pct_fall:30.0
slew_upper_threshold_pct_fall:70.0
#上升沿的阈值点,即下降沿的起始点和终止点
slew_lower_threshold_pct_rise:30.0
slew_upper_threshold_pct_rise:70.0
即从Vdd的70%-30%为下降沿,Vdd的30%-70%为上升沿。而经过阈值则这段时间就是波形的过渡时间。
● 单元延迟: 指从输入经过其阈值点到输出经过其阈值点的延迟。该阈值点一般选择50%Vdd,如下图反相器
从图中可以看出,输入输出过渡时间影响着阈值点的时刻,进而影响单元延迟,而输出过渡时间又取决于输出负载,如下图所示。
由此可得到组合逻辑时序模型
时序模型
组合逻辑的表格模型提供了:在单元输入引脚处输入过渡时间和输出引脚处输出负载电容的各种组合下单元的延迟和输出过渡时间。
以反相器为例,SDF描述如下
pin(OUT){ /* 输出引脚OUT */
max_transition: 1.0; /* 过渡时间允许时间 */
area: 2.35; /* 单元面积 */
timing(){
related_pin:"INP1"; /* 输入引脚INP1 */
timing_sense:negative_unate; /* 负单边类型:输入电平变化与输出电平变化相反 */
cell_rise(delay_template_3x3){ /* 上升沿延迟ns 3x3查找表模板 */
index_1("0.1,0.3,0.7"); /* 输入过渡时间ns */
index_2("0.16,0.35,1.43"); /* 输出负载电容pF */
values( /* 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){ /* 下降沿延迟ns 3x3查找表模板 */
index_1("0.1,0.3,0.7");
index_2("0.16,0.35,1.43");
values( /* 0.16 0.35 1.43 */ \
/* 0.1 */ "0.0617, 0.1537, 0.5280", \
/* 0.3 */ "0.0718, 0.2027, 0.5676", \
/* 0.7 */ "0.1034, 0.2273, 0.6452");
}
rise_transition(delay_template_3x3){ /* 上升过渡时间ns 3x3查找表模板 */
index_1("0.1,0.3,0.7");
index_2("0.16,0.35,1.43");
values( /* 0.16 0.35 1.43 */ \
/* 0.1 */ "0.0417, 0.1337, 0.4680", \
/* 0.3 */ "0.0718, 0.1827, 0.5676", \
/* 0.7 */ "0.1034, 0.2173, 0.6452");
}
fall_transition(delay_template_3x3){ /* 下降沿过渡时间ns 3x3查找表模板 */
index_1("0.1,0.3,0.7");
index_2("0.16,0.35,1.43");
values( /* 0.16 0.35 1.43 */ \
/* 0.1 */ "0.0817, 0.1937, 0.7280", \
/* 0.3 */ "0.1018, 0.2327, 0.7676", \
/* 0.7 */ "0.1334, 0.2973, 0.8452");
}
}
}
对于多个输入端口,则需要为每一对输入输出组合列写SDF。
如果某对输入输出端口的电平变化极性可能相同也可能不同,说明二者是非单边类型(non-unate)的。例如异或门,一端输入单边类型取决于另一端输入的值,因此SDF如下
pin(OUT){ /* 引脚OUT */
direction: output; /* 引脚OUT为输出引脚 */
max_transition:0.0842; /* 过渡时间允许时间 */
area: 2.35; /* 单元面积 */
function: "(A1^A2)"; /* 单元功能 */
timing(){
related_pin:"A1"; /* 输入引脚A1 */
when: "!A2"; /* 输入引脚A2为低时 */
sdf_cond:"A2 == 1'b0"; /* 输入引脚A2为低时 */
timing_sense:positive_unate; /* 负单边类型:输入电平变化与输出电平变化相反 */
cell_rise(delay_template_3x3){ /* 上升沿延迟ns 3x3查找表模板 */
index_1("0.1,0.3,0.7"); /* 输入过渡时间ns */
index_2("0.16,0.35,1.43"); /* 输出负载电容pF */
values( /* 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");
}
...
}
}
表格条目无法找到:二维插值
如果输入过渡时间和输出负载电容无法在表格中找到,那就需要通过二维插值的方法计算。
例如3x3查找表模板如下
fall_transition(delay_template_3x3){ /* 下降沿过渡时间ns 3x3查找表模板 */
index_1("x_0,x_1,x_2");
index_2("y_0,y_1,y_2");
values( /* y_0 y_1 y_2 */ \
/* x_0 */ "T_00, T_01, T_02", \
/* x_1 */ "T_10, T_11, T_12", \
/* x_2 */ "T_20, T_21, T_22");
}
若输入过渡时间为 x 0 < x < x 1 x_0 < x < x_1 x0<x<x1、输出负载电容为 y 0 < y < y 1 y_0 < y < y_1 y0<y<y1
那么 x x x和 y y y的下降沿过渡时间就为
T x y = x 1 − x x 1 − x 0 ⋅ y 1 − y y 1 − y 0 ⋅ T 00 + x 1 − x x 1 − x 0 ⋅ y − y 0 y 1 − y 0 ⋅ T 01 + x − x 0 x 1 − x 0 ⋅ y 1 − y y 1 − y 0 ⋅ T 10 + x − x 0 x 1 − x 0 ⋅ y − y 0 y 1 − y 0 ⋅ T 11 T_{xy}=\frac{x_1-x}{x_1-x_0}·\frac{y_1-y}{y_1-y_0}·T_{00} +\frac{x_1-x}{x_1-x_0}·\frac{y-y_0}{y_1-y_0}·T_{01} +\frac{x-x_0}{x_1-x_0}·\frac{y_1-y}{y_1-y_0}·T_{10} +\frac{x-x_0}{x_1-x_0}·\frac{y-y_0}{y_1-y_0}·T_{11} Txy=x1−x0x1−x⋅y1−y0y1−y⋅T00+x1−x0x1−x⋅y1−y0y−y0⋅T01+x1−x0x−x0⋅y1−y0y1−y⋅T10+x1−x0x−x0⋅y1−y0y−y0⋅T11
2.2. 时序逻辑单元
基本的时序逻辑单元就是D触发器了。此处只介绍D触发器建立时间、保持时间和传播延迟。
● 建立时间(setup time): :输入的数据D必须在有效时钟沿CK之前保持稳定的最短时间,一般为Vdd的50%
● 保持时间(hold time): :时钟有效沿CK之后输入的数据D必须保持稳定的最短时间,一般为Vdd的50%
● 传播延迟(propagation delay): :从时钟的有效沿CK到输出Q的上升沿或下降沿,一般为Vdd的50%
时序模型
时序逻辑的表格模型提供了:在输入引脚D处输入过渡时间和时钟引脚CK处时钟过渡时间的各种组合下建立时间和保持时间。
pin(D){ /* 数据引脚D */
direction:input; /* 输入 */
area: 2.35; /* 单元面积 */
...
timing(){
related_pin:"CK"; /* 时钟引脚CK */
timing_type:"setup_rising"; /* 建立时间ns */
rise_constraint("setuphold_template_3x3"){ /* 引脚D上升沿建立时间ns 3x3查找表模板 */
index_1("0.4,0.57,0.84"); /* 数据引脚D过渡时间ns */
index_2("0.4,0.57,0.84"); /* 时钟引脚D过渡时间ns */
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"){ /* 引脚D下降沿建立时间ns 3x3查找表模板 */
index_1("0.4,0.57,0.84"); /* 数据引脚D过渡时间ns */
index_2("0.4,0.57,0.84"); /* 时钟引脚D过渡时间ns */
values( /* 0.4 0.57 0.84 */ \
/* 0.4 */ "0.762, 0.865, 0.969", \
/* 0.57 */ "0.804, 0.952, 0.166", \
/* 0.84 */ "0.159, 0.170, 0.245");
}
}
timing(){
related_pin:"CK"; /* 时钟引脚CK */
timing_type:"hold_rising"; /* 保持时间ns */
rise_constraint("setuphold_template_3x3"){ /* 引脚D上升沿保持时间ns 3x3查找表模板 */
index_1("0.4,0.57,0.84"); /* 数据引脚D过渡时间ns */
index_2("0.4,0.57,0.84"); /* 时钟引脚D过渡时间ns */
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"){ /* 引脚D下降沿保持时间ns 3x3查找表模板 */
index_1("0.4,0.57,0.84"); /* 数据引脚D过渡时间ns */
index_2("0.4,0.57,0.84"); /* 时钟引脚D过渡时间ns */
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");
}
}
timing(){
related_pin:"CK"; /* 时钟引脚CK */
timing_type:"rising_edge"; /* CK为上升沿触发 */
timing_sense:"non_unate"; /* 非单边时序:CK电平变化与输出电平变化无关 */
cell_rise(delay_template_3x3){ /* CK上升沿延迟ns 3x3查找表模板 */
index_1("0.1,0.3,0.7"); /* CK过渡时间ns */
index_2("0.16,0.35,1.43"); /* 输出Q负载电容pF */
values( /* 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){ /* CK下降沿延迟ns 3x3查找表模板 */
index_1("0.1,0.3,0.7");
index_2("0.16,0.35,1.43");
values( /* 0.16 0.35 1.43 */ \
/* 0.1 */ "0.0617, 0.1537, 0.5280", \
/* 0.3 */ "0.0718, 0.2027, 0.5676", \
/* 0.7 */ "0.1034, 0.2273, 0.6452");
}
rise_transition(delay_template_3x3){ /* CK上升沿过渡时间ns 3x3查找表模板 */
index_1("0.1,0.3,0.7");
index_2("0.16,0.35,1.43");
values( /* 0.16 0.35 1.43 */ \
/* 0.1 */ "0.0417, 0.1337, 0.4680", \
/* 0.3 */ "0.0718, 0.1827, 0.5676", \
/* 0.7 */ "0.1034, 0.2173, 0.6452");
}
fall_transition(delay_template_3x3){ /* CK下降沿过渡时间ns 3x3查找表模板 */
index_1("0.1,0.3,0.7");
index_2("0.16,0.35,1.43");
values( /* 0.16 0.35 1.43 */ \
/* 0.1 */ "0.0817, 0.1937, 0.7280", \
/* 0.3 */ "0.1018, 0.2327, 0.7676", \
/* 0.7 */ "0.1334, 0.2973, 0.8452");
}
}
}
注意上述表格中保持时间有负值,说明在CK沿到达之前D就可以变化,不会时序违规,但也无法捕获到正确数据,需要复查是否满足设计意图。
3. 内部开关功率
单元库中应包括功率信息,包括有功功率(active power)以及待机(standby)功率。有功功率与设计中的行为有关,而待机功率是待机模式下的功耗,这主要是由于漏电引起的。
单元中的有功功率是由于输出负载的充电以及内部的开关引起的,通常分别称
这两个为输出开关功率(output switching power)和内部开关功率(internal switching power)。
输出开关功率与单元类型无关,仅取决于输出负载电容、开关频率和供电电源;内部开关功率取决于单元的类型,因此该值会包含在单元库中,接下来将介绍库中的内部开关功率。
● 内部开关功率(internal power): 输入引脚的电平跳变会导致输出引脚的电平跳变,从而导致内部开关功耗。
组合逻辑开关功率SDF如下
pin(OUT){ /* 引脚OUT */
...
power_down_function: "!VDD + VSS"; /* 单元断电条件 */
related_power_pin: "VDD"; /* 电源引脚 */
related_ground_pin: "VSS"; /* 接地引脚 */
internal_power(){
related_pin:"A1"; /* 输入引脚A1 */
power(template_3x3){ /* 上升沿延迟ns 3x3查找表模板 */
index_1("0.1,0.3,0.7"); /* 输入过渡时间ns */
index_2("0.16,0.35,1.43"); /* 输出负载电容pF */
values( /* 0.16 0.35 1.43 */ \
/* 0.1 */ "0.013, 0.537, 0.280", \
/* 0.3 */ "0.118, 0.237, 0.476", \
/* 0.7 */ "0.134, 0.273, 0.252");
}
...
}
}
时序逻辑开关功率如下
pin(Q){ /* 输出引脚Q */
...
internal_power(){
related_pin:"CK"; /* 时钟引脚CK */
rise_power("energy_template_3x3"){ /* Q上升沿功耗3x3查找表模板 */
index_1("0.4,0.57,0.84"); /* 时钟引脚CK过渡时间ns */
index_2("0.4,0.57,0.84"); /* 输出引脚Q负载电容pF */
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_power("energy_template_3x3"){ /* Q下降沿功耗3x3查找表模板 */
index_1("0.4,0.57,0.84"); /* 时钟引脚CK过渡时间ns */
index_2("0.4,0.57,0.84"); /* 输出引脚Q负载电容pF */
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");
}
}
}