
1. 混合信号仿真的核心痛点模拟和数字各说各话谁能来翻译做了几年模拟IC或数模混合电路设计的朋友基本都会撞上同一个尴尬纯模拟的 Spectre 仿真跑得稳稳的纯数字的 Xcelium 仿真也顺顺利利可一旦把带数字控制逻辑的模拟前端、或者带模拟接口的数字模块放在同一个 testbench 里事情就开始变得拧巴。你今天想让一个 ADC 的 SAR 逻辑和比较器一起工作明天想让一个 DC-DC 的环路里混进数字补偿算法如果拿纯 SPICE 去跑那点数字门速度慢到怀疑人生拿数字仿真器去处理模拟节点它又根本不认识电压连续变化这回事。这就是 Cadence ams 仿真器真正要解决的问题——它把模拟仿真引擎和数字事件驱动引擎拼在同一个仿真框架里让模拟信号和数字信号在同一个时间轴上正常工作。你可以让一个用 Verilog 写的数字状态机去控制一个用晶体管搭出来的电荷泵也可以让一个模拟比较器的输出直接变成下游数字逻辑的时钟沿。ams 负责在两者之间搭桥把连续时间、连续电平的模拟信号翻译成离散时间、离散电平的数字信号再反向翻译回来。整个过程里你不需要自己手工建模接口电路也不用把数字逻辑硬掰成 SPICE 网表。对做混合信号电路的人来说这个东西解决的不只是能不能跑的问题而是跑得准不准、快不快的问题。纯模拟网表跑一个带数字校准环路的 PLL 或者 SAR ADC收敛到天荒地老都是常态纯数字仿真又没法评估模拟部分的噪声、失调、建立时间这些真实物理特性。ams 这种联合仿真方式让你可以在同一个环境里同时看到模拟域的瞬态行为和数字域的时序行为调试的时候直接在 Virtuoso 波形窗口里看数模交界处的信号是怎么衔接的比来回切两个工具、对两遍波形要省心太多。这篇文章主要围绕 Cadence ams 仿真器对混合信号电路进行仿真的完整链路来写从工程搭建、connect rule 配置、瞬态仿真设置到常见的仿真不收敛、器件未定义、波形异常这类扎手问题的排查思路再到工程实践中怎么让大型混合信号电路跑得又快又稳。内容基于我自己在多个混合信号项目里的实测经验适合刚接触 ams 的设计工程师也适合被几个疑难报错卡了很久、想换个排查思路的老手。2. 工程搭建阶段最容易忽略的地基问题很多人跑 ams 仿真上来就打开 Virtuoso 画 testbench画完直接 New Simulation 选 AMS结果一堆匪夷所思的报错找不到仿真器、顶层视图冲突、数字库起不来、connect rule 不生效。这些问题的根源基本都在工程搭建这一步埋下了。2.1 顶层视图别用 schematic用 config 视图这里先明确一个概念在 Cadence 环境里做混合信号仿真顶层一定不是一个普通的 schematic 视图而是一个 config 视图。config 视图做的事情是把整个设计里每一个 instance 所对应的仿真视图给编排好——模拟模块用 schematic 还是 extracted 视图跑数字模块用 Verilog netlist 还是行为级描述都在 config 里统一指定。新建 config 视图的操作不复杂在顶层 cell 上 Create Cellview From Cellview或者直接用 Hierarchy Editor 打开然后 Library 选好、View 选 config之后会弹出一个对话框仿真的类型要选 AMS而不是 Spectre 或者 Xcelium 单独跑的那种。选完之后Hierarchy Editor 里会把整个顶层列出来你要逐行检查每一个 instance 的 View 列模拟模块对应的是 schematic数字模块对应的应该是一个支持数字仿真的视图名比如 functional 或者 Verilog。这个步骤很关键因为如果你在顶层直接放了一个数字模块而它的 View 列写的是 schematicams 会尝试用模拟引擎去解释 Verilog 的行为——大概率直接报错或者仿真结果完全不对。我曾经在做一个带数字校正的流水线 ADC 时顶层有一个很大的数字校准模块工程师建完 config 之后没检查 View 列直接开跑结果仿真器报了一堆类似unknown module type的错。后来把那个数字模块的 View 列改成 functional 才正常但中间排查浪费了大半天。所以 config 视图建好之后别急着跑花两分钟把每个 instance 的仿真视图检查一遍省下来的时间远超这两分钟。2.2 connect rule数值模拟与数字逻辑之间的翻译规则另一个容易在工程搭建阶段被忽略、但直接影响仿真正确性的是 connect rule。混合信号仿真里模拟信号和数字信号碰面时不能直接硬接需要一个中间模块做信号翻译——模拟域的电压值变成数字域的二值逻辑数字域的 0/1 变成模拟域的电压摆幅。这个翻译不是随便定一个阈值就行它包含一系列规则高电平检测阈值是多少、低电平检测阈值是多少、上升沿之后信号要稳定多少时间才认为是有效电平、从数字域返回模拟域时驱动能力怎么模拟。Cadence 自带的 connect rule 里会预置几套常用配置比如connect_rules里会有针对cmos电平的一套规则也有更精细的eEn之类的用于不同电域匹配的规则。你需要在仿真设置里显式指定使用哪一套 connect rule否则 ams 很可能默认不插入任何翻译模块最后数字输出直接对接模拟节点波形乱七八糟信号看起来像悬空一样。选择 connect rule 的原则很简单数字部分的供电域是多少伏就选对应电平的规则。3.3V 的数字逻辑和 1.8V 的数字逻辑阈值标准差很多如果规则选错可能模拟输出 2.5V 的时候数字端已经判定为高电平了甚至可能出现亚稳态误判。尤其在一个芯片里同时存在多个电压域的时候你要给不同的接口分别指定不同的 connect rule。这个工作在 config 视图或者 AMS 仿真设置界面的 Connect Rules 标签里完成是一个多对多的映射关系做的时候要有点耐心。2.3 库的加载顺序和数字 view 引用路径混合信号仿真比纯模拟仿真多出一个数字仿真引擎所以启动仿真时数字库的加载路径是否完整直接影响你能不能跑起来。当年 Cadence 的 AMS 仿真器在启动时会去读cds.lib和hdl.var这两个文件里定义了数字库的位置和仿真器要用到的语言标准。如果你在做一个项目时发现纯模拟跑得好好的电路加上数字模块之后报library not found十有八九是当前启动目录下的cds.lib没有把数字库的路径包含进去。这种问题在多人协作的大型项目里特别常见——模拟工程师的启动环境只配置了模拟库路径数字工程师的启动环境只配了数字库路径到了混合信号联调阶段谁都没想起来要把两边的库路径合到一起。处理方法也简单在仿真启动目录的cds.lib里把数字库所在的路径一行行加进去或者在软件界面里选 Include 对应的库文件。加了之后记得验证一下数字模块的 view 能正常打开否则到了仿真关键时刻再报找不到模块心态真的会崩。3. 实操链路拆解从 testbench 搭建到波形输出当你把 config 和 connect rule 这些地基问题理顺之后真正开始跑仿真的链路其实并不复杂但每一步都有需要注意的细节。这一节我把完整的操作路径拆开讲适合还没有完整跑通过一次 ams 仿真的朋友逐步对照。3.1 testbench 的搭建方式与激励设置混合信号仿真的测试平台比较推荐的搭建方式仍然是图形化的 schematic testbench而不是网表。原因在于模拟部分需要的激励源——比如斜坡信号、正弦波、带有特定噪声特性的信号——用 AnalogLib 里的vsource、isource来搭非常直观波形参数直接在 CDF 里改就行。数字部分的激励你可以用数字 pin 直接给电平也可以用 Verilog 写一个小的 stimulus 模块把时钟和复位这些基础信号用initial块或者always块来产生。不过有一点要提醒在同一个 testbench 里同时存在模拟激励源和数字激励源的时候要注意它们之间不要直接相连。模拟 source 的输出节点如果接到数字模块的输入端口中间必须经过一个ahdl2dig或者由 connect rule 自动插入的转换模块。同理数字模块的输出也不能直接驱动模拟晶体管的栅极中间需要一个dig2ahdl的转换。这些转换模块通常是由仿真器自动插入的但前提是你在仿真设置里把 connect rule 配好并且没有用一些特殊的端口类型把自动插入机制避开了。我自己习惯的做法是模拟激励源尽量用vsin或者vpulse这种 AnalogLib 的标准源数字激励用 Verilog 写在单独的tb_stimulus.v文件里通过 config 视图把它挂到 testbench 下的一个数字 instance 上。这样分离管理调试的时候想改激励模拟部分直接改 CDF 参数数字部分直接改 Verilog 代码互不干扰比混在一起写要清爽很多。3.2 AMS 仿真设置面板的关键选项在 Virtuoso 里启动 AMS 仿真进入仿真设置面板之后你会看到一大堆选项。这里不用每个都搞懂但几个关键的必须认识清楚Analysis 标签页混合信号仿真用的最多的还是tran也就是瞬态分析。AMS 的 tran 分析和 Spectre 的 tran 不太一样它不仅要设置仿真时长和精度还要为数字引擎指定一个时间分辨率time resolution和数字部分的默认步长。我一般把精度设成跟模拟部分需要的精度一致但数字引擎的时间分辨率可以稍微放宽一点这样仿真速度快一些又不影响数字逻辑的功能验证。如果你的电路里有高频数字时钟记得把数字引擎的时间分辨率设得足够小至少要比时钟周期的 1/100 还小否则数字部分的事件会丢失。Environment 标签页这里要关注的是switch view list。在 AMS 仿真里这个列表决定了一个 instance 优先用哪个视图来仿真。典型的设置是把ams放在最前面然后是schematic、functional、Verilog等。如果你希望某个数字模块用行为级的 Verilog 视图而不用原理图就在这个列表里把对应模块的视图优先级配置好。我遇到过一个案例工程师在 config 里已经把数字模块选成了 functional但 switch view list 里没有把 functional 加进去结果仿真器还是去找 schematic报了找不到视图的错。Connect Rules 标签页这个前面已经提过是混合信号仿真的关键配置。除了选择规则集还要注意 rule 里定义的 supply 电压值是否和你电路里的实际电压一致。比如你的数字逻辑供电是 1.8V但 connect rule 里的默认高低电平阈值是按 3.3V 算的数字输出的高电平就会被错误地映射成 3.3V 摆幅驱动模拟电路时会导致工作点完全错误。这种问题特别隐蔽因为波形看起来很正常只是幅值不对很容易被误判成电路本身的问题。3.3 初始化状态和电源上电顺序混合信号电路和纯模拟电路有一个显著区别数字部分有寄存器、状态机上电默认状态可能不确定。所以在瞬态仿真里你必须在仿真开始的一小段内把复位信号拉起来让数字逻辑进入到已知状态然后再开始看模拟部分跟数字逻辑交互的状态。这一点看起来简单但很多人跑混合信号仿真会踩到类似的坑复位信号没加或者复位时间不够长状态机进入了一个非法状态整个仿真跑出来的波形奇奇怪怪最后排查半天发现就是复位的时序问题。另外如果电路里有多个电源域上电顺序也要在仿真里体现出来。某些工艺下数字域必须先于模拟域上电否则接口处的 ESD 结构会异常导通仿真波形就会乱七八糟。上电顺序可以写在 Verilog 的initial块里也可以用多个vsource配合延迟参数来模拟。3.4 仿真完成之后的波形检查重点跑完仿真之后在 Virtuoso 的 Visualization Analysis 窗口里把关心的节点都拉出来看看。这里要注意的是数模接口处的信号波形有两种观察方式一种是看模拟域节点的连续电压波形一种是看数字域节点的逻辑电平。如果 connect rule 配置正确这两个观察方式看到的信息应该是对应的——数字节点为高电平时模拟节点上应该稳定在高电平对应的电压值附近。检查波形的重点放在接口处模拟信号进入数字逻辑之后电平翻转的阈值、延时是否符合预期数字信号输出到模拟电路之后驱动能力是否足够上冲下冲是否在可接受范围内。如果发现接口处波形有毛刺、反复震荡多半是 connect rule 里的 hysteresis迟滞设置太小导致数字输入在阈值附近抖动。把阈值迟滞加大一点这类问题通常会缓解。4. 实际项目中躲不开的疑难杂症报错、发散、波形异常跑混合信号仿真报错和波形异常是家常便饭。这一节专门讲我在实际项目里遇到次数最多的几个问题以及完整的排查链路。每个问题都给排查思路而不只是结论这样下次遇到类似状况你知道从哪儿下手。4.1 仿真报器件未定义别急着怀疑电路网表器件未定义这类报错集中出现在两种场景一是你启动仿真的目录环境不完整二是 connect rule 或者某个数字库里的模型绑定出了问题。第一种场景很容易识别报错信息里会明确指出找不到某个库或者某个 view。排查链路是先看报错信息里的库名是否存在于当前cds.lib的搜索路径里如果库里确实有看是不是被 exclude 了如果库是有的看 view name 是不是对得上比如你调用的是一个functional视图但库里只建了schematic肯定报未定义。第二种场景更隐蔽——报错信息可能提示的是某个标准单元或者某个门级模型未定义。这种情况常见于数字模块使用了某个工艺库的门级网表在启动 AMS 仿真时数字引擎需要加载这个工艺库的行为模型而这个模型往往不是 Cadence 自带的标准库需要你用-v或-y参数指定加载。如果这个参数没配置仿真器会直接告诉你某个模块找不到然后终止。排查链路是分析报错的模块名是哪个标准单元去对应的数字工艺库目录下确认是否存在对应的 Verilog 模型文件再看仿真设置里是否正确包含。我在一个项目里遇到过整个数字模块都是行为级 Verilog但顶层里某个子模块的写法生成了一个HDL模型引用而那个文件在项目仓库里已经改名了结果 ams 启动仿真时找了半天不对应的文件最后报了一连串的未定义错误。查清楚之后改了路径名问题迎刃而解。所以遇到这种报错先不急着怀疑自己电路有问题检查环境和库路径比反复审视电路更高效。4.2 瞬态仿真的发散和不收敛先从步长和初始条件下手混合信号仿真里最常见的仿真发散通常不是真的算法不收敛而是某些关键参数设置不合理。在 ams 仿真的 tran 分析里最容易出问题的参数是模拟部分的最大步长和数字部分的事件分辨率。步长设得太大仿真器会跳过一个关键的事件或快速变化的模拟信号步长设得太小仿真时间爆炸式增长甚至在一些强非线性电路里出现局部震荡。排查链路我建议这样走第一步先把模拟部分的时间步长收紧比默认值小一个数量级试试看发散点是否发生变化。如果变化了说明是步长导致的问题。第二步检查电路的初始条件。混合信号电路里有电容、电感这类储能元件也有数字寄存器的初始状态。如果初始条件设置得和稳态工作点相差太远仿真开始后系统会经历一个剧烈的暂态过程很容易发散。第三步检查是否有正反馈环路在仿真里形成了振荡。数字输出经由 connect module 转成模拟电压再反馈回模拟电路这个路径如果延时设置太小或者没有迟滞很容易自我振荡。可以在 connect rule 里给反馈路径加入适当的延时通常能压住这种振荡。还有一个容易忽略的点connect rule 中数字转模拟的转换速度设置。从数字域切到模拟域时转换模块不仅要把逻辑电平映射成电压还要模拟一个有限的驱动能力也就是输出电压转换有一个 slew rate。如果这个 slew rate 设置得非常大对于模拟电路来说相当于一个快速上升沿可能会激起某些寄生效应导致振荡。把 slew rate 调到一个合理的、接近真实工艺的水平很多莫名的发散问题就消失了。4.3 波形红线、悬空感问题多半在接口状态仿真结束后拉波形发现某根信号线是红线表示信号是 X 态或者未驱动或者明明应该有时钟却平得像一条直线这往往不是波形查看器的问题而是混合信号接口没有正确连接或者 connect module 根本没有插入。排查链路第一步回到 config 视图检查该信号所连接的两个 instance 的仿真视图类型。如果一端是模拟模块的 schematic 输出另一端是数字模块的 Verilog 输入那接口处应该有一个 connect module。想确认它有没有插入可以在仿真日志里搜索 connect module 相关的提示。第二步检查该信号在数字模块端口的类型声明。如果数字模块的端口声明成了output reg但实际没有驱动或者声明成了inout但驱动逻辑没有写就会看到红线。第三步如果是模拟信号输入到数字模块的内部节点检查有没有通过一个明显的电平检测环节——数字模块的输入端口默认接收的是逻辑电平如果你把模拟波形直接接到一个数字端口上但 connect rule 里对这种 float 模拟信号的处理策略没有配置好也容易出现 X 态。我遇到过一次很刁钻的情况一个模拟比较器的输出端直接接到了数字模块的时钟输入仿真跑下来数字模块完全没反应。检查半天发现是那个比较器输出在高阻状态的时候数字输入悬空connect module 对悬空输入的处理策略默认是 X而数字模块的时钟输入检测到 X 就不翻转。后来在比较器输出端加了一个弱下拉电阻把悬空态拉到一个确定的电平问题立刻解决。这种问题在设计 real chip 的时候几乎不会暴露因为还有 ESD 二极管拉着但仿真环境里没有这些寄生器件就全靠你手工处理了。5. 让大型混合信号电路跑得又快又稳的实用策略当电路规模变大、仿真时长拉长之后你会发现真正决定项目进度的不是仿真能不能跑而是仿真跑完要多久。一个带数字校准的 PLL 或者一个全数字控制的电源管理芯片如果用最严格的精度去跑一次瞬态仿真可能几小时起步。这一节分享几个我自己实践下来真实有效的提速策略同时兼顾普通工程师通常不会注意到的细节。5.1 数字部分绝不都用晶体管级视图仿真这是混合信号仿真提速的第一法则数字模块该用 RTL 或行为级视图的绝不拉到晶体管级。很多模拟工程师手里拿到的数字模块网表有 Verilog 门级模型也有 SPICE 网表习惯上会把所有模块都设成 schematic 视图觉得这样保证精度。但实际上门级 Verilog 模型和晶体管级 SPICE 模型在功能上是等价的而仿真速度差距是数量级的。只在必须做数模接口时序精调的时候才把关键的数字路径保留在晶体管级或者高精度的模拟视图其余部分统一用行为级 Verilog 跑。我自己常用的做法是整个系统仿真阶段数字部分全部用 RTL 行为级只有当系统仿真找到一个问题点、需要精确定位到底是哪一段数字路径时序出问题的时候才会把数字模块切换到门级网表视图重新跑。这样既保证了调试速度又不会在最终环节被不精确的模型误导。5.2 仿真精度按区域动态配置ams 仿真器允许你针对不同的电路区域设置不同的仿真精度。比如模拟核心部分需要高精度的连续时间求解而一个纯数字的 SPI 接口模块就完全可以用更大的时间步长来跑。这种按区域配置精度的方式可以把仿真总时长压缩一半以上。具体操作上你可以在 config 视图里选择修改某个模块的仿真精度属性或者用 ams 的 simulation resource 相关配置把一个模块指定为低精度或高精度。需要注意精度切换的地方正好是数模接口的话要特别小心。比如一个数字模块的输出经过 connect module 变成模拟电压这个电压本身又会驱动一个高精度的模拟模块那么数字模块即使跑低精度它的输出转换到模拟域时也要确保时间分辨率足够否则模拟部分会因为输入信号跳变太粗而产生错误的瞬态响应。5.3 分段验证策略别等整个芯片全部收敛了再开始看波形混合信号电路一个很大的风险点是验证发现问题的时间点往往很晚。一个全芯片级的数模混合联合仿真从设计稳定到跑通可能要好几天如果这个时候才暴露出一个接口逻辑错误修复成本极高。所以我强烈建议采用分段验证策略。分段方式可以按功能子电路来切先把模拟核心和它的数字控制逻辑单独拿出来搭一个小 testbench 跑通确认这个子系统的模拟控制和数字状态切换是匹配的然后再把各个子系统拼接起来做整体联调。这个策略的价值在于它把混合信号仿真最容易出的那类问题——接口不匹配、状态机转换和模拟建立时间对不上——控制在子系统阶段就暴露出来等你做全芯片联合仿真的时候剩下的主要是各子系统之间的交互问题排查范围小很多。在分段验证时建议始终保持同一个 testbench 架构模拟激励源用 AnalogLib数字激励用 Verilog 文件connect rule 用同一套。这个习惯带来的好处是当你从子系统仿真正式过渡到全芯片仿真时不需要重新调一大堆配置只需要更新 config 视图里的顶层单元名其余设置可以直接复用省时省力也少了一个出错环节。5.4 关于 connect rule 参数的一些实操心得最后聊一点 connect rule 参数调优的心得这部分属于常规文档里不会细讲、但实战中能显著影响仿真结果的内容。**第一个心得阈值迟滞hysteresis不要设成 0。**很多人在做数字输入阈值设定时觉得阈值就是一个固定的电压点高于它就算高电平低于它就算低电平。但实际上如果阈值没有迟滞任何微小的噪声都有可能在阈值附近引起反复翻转在仿真里表现为数字信号上的毛刺甚至导致状态机误触发。我一般建议迟滞设成阈值的 5%~10%既能有效抑制噪声又不影响正常的速度。不过要注意如果电路里本身设计的比较器就自带迟滞那 connect module 里的迟滞就不要再叠加太多了否则接口的门限会变得过于迟钝影响时序判断。**第二个心得数字转模拟的 slew rate 要根据负载来设。**connect module 转出来的模拟电压从 0 到 VDD 的爬升速度不是无穷快它由 rule 里的 slew rate 参数决定。这个参数如果设得太快驱动大电容负载时模拟节点会出现虚高的尖峰如果设得太慢下游模拟电路可能还没完成阈值翻转数字逻辑已经进入下一个状态了。我通常结合 testbench 里实际的负载电容值估算一个合理的 slew rate再在仿真里验证。估算公式很简单slew rate 约等于数字输出的驱动电流除以负载电容。比如驱动电流 1mA负载电容 1pF那么 slew rate 就是 1V/ns设成这个量级比较合理。**第三个心得多个电压域同时存在时connect rule 的电压参数映射一定要逐一核对。**现代混合信号芯片上1.8V、2.5V、3.3V 甚至 5V 的电压域可能同时存在。connect rule 里对每一组 voltage domain 都定义了高低电平阈值和输出驱动电压如果一个 3.3V 的数字输出模块没有按 3.3V 域去映射connect module 用错误的电压参数去转换信号下游模拟电路看到的就是一个幅值错误的驱动。这种问题在波形上很隐蔽因为接口看起来是有信号的只是幅值差一点。多电压域的连接规则配置建议做成一张表格把每个接口对应的 voltage domain 写清楚放在项目文档里方便后续 review 和多人协作时统一。写在最后的经验使用 Cadence ams 仿真器做混合信号电路仿真这件事本身并不复杂很多困扰新手的问题是环境配置和仿真设置层面的而不是电路原理层面的。把 config 视图、connect rule、库路径这些地基打好再熟悉一下瞬态仿真里步长和初始条件的调参逻辑大部分常规混合信号电路的仿真都能顺顺当当跑完。真正花时间的地方往往在那些看起来能跑但结果不对的疑难场景里这时候耐心按接口信号链路的走向一步步排查比不断重跑仿真有效得多。最后分享一个小技巧每次启动一个混合信号项目的联合仿真前先拿一个最小规模的 testbench 把链路跑通——一个模拟 buffer 和一个数字反相器接在一起看看 connect module 是否按要求插入了信号转换是否符合预期。把它当作混合信号仿真的上电自检花不了十分钟但能帮你确认整个环境配置是否健康之后再做正式的大规模仿真时你会少踩非常多莫名其妙的坑。