Innovus批量ECO加Repeater效率优化:setEcoMode实战指南
2026/9/17 18:33:48 网站建设 项目流程

做数字后端的朋友应该都有过这种经历:ECO阶段修timing,一修就是一两千条net,需要往上加repeater。你写个foreach循环,一条net一条net地ecoAddRepeater,结果跑一个多小时,中间还不断弹DRC和overlap告警。我第一次遇到这个场景时,第一反应是“是不是机器不行”,后来才发现问题出在ECO模式上,确切地说,是没用好setEcoMode这个全局总开关。今天就把我优化ecoAddRepeater批量操作效率的经验完整写出来。这篇文章适合正在用 Innovus 做数字后端、被批量ECO加buffer耗时间折磨的工程师;也适合刚接触ECO流程、想少走弯路的新手。核心只有一件事:让工具在一个“批量模式”下干活,而不是在“边做边查”的模式下慢慢磨。

1. 为什么批量加Repeater会慢到怀疑人生

1.1 ecoAddRepeater到底在做什么

ecoAddRepeater是 Innovus 里最常用的ECO命令之一,主要作用是在指定net上插入buffer或者inverter,用来修复max transition、max capacitance、部分DRC违例,以及解决hold或者setup问题。听起来就是“加一个单元”,但实际执行时,工具要考虑的事情远比想象中多。

工具拿到你的请求后,至少要做这几件事:先查一遍目标net当前的topology,确认插在哪个位置最合适;然后从库里面匹配你指定的cell,检查尺寸、阈值电压、是否dontUse;接着要在当前floorplan里找一个能放得下的row,尽量靠近插入点;放完之后还要评估一下对周边cell和net的影响,比如是不是挡住了别人,是不是引入了新的short。整个过程相当于你在一个已经很拥挤的房间里临时加一把椅子,不是把椅子扔进去就行,还得看会不会挡路、会不会让房间里的人走不过去。

如果只加一两个repeater,这些开销完全可以忽略。但问题在于,ECO阶段修timing往往是批量操作,一次就是几百上千条net。每条net都走一遍完整流程,累积起来的时间就非常可观了。

1.2 慢的本质:每次调用都是一次小规模ECO闭环

我自己踩过的一个典型坑是这么写的:

# 低效示例:每加一个repeater都立刻修一遍 foreach net $fixNetList { ecoAddRepeater -cell BUF_X4 -net $net ecoPlace -noSeq check_drc -summary }

这段脚本看起来没错,甚至很“严谨”——每加一个buffer就place一次、查一次DRC。但严谨的背后是巨大的性能浪费。ecoAddRepeater本身是一个完整的ECO动作,工具会同步更新数据库、做局部legalize、计算congestion、检查short。紧接着的ecoPlace -noSeq又把所有ECO cell重新放一遍,check_drc更是把整个design都扫一遍。这三件事串在一起,每循环一次,相当于把ECO流程完整跑了一遍。

我实测过一个28nm模块,大概8000多个instance,需要给1200条net加repeater。用上面这种“边做边查”的写法,平均每条net要花2秒多,跑完全程接近45分钟。而这里面的ecoPlacecheck_drc占了绝大部分时间,因为它们每次都是全芯片级别的操作,不是增量操作。也就是说,很多时间其实浪费在“反复确认同一件事”上,真正用来添加repeater的时间可能只有五分钟。

1.3 软件世界的同款坑:批量写操作

这种问题并不是EDA独有的。写过业务系统的朋友应该马上能联想到数据库操作:一条条insert和一次性batch insert的差距有多大,做过性能优化的人都懂。像MyBatis里,如果你在for循环里逐条调用insert,每条都要走一次事务、一次网络往返,3000条数据可能插到怀疑人生;改成批量提交,同样数据可能几秒钟就完成。区别不在于SQL本身,而在于“提交方式”和“事务粒度”。

