在做电路迁移或库整理时,经常需要把一个库下所有 cell 的引脚批量改为 input 或 output。
逐个 cell 手动改既费时又容易遗漏,用 SKILL 脚本在 CIW 中批量处理是最高效的方式。
本文整理自 Cadence ASK 三篇技术文章,完整覆盖 schematic + symbol 双视图,以及改方向时必须注意的 Floating net 问题。
一、背景:两个视图、两层属性
Virtuoso 中一个 cell 通常同时拥有 schematic 视图和 symbol 视图,两者都独立持有引脚信息:
| 视图 | 引脚属性 | 引脚视觉符号 |
|---|---|---|
| schematic | term~>direction |
basic/ipin、basic/opin、basic/iopin |
| symbol | term~>direction |
同上(symbol 自己的 pin instance) |
两视图的方向必须一致,否则 Check and Save 会报:
1
Warning: Terminal "A" in view schematic is (inputOutput) but is (input) in "cellName symbol".
另一个陷阱:在 schematic 里直接改方向时,pin 的视觉符号(三角形)位置会偏移,导致与之相连的导线断开,产生 Floating net 错误。
二、三种策略选择
| 策略 | 适用场景 | 是否保留 Symbol 自定义外观 |
|---|---|---|
| A. 仅改 schematic,重新生成 symbol | Symbol 无自定义布局,可以整体重建 | 否,symbol 完全重建 |
| B. 分别改 schematic 和 symbol 的 direction 属性 | 需保留 symbol 外观,只同步电气属性 | 是 |
C. 先改 symbol,再用 CCSUpdatePinDir 同步 schematic |
最稳健,自动处理 Floating net | 是 |
三、策略 A:改 schematic → 重建 symbol
适用于 symbol 没有手工定制、可以完全从 schematic 重新生成的场景。
步骤 1:批量修改 schematic 引脚方向
将以下脚本保存为 CCSchgPinDir.il,在 CIW 执行 load "CCSchgPinDir.il":
procedure(CCSchgPinDir(sourceLibName viewName pinList pinDir)
let((cv cellId pin_id)
foreach(sourceCellName ddGetObj(sourceLibName)~>cells~>name
cellId = ddGetObj(sourceLibName sourceCellName)
foreach(view cellId~>views~>name
if(view == viewName
then
cv = dbOpenCellViewByType(sourceLibName sourceCellName view "" "a")
foreach(pin pinList
pin_id = dbFindTermByName(cv pin)
if(pin_id
then
printf("found pin %L in cell %L \n" pin sourceCellName)
pin_id~>direction = pinDir
else
printf("pin %L does not exist in cell %L \n" pin sourceCellName)
) ;if
) ;foreach pin
dbSave(cv)
dbClose(cv)
) ;if
) ;foreach view
) ;foreach cell
) ;let
) ;procedure
在 CIW 调用:
1
2
; 将 mylib 所有 schematic 中名为 A、Z、ZX 的引脚改为 input
CCSchgPinDir("mylib" "schematic" list("A" "Z" "ZX") "input")
步骤 2:从 schematic 重建整库 symbol
将以下脚本保存为 CCSautoCreateSymbol.il,在 CIW 执行:
procedure(CCSautoCreateSymbol(sourceLib reCreate)
let((libId targetLib cellList sourceView targetView funct1 funct2)
libId = ddGetObj(sourceLib)
targetLib = sourceLib
cellList = libId~>cells
sourceView = "schematic"
targetView = "symbol"
funct1 = "schSchemToPinList"
funct2 = "schPinListToSymbol"
foreach(cell cellList
if(member(sourceView cell~>views~>name) then
if(reCreate || !member("symbol" cell~>views~>name) then
hiRegTimer("hiDBoxUser(schReplaceOrModifyDialog nil 1)" 5)
hiRegTimer("hiDBoxOK(cvToCvCreateCDF)" 10)
schViewToView(sourceLib cell~>name targetLib cell~>name
sourceView targetView funct1 funct2)
) ;if
) ;if
) ;foreach
ddReleaseObj(libId)
printf("\nJob Done!\n")
) ;let
) ;procedure
在 CIW 调用:
1
2
3
4
5
6
7
load "CCSautoCreateSymbol.il"
; 重建整库所有 symbol(覆盖已有 symbol)
CCSautoCreateSymbol("myLib" t)
; 仅为还没有 symbol 的 cell 新建(已有 symbol 的不动)
CCSautoCreateSymbol("myLib" nil)
注意:
reCreate=t会完全删除并重建已有 symbol,自定义的图形外观、端口位置均会丢失。
四、策略 B:分别改 schematic 和 symbol 的 direction 属性
如果 symbol 有精心设计的布局,不希望被重建,可以只同步逻辑方向属性(term~>direction),不改图形 master。
用上面的 CCSchgPinDir 对两个视图分别调用即可:
1
2
3
4
5
; schematic 视图
CCSchgPinDir("mylib" "schematic" list("A" "Z" "ZX") "input")
; symbol 视图(同一函数,只改 viewName 参数)
CCSchgPinDir("mylib" "symbol" list("A" "Z" "ZX") "input")
结果:电气方向属性同步,Check and Save 不再报 mismatch 警告;但 symbol 上三角箭头的朝向(ipin/opin 图形)不变。 若要同时替换图形,针对单个 cell 用下面的函数:
procedure(CCSchgPinDirMaster(sourceLibName sourceCellName pinList newDirection)
let((cv cv_sym pin_id pin_cell)
case(newDirection
("input" pin_cell="ipin")
("output" pin_cell="opin")
("inputOutput" pin_cell="iopin")
(t error("Invalid direction %L\n" newDirection))
)
cv_sym = dbOpenCellViewByType("basic" pin_cell "symbol" "schematicSymbol" "r")
cv = dbOpenCellViewByType(sourceLibName sourceCellName "schematic" "schematic" "a")
foreach(pin pinList
pin_id = dbFindTermByName(cv pin)
if(pin_id
then
pin_id~>direction = newDirection
foreach(pin1 pin_id~>pins
pin1~>fig~>master = cv_sym
)
)
)
dbSave(cv)
dbClose(cv)
) ;let
) ;procedure
五、策略 C:先改 symbol,再同步 schematic,自动处理 Floating net
核心优势:CCSUpdatePinDir 在改方向时会自动检测并重建与 pin 相连的导线,彻底避免 Floating net 报错。
此脚本来自 Cadence ASK 文章 a1Od0000000nVZLEA2,专门用于解决 schematic/symbol 方向不一致及 Floating net 的问题。
步骤 1:修改 symbol 引脚方向
若只改指定引脚,用 CCSchgPinDir:
1
CCSchgPinDir("mylib" "symbol" list("A" "Z" "ZX") "input")
若要遍历整库所有 cell 的所有引脚(无需提前知道名称),用以下脚本:
注意:symbol 视图中
pin~>fig返回的是 shape/polygon 对象(图形),不是 instance,不能对其赋值master,否则报dbSetq: Invalid type。
正确做法是只改ter~>direction;若同时需要更新视觉箭头,用schPinListToSymbol()重建 pin 表达(见方式 2)。
方式 1:只改 direction 属性(保留 symbol 外观,视觉箭头不变)
procedure(CCSchangeAllSymbolPinDir(libName newDirection)
let((cv)
foreach(cellName ddGetObj(libName)~>cells~>name
when(ddGetObj(libName cellName "symbol")
cv = dbOpenCellViewByType(libName cellName "symbol" "" "a")
foreach(ter cv~>terminals
ter~>direction = newDirection
printf("Set %L/%L pin %L -> %L\n" libName cellName ter~>name newDirection)
)
dbSave(cv)
dbClose(cv)
)
)
)
)
方式 2:同时更新视觉箭头(用 schPinListToSymbol 重建 pin 表示)
procedure(CCSchangeAllSymbolPinDirWithMaster(libName newDirection)
let((cv pinList)
foreach(cellName ddGetObj(libName)~>cells~>name
when(ddGetObj(libName cellName "symbol")
cv = dbOpenCellViewByType(libName cellName "symbol" "schematicSymbol" "r")
pinList = foreach(mapcar ter cv~>terminals
`(nil name ,(ter~>name) direction ,newDirection)
)
dbClose(cv)
schPinListToSymbol(libName cellName "symbol"
`(nil ports ,pinList))
printf("Updated %L/%L all pins -> %L\n" libName cellName newDirection)
)
)
)
)
在 CIW 调用:
1
2
3
4
5
6
7
load "CCSchangeAllSymbolPinDir.il"
; 方式 1:只改电气属性,不动外观
CCSchangeAllSymbolPinDir("mylib" "inputOutput")
; 方式 2:同时更新视觉箭头(会重建 pin 布局)
CCSchangeAllSymbolPinDirWithMaster("mylib" "inputOutput")
步骤 2:让 schematic 自动跟随 symbol,保留连线
将以下脚本保存为 CCSUpdatePinDir.il,在 CIW 执行 load "CCSUpdatePinDir.il":
procedure(CCSUpdatePinDir(libName @optional (cellList '()))
let((cv cv1 symTer)
if(!cellList then
cellList = ddGetObj(libName)~>cells~>name
)
foreach(cell cellList
when(and(ddGetObj(libName cell "schematic") ddGetObj(libName cell "symbol"))
cv = dbOpenCellViewByType(libName cell "schematic" "schematic" "a")
cv1 = dbOpenCellViewByType(libName cell "symbol")
foreach(ter cv~>terminals
symTer = car(setof(x cv1~>terminals x~>name==ter~>name))
if(ter~>direction != symTer~>direction then
CCSchg_pin_dir(cv list(ter~>name) symTer~>direction)
)
) ;foreach ter
dbSave(cv)
dbClose(cv)
dbClose(cv1)
) ;when
) ;foreach
printf("\nDone ...")
) ;let
) ;procedure
; 内部函数:改方向 + 换 master + 重建连线(避免 Floating net)
procedure(CCSchg_pin_dir(cv pinList newDirection)
let((pin_id pin_cell newMaster pts myBBox myWire myPt)
case(newDirection
("input" pin_cell="ipin")
("output" pin_cell="opin")
("inputOutput" pin_cell="iopin")
(t error("Invalid direction %L\n" newDirection))
)
newMaster = dbOpenCellViewByType("basic" pin_cell "symbol" "schematicSymbol" "r")
foreach(pin1 pinList
pin_id = setof(x cv~>instances and(x~>pin x~>net~>name==pin1))
if(pin_id then
foreach(pin pin_id
myBBox = CCSPinBox(pin)
myWire = car(setof(x dbGetOverlaps(pin~>cellView myBBox)
x~>objType == "line"))
when(myWire
pts = myWire~>points
schDelete(myWire)
foreach(point pts
if(if(dbGetDatabaseType()=="CDBA"
then absIsPointInsideFig(pin point)
else leIsPointInsideFig(pin point))
then nil
else myPt = point)
)
pin~>pin~>term~>direction = newDirection
pin~>master = newMaster
schCreateWire(pin~>cellView "route" "full"
list(myPt centerBox(CCSPinBox(pin)))
0.0625 0.0625 0.0)
) ;when
) ;foreach pin
) ;if
) ;foreach pin1
schCheck(cv)
) ;let
) ;procedure
procedure(CCSPinBox(inst)
let((pinFig newBox)
pinFig = car(setof(x car(dbGetTrueOverlaps(inst~>cellView inst~>bBox
list("pin" "drawing") 1))
x~>objType=="polygon"))
newBox = dbTransformBBox(pinFig~>bBox inst~>transform)
newBox
) ;let
) ;procedure
在 CIW 调用:
1
2
3
4
5
6
7
load "CCSUpdatePinDir.il"
; 更新整库所有 cell(schematic 方向同步到 symbol)
CCSUpdatePinDir("myLib")
; 只更新指定 cell
CCSUpdatePinDir("myLib" '("Cell1" "Cell_A"))
六、完整推荐工作流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
;; === 策略 C 完整流程举例(遍历整库所有引脚,无需指定引脚名)===
;; 1. 先改整库所有 symbol 视图的所有引脚方向(direction + master 一起改)改为input
load "CCSchangeAllSymbolPinDir.il"
CCSchangeAllSymbolPinDir("mylib" "input")
;; 2. 让 schematic 自动跟随 symbol 方向,且重建导线避免 Floating net
load "CCSUpdatePinDir.il"
CCSUpdatePinDir("mylib")
;; === 若 symbol 可以整体重建(策略 A)举例===
;; 1. 先改整库所有 schematic 视图的所有引脚方向(遍历,无需指定引脚名)
load "CCSchangeAllSymbolPinDir.il" ; 函数同样适用于 schematic 视图,改 viewName 即可
; 或直接在 CIW 执行:
foreach(cellName ddGetObj("mylib")~>cells~>name
when(ddGetObj("mylib" cellName "schematic")
cv = dbOpenCellViewByType("mylib" cellName "schematic" "" "a")
foreach(ter cv~>terminals ter~>direction = "input")
dbSave(cv) dbClose(cv)
)
)
;; 2. 从 schematic 重建整库 symbol
load "CCSautoCreateSymbol.il"
CCSautoCreateSymbol("mylib" t) ; t = 覆盖已有 symbol
七、关键 SKILL API 速查
| API | 作用 |
|---|---|
ddGetObj(lib)~>cells~>name |
获取库下所有 cell 名称列表 |
dbOpenCellViewByType(lib cell view type "a") |
以 append 模式打开视图(可写) |
cv~>terminals |
视图中所有逻辑引脚(term) |
dbFindTermByName(cv name) |
按名称查找 term |
term~>direction = "input" |
修改逻辑方向属性 |
pin~>fig~>master = cv_sym |
替换引脚图形 master(ipin/opin/iopin) |
schViewToView(...) |
从 schematic 生成 symbol(重建) |
schCreateWire(...) |
创建导线(用于重建断开的连线) |
dbSave(cv) / dbClose(cv) |
保存并关闭 |
八、注意事项
- 备份优先:所有脚本以 append 模式直接写磁盘,操作前务必备份库目录。
- 策略 A(重建 symbol)会丢失自定义外观:如果 symbol 有手工调整的布局或注释,用策略 B/C。
- Floating net 根因:直接修改 schematic 中
term~>direction时,pin 的 bounding box 会随 master 改变而偏移,导致连线端点落在 pin 框外而断开。策略 C 的CCSchg_pin_dir通过”删线→改 pin→重建线”的顺序解决这个问题。 pinDir合法值:只有"input"、"output"、"inputOutput"(驼峰,区分大小写)。ssgSortPins环境变量:重建 symbol 时,引脚在边框上的排布顺序受此变量控制("alphanumeric"或"geometric"),可在 CIW 执行schSetEnv("ssgSortPins" "geometric")修改。