相关阅读
Library Compiler
https://blog.csdn.net/weixin_45791458/category_13154201.html?spm=1001.2014.3001.5482
描述三态时序弧
三态时序弧用于描述单元中的三态输出引脚。
描述三态关闭时序弧
在定义三态引脚时,要指定一个三态关闭时序弧,需要执行以下步骤:
1、将related_pin属性指定为三态功能的使能引脚。
2、使用cell_rise或rise_transition组定义从0到Z的单元延迟或转换时间(转换延迟)。
3、使用cell_fall或fall_transition组定义从1到Z的单元延迟或转换时间(转换延迟)。
4、将timing_type属性设置为three_state_disable(进入高阻)。
下面展示了一个三态关闭时序弧的例子。
timing () {
related_pin : "OE" ;
timing_type : three_state_disable ;
/* 0 to Z modeling */
cell_rise(scalar) {
values( " 0.0 ");
}
rise_transition(scalar) {
values( " 0.0 ");
}
/* 1 to Z modeling */
cell_fall(scalar) {
values( " 0.0 ");
}
fall_transition(scalar) {
values( " 0.0 ");
}
}
描述三态使能时序弧
在定义三态引脚时,要指定一个三态使能时序弧,需要执行以下步骤:
1、将related_pin属性指定为三态功能的使能引脚。
2、使用cell_rise或rise_transition组定义从Z到1的单元延迟或转换时间(转换延迟)。
3、使用cell_fall或fall_transition组定义从Z到0的单元延迟或转换时间(转换延迟)。
4、将timing_type属性设置为three_state_enable(使能输出)。
下面展示了一个三态使能时序弧的例子。
timing () {
related_pin : "OE" ;
timing_type : three_state_enable ;
/* Z to 1 modeling */
cell_rise(scalar) {
values( " 0.0 ");
}
rise_transition(scalar) {
values( " 0.0 ");
}
/* Z to 0 modeling */
cell_fall(scalar) {
values( " 0.0 ");
}
fall_transition(scalar) {
values( " 0.0 ");
}
}
正如Library Compiler:时序弧建模与约束全解析(二)一文所说,当timing_sense属性用于描述用于计算时序弧延迟的转换边沿,并且该属性出现在包含three_state_disable和three_state_enable属性的timing组中时,其含义不同于传统含义。如果三态单元控制引脚上的值1会使输出引脚变为Z值,那么对于three_state_disable时序弧,timing_sense为positive_unate;对于three_state_enable时序弧,timing_sense为negative_unate。如果三态单元控制引脚上的值0会使输出引脚变为Z值,那么对于three_state_disable时序弧,timing_sense为negative_unate;对于three_state_enable时序弧,timing_sense为positive_unate。
下面展示了一个同时包含三态关闭和三态使能时序弧的三态单元(注意其中的timing_sense属性)。
library(example){
date : "January 14, 2015";
revision : 2015.01;
technology (cmos);
...
cell(TRI_INV2) {
area : 3;
pin(A) {
direction : input;
capacitance : 2;
}
pin(E) {
direction : input;
capacitance : 2;
}
pin(Z) {
direction : output;
function : "A'";
three_state : "E'";
/* Data path: A -> Z (inverter) */
timing() {
related_pin : "A";
timing_sense : negative_unate; /* Z = A' */
}
/* Enable arc: Z -> driven (E: 0 -> 1) */
timing() {
timing_type : three_state_enable;
related_pin : "E";
timing_sense : positive_unate;
}
/* Disable arc: driven -> Z (E: 1 -> 0) */
timing() {
timing_type : three_state_disable;
related_pin : "E";
timing_sense : negative_unate;
}
}
}
}
描述边沿敏感时序弧
边沿敏感时序弧,例如触发器中由时钟沿触发的时序弧,是通过将timing组中timing_type属性设置为rising_edge和falling_edge来标识的。其中rising_edge标识一条时序弧,其输出引脚对输入引脚上的上升信号敏感;falling_edge标识一条时序弧,其输出引脚对输入引脚上的下降信号敏感。
这些时序弧会被路径追踪;路径追踪器只沿着该时序弧传播有效边沿(上升或下降)的路径值。
下面展示了一个边沿敏感时序弧的例子。输出引脚QN在时钟信号上升之后发生转换。
pin(QN) {
direction : output ;
function : "IQN" ;
timing() {
related_pin : "CP" ;
timing_type : rising_edge ;
}
}
描述异步置位和复位时序弧
用户可以将这些时序弧用于触发器或电平敏感锁存器中的异步置位和复位引脚。在正常工作情况下,异步置位时序弧只影响该弧终点引脚的上升到达时间,而异步复位时序弧只影响该弧终点引脚的下降到达时间。对于异步置位时序弧,必须定义上升单元延迟;对于异步复位时序弧,必须定义下降单元延迟。
异步置位时序弧的上升单元延迟在cell_rise组中定义;异步复位时序弧的下降单元延迟在cell_fall组中定义。下面展示了一个异步复位时序弧的例子。
pin(Q) {
direction : output;
timing() {
related_pin : "CLR";
timing_type : clear;
/* Only falling transition exists */
cell_fall (scalar) {
values("0.05");
}
fall_transition (scalar) {
values("0.02");
}
}
}
通常情况下,异步置位时序弧的下降单元延迟以及异步复位时序弧的上升单元延迟是不存在的。但是在某些情况下,异步置位引脚上的转换可能会在该时序弧的终点引脚上引起下降转换,而异步复位引脚上的转换可能会引起上升转换。例如,对于异步置位时序弧,当一个电平敏感锁存器处于透明模式且其输入为逻辑0时,如果置位信号被去使能,会发生什么情况?在这种情况下,锁存器的输出会出现一个下降转换,该转换是由异步置位信号的去使能引起的;对于异步复位时序弧,当一个边沿触发器上的异步复位信号被去使能,而此时异步置位信号仍然被使能且异步复位信号优先于异步置位信号时,会发生什么情况?在这种情况下,触发器的输出会出现一个上升转换,该转换是由异步复位信号的去使能引起的。下面展示了一个异步置位时序弧的例子。
pin(Q) {
direction : output;
timing() {
related_pin : "PRE";
timing_type : preset;
/* Normal behavior: 0 → 1 */
cell_rise (scalar) {
values("0.06");
}
/* Special case: 1 → 0 due to de-assert */
cell_fall (scalar) {
values("0.07");
}
}
}
在常规情况下,Design Compiler和PrimeTime会忽略异步置位时序弧终点引脚上出现下降转换的路径以及异步复位时序弧终点引脚上出现上升转换的路径,这一处理不会产生警告信息。为了强制工具考虑这些路径,必须为异步置位时序弧定义下降单元延迟,并为异步复位时序弧定义上升单元延迟。然而,这些单元上升和下降延迟只应在类似本节所描述的两种情况之一中进行定义。
描述时钟插入延迟时序弧
时钟插入延迟指的是从(宏)单元时钟引脚到(宏)单元内部时钟引脚之前的延迟。这些到达时序路径描述了驱动内部时钟树的引脚在每种输入转换情况下的最小和最大时序约束,如图1所示。