ecoAddRepeater批量操作也是同一个道理。工具每一次命令调用,其实都隐含着“提交”动作:更新增量数据库、刷新状态、维护各种index。如果你能通过setEcoMode告诉工具“现在处于批量模式,暂时不要做额外修正和检查”,工具就可以把大量内部步骤延迟到最后一并处理,整体耗时自然就下来了。

2. setEcoMode:ECO批量操作的全局总开关

2.1 setEcoMode的设计哲学

setEcoMode是 Innovus 中用来配置ECO流程行为的命令,影响的不只是ecoAddRepeater,还包括ecoDeleteRepeaterecoPlaceecoRoute等一整套ECO命令。它的设计初衷很简单:ECO场景千差万别,有的要求精准微调,有的追求速度,有的要保留某些cell不动。工具不可能用一个固定策略覆盖所有场景,所以把这些行为控制项暴露给你,让用户根据自己的需求调整。

你可以在Innovus命令行里直接敲setEcoMode -help,看一下当前版本支持哪些选项。不用怕记不住,常见的就那么几个,真正在批量加repeater场景下高频使用的更是屈指可数。

还有一个很重要的点:setEcoMode设置的是全局状态,不是一次性参数。它一旦设置,在后续的ECO命令中会持续生效,直到你修改它或者退出工具。所以它特别适合放在批处理脚本的开头,作为一个“模式开关”来用。我自己的习惯是,任何批量ECO脚本的第一行一定是setEcoMode,把该关的检查关掉、该开的开关打开。

2.2 和批量加Repeater最相关的几个选项

这里列一下我在实际项目中用得最多的几个选项,以及我为什么这么设置。需要注意,不同Innovus版本支持的选项名可能略有差异,你们以自己版本setEcoMode -help的输出为准。

选项常用设置作用批量加Repeater时的建议
-modifyOnlyCelltrue只允许修改你指定的ECO cell,避免工具动其他逻辑推荐true,防止工具顺手改动无关单元,减少额外计算
-fixOverlapfalse是否在ECO过程中自动修复cell重叠批量阶段先关掉,最后再统一修复
-removeDummyCellsfalse是否自动移除dummy cell批量阶段先关掉,减少不必要的扫描
-summary文件路径输出ECO摘要报告建议打开,方便核对每个repeater加到了哪里
-legalizefalse是否在每次ECO后自动做legalize如果你的版本支持,批量阶段建议先关闭

重点解释一下-fixOverlap。默认情况下,ECO命令会尽量保证放置结果不产生overlap,这个功能本身很好,但代价是每次插入repeater都要做局部的合法化检查,甚至可能为了避让某个overlap而把附近几个cell挪来挪去。批量操作时,这一步会被反复触发,非常耗时。更聪明的做法是先关掉它,让工具快速把repeater都“扔”进去,最后再用一次ecoPlace -noSeq或者setEcoMode -fixOverlap true配合ecoPlace统一整理。

另外,-removeDummyCells也同样。如果在ECO过程中反复扫描dummy cell,时间开销不小。对于批量加buffer这种场景,dummy cell完全可以留到最后一起处理。

2.3 一个原则:把“边做边查”变成“先做后查”

理解了setEcoMode的选项,核心原则就浮出水面了:批量ECO操作要尽量避免在循环过程中做过于频繁的DRC检查、legalize、overlap修复这些“高成本动作”。正确思路是分三个阶段:先配置ECO模式,然后批量执行插入操作,最后统一做收尾检查和修复。这也是setEcoMode真正的价值所在——它让工具知道“现在进入批量模式”,从而延迟那些不必要立即执行的动作。

打个比方,你要在一个小区里装100个快递柜。如果你每装一个柜子,都把整个小区的消防通道检查一遍、把所有车辆重新停一遍,那装完100个柜子基本天黑了。正确做法是先把100个柜子全部装到位,最后统一检查消防通道、调整车辆位置。setEcoMode就是允许你告诉施工队“先别检查,装完再说”的那张授权书。

3. ecoAddRepeater批量操作的实战优化方法

