在 IC 设计中,当需要进行命名规范迁移、供应商更换或大规模库重构时,传统的逐个手动重命名不仅效率低下,更容易导致引用关系混乱。本文介绍一个强大的 SKILL 工具,能够根据前缀映射文件批量重命名 Cell,并智能修复所有引用关系。
需求场景
在实际工作中,我们经常遇到这样的需求:
场景 1:命名规范迁移
1
2
旧规范: INV_1X, NAND_2X, NOR_2X
新规范: XINV_1X, XNAND_2X, XNOR_2X
场景 2:IP 库供应商变更
1
2
旧供应商: VENDOR_A_ADC, VENDOR_A_DAC
新供应商: VENDOR_B_ADC, VENDOR_B_DAC
场景 3:模块版本升级
1
2
旧版本: ADC_V1_CORE, DAC_V1_CORE
新版本: ADC_V2_CORE, DAC_V2_CORE
这类需求的共同特点是:
- 需要批量替换 Cell 名称的前缀(而非添加后缀)
- 有多对前缀映射规则
- 需要同步更新所有引用这些 Cell 的实例
工具功能对比
与之前的后缀添加工具相比,本工具提供了更强大的功能:
| 特性 | https://support.cadence.com/apex/ArticleAttachmentPortal?id=a1Od0000000nZp7EAE&pageName=ArticleContent | CCSRenamePrefix.il |
|---|---|---|
| 重命名方式 | 添加固定后缀 | 根据映射文件替换前缀 |
| 映射规则 | 单一后缀字符串 | 多对前缀映射,从文件读取 |
| 匹配逻辑 | 前缀匹配 + 后缀检测 | 前缀匹配 + 前缀替换 |
| 使用场景 | 版本管理(_v2) | 命名规范迁移(OLD_ -> NEW_) |
| 配置方式 | 硬编码参数 | 外部配置文件 |
| 优先级支持 | 否 | 是(按文件顺序) |
核心设计
GDM 增强的两阶段流程
本工具采用 Cadence 推荐的 GDM (Generic Design Management) 架构:
阶段 0:加载映射与准备
- 从文本文件读取前缀映射规则
- 支持注释和空行
- 构建映射列表和库更新列表
阶段 1:准备库更新列表
- 创建
gdmSpecList对象 - 将库列表 B 中的所有库添加到更新列表
- GDM 引擎将在此列表中自动查找和更新引用
阶段 2:重命名与自动更新
- 遍历指定库列表 A 的所有 Cell
- 根据前缀映射查找新名字
- 调用
ccpRename的CCP_UPDATE_FROM_LIBLIST模式 - GDM 引擎自动更新所有库的引用(无需手动遍历)
关键技术点
1. 文件 I/O:读取映射文件
procedure(loadPrefixMappingFile(fileName)
let((fp oldPrefix newPrefix mappingList line tokens)
mappingList = nil
fp = infile(fileName)
when(fp
while(gets(line fp)
; 去除换行符并解析
line = stringp(line) && buildString(parseString(line) " ")
; 跳过注释和空行
when(line && !rexMatchp("^[ \t]*#" line)
tokens = parseString(line)
when(length(tokens) >= 2
oldPrefix = car(tokens)
newPrefix = cadr(tokens)
mappingList = cons(list(oldPrefix newPrefix) mappingList)
)
)
)
close(fp)
)
reverse(mappingList) ; 保持文件顺序
)
)
关键点:
infile()打开文件,gets()逐行读取parseString()按空白符分割字符串- 支持
#开头的注释行 - 返回反转后的列表以保持文件中的顺序(支持优先级)
2. 前缀匹配与替换
procedure(getNewCellName(cellName mappingList)
let((newName oldPrefix newPrefix)
newName = nil
foreach(mapping mappingList
oldPrefix = car(mapping)
newPrefix = cadr(mapping)
; 检查前缀匹配
when(rexMatchp(strcat("^" oldPrefix) cellName)
; 替换前缀
newName = rexReplace(cellName newPrefix 1)
return(newName) ; 找到第一个匹配就返回
)
)
newName
)
)
关键点:
rexMatchp("^prefix" name)检查是否以指定前缀开头rexReplace(name newPrefix 1)替换第一个匹配项- 按顺序查找,找到第一个匹配就立即返回(优先级支持)
3. 创建库更新列表:gdmSpecList
procedure(createLibSpecList(libList)
let((libSpecList spec)
; 创建 GDM spec 列表对象
libSpecList = gdmCreateSpecList()
; 为每个库创建 spec 并添加到列表
foreach(libName libList
when(ddGetObj(libName)
spec = gdmCreateSpec(libName "" "" "" "CDBA")
gdmAddSpecToSpecList(spec libSpecList)
)
)
libSpecList
)
)
关键点:
gdmCreateSpecList()创建库列表容器gdmCreateSpec()为每个库创建 GDM spec 对象gdmAddSpecToSpecList()将库添加到列表中- 这个列表将传递给
ccpRename进行自动引用更新
4. Cell 重命名与自动引用更新
; 创建源和目标 spec
srcSpec = gdmCreateSpec(libName oldName "" "" "CDBA")
destSpec = gdmCreateSpec(libName newName "" "" "CDBA")
; 调用 ccpRename,使用 CCP_UPDATE_FROM_LIBLIST 自动更新引用
ccpRename(
srcSpec
destSpec
1 ;; 使用 1 而不是 t (OA 2.2+ 要求)
'CCP_EXPAND_COMANAGED ;; 展开 co-managed 文件
'CCP_UPDATE_FROM_LIBLIST ;; 在库列表中自动更新引用 ⭐
libSpecList ;; 库更新列表 ⭐
)
[!IMPORTANT] Cadence 官方推荐的 GDM 方法
- 使用
CCP_UPDATE_FROM_LIBLIST而不是手动遍历实例- 在 GDM 层面自动更新所有引用,包括
data.dm等元数据- 比手动
dbSetInstHeaderMasterName更快、更安全、更完整- 布尔参数必须使用
1/0,不能使用t/nil
GDM 自动更新机制
当我们使用 CCP_UPDATE_FROM_LIBLIST 时,Cadence GDM 引擎会:
- 扫描库列表:遍历
libSpecList中的所有库 - 查找引用:在每个库的元数据中查找对被重命名 cell 的引用
- 自动更新:更新以下所有内容:
- 实例引用 (instances)
- 元数据文件 (
data.dm) - Co-managed 文件
- 自定义 Via 引用
性能优势对比:
| 方法 | 处理方式 | 速度 | 完整性 |
|---|---|---|---|
| 手动遍历 | 打开每个 cellview → 遍历实例 → 保存 | ⭐⭐ | ⭐⭐⭐ |
| GDM 自动 | 一次 ccpRename 调用,底层批量处理 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
使用方法
1. 准备映射文件
创建 cellname_prefix_change_map.txt:
1
2
3
4
5
6
7
8
9
10
11
12
# Cell 前缀映射规则
# 格式: OLD_PREFIX NEW_PREFIX (空格或制表符分隔)
# 标准单元前缀更新
INV_ XINV_
NAND_ XNAND_
NOR_ XNOR_
BUF_ XBUF_
# 特殊模块前缀
ADC_OLD_ ADC_NEW_
DAC_V1_ DAC_V2_
文件格式规则:
- 每行一对映射:
OLD_PREFIX NEW_PREFIX - 使用空格或制表符分隔
#开头的行为注释- 空行会被忽略
- 按顺序匹配(前面的规则优先)
2. 加载脚本
在 Virtuoso CIW 中:
load("CCSRenamePrefix.il")
3. 定义库列表
; 库列表 A:需要重命名 Cell 的库
renameLibs = list("IP_ANA_LIB" "IP_DIG_LIB")
; 库列表 B:需要扫描并更新引用的库
scanLibs = list("IP_ANA_LIB" "IP_DIG_LIB" "PROJECT_TOP" "TB_LIB")
[!TIP] 最佳实践:将库列表 A 包含在列表 B 中,以处理库内部的自引用。
4. 执行重命名
CCSRenamePrefixAndFixRefs(
renameLibs
scanLibs
"cellname_prefix_change_map.txt"
)
5. 查看执行日志
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
27
28
29
=============================================================
Cadence Cell Prefix Renaming Tool (GDM-Enhanced)
=============================================================
Mapping File: cellname_prefix_change_map.txt
Source Libs: ("IP_ANA_LIB" "IP_DIG_LIB") (cells will be renamed)
Update Libs: ("IP_ANA_LIB" "IP_DIG_LIB" "PROJECT_TOP" "TB_LIB") (references will be updated)
Method: ccpRename with CCP_UPDATE_FROM_LIBLIST
=============================================================
>>> [Step 0: Load] Reading prefix mapping file...
Loaded mapping: 'INV_' -> 'XINV_'
Loaded mapping: 'NAND_' -> 'XNAND_'
>>> [Step 0: Load] Loaded 2 prefix mapping(s).
>>> [Step 1: Prepare] Creating library spec list for reference updates...
Added to update list: IP_ANA_LIB
Added to update list: IP_DIG_LIB
Added to update list: PROJECT_TOP
Added to update list: TB_LIB
>>> [Step 2: Rename] Processing cells with prefix mapping...
Processing Library: IP_ANA_LIB
Action: Renaming INV_1X -> XINV_1X
Action: Renaming NAND_2X -> XNAND_2X
>>> Summary: Renamed 2 cell(s) successfully.
>>> Note: GDM automatically updated all references in the specified libraries.
>>> All Done. Check the output above for details.
实际应用案例
案例 1:标准单元库规范迁移
背景:从旧版命名规范迁移到公司新规范
步骤:
- 准备映射文件
stdcell_rename.txt:1 2 3 4 5 6
INV STD_INV NAND STD_NAND NOR STD_NOR BUF STD_BUF FF STD_FF LATCH STD_LATCH
- 执行重命名:
renameLibs = list("OLD_STD_CELL_LIB") scanLibs = list("OLD_STD_CELL_LIB" "ANALOG_LIB" "DIGITAL_LIB" "TOP_DESIGN") CCSRenamePrefixAndFixRefs(renameLibs scanLibs "stdcell_rename.txt")
结果:
INV1→STD_INV1NAND2X→STD_NAND2X- 所有设计库中的引用自动更新
案例 2:IP 库供应商变更
背景:从 Vendor A 迁移到 Vendor B
映射文件:
1
2
3
4
5
# Vendor A -> Vendor B 映射
VA_ADC VB_ADC
VA_DAC VB_DAC
VA_PLL VB_PLL
VENDOR_A_ VENDOR_B_
案例 3:模块版本批量升级
背景:将所有 V1 模块升级到 V2
映射文件:
1
2
3
4
ADC_V1_ ADC_V2_
DAC_V1_ DAC_V2_
PLL_V1_ PLL_V2_
MEM_V1_ MEM_V2_
高级功能
优先级匹配
映射文件中规则的顺序决定了匹配优先级。更具体的规则应放在前面:
1
2
3
4
5
6
7
# 更具体的规则在前
INV_SPECIAL_ XINV_SPECIAL_
INV_ XINV_
# 示例:
# INV_SPECIAL_1X 匹配第一条 → XINV_SPECIAL_1X
# INV_COMMON_1X 匹配第二条 → XINV_COMMON_1X
处理复杂前缀
1
2
3
4
5
6
# 处理多层前缀
OLD_IP_V1_ NEW_IP_V2_
OLD_IP_ NEW_IP_
# 处理带下划线的前缀
MY_OLD_PREFIX_ MY_NEW_PREFIX_
注意事项与最佳实践
[!WARNING] 重要提醒
- 重命名操作不可逆,务必先备份库
- 建议在测试库中先验证映射规则
- 确保所有相关库都有写权限
- 执行前关闭所有被重命名的 cellview
[!TIP] 最佳实践
- 映射文件使用版本控制(Git)
- 在映射文件中添加详细注释说明变更原因
- 将库列表 A 包含在列表 B 中(处理内部引用)
- 执行前先测试
loadPrefixMappingFile()确认映射正确- 为重要操作保留操作日志
故障排查
问题 1:映射文件不存在
症状:
1
error: 映射文件不存在: cellname_prefix_change_map.txt
解决方法:
; 检查文件是否存在
isFile("cellname_prefix_change_map.txt")
; 使用绝对路径
CCSRenamePrefixAndFixRefs(
renameLibs
scanLibs
"/full/path/to/cellname_prefix_change_map.txt"
)
问题 2:没有有效映射
症状:
1
error: No valid prefix mappings found in file: xxx
原因:
- 文件格式错误(缺少空格分隔)
- 所有行都是注释或空行
正确格式:
1
2
3
4
5
6
7
8
# ✗ 错误:缺少分隔符
INV_XINV_
# ✓ 正确:空格分隔
INV_ XINV_
# ✓ 正确:制表符分隔
INV_ XINV_
问题 3:Cell 重命名后引用未更新
症状:Step 1 成功但 Step 2 没有更新任何实例
可能原因:
- 库列表 B 不包含引用这些 Cell 的库
- Cellview 没有正确保存
调试方法:
; 检查某个库是否包含对指定 Cell 的引用
cv = dbOpenCellView("PROJECT_TOP" "CHIP" "schematic")
foreach(inst cv~>instances
printf("Instance: %s/%s\n" inst~>libName inst~>cellName)
)
dbClose(cv)
问题 4:OA 版本兼容性
症状:ccpRename 执行失败
原因:OA 2.2+ 要求布尔参数使用整数
解决:确保脚本中使用 1/0 而不是 t/nil:
; ✓ 正确
ccpRename(srcSpec destSpec 1 ...)
; ✗ 错误(旧版本语法)
ccpRename(srcSpec destSpec t ...)
工具选择指南
| 使用场景 | 推荐工具 |
|---|---|
| 版本管理(添加 _v2, _bak 等) | CCSRenameSuffix.il |
| 前缀规范化(OLD_ -> NEW_) | CCSRenamePrefix.il |
| 供应商迁移(批量前缀更换) | CCSRenamePrefix.il |
| 简单的后缀添加 | CCSRenameSuffix.il |
| 复杂的多对映射 | CCSRenamePrefix.il |
| 需要外部配置文件 | CCSRenamePrefix.il |
完整代码
CCSRenamePrefix.il
;;--------------------------------------------------------------------
;; File : CCSRenamePrefix.il
;; Purpose : 根据前缀映射文件重命名 Cell,利用 GDM 自动更新引用
;; Author : Enhanced with Cadence GDM best practices
;; Updated : 2026/01/25
;;--------------------------------------------------------------------
;;
;; 功能说明:
;; 1. 从映射文件读取前缀替换规则(oldPrefix newPrefix)
;; 2. 在指定库列表 A 中重命名匹配前缀的 cell
;; 3. 利用 ccpRename 的 CCP_UPDATE_FROM_LIBLIST 自动更新库列表 B 的引用
;;
;; 使用示例:
;; renameLibs = list("IP_LIB_A" "IP_LIB_B")
;; scanLibs = list("IP_LIB_A" "IP_LIB_B" "TOP_LIB" "TB_LIB")
;; CCSRenamePrefixAndFixRefs(renameLibs scanLibs "cellname_prefix_change_map.txt")
;;--------------------------------------------------------------------
;; === 辅助函数:从文件读取前缀映射 ===
procedure(loadPrefixMappingFile(fileName)
let((fp oldPrefix newPrefix mappingList line tokens)
mappingList = nil
; 检查文件是否存在
unless(isFile(fileName)
error("映射文件不存在: %s" fileName)
)
; 打开文件读取
fp = infile(fileName)
when(fp
; 逐行读取
while(gets(line fp)
; 去除行尾换行符
line = stringp(line) && buildString(parseString(line) " ")
; 跳过空行和注释行
when(line && !rexMatchp("^[ \t]*$" line) && !rexMatchp("^[ \t]*#" line)
; 解析为 tokens
tokens = parseString(line)
; 需要至少两个 token (oldPrefix newPrefix)
when(length(tokens) >= 2
oldPrefix = car(tokens)
newPrefix = cadr(tokens)
; 添加到映射列表
mappingList = cons(list(oldPrefix newPrefix) mappingList)
printf(" Loaded mapping: '%s' -> '%s'\n" oldPrefix newPrefix)
)
)
)
close(fp)
)
; 返回映射列表(反转以保持文件中的顺序)
reverse(mappingList)
)
)
;; === 辅助函数:检查 cellname 是否匹配前缀,并返回新名字 ===
procedure(getNewCellName(cellName mappingList)
let((newName oldPrefix newPrefix)
newName = nil
; 遍历所有映射规则
foreach(mapping mappingList
oldPrefix = car(mapping)
newPrefix = cadr(mapping)
; 检查是否匹配前缀
when(rexMatchp(strcat("^" oldPrefix) cellName)
; 替换前缀
newName = rexReplace(cellName newPrefix 1)
; 找到第一个匹配就返回
return(newName)
)
)
; 没有匹配的映射,返回 nil
newName
)
)
;; === 辅助函数:创建库更新列表 (gdmSpecList) ===
procedure(createLibSpecList(libList)
let((libSpecList spec)
; 创建 GDM spec 列表对象
libSpecList = gdmCreateSpecList()
; 为每个库创建 spec 并添加到列表
foreach(libName libList
when(ddGetObj(libName)
spec = gdmCreateSpec(libName "" "" "" "CDBA")
gdmAddSpecToSpecList(spec libSpecList)
printf(" Added to update list: %s\n" libName)
)
)
libSpecList
)
)
;; === 主流程:根据前缀映射重命名 Cell,并利用 GDM 自动更新引用 ===
procedure(renameCellsByPrefixMappingGDM(libsToRename libsToScan mappingList)
let((oldName newName srcSpec destSpec libSpecList renameCount)
renameCount = 0
; Step 1: 创建库更新列表
printf("\n>>> [Step 1: Prepare] Creating library spec list for reference updates...\n")
libSpecList = createLibSpecList(libsToScan)
; Step 2: 遍历源库,重命名 Cell
printf("\n>>> [Step 2: Rename] Processing cells with prefix mapping...\n")
foreach(libName libsToRename
printf(" Processing Library: %s\n" libName)
when(ddGetObj(libName)
foreach(cell ddGetObj(libName)~>cells
oldName = cell~>name
; 检查是否有匹配的新名字
newName = getNewCellName(oldName mappingList)
when(newName && newName != oldName
printf(" Action: Renaming %s -> %s\n" oldName newName)
; 创建源和目标 spec
srcSpec = gdmCreateSpec(libName oldName "" "" "CDBA")
destSpec = gdmCreateSpec(libName newName "" "" "CDBA")
; 调用 ccpRename,使用 CCP_UPDATE_FROM_LIBLIST 自动更新引用
; 参数说明:
; src/dst: 源和目标 spec
; 1: 覆盖已存在的对象
; 'CCP_EXPAND_COMANAGED: 展开 co-managed 文件
; 'CCP_UPDATE_FROM_LIBLIST: 在库列表中自动更新引用
; libSpecList: 需要更新引用的库列表
ccpRename(
srcSpec
destSpec
1 ;; 使用 1 而不是 t (OA 2.2+ 要求)
'CCP_EXPAND_COMANAGED ;; 展开 co-managed 文件
'CCP_UPDATE_FROM_LIBLIST ;; 在库列表中自动更新引用
libSpecList ;; 库更新列表
)
renameCount = renameCount + 1
)
)
)
)
printf("\n>>> Summary: Renamed %d cell(s) successfully.\n" renameCount)
printf(">>> Note: GDM automatically updated all references in the specified libraries.\n")
)
)
;; === 顶层主函数 ===
procedure(CCSRenamePrefixAndFixRefs(libsToRename libsToScan mappingFile)
let((mappingList)
printf("\n=============================================================\n")
printf("Cadence Cell Prefix Renaming Tool (GDM-Enhanced)\n")
printf("=============================================================\n")
printf("Mapping File: %s\n" mappingFile)
printf("Source Libs: %L (cells will be renamed)\n" libsToRename)
printf("Update Libs: %L (references will be updated)\n" libsToScan)
printf("Method: ccpRename with CCP_UPDATE_FROM_LIBLIST\n")
printf("=============================================================\n\n")
; Step 0: 加载前缀映射文件
printf(">>> [Step 0: Load] Reading prefix mapping file...\n")
mappingList = loadPrefixMappingFile(mappingFile)
unless(mappingList
error("No valid prefix mappings found in file: %s" mappingFile)
)
printf(">>> [Step 0: Load] Loaded %d prefix mapping(s).\n" length(mappingList))
; 执行重命名和引用更新
renameCellsByPrefixMappingGDM(libsToRename libsToScan mappingList)
printf("\n>>> All Done. Check the output above for details.\n\n")
)
)
;;--------------------------------------------------------------------
;; 使用示例
;;--------------------------------------------------------------------
;;
;; 1. 准备映射文件 cellname_prefix_change_map.txt:
;; # 前缀映射规则(每行一对,空格分隔)
;; OLD_PREFIX1 NEW_PREFIX1
;; OLD_PREFIX2 NEW_PREFIX2
;; INV_ XINV_
;; NAND_ XNAND_
;;
;; 2. 加载脚本:
;; load("CCSRenamePrefix.il")
;;
;; 3. 定义库列表:
;; renameLibs = list("IP_ANA_LIB" "IP_DIG_LIB")
;; scanLibs = list("IP_ANA_LIB" "IP_DIG_LIB" "PROJECT_TOP" "TB_LIB")
;;
;; 4. 执行重命名:
;; CCSRenamePrefixAndFixRefs(renameLibs scanLibs "cellname_prefix_change_map.txt")
;;
;; 注意事项:
;; - 建议将 libsToRename 包含在 libsToScan 中,以处理库内部引用
;; - ccpRename 会在 GDM 层面自动更新所有引用,包括 data.dm 等元数据
;; - 对于大规模库(数万个 cell),这种方式比手动遍历实例快得多
;;--------------------------------------------------------------------
cellname_prefix_change_map.txt
1
2
3
4
5
6
7
8
9
10
# Cadence SKILL Cell Prefix Renaming - Mapping File
# Format: OLD_PREFIX NEW_PREFIX (space-separated)
# Lines starting with # are comments
# Example mappings:
INV_ XINV_
NAND_ XNAND_
NOR_ XNOR_
BUF_ XBUF_
OLD_PREFIX NEW_PREFIX
扩展可能性
1. 支持正则表达式替换
; 在 getNewCellName 中使用更复杂的正则表达式
rexReplace(cellName "^OLD_(.*)" "NEW_\\1" 1)
2. 支持 view 级别过滤
; 只处理特定 view
procedure(renameCellsByPrefixMapping(libsToRename mappingList viewFilter)
; viewFilter = '("layout" "schematic")
...
)
3. 生成重命名报告
; 输出 CSV 格式报告
fp = outfile("rename_report.csv")
fprintf(fp "Library,OldName,NewName,Timestamp\n")
fprintf(fp "%s,%s,%s,%s\n" libName oldName newName getCurrentTime())
close(fp)
4. Dry-Run 模式
procedure(CCSRenamePrefixAndFixRefs(libsToRename libsToScan mappingFile @optional (dryRun nil))
when(dryRun
printf(">>> DRY RUN MODE - No actual changes will be made\n")
)
; 在实际操作前检查 dryRun 标志
)
总结
本工具提供了一套基于 Cadence GDM 最佳实践的 Cell 前缀批量重命名解决方案:
- ✅ 灵活配置:从外部文件读取映射规则,支持版本控制
- ✅ 批量处理:使用
ccpRename可靠重命名所有匹配的 Cell - ✅ GDM 自动更新:利用
CCP_UPDATE_FROM_LIBLIST在底层自动更新所有引用 ⭐ - ✅ 完整性保证:自动处理
data.dm、co-managed文件、Via 引用等元数据 - ✅ 性能卓越:比手动遍历实例快数倍,特别适合大规模库
- ✅ 优先级支持:支持复杂的前缀映射规则和匹配优先级
- ✅ 详细日志:完整的执行日志便于调试和审计
技术亮点:
本实现采用 Cadence 官方推荐的 GDM (Generic Design Management) 机制,通过 gdm CreateSpecList 和 CCP_UPDATE_FROM_LIBLIST 参数,将引用更新任务交给 Cadence 底层引擎处理。相比手动遍历 cellview 和实例的方式:
- 更快:一次
ccpRename调用完成重命名和引用更新 - 更安全:GDM 引擎确保数据一致性
- 更完整:自动处理所有 GDM 管理的元数据文件
适用于命名规范迁移、供应商变更、版本升级等大规模库重构场景。合理使用该工具,可以大大提高 IC 设计中库管理和版本控制的效率。