深入解析Skill基础语法:从入门到实战避坑指南

2次阅读
没有评论

共计 2284 个字符,预计需要花费 6 分钟才能阅读完成。

image.webp

从版图生成失败说起

上周在 Cadence Virtuoso 中遇到一个典型问题:使用脚本批量生成 MOS 管时,部分器件神秘消失。最终定位到是 Skill 变量作用域问题——在循环内误用 global 声明导致变量覆盖。这促使我系统梳理 Skill 语法要点,以下是实战中总结的经验。

深入解析 Skill 基础语法:从入门到实战避坑指南

Skill vs Tcl/Python 的领域优势

  • EDA 原生支持 :Skill 直接调用geGetEditCellView 等 Virtuoso 内部 API,而 Python 需通过 PCI 接口绕行
  • 性能敏感操作 :版图数据处理时,Skill 的foreach 比 Python 列表推导快 3 - 5 倍(实测 5000 个 instance 场景)
  • 语法简洁性 :工艺规则检查这类任务,Skill 的when 条件判断比 Tcl 的 if-else 链条更紧凑

核心语法三剑客

1. 变量作用域:防污染指南

; 危险示范(全局变量污染)globalVar = 10
procedure(dangerousProc()
  println(globalVar) ; 输出 10
  globalVar = 20    ; 意外修改全局变量
)

; 推荐做法(局部变量 + 参数传递)procedure(safeProc(@optional (localVar 5))
  let((tempVar)
    tempVar = localVar * 2 ; 安全使用局部变量
    println(tempVar)
  )
)

2. 条件语句:cond/case 性能对比

  • cond适用场景:多条件判断且需执行不同代码块时
    cond((layer == "METAL1" => println("0.1um width")),
      (layer == "VIA1"   => println("0.05um size")),
      (t                 => println("Default rule"))
    )
  • case优势:纯值匹配时速度提升约 30%
    case(layer
      ("POLY"   0.12)
      ("DIFF"   0.15)
      (t        0.08) ; 默认值
    )

3. 循环结构:大数据量实战

; 避免使用 while 做集合遍历
procedure(slowIterate()
  let((i list)
    list = list(1 2 3 4 5)
    i = 0
    while(i < length(list) ; 每次循环都计算 length
      println(list[i])
      i++
    )
  )
)

; 推荐 foreach+lambda(实测快 2 倍)procedure(fastIterate()
  foreach(item list(1 2 3 4 5)
    println(item)
  )
)

工业级代码示例:版图元件生成

/* 
 * 批量创建 MOS 管单元
 * @param libName   库名称
 * @param cellName  单元名称
 * @param width     器件宽度(um)
 * @param fingers   指数
 */
procedure(createMosArray(libName cellName width fingers @optional (step 0.5))
  let((cv inst bBox)
    unless(ddGetObj(libName) 
      error("Library %s not found" libName))

    cv = geGetEditCellView()
    when(cv
      for(i 0 fingers-1
        inst = dbCreateInst(
          cv
          ddGetObj(libName cellName)
          sprintf(nil "M%d" i)
          list(i*step 0) ; 自动步进排版
          "R0"
        )
        ; 添加参数化属性
        dbSetProp(inst "w" width)
        dbSetProp(inst "l" 0.05)
      )
      geRedraw()

      ; 错误处理示例
      t = catchAll(bBox = geGetSelSet()~>bBox
        println(sprintf(nil "Total width: %f" bBox->width))
      )
      when(t
        println("WARNING: Bounding box calculation failed")
      )
    )
  )
)

性能优化进阶

内存泄漏检测

  1. 使用 dbMemReport 查看对象分配
  2. 重点检查未释放的 listtable
  3. 推荐 let 作用域自动回收
procedure(checkMemory()
  let((before)
    before = dbMemReport()
    ; ... 执行可疑代码...
    println(difference(dbMemReport() before))
  )
)

大数据分块策略

; 处理 10 万个 instance 的 DRC 检查
procedure(batchDrcCheck()
  let((allInsts batchSize)
    allInsts = geGetAllInstances()
    batchSize = 5000 ; 每批处理量

    for(i 0 length(allInsts)-1 batchSize
      let((batch)
        batch = slice(allInsts i min(i+batchSize length(allInsts)-1))
        foreach(inst batch
          drcCheckSingleInst(inst)
        )
        gc() ; 主动触发垃圾回收)
    )
  )
)

思考与延伸

  1. 跨工艺移植方案
  2. 使用 technology 变量封装工艺参数
  3. 正则表达式替换尺寸单位
  4. 建立工艺映射表techMap = '(("TSMC40"0.04) ("SMIC28" 0.028))

  5. CI/CD 集成思路

  6. skillpp 做语法检查
  7. 通过 skill -n -l script.il 运行测试用例
  8. 结合 Jenkins 的 Violation 插件统计警告

最后建议:在 Virtuoso 中开启skillDevelopmentMode,遇到语法错误时能获得更详细的堆栈信息。Happy scripting!

正文完
 0
评论(没有评论)