3.1 优化前:典型的低效脚本长什么样

很多从ICC转过来的工程师,刚接触Innovus时写的脚本风格都差不多。举个常见的例子:

# 低效示例 set fixNetList [get_nets -hier -filter "max_transition_violation"] foreach net $fixNetList { ecoAddRepeater -cell BUF_X4 -net $net ecoPlace -noSeq }

这段脚本有两个问题:第一,ecoAddRepeater默认的ECO模式会做很多额外保护,每次调用都有不小开销;第二,ecoPlace -noSeq放在循环内,每次加完一个repeater就全量重新place一次。这两个问题叠加,性能自然惨不忍睹。更隐蔽的是,如果某个net因为congestion或者row资源不足导致ecoAddRepeater执行失败,脚本会直接中断,前面加的所有repeater状态都悬在那里,排查起来也麻烦。

所以,优化批量操作的第一步不是换命令,而是改脚本结构:把“加一个、查一次”改成“全部添加、统一收尾”。

3.2 推荐:先用setEcoMode进入ECO批量模式,再统一收尾

我在实际项目里大量使用下面这套批量加repeater的模板,经过多次验证,效率提升非常明显:

# Step 1: 进入ECO批量模式 setEcoMode -modifyOnlyCell true \ -fixOverlap false \ -removeDummyCells false \ -summary eco_summary.txt # Step 2: 批量添加repeater foreach net $fixNetList { if {[catch {ecoAddRepeater -cell BUF_X4 -net $net} err]} { puts "Warning: add repeater on $net failed: $err" } } # Step 3: 恢复ECO常规模式,统一收尾 setEcoMode -fixOverlap true -removeDummyCells true ecoPlace -noSeq check_drc -summary

Step 1里面,-modifyOnlyCell true告诉工具只允许操作指定的逻辑单元,避免它“好心”去改动周边逻辑。-fixOverlap false-removeDummyCells false是把最耗时的实时修正延后。-summary会生成一份ECO摘要,方便后面核对哪些net成功加了repeater,哪些失败了。

Step 2里用catch包住ecoAddRepeater,是防止某条net失败导致整个脚本中断。这一步非常重要,批量操作时一定会遇到个别加不进去的情况,比如所在区域太挤、row类型不匹配等。让脚本“报错但继续跑”,最后统一看summary,比一次中断、反复调试要高效得多。

Step 3是收尾,把-fixOverlap-removeDummyCells重新打开,然后跑一次ecoPlace -noSeq统一处理所有ECO cell的摆放,最后再检查DRC。这套流程下来,45分钟的工作量基本能压到10分钟以内。

3.3 多技能组合:位置指定、批量传参、并行切分

如果只是简单把所有net遍历一遍,上面的模板已经够用了。但实际项目里,还需要处理一些更复杂的场景。

有些net必须在特定位置附近加repeater,比如在高扇出网络的中间节点插入buffer,或者必须插在某个hard macro旁边。这时可以用-loc {x y}指定插入位置。不过我要提醒一句:指定位置后,工具不会主动帮你选最优插入点,如果你给的坐标附近已经没有row空间,命令照样会失败。所以除非你清楚自己在做什么,否则更推荐让工具自动决定位置。

如果一条net需要加多个repeater,可以用-num参数,比如:

ecoAddRepeater -cell BUF_X4 -net n12345 -num 3

这样一条net直接插3个buffer,比循环插3次效率高很多。

另外,如果netlist量特别大,可以考虑把netlist按区域切分成几份,同时开几个Innovus session并行处理,最后再merge。但这要求你有足够的license和内存,而且merge过程有风险,容易产生跨区域冲突。我个人的建议是,除非net数量真的上到几千条,否则不要轻易并行,单线程配合setEcoMode已经能获得很好的收益。

还有一个小技巧:如果你嫌Tcl的foreach效率低,可以用perl或python脚本提前生成ECO命令文件,然后用source一次性灌进去。这样能省去Tcl解释器的解析开销。实际效果取决于netlist规模,但对几千条net的场景,确实能再省一点时间。

