共计 3043 个字符,预计需要花费 8 分钟才能阅读完成。
背景痛点:为什么需要学习 Skill 语言
作为 IC 设计工程师,每天都要面对大量重复性操作:

- 手工调整数百个相同结构的单元版图
- 逐个检查设计规则违反项
- 反复导出 / 导入 GDSII 文件进行验证
- 手动标注尺寸和参数
这些操作不仅耗时(占日常工作时间的 40%+),而且容易出错。某次手工操作失误可能导致整个版图需要返工,这种经历相信很多工程师都遇到过。
技术对比:Skill 在 EDA 领域的独特优势
| 语言特性 | Skill | Python | Tcl |
|---|---|---|---|
| 执行效率 | ★★★★★(直接调用 EDA 内核) | ★★★☆(需 API 中转) | ★★★★(原生集成) |
| 开发便利性 | ★★★☆(专用 IDE 支持) | ★★★★★(丰富生态) | ★★★☆(基础功能) |
| 底层访问能力 | ★★★★★(直接操作数据库) | ★★☆☆(受限接口) | ★★★☆(部分权限) |
| 学习曲线 | ★★★☆☆ | ★★☆☆☆ | ★★★☆☆ |
典型应用场景建议:
- 选择 Skill:版图批处理、PDK 开发、设计规则自动化检查
- 选择 Python:数据分析、机器学习辅助优化
- 选择 Tcl:工具流程控制、EDA 工具基础脚本
核心语法精要(IC618 版本)
1. 数据结构操作
; 创建并操作 list(CADENCE 官方推荐使用 cons 而非 list)metalLayers = cons("M1" "M2" "M3")
metalWidths = list(0.1 0.12 0.14) ; 需要索引时用 list
; 常用操作
dbgPrint(car(metalLayers)) ; 取第一个元素 → "M1"
dbgPrint(cdr(metalLayers)) ; 取剩余元素 → ("M2" "M3")
; 关联数组(类似 Python 字典)ruleTable = makeTable("DRC Rules")
tableSet(ruleTable "minWidth" 0.12)
2. 流程控制结构
; 条件判断(注意:nil 相当于 False)when(metalWidth > 0.1
println("满足最小宽度要求")
; 嵌套 when 替代 if-else
when(metalWidth < 0.15
println("中等宽度")
)
)
; 循环处理(推荐 foreach 而非 while)foreach(layer metalLayers
printf("Processing %s layer\n" layer)
; 实际处理代码...
)
3. 函数定义规范
procedure( createViaArray(@optional (viaType "V1") ; 可选参数
@key (rows 5) (cols 5) ; 关键字参数
@rest otherParams ; 剩余参数
)
"创建 via 阵列并返回对象列表" ; 函数说明
let((viaList)
for(i 1 rows
for(j 1 cols
via = dbCreateVia(
?layer1 "M1"
?layer2 "M2"
?viaType viaType
)
viaList = cons(via viaList)
)
)
reverse(viaList) ; 保持创建顺序
)
)
实战案例:版图自动化处理脚本
/*------------------------------------------------*
* 功能:自动检查并修正金属层最小间距
* 版本:IC618+ 已验证
* 输入:当前打开的版图窗口
* 输出:修正后的版图 + 违规报告
*------------------------------------------------*/
procedure(autoFixMetalSpace()
let((cv violations reportFile)
cv = geGetEditCellView()
unless(cv error("请先打开版图窗口"))
; 1. 设置检查参数
ruleTable = makeTable("Metal Space Rules")
tableSet(ruleTable "M1_space" 0.15)
tableSet(ruleTable "M2_space" 0.18)
; 2. 执行批处理检查
violations = nil
foreach(layer list("M1" "M2")
dbCheckSpacing(
?layer layer
?value tableGet(ruleTable strcat(layer "_space"))
?results violations
)
)
; 3. 生成报告并自动修正
reportFile = strcat(getShellEnvVar("HOME") "/metal_space_report.txt")
withOpenFile(reportFile "w"
fprintf(fp "金属间距检查报告:%s\n" getCurrentTime())
foreach(viol violations
; 写入报告
fprintf(fp "违规 @(%.3f,%.3f): %s\n"
car(viol->xy) cadr(viol->xy) viol->msg)
; 自动加宽金属(示例:向右扩展 0.05um)when(viol->obj && (viol->obj->objType == "path")
dbSetPathWidth(viol->obj viol->obj->width+0.05)
)
)
)
printf("生成报告文件:%s\n" reportFile)
)
)
调试技巧
- 调试器使用:
- 启动:在 CIW 输入
debugSkill()进入调试模式 -
快捷键:
s:单步执行n:跳过函数c:继续运行q:退出调试
-
常见错误排查:
*Error*开头的错误:通常是语法或运行时错误nil值问题:检查函数是否忘记 return-
内存泄漏:用
status(freeMemory)监控 -
日志输出技巧:
; 推荐使用带时间戳的日志 procedure(myLog(msg) printf("[%s] %s\n" getCurrentTime() msg) )
性能优化方案
- 数据库访问优化:
- 错误方式:在循环内多次
dbGetObjByName -
正确方式:预先
dbCreateQuery建立查询索引 -
内存管理:
- 大列表处理:用
array代替list(节省 30% 内存) -
及时释放:
delete()不再使用的对象 -
并行处理:
; IC617+ 支持多线程 threadCreate("proc1" processLayer1) threadCreate("proc2" processLayer2) threadWait("proc1") threadWait("proc2")
新手避坑指南
- 变量作用域:
- 问题:在
let外部访问内部变量 -
解决:始终用
let明确作用域 -
字符串比较:
- 错误:
if(layer == "M1")(应使用equal) -
正确:
if(equal(layer "M1")) -
路径处理:
- 错误:直接拼接
"~/project"(Unix 路径需转换) -
正确:
expandFileName("~/project") -
单位混淆:
- 陷阱:数据库单位可能是微米或纳米
-
方案:开始前先
dbGetUnit确认 -
版本兼容:
- 注意:IC6.1.7 与 IC618 的 API 差异
- 技巧:用
isCallable检查函数是否存在
进阶练习
- 开发一个自动识别并标注特殊尺寸结构的脚本
- 实现跨 cellview 的参数传递与同步更新
- 创建带 GUI 界面的版图批处理工具(使用
hiCreateAppForm)
结语
经过两周的 Skill 脚本开发,我们团队将版图验证时间从 8 小时缩短到 30 分钟。最初的学习曲线确实存在,但一旦掌握核心模式,就能显著提升工作效率。建议从小的自动化任务开始,逐步构建自己的工具库。当你发现自己在重复第三个相似操作时,就是时候写个 Skill 脚本了。
正文完
发表至: 未分类
近两天内
