skill实现不打开窗口checkandsave 库中所有schematic和symbol

在整理设计库时,逐个打开 schematic 和 symbol,再执行检查与保存,会产生大量重复操作。本教程以给定的 SKILL 过程为例,通过遍历库中的 cell、取得 cellView 数据库对象并执行检查与保存,减少手动打开编辑窗口的步骤。

一、目标与操作范围

这里的“不打开窗口”指代码没有调用打开图形编辑窗口的函数,而是直接使用 dbOpenCellViewByType 取得数据库对象。它不等于“不修改数据库”:代码使用可写打开方式并执行保存,会影响库里的设计数据。

二、完整代码

check_library.il
procedure(check(source_lib)
  let((libObj libCells cv)
    libObj = ddGetObj(source_lib)

    if(libObj then
      libCells = libObj~>cells

      foreach(cell libCells
        foreach(viewName '("schematic" "symbol")
          when(ddGetObj(source_lib cell~>name viewName)
            printf("Check and save: %s/%s/%s\n"
                   source_lib cell~>name viewName)

            cv = dbOpenCellViewByType(
                   source_lib
                   cell~>name
                   viewName
                   viewName
                   "a"
                 )

            when(cv
              schCheck(cv)

              if(dbSave(cv) then
                dbReopen(cv "r") ; 保存成功后切换为只读
              else
                printf("Save failed: %s/%s/%s\n"
                       source_lib cell~>name viewName)
              )

              dbClose(cv)       ; 释放本次打开的引用
            )
          )
        )
      )
    else
      printf("Library not found: %s\n" source_lib)
    )
  )
)

三、逐段理解执行逻辑

1. 获取库对象,处理库不存在的情况

libObj = ddGetObj(source_lib)

代码将查询结果放入 libObj,然后通过 if 判断是否取得对象。没有取得库对象时,只打印 Library not found,不进入后续遍历。输入的库名应与当前会话中能够访问的库名一致。

2. 遍历 cell 与目标 view

libCells = libObj~>cells
foreach(cell libCells
  foreach(viewName '("schematic" "symbol")
    ...
  )
)

外层循环遍历 libCells,内层循环分别处理 schematic 和 symbol。cell~>name 取得当前 cell 的名称。固定 view 列表意味着本代码不会处理 schematic_test、layout 等其他名称的 view。

3. 先判断 view 是否存在,再打开

when(ddGetObj(source_lib cell~>name viewName)
  ...
)

只有查询返回对象时才执行 when 内的代码。一个 cell 只有 symbol、没有 schematic 时,不存在的 view 会被跳过。存在性检查与后面的可写打开是两回事:代码仍需要检查 cv 是否取得。

4. 获取数据库对象,不主动创建编辑窗口

cv = dbOpenCellViewByType(
       source_lib
       cell~>name
       viewName
       viewName
       "a"
     )

该调用传入库名、cell 名、view 名,以及与 view 名相同的类型字符串。末尾使用 "a",表达本过程打开后要检查并保存的意图。返回结果进入 cv,后续通过 when(cv ...) 避免对空对象继续执行检查和保存。

注意:代码假定 view 名与传入的类型字符串一致。对于自定义 view 或不同库组织方式,不能仅通过修改名称列表就认定类型也正确。

5. 检查、保存与关闭

schCheck(cv)
if(dbSave(cv) then
  dbReopen(cv "r")
else
  printf("Save failed: %s/%s/%s\n"
         source_lib cell~>name viewName)
)
dbClose(cv)

代码先执行 schCheck,再判断 dbSave 的返回值。保存分支成功时调用 dbReopen(cv "r");失败时输出 Save failed。若前面的调用均正常返回,最后会执行 dbClose(cv)。

这里必须区分“运行过检查”“检查结果满足要求”和“保存成功”。原代码没有对 schCheck 的检查结果进行分级处理,也没有收集检查告警;因此不能把保存成功解读为电路已经通过所有规则验证。

四、如何调用

将完整过程保存为 check_library.il,在 Virtuoso 的 CIW 中加载该文件,再传入目标库名调用。下面的库名与文件位置仅为示例。

CIW
load("check_library.il")
check("my_design_lib")

当文件不在当前可解析的位置时,load 中应填写实际文件路径。执行前先选择一个可写的测试库副本,包含少量 schematic 和 symbol,用于核对打开、检查、保存和关闭的行为。

五、如何读日志

Check and save: my_design_lib/inverter/schematic
Check and save: my_design_lib/inverter/symbol

以上是日志格式示例,不是实际测试结果。原代码在打开 cellView 之前就打印 Check and save,所以看到这一行,只能说明目标 view 进入处理流程,不能证明打开或保存成功。

六、正式工程脚本的改进方向

总结

这段 SKILL 的核心路径是:获取库 → 遍历 cell → 筛选 schematic/symbol → 打开数据库对象 → 检查 → 保存 → 关闭引用。它将重复的手动操作转成批处理流程,但仍需要用测试库验证 view 类型、检查行为和异常处理。本教程基于用户提供的代码进行解析,未宣称已完成实际运行或环境兼容性测试。