1. 从一次改标注的崩溃说起
如果你正在用 Cadence Virtuoso IC61 做模拟电路设计,大概率经历过这样的场景:花了一下午把 schematic 画得整整齐齐,仿真跑通,结果导出网表给同事 review 时,对方一句“这个管子的 W/L 怎么没标出来”让你瞬间破防。更崩溃的是,你明明记得自己改过 annotation,但打开一看,要么显示的是默认值,要么干脆一片空白。
这不是你操作有问题,而是 Virtuoso 的 annotation 机制本身就有点“反直觉”。它不像大多数 EDA 工具那样,改一个全局开关就能让所有器件显示你想要的参数。在 IC61 里,annotation 的显示逻辑分散在三个层级:全局环境变量、cellview 级别的属性、以及单个 instance 的 property。这三个层级互相覆盖,优先级从低到高,任何一个环节没配对,你看到的 annotation 就不是你想要的。
我见过太多工程师在这上面浪费时间——有人每次手动改每个管子的 label,有人干脆放弃 annotation 直接看网表,还有人把 display 选项翻了个底朝天也没找到正确的开关。其实只要理解了它的覆盖逻辑,改 annotation 就是几分钟的事。
这篇文章就是把我这些年踩过的坑、试过的配置、以及最终沉淀下来的操作流程完整梳理一遍。不管你是刚接触 Virtuoso 的版图新手,还是已经画了几年 schematic 但一直没搞明白 annotation 机制的老手,看完都能直接上手操作。我会从最基础的显示原理讲起,然后给出三种不同场景下的修改方案,最后附上我自己的速查表和避坑清单。
2. Annotation 显示机制到底是怎么工作的
2.1 三个层级的覆盖关系
Virtuoso 的 annotation 显示遵循一个“就近原则”:离器件越近的设置,优先级越高。具体来说:
- 全局层级:在 CIW(Command Interpreter Window)里通过
envSetVal设置的变量,或者通过 Options → Display 菜单配置的全局显示选项。这一层影响所有打开的 cellview,但优先级最低。 - Cellview 层级:在 schematic 编辑器中通过 Edit → Properties → Cellview 设置的属性,或者通过
schSetCellViewProperty函数设置的属性。这一层只影响当前 cellview,优先级居中。 - Instance 层级:选中单个器件后通过 Edit → Properties → Object 设置的属性,或者通过
dbReplaceProp函数直接修改 instance 的 property。这一层只影响选中的那个器件,优先级最高。
举个例子:假设你在全局设置里让所有 MOS 管显示 W/L,但在某个 cellview 里设置了只显示 W,那么打开这个 cellview 时,所有管子都只显示 W。如果你再选中其中一个管子,单独设置它显示 W/L/M,那么这个管子就会显示三个参数,而其他管子仍然只显示 W。
这个机制的好处是灵活,坏处是容易乱。我建议在项目初期就定好一个统一的 annotation 策略,比如“全局只显示 W/L,特殊器件在 instance 层级单独标注”,然后写进设计规范里,避免每个人按自己的习惯乱改。
2.2 Annotation 的存储位置
理解 annotation 存在哪里,对排查问题非常关键。Virtuoso 的 annotation 信息主要存在两个地方:
- Cellview 的 property 列表:比如
schAnnotation、schDisplayAnnotation这些属性,它们决定了打开这个 cellview 时默认显示什么。 - Instance 的 property 列表:比如
w、l、m、nf这些参数,以及annotate相关的属性。当你选中一个器件并修改它的 annotation 时,实际上是在改这个 instance 的 property。
这里有个坑:很多人以为改了 instance 的 annotation 就完事了,但如果 cellview 层级的设置里明确指定了“不显示 annotation”,那么 instance 层级的设置也可能被忽略。反过来,如果 cellview 层级设置了“显示所有 annotation”,但 instance 层级没有对应的 property,那也显示不出来。
所以正确的做法是:先确认 cellview 层级的 annotation 开关是打开的,然后再去调 instance 层级的显示内容。顺序反了,怎么改都看不到效果。
2.3 为什么 IC61 的 annotation 这么难搞
IC61 是 Cadence 在 2000 年代中期推出的版本,虽然现在已经有 IC617、IC618 甚至 IC23,但很多公司还在用 IC61,因为它的 license 便宜、稳定、而且和很多老工艺库兼容。但它的 annotation 机制确实不太友好,主要原因有三个:
第一,菜单入口太深。改一个 annotation 要经过 Edit → Properties → Object,然后在弹出的对话框里找到 Parameter 标签页,再在一堆属性里找到annotate相关的选项。新手根本不知道要来这里改。
第二,文档太少。Cadence 的官方文档虽然全,但写得像天书,而且很多函数和变量的说明只有一句话,没有示例。网上能找到的教程大多是针对 IC51 或 IC617 的,IC61 的资料少得可怜。
第三,不同工艺库的默认设置不一样。有些 PDK 的管子默认就显示 W/L,有些什么都不显示。你换一个工艺,之前的经验可能就不管用了。
我自己的做法是:不管用什么工艺,先花十分钟把 annotation 的全局设置调好,然后在项目启动会上统一告诉大家怎么改。这样后面就不会有人反复来问“为什么我的管子不显示参数”。
3. 三种场景下的 Annotation 修改方案
3.1 场景一:全局修改,让所有器件默认显示 W/L
这是最常见的需求。你希望打开任何一个 schematic,所有 MOS 管都自动显示 W/L,不用手动一个个改。操作步骤如下:
第一步,打开 CIW,输入以下命令:
envSetVal("schematic" "annotate" 'string "W/L")这条命令的意思是:在 schematic 编辑器里,默认 annotation 显示 W 和 L 两个参数。注意'string是 Skill 语言的类型声明,不能省略。
第二步,如果你还想显示其他参数,比如 M(倍数)或 NF(指状数),可以这样写:
envSetVal("schematic" "annotate" 'string "W/L/M/NF")参数之间用斜杠分隔,顺序就是你希望显示的顺序。
第三步,如果你希望这个设置永久生效,需要把它写进.cdsinit文件。这个文件通常在你的 home 目录下,如果没有就新建一个。在里面加上:
envSetVal("schematic" "annotate" 'string "W/L")这样每次启动 Virtuoso 时都会自动加载这个设置。
注意:
envSetVal设置的变量是 session 级别的,关掉 Virtuoso 就失效了。写进.cdsinit才能永久保存。
但这里有个问题:有些工艺库的管子默认不显示 annotation,即使你设置了全局变量也没用。这是因为 PDK 的 CDF(Component Description Format)里可能把 annotation 关掉了。这时候你需要改 CDF 或者用下面的方法。
3.2 场景二:针对单个 Cellview 修改 Annotation
如果你不想改全局设置,只想让当前这个 schematic 显示特定的 annotation,可以用 cellview 层级的设置。操作步骤如下:
第一步,在 schematic 编辑器里,点击 Edit → Properties → Cellview。
第二步,在弹出的对话框里找到Annotation相关的选项。不同版本的 IC61 可能位置不太一样,通常在Display或Schematic标签页下。
第三步,在Annotate字段里输入你想要的参数,比如W/L。如果你想显示多个参数,用空格或斜杠分隔。
第四步,点击 OK 保存。这时候当前 cellview 里的所有器件都会按照这个设置显示 annotation。
如果你更喜欢用 Skill 命令,可以这样写:
schSetCellViewProperty(cellView "annotate" "W/L")其中cellView是当前 cellview 的 ID,可以通过geGetEditCellView()获取。
这个方法的优点是只影响当前 cellview,不会干扰其他设计。缺点是每个新 cellview 都要重新设置一遍。如果你有几十个 schematic,手动改会很累。这时候可以写一个脚本批量处理:
foreach(cv geGetEditCellViewList() schSetCellViewProperty(cv "annotate" "W/L") )这段代码会遍历所有打开的 cellview,统一设置 annotation。
3.3 场景三:只改某个器件的 Annotation
有时候你只想让某个特定的管子显示额外的参数,比如它的 M 值或 NF 值,而其他管子保持默认。这时候就需要在 instance 层级修改。操作步骤如下:
第一步,选中你要修改的器件。
第二步,点击 Edit → Properties → Object,或者直接按q键。
第三步,在弹出的对话框里找到Parameter标签页。
第四步,找到Annotate这一项。如果看不到,可能需要点击Show All或Advanced按钮。
第五步,在Annotate字段里输入你想要的参数,比如W/L/M。
第六步,点击 OK 保存。
用 Skill 命令的话,可以这样写:
dbReplaceProp(instance "annotate" "string" "W/L/M")其中instance是选中器件的 ID,可以通过car(geGetSelSet())获取。
这里有个细节:dbReplaceProp的第三个参数是属性类型,通常是"string"。如果你写错了类型,属性可能设置不成功。
提示:如果你想让某个器件完全不显示 annotation,可以把
annotate设置为空字符串""。
4. 实操中遇到的典型问题与排查方法
4.1 改了设置但 annotation 还是不显示
这是最常见的问题。可能的原因有以下几个:
原因一:CDF 参数被锁定。有些 PDK 的 CDF 里把annotate属性设置成了fixed,不允许用户修改。这时候你需要先解锁 CDF。方法是:在 CIW 里输入cdfEdit(),找到对应的 cell,然后把annotate属性的fixed选项去掉。
原因二:Display 选项没打开。即使 annotation 设置正确,如果 Display 选项里把 annotation 关掉了,也看不到。检查方法是:点击 Options → Display,找到Annotation相关的选项,确保它是打开的。
原因三:Layer Purpose Pair 的问题。Annotation 的显示依赖于 LPP(Layer Purpose Pair)。如果 LPP 设置不对,annotation 可能被隐藏了。检查方法是:在 Display Options 里找到Annotation对应的 LPP,确保它的可见性是打开的。
原因四:Cellview 的 property 覆盖了全局设置。如果你之前在这个 cellview 里设置过 annotation,它会覆盖全局设置。检查方法是:用schGetCellViewProperty查看当前 cellview 的 annotation 设置。
排查顺序建议:先检查 Display 选项,再检查 cellview property,最后检查 CDF。这个顺序是从简单到复杂,能快速定位问题。
4.2 Annotation 显示不全或格式错乱
有时候 annotation 能显示,但只显示了一部分,或者格式乱七八糟。比如你想显示W/L,结果只显示了W,或者显示成了W=1u L=0.1u这种带等号的格式。
这通常是因为 annotation 的格式字符串设置不对。Virtuoso 支持两种格式:
- 简单格式:直接写参数名,比如
W/L,显示时就是1u/0.1u。 - 带标签格式:用
%符号,比如W=%W L=%L,显示时就是W=1u L=0.1u。
如果你想要带标签的格式,需要在 annotation 字符串里加上%和参数名。比如:
envSetVal("schematic" "annotate" 'string "W=%W L=%L")这样显示出来就是W=1u L=0.1u,比单纯的1u/0.1u更清楚。
另外,如果你发现 annotation 显示不全,可能是参数名写错了。比如 MOS 管的宽度参数是w而不是W,长度是l而不是L。Skill 语言是大小写敏感的,写错了就显示不出来。
4.3 批量修改时部分器件没生效
如果你用脚本批量修改 annotation,可能会发现有些器件改了,有些没改。这通常是因为这些器件的类型不一样。比如 MOS 管、电阻、电容的 annotation 属性名可能不同。
解决方法是:先判断器件类型,再设置对应的 annotation。比如:
foreach(inst geGetSelSet() let((cellName) cellName = inst~>cellName cond( (cellName == "nmos" || cellName == "pmos" dbReplaceProp(inst "annotate" "string" "W/L") ) (cellName == "res" dbReplaceProp(inst "annotate" "string" "R") ) (cellName == "cap" dbReplaceProp(inst "annotate" "string" "C") ) ) ) )这段代码会根据器件的 cellName 判断类型,然后设置不同的 annotation。实际使用时,你需要把nmos、pmos、res、cap替换成你工艺库里的实际 cell 名称。
4.4 常见问题速查表
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| 改了设置但不显示 | Display 选项关闭 | Options → Display → 打开 Annotation |
| 只显示部分参数 | 参数名大小写错误 | 检查w/l是否写成W/L |
| 格式不对 | annotation 字符串格式错误 | 用%W代替W实现带标签格式 |
| 批量修改部分失效 | 器件类型不同 | 先判断 cellName 再设置 |
| 重启后设置丢失 | 没写进.cdsinit | 把envSetVal写入.cdsinit |
| CDF 不允许修改 | CDF 属性被锁定 | 用cdfEdit()解锁 |
5. 我自己的操作习惯和避坑经验
5.1 项目启动时统一配置
我现在的习惯是:每次新项目启动时,先花十分钟把 annotation 的全局设置调好,然后写一个简单的 Skill 脚本放在项目目录下,让团队成员在启动 Virtuoso 时自动加载。这样大家看到的 annotation 格式都是一致的,review 的时候不会因为格式问题浪费时间。
具体做法是:在项目目录下建一个project_setup.il文件,内容如下:
envSetVal("schematic" "annotate" 'string "W/L/M") envSetVal("schematic" "annotateFormat" 'string "%W/%L/%M")然后在.cdsinit里加上:
load("/path/to/project_setup.il")这样每次启动都会自动加载项目配置。
5.2 不要依赖默认设置
很多 PDK 的默认 annotation 设置是“不显示”或者“只显示 W”。如果你直接开始画图,后面再改会很麻烦。我的建议是:拿到一个新工艺库后,先画一个测试 schematic,放几个管子,然后试试各种 annotation 设置,看看哪些参数能显示、格式是什么样的。摸清楚之后再开始正式设计。
5.3 用颜色区分不同参数的 annotation
如果你同时显示多个参数,比如 W、L、M、NF,建议用不同的颜色区分。这样在 review 的时候一眼就能看出哪个是哪个。设置方法是:在 Display Options 里找到Annotation对应的 LPP,然后给不同的参数设置不同的颜色。
不过 IC61 对 annotation 颜色的支持有限,可能只能设置一个统一的颜色。如果你用的是 IC617 或更高版本,可以用annotateColor属性给每个参数单独设颜色。
5.4 定期清理不需要的 annotation
有些工程师喜欢把所有参数都显示出来,结果 schematic 上密密麻麻全是数字,根本看不清电路结构。我的建议是:只显示最关键的参数,比如 W/L。其他参数如果需要看,可以选中器件后按q查看,或者在仿真时输出到 log 文件里。
如果你发现某个 schematic 的 annotation 太乱,可以用以下命令批量清理:
foreach(inst geGetEditCellView()~>instances dbReplaceProp(inst "annotate" "string" "") )这段代码会把当前 cellview 里所有器件的 annotation 清空。然后你再根据需要重新设置。
5.5 备份你的配置
Skill 脚本和.cdsinit文件建议用 Git 管理起来。这样换电脑或者重装系统时,直接 clone 下来就能用。我见过太多人因为没备份,换了一台机器后所有配置都要重新弄,浪费半天时间。
另外,如果你在公司环境里工作,注意不要把自己的.cdsinit覆盖掉系统默认的。正确的做法是在自己的.cdsinit里用load加载项目配置,而不是直接修改系统文件。
6. 进阶技巧:用 Skill 脚本自动化 Annotation 管理
6.1 写一个交互式的 annotation 设置工具
如果你经常需要切换 annotation 的显示内容,可以写一个简单的交互式工具。比如下面这个脚本会弹出一个对话框,让你选择要显示的参数:
procedure(SetAnnotation() let((params choice) params = list("W/L" "W/L/M" "W/L/M/NF" "None") choice = hiSelectFromList("Select Annotation" params) if(choice then envSetVal("schematic" "annotate" 'string choice) hiRegTimer("schHiRedraw()" 1) ) ) )把这个脚本加载到 Virtuoso 里,然后绑定一个快捷键,比如Ctrl+A,就可以快速切换 annotation 了。
6.2 根据仿真结果自动标注
如果你想让 annotation 显示仿真得到的实际值,比如管子的 Vth 或 gm,可以写一个脚本从仿真结果里读取这些值,然后写回 instance 的 property。这个稍微复杂一点,需要用到ocnDisplay或asiGetResult等函数。但思路很简单:仿真完成后,遍历所有器件,读取它们的仿真值,然后设置对应的 annotation。
这个技巧在做 bias 电路时特别有用。你可以让每个管子的 annotation 显示它的 Vgs 和 Id,这样一眼就能看出哪个管子工作在线性区、哪个在饱和区。
6.3 用 annotation 做设计规则检查
你可以在 annotation 里显示一些关键参数,然后写一个脚本检查这些参数是否满足设计规则。比如:所有管子的 L 不能小于某个值,所有管子的 W/L 比不能超过某个范围。如果发现违规,就把对应的器件高亮显示。
这个做法比传统的 DRC 更灵活,因为你可以根据自己的设计需求定制检查规则。而且 annotation 是实时显示的,改一个参数就能立刻看到是否合规。
7. 一些容易忽略的细节
7.1 Annotation 和 Label 的区别
很多人把 annotation 和 label 搞混。简单来说:
- Annotation:显示在器件旁边的参数值,比如
1u/0.1u。它是自动生成的,不需要手动放置。 - Label:手动放置的文本标签,比如
VDD、GND、Ibias。它需要你手动创建和放置。
Annotation 是跟着器件走的,器件移动了 annotation 也跟着移动。Label 是独立的,可以放在任何位置。
7.2 Annotation 的显示层级
如果你在 schematic 里用了 hierarchy(层次化设计),annotation 的显示会遵循层次规则。默认情况下,只有最底层的器件才会显示 annotation,上层 symbol 不显示。如果你想让上层 symbol 也显示 annotation,需要在 symbol 的 property 里设置annotate属性。
7.3 不同工艺库的 annotation 差异
不同工艺库的 annotation 设置可能完全不同。比如:
- 某工艺库的 MOS 管默认显示
W/L,但另一个工艺库可能默认什么都不显示。 - 某工艺库的电阻默认显示
R,但另一个工艺库可能显示W/L。
所以换工艺库时,一定要重新检查 annotation 设置。不要以为之前的经验可以直接套用。
7.4 Annotation 对性能的影响
如果你在一个很大的 schematic 里显示大量 annotation,Virtuoso 的响应速度可能会变慢。这是因为每次重绘时都要计算和渲染这些 annotation。如果你的 schematic 有几千个器件,建议只显示最关键的 annotation,或者用Options → Display里的Fast Redraw选项来加速。
8. 最后分享几个实用技巧
第一个技巧:如果你想让 annotation 显示在器件的特定位置,比如管子的上方或下方,可以在annotate属性里加上位置信息。比如W/L@top表示显示在器件上方,W/L@bottom表示显示在下方。不过这个功能在 IC61 里支持有限,可能需要用 Skill 脚本实现。
第二个技巧:如果你想让 annotation 的字体大小可调,可以在 Display Options 里找到Annotation对应的字体设置。IC61 默认的字体可能偏小,在大的 schematic 里看不清。调大一点会舒服很多。
第三个技巧:如果你经常需要把 annotation 导出到报告里,可以用schReportAnnotation函数生成一个文本报告,里面包含所有器件的 annotation 信息。这个报告可以直接贴到设计文档里,省去手动整理的麻烦。
第四个技巧:如果你发现某个器件的 annotation 怎么都改不了,可能是它的 CDF 参数被锁定了。这时候可以试试用dbReplaceProp直接修改 instance 的 property,绕过 CDF 的限制。不过这样做可能会导致 CDF 和 instance property 不一致,需要谨慎使用。
第五个技巧:如果你在团队里工作,建议把 annotation 的设置写进设计规范文档里,包括全局设置、cellview 设置、以及特殊器件的处理方式。这样新同事入职时可以直接参考,不用从头摸索。