图1 最大和最小时钟树延迟
对于任意一个时钟,其时钟树路径根据引脚的单调性以及最快和最慢路径,最多可以有八个取值。可以使用查找表来建模单元延迟,查找表仅以时钟的输入转换时间作为索引。对于timing_sense属性设置为non_unate且唯一变量为input_net_transition的timing组,需要使用成对的查找表来分别建模正单调和负单调情况。
下面展示了一个时钟插入延迟时序弧的例子。
library (vendor_a) {
delay_model : table_lookup;
/* 1. Define library-level one-dimensional lu_table of size 4 */
lu_table_template (lu_template) {
variable_1 : input_net_transition;
index_1 ("0.0, 0.5, 1.5, 2.0");
}
/* 2. Define a cell and pins within it which has clock tree path */
cell (general) {
...
pin (clk) {
direction : input;
timing () {
timing_type : max_clock_tree_path;
timing_sense : positive_unate;
cell_rise (lu_template) {
values ("0.1, 0.15, 0.20, 0.29");
}
cell_fall (lu_template) {
values ("0.2, 0.25, 0.30, 0.39");
}
}
timing () {
timing_type : min_clock_tree_path;
timing_sense : positive_unate;
cell_rise (lu_template) {
values ("0.2, 0.35, 0.40, 0.59");
}
cell_fall (lu_template) {
values ("0.3, 0.45, 0.50, 0.69");
}
}
}
...
}
}
描述单元延迟时序弧
单元延迟由两种描述方式,第一种是在timing组中直接使用cell_rise和cell_fall组表示单元延迟;第二种是在timing组中将单元延迟分为转换时间(转换延迟)和传播延迟,转换时间(转换延迟)使用rise_transition和fall_transition组表示(即使使用cell_rise和cell_fall组描述单元延迟,也必须有该组,用于描述转换时间),而传播延迟使用rise_propagation和fall_propagation组表示。二者只能选其中之一,Fab厂会选择最适合的库数据表征方式。
关于单元延迟和转换时间(转换延迟)的更详细介绍,可以参考下面的博客。
描述保持(retain)延迟
保持延迟是指在相关输入端口发生电压上升或下降之后,输出端口保持其当前逻辑值的时间。保持延迟是单元延迟的一部分,因此保持延迟不能超过该时序弧的单元延迟,且保持延迟定义在单元延迟时序弧内部。
为retaining_rise组指定的值决定了在相关输入端口的值发生变化之后,输出引脚保持其当前值0的持续时间;为retaining_fall组指定的值决定了在相关输入端口的值发生变化之后,输出引脚保持其当前值1的持续时间。图2展示了在相关输入端口变化情况下的保持延迟。

