在经历过place之后,我们要迎来我们最真挚的朋友clock了。
clock是整个timing closure中最重要的部分,只有把这颗时钟树(clock tree)种好了,我们才能吃到甜美的果实。
按照惯例,先拿流程图来做以总览

由于clock是在给实际放置好std-cell的数据库,构建真实的clock tree,每一个std-cell的位置都会影响到CTS的构建,所以,一个要用来build clock tree的数据库需要有以下的基本质量:
1:所有的cell 都是经过优化处理的
2:所有的cell的放置都是合法化的(legalize),CTS是不会动已经放置好的cell的,在CTS步骤里边legalize,一般的cell只会非常位置偏移。这是保证place timing、congestion最好的选择)
3:数据库里的data path没有大扇出的max_fanout问题
我们经常说clock tree。那么什么是clock tree呢,在开始CTS之前,我们先来认识一下什么是clock tree。
一般把clock称之为tree(树状结构),是非常形象的。我们用下面这个二叉树的拓扑结构图,表明了一个clock domain的逻辑结构:

如图所示,我们对各个点位做如下设定
点位1: primary clock source。使用create_clock命令所对应的clock点
点位6/7/8/9/10: 挂靠在这个primary clock 下面的leaf FF。
点位2/3: 隶属于在这个 primary clock 下面的generated clock:从属于primary clock的generated clock
点位4/5: 点位2的generated clock tree里边的组合逻辑:一般的设计都会有DFT的mux在这些位置上。
从以上树状图示例里边,可以看到一个简单clock domain里边的各个元素。
理论上讲,所有隶属于primary clock source (点位1)的leaf cell (点位6/7/8/9/10),它们之间都是可能有timing check的。从clock tree的角度而言,每一个leaf cell 的clock pin到clock source的delay都要尽可能的相似,这样才会尽可能的接近place的时序结果(都为0,也是一种相似)。因为在place阶段,我们假设所有的leaf FF到clock source 都是0 delay的(ideal_clock)。
在了解了clock 的树状结构后,这里要再澄清几个基本概念,有助于我们理解clock tree和工具的行为。
Primary clock: 这个是模块的主时钟,一般的模块至少有一个主时钟,有时会有多个,但是相互之间通常互为异步关系。一般使用create_clock命令定义的clock就是主时钟。这种clock一般的定义点无外乎port或者内部macro的输出。
命令示例:
create_clock [get_ports func_clk_i] -name clk_func_clk -period 100 -waveform {0 50}
Generated clock: 这个是模块内部的分频时钟。这个clock 的source通常来自于primary clock,或者另外一个generated clock(在层叠(cascaded)generated clock的 情况下)。它的定义点一般来自于一个clock gating cell (latch output)或者一个DFF的输出点。
命令示例:
create_generated_clock [get_pins gated_clk_latch/o] -name gclk_1_func_clk -source [get_ports func_clk_i] -master_clock clk_func_clk -edges {1 2 5} ; # a latch as clock gating cell, half frequency with 25/75 duty cycle
create_generated_clock [get_pins divider_reg/o] -name gclk_2_func_clk -source [get_ports func_clk_i] -master_clock clk_func_clk -edges {1 5 9} ; # DFF divider for a clock, 1/4 frequency with half-half duty cycle.
Latency:时钟延迟值。这个是从clock source到你的leaf cell的 clock pin的时延值。
Skew:同一clock domain下边的,任意两个leaf cell时钟延迟之差的最大值。这个是评估一个clock tree做的好还是不好的关键指标。一般是基于一个clock domain的所有leaf FF/macro clock pin。Skew越大,timing越难收敛,hold/setup也容易出现冲突。通常来讲,CTS的目标就是降低skew,如果做到极致,skew为零,那么我们的时钟树就是理想的树了。
以下图为例,构建了连带上述命令描述的一个clock domain结构

从上图这个clock domain上可以抽取出以下信息

有了上面的这个latency,就可以推算出来skew如下

