3、Calibre DRC 高级规则:复杂条件规则、自定义规则编写、层次化DRC
好,咱们继续往下聊。前面几章我们把 DRC 的基础规则和常用命令都过了一遍。说实话,那些基础规则就像搭积木,能解决大部分常规问题。但真正让 Calibre 变得强大的,是它处理复杂逻辑的能力。这一章,我们就来啃啃硬骨头——条件规则、循环、自定义规则,还有层次化 DRC。
我个人习惯把这一章叫做「规则的艺术」。为什么?因为当你开始写这些高级规则时,你就不再是简单的规则搬运工,而是在设计一套智能的检查系统。嗯,这感觉挺爽的。
3.1 条件规则:让规则「活」起来
先说说条件规则。说白了,就是让规则根据不同的情况,执行不同的检查。我在项目中遇到过一种情况:同一个工艺,不同电压域的金属线间距要求不一样。1.8V 的线间距可以小一点,3.3V 的线间距必须大。这时候,条件规则就派上用场了。
Calibre 里最常用的条件语句是 IF 和 SELECT。看个例子:
// 条件规则示例:根据电压域选择不同的间距检查
IF ( VOLTAGE == "1.8V" ) THEN
M1_SPACING {
@ 1.8V 域:M1 间距 >= 0.1um
INTERNAL M1 < 0.1 UM
}
ELSE IF ( VOLTAGE == "3.3V" ) THEN
M1_SPACING_HV {
@ 3.3V 域:M1 间距 >= 0.2um
INTERNAL M1 < 0.2 UM
}
ELSE
M1_SPACING_DEFAULT {
@ 默认:M1 间距 >= 0.15um
INTERNAL M1 < 0.15 UM
}
你想想看,如果没有条件规则,你得写三条独立的规则,然后在运行的时候手动切换。有了 IF,规则自己就能判断该用哪条。避坑指南来了:我曾经犯过一个错误,在 IF 条件里用了字符串比较,但忘了加引号。结果 Calibre 把变量名当成了字符串,所有条件都不匹配,直接走了 ELSE 分支。嗯,查了半天才发现。
-dofile 传入。规则文件内部不能定义变量值。
3.2 循环:批量处理的艺术
循环在 DRC 规则里用得不多,但一旦用上,就能解决大问题。我印象最深的是处理多层金属的密度检查。你有 10 层金属,每层的密度规则几乎一样,只是层名不同。难道要写 10 遍?当然不。
Calibre 支持 FOREACH 循环,语法很直观:
// 循环示例:对 M1 到 M10 执行相同的密度检查
FOREACH ( layer IN { M1 M2 M3 M4 M5 M6 M7 M8 M9 M10 } ) DO
DENSITY_CHECK_{layer} {
@ 检查 {layer} 的密度
DENSITY {layer} 20.0 80.0 BY 100 UM
}
这里有个小技巧:我建议在循环体内使用 {layer} 这样的占位符,Calibre 会自动替换成当前迭代的层名。这样生成的规则名也是唯一的,方便查错。
为什么会用到循环?说白了,就是减少重复劳动。你想想看,如果工艺从 10 层金属升级到 12 层,你只需要在列表里加两个名字,规则就自动扩展了。维护成本大大降低。
3.3 自定义规则:打造你的专属检查
接下来是重头戏——自定义规则。Calibre 的 SVRF 语言非常灵活,你可以用 INT、REAL、STRING 定义变量,用 IF、WHILE 控制流程,甚至可以用 EXTERNAL 调用外部程序。
我在项目中遇到过一种特殊需求:检查两条平行走线之间的耦合电容是否超标。标准 DRC 规则没有这个功能,怎么办?自己写。
// 自定义规则:检查平行线耦合电容
INT length_threshold = 100 // 长度阈值,单位 um
REAL cap_per_um = 0.05 // 每微米耦合电容,单位 fF/um
REAL cap_limit = 10.0 // 总电容上限,单位 fF
// 第一步:找出所有平行且间距小于 0.5um 的线对
COUPLED_NETS {
@ 检查平行线耦合
EXT M1 < 0.5 UM ABUT > 100 UM SINGULAR
}
// 第二步:计算耦合长度
COUPLED_LENGTH = LENGTH COUPLED_NETS
// 第三步:计算总电容并判断
IF ( COUPLED_LENGTH * cap_per_um > cap_limit ) THEN
COUPLING_VIOLATION {
@ 耦合电容超标
COPY COUPLED_NETS
}
这个例子展示了自定义规则的三个核心步骤:定义变量、组合运算、条件判断。你完全可以按照自己的需求,设计出任何检查逻辑。
3.4 层次化DRC:从平面到立体
最后聊聊层次化 DRC。这是很多工程师的盲区。平面 DRC 检查的是当前层的图形,层次化 DRC 则能跨层、跨模块检查。
举个例子:你有一个顶层模块,里面调用了多个子模块。子模块内部的 DRC 已经通过了,但子模块之间的连接处可能有问题。层次化 DRC 就是干这个的。
Calibre 的层次化 DRC 主要通过 HIERARCHY 关键字实现:
// 层次化 DRC 示例:检查顶层模块中不同子模块的 M1 间距
HIERARCHY CHECK_TOP {
@ 检查顶层模块中不同子模块的 M1 间距
INTERNAL M1 < 0.15 UM
// 只检查顶层,不检查子模块内部
HIERARCHY TOP
}
// 另一种:检查子模块边界处的连接
HIERARCHY CHECK_BOUNDARY {
@ 检查子模块边界处的 M1 连接
CONNECT M1 BY V1
// 只检查边界
HIERARCHY BOUNDARY
}
我个人习惯在项目后期跑一遍层次化 DRC。为什么?因为平面 DRC 只能发现「图形」问题,层次化 DRC 能发现「结构」问题。我记得有一次,一个模块内部的 DRC 全过了,但集成到顶层后,两个模块的电源线在边界处没连上。平面 DRC 看不出来,层次化 DRC 一跑就抓到了。
3.5 实战建议:如何组织你的规则文件
讲了这么多,最后给点实战建议。一个复杂的 DRC 规则文件,如果组织不好,后期维护就是噩梦。我一般这样组织:
- 变量定义区:所有
INT、REAL、STRING变量放在文件头部,方便修改。 - 基础规则区:间距、宽度、包围等标准规则。
- 条件规则区:所有带
IF、SELECT的规则。 - 循环规则区:用
FOREACH批量生成的规则。 - 自定义规则区:复杂的、需要多步运算的规则。
- 层次化规则区:专门用于顶层检查的规则。
嗯,这样分区的最大好处是:出了问题,你能快速定位到对应的区域。我曾经接手过一个同事的规则文件,所有规则混在一起,足足 5000 行。我花了三天才理清楚。从那以后,我自己的规则文件一定分区写。
好了,这一章的内容就到这。条件规则、循环、自定义规则、层次化 DRC,每一个都是进阶的利器。别怕复杂,多用几次就熟了。下一章我们聊聊 DRC 的调试技巧,保证让你少走弯路。