4. 真实案例复盘:45分钟到6分钟的优化全过程

4.1 场景描述

这个案例来自我之前做的一个28nm芯片项目。其中有个模块,大概8000多个instance,后端实现完成后,PR工具报了一堆max transition违例,主要集中在高扇出的时钟末端和数据通路上。修这类违例最直接的方法就是加repeater,我数了一下,需要处理的net大概1200条左右。

最开始我用的就是最“朴实无华”的脚本:foreach循环,每个netecoAddRepeater,然后立刻ecoPlace -noSeq,偶尔中间加一条check_drc。跑一次全流程需要45分钟左右。如果只是偶尔跑一次也就算了,问题是修完一轮之后还要重新做时序收敛,来回迭代好几次,每次都要等接近一个小时,效率实在太低。

4.2 优化过程:分三步把时间压下来

第一步,我在脚本开头加了setEcoMode -modifyOnlyCell true -fixOverlap false -removeDummyCells false -summary eco_summary.txt,同时把循环里的ecoPlacecheck_drc全部去掉,只保留纯粹的ecoAddRepeater。跑完发现时间从45分钟降到了18分钟,效果立竿见影。这说明之前的耗时大头确实不在“加repeater”本身,而是每轮循环附带的place和check操作。

第二步,我发现18分钟里仍然有一部分时间花在Tcl循环本身的解析和ecoAddRepeater每次调用的固定开销上。于是我干脆生成一个包含1200条ecoAddRepeater -cell BUF_X4 -net ...命令的脚本文件,然后用source ./add_rep.tcl一次性灌进去。这个改动让时间从18分钟降到了11分钟左右。有人可能会问,Tcl的foreach和source一个长脚本到底差在哪?区别在于,source一个文件时,Innovus可以连续解析并执行命令,省去了很多脚本解释层面的往返开销。另外,我还把每条命令的反馈输出用redirect重定向到了文件里,防止终端交互拖慢速度。

第三步,我在netlist里筛选了一遍,把扇出特别大、单根repeater搞不定的net标记出来,直接使用-num 2-num 3一次插入多个buffer,而不是把同一条net重复加多次。这步又把时间压缩到了6分钟左右。最终全部1200条net处理完毕,耗时约6分20秒,相比最初的45分钟,提升了7倍左右。

4.3 结果与质量检查

优化后的流程跑完,我做了完整的质量检查。setEcoMode -summary生成的摘要文件里,1200条net中成功插入repeater的有1192条,失败的8条主要是因为局部区域congestion太高,没有足够的row空间。对于这8条,我单独用ecoAddRepeater -cell BUF_X1换小尺寸buffer重新处理,最后8条也全部搞定。

overlap方面,因为我批量阶段关闭了-fixOverlap,所以跑完后确实出现了3处overlap,集中在几个比较拥挤的局部区域。我在收尾阶段重新打开了setEcoMode -fixOverlap true,执行了一次ecoPlace -noSeq,3处overlap全部修复。DRC方面,新增的violation只有寥寥几条,都是间距问题,简单shrink一下线宽或者绕一下就解决了。

4.4 这么折腾值不值

有朋友问过我,实际开发时这种情况多吗?说实话,非常普遍。ECO阶段本来就是时序和DRC问题最多的时候,加repeater是最常用的修复手段之一,批量场景几乎天天遇到。45分钟和6分钟的差距,在一天要迭代四五次的节奏下,差距是“能不能在下班前跑完”级别的。

当然,我也要提醒一点:不是所有场景都需要这么折腾。如果只有二三十条net需要加repeater,默认ECO模式直接跑,可能两三分钟就完事了,没必要关掉-fixOverlap再开回来。优化的前提是“批量”足够大,大到开销已经影响迭代效率。我的经验是,net数量超过300条,就值得用这套方法了。

5. 常见问题与避坑指南

5.1 问题速查表