最终的评判某一个clock tee是不是做的好,就是来自于上边这个clock skew值。
这里需要在做以下说明以帮助大家理解
1:示例里边有有三个clock domain:一个primary clock 外加两个generated clock
2:在CTS的优化中,如果一个leaf cell的位置同时处于primary clock 和 generated clock 的fanout,CTS约定,在构建clock tree 的时候,它只属于离它最近的generated clock。Skew的计算机制也是基于此。
3;通常来讲,同属于一个primary clock下边的所有generated clock 以及它们的primary clock都是一个同步组(sync-group),它们之间的leaf cell都有timing check。所以这里边会有 func_clk_ff* 和 gclk*_ff* 的timing check。
有了这些基本概念后,现在开始做CTS前的配置工作:
1: clock reference lib cell 设定
一般的clock buffer、inverter都是相较于普通buffer/inverter更快,但是面积、漏电流也更大。所以这些cell只用于做 clock tree的构建。来获得更小的skew和latency。整个芯片在这样的规划下,达到一个面积、功耗和clock skew的平衡点。
所以在整个流程中,严格来讲,只有在CTS这一步才会打开clock buffer/inverter 给clock tree使用,剩下的所有步骤都是禁止使用clock buffer/inverter的,这里会提出一个新的一个检查点,在你准备做CTS之前,先检查一下你的place数据库,如果有clock library cell存在的情况,请查阅你的target library 来定位问题。
命令示例如下:
set_clock_tree_references -references {clk_buf1 clk_buf2 clk_inv1 clk_inv2}
ICC的这个命令优先级很高,无论这个lib_cell在之前是不是被dont_use,这个命令都会让CTS使用这些cell来构建clock tree(但是如果命令set_clock_tree_references 之后,仍然对这些lib_cell进行dont_use设定,这样依然会阻碍CTS的使用)。这里一定要注意一个问题,就是这个列表里边一定要有inverter,否则在CTS时候出错。
2:clock NDR rule
NDR是一个缩写,全称是None Default Routing-rule。我们在进行CTS的时候要引入这个特殊的clock routing rule,以备工具测算真实的clock net routing resources使用。这里我们需要对clock设定较普通绕线更为严格的routing rule
一般讲,在同一层的两根普通绕线,可以落在相邻的两个track上,在线宽合规的情形下,就不会有PV DRC spacing的问题。但是为了能削弱SI对clock net routing的影响,我们这里给clock定义了更为严格的multiple spacing routing rule,这个multiple至少是2或者3。设定后,工具在规划资源的时候就会考虑clock的额外需求。下面的命令定义了一个3倍spacing的NDR rule。
define_routing_rule clk_NDR_rule -default_reference_rule -multiplier_spacing 3
而后,我们需要把这个NDR rule关联到clock 上就好了,命令如下
set_clock_tree_options -routing_rule clk_NDR_rule
3: clock routing layer的设定
还记得我们在第三章,power那一部分的讲解吗?在那里,我们提到过clock的routing layer的信息。Clock routing的绕线优先级是高于data path的,所以在绕线层的定义上,我们会把clock routing layer尽量定义到高层。
如果我们最高绕线层是M8,我们可以定义如下
set_clock_tree_options -layer_list {M6 M7 M8}
4;logical DRC的设定
我们知道,在timing分析里边,都会有DRC的目标,在CTS中,基于项目需求,我们会有更严格的目标设定,下边是一个示例,具体需要依据项目和工艺的要求设定:
set_clock_tree_options -max_transition 0.3
set_clock_tree_options -max_capacitance 0.1
set_clock_tree_options -max_fanout 32
还有一个就是我们前面提到的CTS的重要目标:skew (尽管这个不是DRC的范畴)
默认工具是按照0来约束skew的,这是一个理论值,实际是不可能达到的,只有ideal clock tree才能达到。我们基于项目需要和clock period设定一个稍微宽松的值,对于rum time、power、面积等指标回事一个科学的折中,示例如下:
set_clock_tree_options -target_skew 0.2
5: 特征点的设定:
CTS支持以下特殊点的设定,这些设定会影响CTS的细节,正常情况下,用户不用干预,这里我们不做展开,会有一篇CTS番外来介绍他们的细节,有兴趣的同学可以关注下。
Stop pin: 停留点位
None-stop pin: 非停留点位
Exclude pin: 除外点位
Floating pin: 单列点位
Ignore pin: 忽略点位
到达这里,我们已经有了大体的概念了,接下来我们就来看看CTS 到底在我们的数据库里做了哪些神操作。
工具在读取了上述的各项设置后,就可以开始愉快的build tree了(真的会愉快吗?^_^)
大家回看一下在本文开始的那个树状结构图,对于这个树状结构,cts其实是在做一个多叉树的遍历过程。所以在build tree的时候,有两种方式可以选择top-down和bottom up。
在一般的应用中,我们习惯使用top-down方式, 从clock source 做起,直到找到一点的leaf cell clock pin,然后构建这点到clock source的clock buffer tree;接下来依次查找下一个leaf cell clock pin,然后再次构建这个新点到clock source的clock buffer tree。如此往复,直到把整个多叉树的结构遍历完成。
但是在cts里边,它的目标是控制latency和保证skew,如果是top-down的方式,工具永远不知道当下节点的多叉树有多深,很难判定你在当前节点需要构建多少latency,很有可能带来反复修正的问题,这样的会大大降低clock tree的质量。所以从收敛skew的角度,选择bottom-up的方式是更为合理的。
于是就有了下边这张cts遍历多叉树顺序图。有了这张图,再也不用担心cts看不懂了。

为了保证完备性,不漏掉任何一个leaf cell clock pin。这里的多叉树的遍历本质上是一个递归的过程。在每一次递归的节点,cts都会记录下当前的phase delay(从当前结点到leaf cell clk pin的delay信息),依据这个phas delay信息,无论leaf cell距离clock sourced的深度有多大的不同,工具都尽量让每一个leaf cell clk pin的latency相近,这就是使用clock buffer/inverter 要完成的目标。
同时在构建clock tree的时候,工具一定会兼顾max_tran,max_cap等DRC的需求。一个tree有好的skew那么他的hold就好控制,有了高质量的transition、cap那么他的aocv效应的影响就能降低,最终都朝着mcmm timing clean的目标进发。
到这里,CTS的创建就告一段落了。至此,我们已经讲解完layout流程里边最重要的两个步骤,place和cts了,大家这里稍作思考,回望一下我们讲过的东东,理解到了里边的本质,你的版图之路一定会轻松许多。
网友评论