数字后端PR绕线short修复实战:Innovus与ICC2脚本批量处理与定位技巧

发布时间:2026/9/29 4:56:19
数字后端PR绕线short修复实战:Innovus与ICC2脚本批量处理与定位技巧 数字后端PR阶段最让人头疼的问题之一就是绕线完成后那一堆short。不管你是用Innovus还是ICC2跑完route看到timing report里蹦出几十上百个short那种感觉就像考试交卷前发现答题卡涂串行了。我做了十多年后端从ICC到ICC2再到Innovus每个工具都踩过short的坑也攒下了一些能批量处理、快速定位的脚本套路。这篇内容就是把我自己反复验证过的short修复思路和脚本框架整理出来不管你是刚入行的PR新手还是已经带过几个项目的熟手都能直接拿去改改用。核心讲三件事short到底怎么产生的、怎么用脚本批量抓取和分类、不同工具下怎么高效修掉它们。1. 先搞清楚short在后端流程里到底从哪冒出来的很多人一看到short就急着去修结果修完一批又冒一批根本原因是没搞明白short的来源。PR阶段的short不是随机事件它跟你的floorplan、placement密度、power plan、route策略都有直接关系。你得先知道敌人从哪来才能决定用哪种脚本去治它。1.1 绕线资源竞争导致的short占大多数最常见的short类型是绕线资源不够导致的信号线之间短路。当某个区域的standard cell密度过高或者macro周围没有留够halorouter在有限的空间里挤来挤去最后两条net的wire就撞在一起了。这种short在Innovus里通常表现为SHORT类型的DRC violation在ICC2里则是Short类的LVS/DRC报错。判断这类short有个简单方法看short发生的layer。如果集中在M2/M3这种低层金属基本就是局部绕线资源不足如果出现在M5以上往往是power stripe或者macro pin access的问题。我一般会先用工具自带的report_drc或者verify_drc把short按layer和坐标分类然后再决定是局部降密度还是调整power plan。1.2 power/ground网络与信号线的short更隐蔽PG net和signal net之间的short是另一大类而且比signal-signal short更难查。因为PG网络通常是全局的一条VDD stripe可能横跨整个chip如果某个signal net在route时不小心碰到了它报出来的short坐标可能离你实际需要修改的地方很远。这类short的典型特征是short的两条net里有一条名字带VDD/VSS或者PG相关的prefix。在Innovus里可以用dbGet配合selectNet来筛选ICC2里则可以用get_nets加filter。我习惯在修复前先把所有PG相关的short单独列一张表因为它们的修法跟普通signal short完全不一样——往往需要调整power plan的spacing或者加route blockage而不是简单挪线。1.3 placement阶段埋下的隐患在route后才爆发有些short的根因其实在placement阶段就种下了。比如两个cell的pin挨得太近或者某个cell的output pin正好对着另一个cell的input pinroute时稍微一绕就short了。这种short的特点是反复出现在同一对cell附近你挪一次线它好了过两天重新route又在旁边冒出来。我的经验是如果同一个坐标附近反复出现short不要只修route要回到placement去看cell的摆放。可以用checkPlace或者check_legality先确认有没有overlap然后用refinePlace或者手动挪几个cell往往比反复修route有效得多。2. 用脚本批量抓取short信息别再一个个手点了工具自带的GUI确实能看short但一个chip上几十上百个short你一个个点过去一天就没了。而且GUI里看到的坐标和layer信息复制出来还要手动整理效率极低。我自己的做法是写一套抓取脚本把short的坐标、layer、涉及的net name、net type全部导出成结构化数据后面分类和修复都基于这份数据来做。2.1 Innovus下用dbGet抓short的核心命令链Innovus的dbGet命令体系非常强大但文档写得比较散很多人不知道怎么组合。抓short的基本思路是先找到所有DRC violation再filter出SHORT类型然后逐个提取坐标和net信息。# 抓取所有short violation并输出到文件 set outFile short_report.rpt set fp [open $outFile w] puts $fp Layer\tX\tY\tNet1\tNet2 set shorts [dbGet top.markers.type SHORT -p] foreach short $shorts { set layer [dbGet $short.layer.name] set bbox [dbGet $short.bbox] set x [expr ([lindex $bbox 0] [lindex $bbox 2]) / 2] set y [expr ([lindex $bbox 1] [lindex $bbox 3]) / 2] set nets [dbGet $short.nets.name] set net1 [lindex $nets 0] set net2 [lindex $nets 1] puts $fp $layer\t$x\t$y\t$net1\t$net2 } close $fp这段脚本跑完你会得到一个tab分隔的表格直接拖进Excel就能做透视分析。我一般会按layer做一次统计看看short集中在哪几层再按net name的prefix做一次分类区分PG short和signal short。注意dbGet top.markers在不同版本的Innovus里语法略有差异有些版本需要用dbGet top.markers.type有些需要用dbGet [dbGet top.markers].type。建议先在交互模式下试一下再写进脚本。2.2 ICC2下用get_drc_violations配合Tcl筛选ICC2的DRC violation抓取走的是另一套API。get_drc_violations返回的是collection你需要用get_attribute去提取具体信息。下面是我常用的一个脚本框架set outFile short_report_icc2.rpt set fp [open $outFile w] puts $fp Layer\tX\tY\tNet1\tNet2 set violations [get_drc_violations -type short] foreach_in_collection vio $violations { set layer [get_attribute $vio layer_name] set bbox [get_attribute $vio bbox] set x [expr ([lindex $bbox 0] [lindex $bbox 2]) / 2] set y [expr ([lindex $bbox 1] [lindex $bbox 3]) / 2] set nets [get_attribute $vio related_nets] set net_names {} foreach_in_collection n $nets { lappend net_names [get_attribute $n full_name] } set net1 [lindex $net_names 0] set net2 [lindex $net_names 1] puts $fp $layer\t$x\t$y\t$net1\t$net2 } close $fpICC2的collection操作比Innovus的dbGet要繁琐一些但好处是API更规范不太会出现版本间语法大变的情况。跑完这个脚本同样能得到一份结构化的short列表。2.3 把short按类型和区域自动分类拿到原始short列表之后下一步是分类。我一般会按三个维度来分layer、net type、坐标聚类。Layer分类前面说了net type分类主要看net name里有没有PG相关的关键词坐标聚类则是把距离在10um以内的short归为一组因为同一组short往往可以用同一个策略批量修。# 简单的坐标聚类示例 set shortList {} # ... 假设shortList里已经存了 {layer x y net1 net2} 的列表 set clustered {} set used 0 foreach s $shortList { if {$used} { continue } set group [list $s] set sx [lindex $s 1] set sy [lindex $s 2] foreach t $shortList { if {$t $s} { continue } set tx [lindex $t 1] set ty [lindex $t 2] set dist [expr sqrt(($sx-$tx)**2 ($sy-$ty)**2)] if {$dist 10} { lappend group $t } } lappend clustered $group incr used }这个聚类逻辑比较粗糙实际用的时候我会用更严格的DBSCAN或者简单的grid-based方法。但核心思路就是把空间上接近的short归到一起修的时候一起处理避免东修一个西修一个。3. 不同工具下的short修复策略Innovus和ICC2的差异比你想的大Innovus和ICC2虽然都是PR工具但修short的底层逻辑和可用命令差别很大。Innovus的route engine更“激进”修short时倾向于局部重绕ICC2则更“保守”很多时候需要你手动给guide或者调整route rule。下面分别说。3.1 Innovus下用ecoRoute配合setAttribute精准修shortInnovus修short最直接的方法是ecoRoute但直接跑全chip ecoRoute往往会把已经修好的timing又搞乱。我的做法是先用setAttribute把short附近的区域标记出来然后只对这个区域做局部ecoRoute。# 选中short附近的区域做局部ecoRoute set shortBox {100 200 150 250} # 先删掉short附近的现有route editDelete -area $shortBox -type regular_wire # 然后做局部ecoRoute ecoRoute -area $shortBox -target shortecoRoute -target short这个option很多人不知道它会让router优先解决short而不是timing。在short密集的区域我会先用这个option跑一轮把short清掉然后再跑一轮正常的ecoRoute修timing。还有一个技巧是用setAttribute给short net设置routeType强制router用不同的layer或者不同的width去绕。比如setAttribute [get_nets net1] routeType special这样router在绕net1的时候会更“小心”不容易再跟别的net撞上。3.2 ICC2下用route_zrt_eco和create_route_guide组合拳ICC2修short的流程跟Innovus不太一样。ICC2的route_zrt_eco是主力命令但它默认是全局的你需要配合create_route_guide来限定范围。# 创建route guide限定修复区域 create_route_guide -name short_fix_guide -coordinate {100 200 150 250} # 对guide内的net做eco route route_zrt_eco -route_guide short_fix_guide -open_net_driven true-open_net_driven true这个option会让router优先处理open和short而不是timing。在short修复阶段我一般会先开这个option跑一轮把short清干净再关掉它跑正常的timing eco。ICC2还有一个很有用的命令是set_route_zrt_common_options里面可以设置-post_route_repair_short相关的参数。我通常会把-post_route_repair_short true打开让router在route完成后自动尝试修short。但这个option会稍微增加run time所以只在short比较多的项目上开。3.3 两个工具都需要注意的“修完又冒”问题不管你用哪个工具修short最怕的就是“修完又冒”。你今天修了10个short明天重新route又冒出8个新的。这个问题的根源通常是route strategy没有根本改变router只是在同一个约束下反复尝试。我的经验是修short要分三步走第一步先修PG相关的short因为PG short会影响整个power network的完整性第二步修高layer的short因为高layer short往往意味着floorplan或者power plan有问题第三步修低layer的signal short这类short通常靠局部降密度或者调整placement就能解决。另外每次修完short之后不要急着跑全chip的DRC先跑一次局部DRC确认修掉了再跑全chip。这样可以避免全chip DRC跑一次要几个小时结果发现short根本没修掉。4. 脚本实战一个能跨工具复用的short修复框架前面讲了抓取和修复的思路这一节我把它们串起来给一个能跨Innovus和ICC2复用的脚本框架。这个框架的核心思想是把short处理分成“抓取-分类-修复-验证”四个阶段每个阶段用独立的脚本模块方便调试和复用。4.1 抓取阶段的跨工具适配层抓取阶段最大的差异是Innovus用dbGetICC2用get_attribute。我一般会写一个适配层根据当前工具自动选择对应的命令。proc get_tool_name {} { if {[info commands dbGet] ne } { return innovus } elseif {[info commands get_drc_violations] ne } { return icc2 } else { return unknown } } proc grab_shorts {} { set tool [get_tool_name] if {$tool eq innovus} { return [grab_shorts_innovus] } elseif {$tool eq icc2} { return [grab_shorts_icc2] } else { puts Unsupported tool return {} } }这个适配层看起来简单但实际用起来非常省事。你只需要维护一套上层逻辑底层的工具差异被封装在grab_shorts_innovus和grab_shorts_icc2两个函数里。4.2 分类阶段的规则引擎分类阶段我一般会定义一个规则表每条规则包含匹配条件和对应的处理策略。比如规则名匹配条件处理策略PG_SHORTnet name含VDD/VSS调整power plan spacingHIGH_LAYERlayer M5检查macro pin accessLOW_LAYERlayer M3局部降密度或refinePlaceCLUSTER10um内超过3个short区域重route这个规则表可以用Tcl的dict或者list来实现匹配的时候逐条过。实际项目中我会根据每个chip的特点调整规则表比如有些chip的M4 layer特别容易short我就会加一条M4相关的规则。4.3 修复阶段的策略选择器修复阶段根据分类结果选择不同的修复命令。Innovus下主要是ecoRoute的各种变体ICC2下主要是route_zrt_eco配合guide。我一般会写一个fix_short函数根据short的类型和当前工具自动选择修复命令。proc fix_short {short_info} { set tool [get_tool_name] set type [lindex $short_info 0] set bbox [lindex $short_info 1] if {$tool eq innovus} { fix_short_innovus $type $bbox } elseif {$tool eq icc2} { fix_short_icc2 $type $bbox } }fix_short_innovus和fix_short_icc2里面就是具体的命令组合比如Innovus下对LOW_LAYER类型的short用ecoRoute -area $bbox -target shortICC2下对同样的short用route_zrt_eco -route_guide $guide -open_net_driven true。4.4 验证阶段的自动化检查修完short之后验证阶段不能少。我一般会写一个verify_short_fix函数重新抓一次short跟修复前的列表做对比确认修掉了多少、还剩多少、有没有新冒出来的。proc verify_short_fix {before_list after_list} { set fixed 0 set remaining 0 set new 0 foreach s $before_list { if {[lsearch $after_list $s] 0} { incr remaining } else { incr fixed } } foreach s $after_list { if {[lsearch $before_list $s] 0} { incr new } } puts Fixed: $fixed, Remaining: $remaining, New: $new }这个统计看起来简单但实际项目中非常有用。如果New的数量很大说明你的修复策略有问题需要回去调整如果Remaining很多说明修复力度不够可能需要换更激进的策略。5. 几个我踩过的坑和对应的解法脚本写得再好实际项目中还是会遇到各种意外。这一节我挑几个印象深刻的坑说说当时是怎么排查和解决的。5.1 short修完了但DRC还是报错有一次我用ecoRoute -target short跑完short report里确实没有short了但全chip DRC还是报了几百个错误。查了半天发现是ecoRoute在修short的时候把一些wire的width改小了导致出现了min width violation。这个问题的解法是在ecoRoute之后加一轮optDesign -postRoute -drv把DRC一起修掉。提示ecoRoute -target short会优先保证short被修掉但可能会引入其他DRC。修完short之后一定要跑一轮DRV修复。5.2 ICC2下route_zrt_eco跑完short没变化ICC2的route_zrt_eco有时候跑完short report里一个都没少。排查后发现是route guide没有正确创建或者guide的坐标跟short的实际坐标对不上。ICC2的坐标单位有时候是DBU有时候是micron需要确认清楚。我一般会在创建guide之前先用get_attribute确认一下short的bbox单位然后再创建guide。另一个常见原因是route_zrt_eco默认只处理open不处理short。需要显式加上-open_net_driven true或者-short_net_driven true。这个option在ICC2的不同版本里名字可能不一样建议先man route_zrt_eco确认一下。5.3 修short把timing搞崩了这是最让人崩溃的情况short修完了timing report里多了几百条violation。原因是ecoRoute在修short的时候把一些critical path的net绕远了或者换了layer导致RC变大。解法是在修short之前先把critical path的net用setAttribute标记为dontTouch让router不要动它们。# 标记critical path net为dontTouch foreach net [get_nets -of [get_timing_paths -max_paths 1000]] { setAttribute $net dontTouch true }这样router在修short的时候会避开这些nettiming就不会被搞崩。当然代价是short修复的灵活性降低了可能需要多跑几轮才能修干净。5.4 脚本跑一半报错退出Tcl脚本在跑长流程的时候最怕的就是跑一半报错退出前面的工作全白费。我的做法是在脚本里加异常捕获每个阶段跑完都把中间结果存到文件里下次可以从断点继续。if {[catch { set shorts [grab_shorts] set classified [classify_shorts $shorts] fix_shorts $classified } errMsg]} { puts Error: $errMsg # 保存中间结果 set fp [open short_checkpoint.txt w] puts $fp $shorts close $fp }这样即使脚本中途报错你也可以从checkpoint文件里恢复不用从头再跑一遍。6. 关于short修复的一些个人体会做了这么多年后端我越来越觉得short修复不是单纯的技术问题更多是流程和策略问题。工具的命令就那些但什么时候用哪个命令、用到什么程度这些判断才是真正值钱的经验。我自己的习惯是在route之前就先做一轮short预防。比如在placement阶段控制好density在power plan阶段留够spacing在route stage设置里把short相关的option提前打开。这些预防措施做到位route之后的short数量能少一半以上。另外short修复不要追求一次修完。我一般会分两到三轮第一轮修PG short和高layer short第二轮修低layer signal short第三轮做全chip DRC确认。每轮之间跑一次timing check确保没有把timing搞崩。这个流程看起来慢但实际上比一次修完再返工要快得多。脚本方面我建议不要追求“万能脚本”。每个chip的short情况都不一样万能脚本往往意味着什么都能修但什么都修不干净。更好的做法是维护一套脚本框架把抓取、分类、修复、验证四个阶段分开每个阶段根据项目特点做定制。这样既保证了复用性又保留了灵活性。最后说一个细节short report里的坐标有时候是bbox的左上角有时候是中心点不同工具、不同版本可能不一样。写脚本的时候一定要先确认坐标的定义不然你拿到的坐标去修short可能修的是隔壁的net。这个坑我踩过不止一次每次都要花半天时间排查。