批量ECO加repeater的过程中,有几类问题是高频出现的。我整理了一个速查表,方便大家直接对照排查。

现象可能原因解决方案
设置了setEcoMode但没效果版本不支持某个选项,或设置顺序不对先看setEcoMode -help;把设置放到脚本最前面
ecoAddRepeater报physical相关错误目标区域congestion高、row资源不够、cell与row类型不匹配换小尺寸cell;关闭dontUse限制;换个插入位置
批量后overlap暴增批量阶段关闭了fixOverlap但没有统一收尾在循环后重新打开fixOverlap并执行ecoPlace
添加的buffer带了PG pin,导致PG short选中的cell带PG pin,ECO时没有正确连接PG net用不带PG pin的buffer/inverter,或先用dbGet确认PG term
脚本跑一半中断某条net失败导致Tcl报错退出用catch包住ecoAddRepeater,记录失败并继续

5.2 如何正确获取标准单元的PG term

有朋友在交流群里问过:Innovus里怎么选中标准单元名字为biasnw的pg term?这个在批量加repeater时确实会遇到。比如你想检查某个库单元是否带PG pin,或者在ECO后确认某个inst的PG连接是否正确,就要用到dbGet

假设你要选中名字为biasnw的标准单元的PG term,可以这样写:

# 先找到这个instance set instDb [dbGet -p top.insts.biasnw -if {.name == biasnw}] # 再取它的所有PG term set pgTerms [dbGet -p $instDb.pgTerms.name] puts $pgTerms

如果只想找VDD或者VSS这种特定PG term,加上过滤条件:

set pgVdd [dbGet -p $instDb.pgTerms.name -if {@name == "VDD"}]

为什么要关注这个?因为批量加repeater的时候,如果你选的库单元自带PG pin(比如某些buffer标准单元),工具在ECO放置时可能需要额外处理PG connection。如果PG net没有正确连接,后面就会出现short或isolation violation。比较稳妥的做法是在批量操作前,先用dbGet把目标库单元的PG term情况摸清楚,如果不需要PG,就尽量选不带PG pin的单元;如果必须用带PG的单元,那就要确保PG net存在且可连接。

5.3 批量操作时怎么控制输出和日志

批量跑几百上千条ECO命令时,终端疯狂刷屏不仅看着烦,还会拖慢运行速度。我通常会用redirect把输出重定向到日志文件,同时打开setEcoMode -summary,这样既能保留完整进度,又不让交互输出拖慢速度。

redirect -file eco_add_repeater.log { source ./add_rep.tcl }

另外,建议在脚本里多用puts打印阶段性进度,但别在循环内打印太多细节。比如每处理50条net打印一次当前时间,既能观察进度,又不会产生大量IO开销。这个细节看似不起眼,在1200条net的规模下,能省下不少时间。

5.4 最后一个坑:别忘了恢复setEcoMode

这是我特别想强调的一点。setEcoMode设置的是全局状态,如果你在批量脚本里关闭了-fixOverlap,跑完之后没有恢复,后续其他ECO操作会继续沿用这个“只插入不修正”的模式,很可能产生一堆意想不到的overlap和DRC问题。我的习惯是,批量脚本的最后几行必须包含恢复配置:

setEcoMode -fixOverlap true -removeDummyCells true

最好在验证收尾完成后,再执行一次report_eco_mode或者直接查看当前设置,确认已经恢复到常规状态。否则下次跑别的ECO脚本时,很容易被这个“历史遗留模式”坑一把。

最后再分享一个我自己的实际操作体会:批量ECO这块,最重要的不是把某个命令研究到极致,而是建立起“批量模式”的思维方式。setEcoMode不是魔法,它只是把工具的工作方式调到更适合批量处理的档位。先在小样本上试跑,确认设置合理,再铺开到全量netlist,是我长期跑ECO流程养成的习惯。如果你现在正被批量ecoAddRepeater折磨,不妨把今天的思路拿回去试一试,时间上的惊喜大概率比我这个案例还明显。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询