ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Innovus VIA1 DRC自动修复:verify_drc与TCL脚本实战

2026/9/29 1:46:06 拓冰建站 浏览量
Innovus VIA1 DRC自动修复:verify_drc与TCL脚本实战 数字后端项目推到布线收尾阶段最让人头疼的场景往往不是setup还差几皮秒而是打开Innovus跑一遍verify_drc报告里齐刷刷铺着几百条VIA1的违规。明明布线器已经报过route完成为什么过孔这层还留着这么多问题更麻烦的是,这些VIA1 DRC Violation分布零散、成因各异,靠手点图形界面一个个去修,一个晚上就搭进去了。我做过几个28nm和40nm的项目,几乎每个都会在VIA1这层卡一下,后来逼着自己把这套流程做成了半自动的脚本方案,现在同样的活量从大半天压缩到一两个小时。这篇就把Innovus里verify_drc对VIA1违规的检查逻辑、常见违规类型的成因、以及一套能直接落地跑的TCL自动化修复脚本完整拆开讲一遍。不管你是刚接手后端flow的新人,还是已经能独立跑PR的老手,只要你的项目里VIA1 DRC还在反复报错,这里面的排查思路和脚本骨架都能直接拿去改。1. Innovus DRC检查的核心逻辑与VIA1问题的特殊性要把VIA1的违规修干净,先得搞清楚verify_drc这个命令在背后到底干了什么。很多人只是把它当成一个跑一下看有没有错的黑盒,报告出来就懵,不知道从哪下手。其实理解了它的检查机制和VIA1在版图里的定位,后面修起来会顺很多。1.1 verify_drc到底在验证什么verify_drc是Innovus里基于工艺LEF和规则文件做几何检查的命令,它做的事情本质上是把当前设计里所有物理图形的坐标、层次、尺寸和间距,逐条跟工艺规则去比。你可以在命令行直接敲:verify_drc -limit 10000 -report via1_drc.rpt这里的-limit控制每个规则类型的最大报错数量,设太小会漏,设太大报告会爆炸。我一般先设10000跑一遍看总量,再决定要不要细分。-report把结果写到文件,方便后续用脚本解析。需要提醒的是,Innovus里其实有两套常用的DRC验证入口:一套是内建的verify_drc(走LEF规则),另一套是配合外部signoff工具(比如Calibre、PVS)的接口。日常在PR阶段快速收敛,用verify_drc就够了,它的速度比调外部工具快得多,虽然精度上跟signoff有差距,但作为迭代手段完全够用。真正到tapeout前才需要拿signoff结果做最终确认。verify_drc检查的层次包括金属层、通孔层、多晶硅层等等,而VIA1属于通孔层里的第一层连接孔,通常连接METAL1和METAL2。它涉及的不只是孔本身的尺寸,还有上下金属对孔的包围(enclosure)、孔与孔之间的间距、孔到金属边缘的距离等等。这就是为什么VIA1的违规往往不是孤立出现的,而是跟上下层金属的布线形态强相关。1.2 VIA1为什么成了后端DRC的重灾区做了几个项目下来,我发现VIA1是整个DRC报告里出问题频率最高的层次之一,原因有这么几个。第一,过孔数量巨大。一个中等规模的模块,VIA1的数量动辄几十万甚至上百万个,基数大自然就容易出问题。第二个原因是过孔是自动生成的。布线器在走线的时候会根据metal的层间连接需求自动插入via,它追求的是连通性和时序,对某些细节工艺规则未必能百分百照顾到。第三,VIA1的规则本身比较复杂,不同工艺节点对via enclosure、via spacing、via array的要求差异很大,有些规则还跟金属的线宽、线间距联动。我印象最深的一次,一个模块跑完route,verify_drc报出来800多条VIA1 violation,打开一看绝大多数都是via enclosure不足这一类。当时以为是布线器配置有问题,后来查LEF才发现是这个工艺对宽金属上的via阵列有额外的enclosure要求,而布线器默认按单孔规则处理了。这种问题靠手动一个个改几乎不可能,必须靠脚本批量处理。这也是我这套自动化方案最初的出发点。注意:不同工艺节点的VIA1规则差异极大,拿到一个新工艺,第一件事是把LEF里的via相关规则通读一遍,尤其是VIA、VIARULE、SPACING这几个section,搞清楚这个工艺到底对via有哪些硬性要求。2. VIA1 DRC Violation的分类与成因拆解盲修违规是最浪费时间的做法。我习惯先把verify_drc报告里的VIA1违规按类型归类,看清楚每一类的分布和成因,再决定用哪种修复策略。下面把最常见的几类拆开讲。2.1 常见违规类型速查我把手上项目里遇到过的VIA1违规做了一个归类,大致是这么几类,每一类的成因和修复难度都不一样:违规类型典型报错关键词主要成因修复难度Via Enclosureenclosure, V1.EN上下金属对孔的包围不足中Via Spacingspacing, V1.S两个via距离过近高Via Cut Spacingcut spacing孔切割间距不够中Via Array Rulearray, VIARULE阵列孔不符合规则中Metal EnclosureM1.EN, M2.EN金属层包围不足中Via Densitydensity局部via密度超限低这张表不是绝对的,不同工艺的关键词会有出入,但大方向是这样。看报告的时候,先grep一下VIA1相关的关键词,把违规数量按类型统计出来,心里有数了再动手。2.2 从工艺规则到版图表现的因果链光知道类型还不够,得理解每一类违规背后的物理原因,修的时候才不会瞎改。Via Enclosure不足是最常见的一种。简单说,就是via上下两层的金属没有把via包够。工艺要求在via周围一定范围内必须有足够的金属覆盖,原因是在光刻和刻蚀过程中,如果金属包围不够,via可能会因为对准偏差而露出来,导致连接不良。这个规则通常用ENCLOSURE关键字定义,格式类似ENCLOSURE 0.03 0.01,表示某个方向要包0.03,另一个方向包0.01。修这类问题的思路通常是给via周围补金属,或者把via挪到金属更宽的位置。Via Spacing违规是指两个via之间距离太近。这个跟金属间距规则类似,但因为via是立体的,涉及到上下层的投影,情况更复杂。有些工艺还区分同电位via和不同电位via的间距要求,同电位的可以近一点,不同电位的必须拉开。修这类问题要么挪via,要么删掉重放。Via Array Rule是宽金属上的特殊规则。很多工艺规定,当金属宽度超过某个阈值时,上面的via必须用阵列形式,而且阵列的行列间距有明确要求。单一via在宽金属上是不允许的。这类问题在电源网络(power mesh)上特别多,因为power stripe都很宽。理解了这些因果,修的时候就知道该往哪个方向使劲。比如enclosure不足,你可以选择加宽金属、移动via或者换更大的via类型;而spacing不足,你只能移动或删除via,加金属是没用的。实操心得:我一般会在修复前把违规按坐标聚一下类,相邻的违规往往是同一个根因,一起修效率更高,也避免修了一个又冒出另一个。3. verify_drc的实操命令与结果解析命令谁都会敲,但要把报告读透、把违规定位准,还是有不少门道的。这一节把命令配置和报告解析的细节讲清楚。3.1 命令参数与运行策略先说命令本身。基础的跑法是这样:# 全芯片检查,限制每类规则报错数量,输出报告 verify_drc -limit 10000 -report ./drc/via1_check.rpt # 只检查指定层次,加快速度 verify_drc -limit 10000 -layer {VIA1 M1 M2} -report ./drc/via1_only.rpt # 带坐标信息输出,方便脚本解析 verify_drc -limit 10000 -report ./drc/via1_coord.rpt -coordinates-layer这个参数在你只关心VIA1相关问题时特别有用,能大幅缩短运行时间,尤其是大芯片上。-coordinates让报告里带上具体坐标,这是后面脚本自动解析的关键,一定要开。运行策略上,我建议分两轮跑。第一轮全量跑,看整体违规数量和分布;第二轮针对VIA1做细查,拿坐标报告做自动化修复的输入。如果设计特别大,可以先在模块级跑,修干净了再上层集成,避免全芯片跑一次等半天。另外一个容易被忽略的点是DRC的运行时机。我一般在route完成之后、opt之前跑一次,opt之后再跑一次。因为opt可能会移动或者增删via,原来干净的地方可能又出问题。把verify_drc嵌到flow的关键节点上,能及早发现问题,别攒到最后一起爆。3.2 违规报文的读取与定位报告出来了,怎么看是关键。verify_drc的报错格式大致长这样:V1.EN.1 : VIA1 enclosure by M1 0.03 VIA1 at (125.340, 89.720) M1 at (125.310, 89.690) ...每一段以规则名打头,后面跟着违规的具体坐标和涉及的图层。规则名里的V1.EN就提示你是via的enclosure问题。坐标是修复脚本最需要的信息。人工看报告的时候,我一般用文本编辑器的搜索功能,先把规则名统计一遍:grep -oE V[0-9]\.[A-Z] via1_coord.rpt | sort | uniq -c | sort -rn这条命令能把报告里所有via相关的规则名按出现次数排序,一眼就能看出哪类违规最多。别小看这一步,有时候800条违规其实就集中在两三个规则上,针对性修起来很快。定位到具体位置之后,可以用Innovus的图形界面跳转过去看:# 把违规点标记出来并在界面高亮 drcBrowser -report ./drc/via1_coord.rpt或者用zoomBox配合坐标跳转。图形界面适合抽查看具体的版图形态,但批量处理还是要靠报告文本和脚本。注意:报错坐标是violation的标记点,不一定是via的中心点,修的时候要结合图层信息一起判断,别直接拿坐标当via位置用。4. 脚本自动化修复方案的设计与实现这一节是重点。前面铺垫了那么多,就是为了这步能水到渠成。我把自己用的脚本方案拆成策略选型和代码实现两部分来讲。4.1 修复策略的选型自动化修复不是无脑删了重放。在写脚本之前,得先定策略。我的原则是:能局部补的绝不全局动,能改动小的绝不改动大。具体到VIA1违规,常见策略有这几种:补金属:针对enclosure不足,在via周围加patch metal。改动小,风险低,但要注意加的金属不能引入新的spacing违规。移动via:针对spacing或者位置不当,把via挪到合法位置。需要重新检查新位置是否合法。替换via类型:如果工艺提供了多种via定义(比如单孔和双孔、大孔和小孔),可以替换成满足规则的via。这是最省事的,前提是工艺库支持。重放via:把违规via删掉,让布线器重新生成。适合零星违规。删除冗余via:有些via是布线器多放的,删掉不影响连接,这类可以直接清掉。策略选型的原则是看违规的集中程度。如果某一片区域大量违规,可能是布线器在这个区域的策略本身有问题,需要对症下药;如果是零星散布的,逐个处理即可。我在《数字IC后端手把手实战教程》这个系列里一直强调一点,脚本要可控可回溯,每一步操作都要有日志,万一修出新问题能退回去。4.2 TCL脚本核心实现下面这套脚本骨架,我用了好几个项目,改改参数就能跑。核心思路是:解析报告 → 分类违规 → 逐类修复 → 重新验证。先写报告解析部分:# # 解析verify_drc报告,提取VIA1相关违规 # proc parseVia1Drc {rptFile} { set fp [open $rptFile r] set content [read $fp] close $fp set violations {} set lines [split $content \n] set curRule set curCoord foreach line $lines { # 匹配规则名行,例如 V1.EN.1 : VIA1 enclosure... if {[regexp {^\s*(V[0-9]\.[A-Z0-9._])\s*:} $line - rule]} { set curRule $rule } # 匹配坐标行,例如 VIA1 at (125.340, 89.720) if {[regexp {([A-Z0-9])\sat\s\(([0-9.]),\s*([0-9.])\)} $line - layer x y]} { if {$curRule ne [string match V1* $curRule]} { lappend violations [list $curRule $layer $x $y] } } } puts 解析到 VIA1 违规 [llength $violations] 条 return $violations }解析出来之后,按规则类型分桶:# # 按规则类型归类 # proc classifyViolations {violations} { array set buckets {} foreach v $violations { lassign $v rule layer x y # 提取规则大类,去掉末尾编号 set klass [lindex [split $rule .] 0].[lindex [split $rule .] 1] lappend buckets($klass) [list $layer $x $y] } foreach k [array names buckets] { puts 类型 $k : [llength $buckets($k)] 条 } return [array get buckets] }修复部分以enclosure不足为例,思路是在via周围补patch metal:# # 修复enclosure不足:在via周围补金属 # proc fixEnclosure {coordList patchSize} { set fixed 0 foreach c $coordList { lassign $c layer x y # 以via坐标为中心,按patchSize加一圈金属 set x1 [expr {$x - $patchSize}] set y1 [expr {$y - $patchSize}] set x2 [expr {$x $patchSize}] set y2 [expr {$y $patchSize}] # 在M1和M2上补矩形金属 addMetalRect M1 $x1 $y1 $x2 $y2 addMetalRect M2 $x1 $y1 $x2 $y2 incr fixed } puts enclosure修复: 处理 $fixed 个点 return $fixed }这里addMetalRect是封装好调用Innovus编辑命令的过程,实际用的时候要换成你环境里可用的命令,比如editAddRectangle之类。补金属的尺寸patchSize要结合工艺规则算,一般取规则要求的enclosure值再留点余量。假设规则要求0.03,via半径是0.05,那patchSize至少得是0.05加0.03,再留20%余量,大概0.1左右比较稳。移动via的部分:# # 修复spacing:尝试微调via位置 # proc fixSpacing {coordList offset} { set fixed 0 set failed 0 foreach c $coordList { lassign $c layer x y # 先尝试沿X偏移 set newX [expr {$x $offset}] if {[isViaLegal $layer $newX $y]} { moveVia $layer $x $y $newX $y incr fixed } else { incr failed puts 无法自动修复: ($x, $y) 需人工介入 } } puts spacing修复: 成功 $fixed, 待人工 $failed return [list $fixed $failed] }注意这里的isViaLegal是个关键函数,它需要重新对这个via做局部DRC检查,确认挪过去之后不违反其他规则。没有这个检查,你挪完可能又出新的违规,陷入死循环。整个流程串起来:# # 主流程 # set rpt ./drc/via1_coord.rpt set violations [parseVia1Drc $rpt] set buckets [classifyViolations $violations] foreach {klass coords} $buckets { switch -glob $klass { V1.EN { fixEnclosure $coords 0.1 } V1.S { fixSpacing $coords 0.02 } default { puts 类型 $klass 暂不支持自动修复,请人工处理 } } } # 修复后重新验证 verify_drc -limit 10000 -report ./drc/via1_after_fix.rpt -coordinates跑了之后对比修复前后的报告,违规数量应该明显下降。我实际项目里这套脚本大概能自动消化70%到85%的VIA1违规,剩下的再人工处理,整体效率提升很明显。4.3 修复效果验证与迭代脚本跑完不是就完事了,一定要验证。我一般会做三件事。第一,对比修复前后的违规数量,看下降比例。如果某类违规没降反而升了,说明修复策略有问题。第二,检查有没有引入新类型的违规,把修复后的报告和修复前的做差集。第三,抽几个修复点,到图形界面里看实际版图是不是真的合理,别修出来形状很怪异。迭代上,我习惯把修复过程做成一个循环:跑修复脚本 → verify_drc → 如果还有VIA1违规,调整策略再跑一轮 → 直到违规收敛到可接受范围。一般两三轮就能收敛。这里要注意避免死循环,设个最大轮次,比如5轮,超过就停下来人工介入。避坑技巧:每轮修复前先存一个design snapshot,命名带上轮次和日期。一旦发现修坏了能立刻退回去。我踩过最惨的一次是脚本改错了坐标单位,把整片power mesh的via都动了,幸好有snapshot,rollback只损失了十分钟。5. 常见问题排查与避坑经验实录脚本跑起来之后,会遇到各种意料之外的情况。这一节把踩过的坑整理出来,遇到问题时可以直接对照排查。5.1 常见问题速查表现象可能原因排查方法解决办法脚本解析出0条违规报告格式不符,正则没匹配上打开报告看实际格式,对比正则调整正则表达式修完违规数量没变修复命令没生效或被覆盖检查命令返回值,看log确认命令用法,加验证修完冒出新的违规补金属引入spacing问题对比前后报告差集补金属尺寸调小或加间距检查脚本跑到一半卡住坐标数据量太大,循环慢看进程状态,加进度打印分批处理,或用批量命令挪via后连接断开挪动导致连接不合法检查connectivity挪动后跑verifyConnectivity报告里坐标重复同一违规多点标记去重统计坐标去重后再处理verify速度太慢全芯片跑,数据量大看运行时长的层次分布分模块跑,用-layer限定这张表建议存下来,遇到问题先扫一眼,大部分情况都能对上号。5.2 独家避坑经验总结除了上面的速查,再分享几个只有踩过才知道的经验。坐标单位要对齐。Innovus里不同命令用的坐标单位可能不一样,有的用微米,有的用数据库单位(DBU)。我最早写脚本的时候没注意这个,补金属补出来尺寸差了1000倍,直接修出一堆新违规。写脚本第一步,先用dbGet head.libs.model或者类似的命令确认当前设计的单位,把坐标都转换一致了再处理。修复顺序有讲究。先修enclosure还是先修spacing,结果差别很大。我的经验是先修enclosure不足,因为补金属的过程可能顺带把一些spacing问题也解决了(金属加宽后via挪动空间更大);反过来先修spacing,挪完via可能又触发新的enclosure问题。所以脚本里策略的执行顺序不能随便排。别迷信全自动。再好的脚本也有搞不定的情况,尤其是涉及复杂版图形态的地方。我一般把自动修复的覆盖率目标定在80%左右,剩下的20%留人工。人工处理的时候反而能发现一些脚本没考虑到的边界情况,反过来优化脚本。全自动100%修复听起来美好,实际风险很高,一旦出了隐蔽错误,到signoff阶段才发现,返工成本巨大。保留完整的操作日志。脚本每一步做了什么、动了哪些坐标、调用了什么命令,都要记到log里。这不只是为了排查问题,也是为了在项目复盘的时候能说清楚每个改动。有次项目review,问我为什么某个区域via密度异常,就是靠日志翻出来是脚本某一轮的修复造成的。没有日志,这种问题根本无从查起。注意和其他约束的相互作用。VIA1的修复可能会影响时序、功耗、甚至EM(电迁移)。补金属会改变局部电容,挪via可能改变电阻。所以在大批量修复之后,我一般会再跑一次时序分析,确认没有引入明显的退化。这一步容易被忽略,但很重要。提示:如果你用的是较新版本的Innovus,部分修补命令的API可能和旧版本不同,建议先在文档里确认命令签名,再写进脚本。我升级工具版本的时候,就遇到过命令参数变化导致脚本报错的情况。关于VIA1 DRC的修复,我个人最深的体会是:与其在违规爆发后拼命扑火,不如在布线阶段就做好预防。比如合理配置布线器的via相关参数,控制单孔的生成策略,让布线器尽量使用符合工艺规则的标准via。这样从源头就能减少一多半的违规。脚本自动化是兜底手段,不是万能药。真正让DRC干净的,还是对工艺规则的深刻理解和布线阶段的精细控制。我现在的习惯是,每个新项目开始前,先把工艺的via规则文档过一遍,把关键参数记到项目笔记里,布线阶段就盯着这几个点,收尾的时候会轻松很多。遇到特别棘手的违规聚集区,与其硬修,不如看看是不是布线策略本身需要调整,有时候改一个布线参数,比修一百个via管用得多。