自动时钟树ECO解决方案

相信大家在route之后,都有过手工ECO的经历。目前,对于45nm的工艺而言,方法不外乎有换BUFFER, 高层金属走线,多倍线宽、线间距,时钟树偏移,以及BUFFER换INV等方法。
这次,主要与大家分享的是,我在做自动时钟树偏移脚本时的心得。
众所周知,usefulskew一般是修timing的最后一步才用的手段。但只要对关键路径的前后级进行过分析,就不难发现,Encounter并没有将前后级空余完全利用上,或者说没有最大程度上平衡前后级的Slack。因此,才有了人工做时钟树ECO的需求。
  人工修CTS,主要原理并不复杂,基本上就是在时钟路径上插BUFFER,把时钟路径延时增加,以达到时钟借用的目的。

但实际操作中,则会遇到各种各样问题:
1,如果只对单一路径插入BUFFER,则会造成标准单元浪费。因为,很多关键路径的时钟路径,有公共部分,对于公共路径操作,可以一次修许多条,还不会带来额外的BUFFER数量。另外,如果做的ECO数量多了,只对单一路径插入BUFFER,会造成标准单元拥塞,而修得少,又达不到timing收敛的目的。
2,如果是对公共路径进行插入BUFFER的操作,则会出现各路径后续slack富余不同的情况。如果按最大的借,往往会使别的路径恶化,如果按最小的借,关键路径所获得的好处又有限。这就成为了一个两难的选择。
3,对于插入BUFFER数量的估算,是个难点。举个例子,如果一个CKBUFFER的延时是20ps左右,你将其插入时钟路径后,并不一定会带来20ps的时钟借用。举例来说,如果是插入长线之间,反而会加快时钟路径,导致时序进一步恶化。而根据你插入的地点不同,时序的变化结果也不相同,这就造成了,即使你知道要借80ps,却估不出要插入多少级BUFFER。
针对以上三个问题,结合我在工作中编写ECO脚本的经验,我用了以下方案实现时钟树自动借用。

整体分为 五步:
第一步,通过对时序报告的分析,提取出关键路径中,时钟路径中最靠近寄存器的那根net的名字。并提取出,该级的slack,终点reg名,以及该net的fanout。
第二步,用encounter中的DB命令和report命令,得出与该NET所接的所有reg的名字,并将这些reg的最大的后一级slack报出来。
第三步,粗略计算出,需要插入的buffer数量。
第四步,进行ECO操作。(之后返回第一步,迭代1-2遍)
第五步,对于最后2%左右的路径。提取其最后一根NET的两个term名字,对单一路径进行ECO操作。迭代两遍。

时钟树自动ECO脚本的操作基本完成。

下面,我对这几个步骤进行一下说明:
首先,我选取最后一级NET,是希望,操作针对公共路径进行,但要尽量减少需要同时考虑的公共路径数量,提升脚本可操作性。
其次,迭代多遍,是因为,对于同一条线,插入第一个BUFFER,对于时钟的影响是不确定的。但插入后,以后再插入的buffer,由于驱动以达到饱和,因此,每多插入一级buffer,时钟路径都会稳定的增加相应的延迟。因此,迭代2-3遍,所估算的BUFFER插入数量就变得比较精确了。
最后,对于少量的关键路径。采用对公共的借用已然达不到要求,这时,就在该路径的时钟路径的非公共部分,进行ECO操作。因为,这类操作
需要插入的buffer数量较多,因此,只对1-2%操作,才不容易造成标准单元拥塞。
此外,首次迭代,我建议设置一个ECObuffer插入的最大数量,例如,我设置是5,这样,可以防止时钟树借用过大,造成的后续问题。比如hold等等。

最后说一下实现:
在提取参数阶段,我推荐使用perl语言编写,perl对大量文本的查找,提取和生成报表,效率比tcl要好一些。
在需要跟ENCOUNTER进行交互部分的脚本,还是用tcl编写比较好,这样实现起来比较容易。
最后给出一个初步BUFFER数量的运算公式:数量= (后一级最大slack - 当前一级最大slack)/ 一个buffer的延迟。

==========================================

后记:

这个脚本已经写完了,调试也通过了。
效果还是很明显的,在我的设计中,能将slack从-92ps修到-12ps
其实复杂度还可以,写脚本都是熟能生巧的功夫。
原理搞定,实现起来,也不是太难。
4个嵌套脚本工程量大概也就1000行左右吧,编写用3天时间。
不过迭代调试,用了4天多。(主要是实验一些参数)

(0)

相关推荐