图2 保持延迟和单元延迟的对比
下面展示了一个保持延迟的例子。
library (foo) {
...
lu_table_template (retaining_table_template) {
variable_1 : total_output_net_capacitance;
variable_2 : input_net_transition;
index_1 ("0.0, 1.5");
index_2 ("1.0, 2.1");
}
cell (DFF_X1) {
area : 1.0;
pin (CLK) {
direction : input;
clock : true;
}
pin (Q) {
direction : output;
function : "IQ";
timing () {
related_pin : "CLK";
timing_type : rising_edge;
cell_rise (basic_template) {
values ("0.10, 0.20", "0.30, 0.40");
}
cell_fall (basic_template) {
values ("0.15, 0.25", "0.35, 0.45");
}
retaining_rise (retaining_table_template) {
values ("0.00, 0.10", "0.05, 0.15");
}
retaining_fall (retaining_table_template) {
values ("0.01, 0.12", "0.06, 0.18");
}
}
}
...
}
}
描述保持转换时间
retain_rise_slew和retain_fall_slew组允许为保持延迟指定一个独立于单元延迟时序弧的转换时间表,以表示在相关输入引脚发生变化之后,输出引脚开始失去其当前逻辑值所需要的时间。输出逻辑值的这种衰减发生的转换时间不同于最终逻辑值传播的转换时间,并且其变化速率也不同。
为retain_rise_slew组指定的值决定了在相关输入端口的值发生变化之后,输出引脚从0到1的转换时间;为retain_fall_slew组指定的值决定了在相关输入端口的值发生变化之后,输出引脚从1到0的转换时间。
下面展示了一个保持转换时间的例子。
library (library_name) {
...
lu_table_template (retaining_table_template) {
...
variable_1 : total_output_net_capacitance;
variable_2 : input_net_transition;
index_1 ("0.0, 1.5");
index_2 ("1.0, 2.1");
}
cell (cell_name) {
...
pin (CLK) {
direction : input;
clock : true;
}
pin (Q) {
direction : output;
function : "IQ";
timing () {
related_pin : "CLK";
timing_type : rising_edge;
cell_rise (basic_template) {
values ("0.10, 0.20", "0.30, 0.40");
}
cell_fall (basic_template) {
values ("0.15, 0.25", "0.35, 0.45");
}
retaining_rise (retaining_table_template) {
values ("0.00, 0.23", "0.11, 0.28");
}
retaining_fall (retaining_table_template) {
values ("0.01, 0.30", "0.12, 0.18");
}
retain_rise_slew (retaining_time_template) {
values ("0.01, 0.02");
}
retain_fall_slew (retaining_time_template) {
values ("0.01, 0.02");
}
} /* end of timing() */
} /* end of pin() */
...
} /* end of cell() */
...
} /* end of library() */
描述转换时间的退化
当前的非线性延迟模型基于这样一个假设:负载引脚处的转换时间与驱动引脚产生的转换时间相同。实际上,线网表现为一个低通滤波器,随着信号从线网的驱动端传播到各个负载端,转换会逐渐变平缓,如图3所示。互连负载越大,平缓效应越明显,负载引脚处的转换时间也越大。

图3 转换时间退化
为了对转换时间从输出引脚经过线网传播到下一个输入引脚过程中产生的退化进行建模,需要在逻辑库中包含rise_transition_degradation和fall_transition_degradation库级组。
这些组包含以查找表形式描述上升和下降转换退化函数的数值。查找表的索引变量包括:线网驱动端的转换时间(output_pin_transition)和驱动端与负载端之间的互联延迟(connect_delay)。
当Design Compiler在一个使用input_net_transition、constrained_pin_transition或related_pin_transition作为lu_table_template组参数的表中进行索引时,会使用转换时间退化表。库中的转换时间退化表不会影响来自其他库单元的计算。
下面展示了一个转换时间退化表的例子。
library (simple_tlu) {
delay_model : table_lookup;
/* define the table templates */
lu_table_template(prop) {
variable_1 : input_net_transition ;
variable_2 : total_output_net_capacitance ;
index_1("0, 1, 2");
index_2("0, 1, 2");
}
lu_table_template(tran) {
variable_1 : total_output_net_capacitance ;
variable_2 : input_net_transition ;
index_1("0, 1, 2");
index_2("0, 1, 2");
}
lu_table_template(constraint) {
variable_1 : constrained_pin_transition ;
index_1("0, 1, 2");
variable_2 : related_pin_transition ;
index_2("0, 1, 2");
}
lu_table_template(trans_deg) {
variable_1 : output_pin_transition ;
index_1("0, 1");
variable_2 : connect_delay ;
index_2("0, 1");
}
/* the new degradation tables */
rise_transition_degradation(trans_deg) {
values("0.0, 0.6", "1.0, 1.6");
}
fall_transition_degradation(trans_deg) {
values("0.0, 0.8", "1.0, 1.8");
}
/* other library level defaults */
default_inout_pin_cap : 1.0;
...
k_process_fall_transition : 1.0;
...
nom_process : 1.0;
nom_temperature : 25.0;
nom_voltage : 5.0;
operating_conditions(BASIC_WORST) {
process : 1.5 ;
temperature : 70 ;
voltage : 4.75 ;
tree_type : "worst_case_tree" ;
}
/* list of cell descriptions */
cell(AN2) {
....
}
}