做混合信号验证的兄弟应该都有过这种体验:模拟工程师交付一个SPICE模型,数字验证的同学一跑就发现仿真速度慢到怀疑人生;等数字侧把UVM环境搭好了,模拟模块的行为又抽象得没法跟真实电路对得上。MSDV(Mixed-Signal Design Verification)这摊事,说到底是把“模拟世界的连续行为”和“数字世界的离散逻辑”强行揉进同一个验证流程里。我这些年从RNM建模一路做到Verilog-on-Top的混合信号验证环境,再看着模型最终落地成一份能在PR或者PCB工具里跑起来的网表,踩过的坑确实不少。这篇就把整套思路和实操路径完整捋一遍,重点讲清楚RNM抽象怎么做、Verilog-on-Top为什么是目前最务实的验证架构,以及验证模型到底怎么一步步变成能交付、能落地的网表。
这篇文章适合正在做或准备做混合信号项目的验证工程师、芯片设计工程师,也适合想搞清楚网表在数模混合流程里怎么流转的入门者。内容偏实战,从建模选型到仿真环境搭建,再到网表导出导入的具体操作,都会说透。
1. MSDV的整体思路:为什么混合信号验证需要三个台阶
1.1 传统混合信号验证卡在哪
混合信号芯片的验证困境,本质上是“效率”和“精度”的博弈。SPICE做晶体管级仿真,精度是够了,但一个带小数控振荡器、LDO、PLL、ADC的SoC,随便跑个几毫秒的带场景仿真,仿真器就要跑几天甚至几周,这对需要大量回归的数字验证来说完全不现实。反过来,如果只用纯数字模型描述模拟模块,行为又粗糙得没法覆盖电压纹波、建立时间、非线性这些模拟特性,等芯片回来才发现问题,改版成本高得吓人。
传统做法里,模拟团队和数字团队通常是各干各的:模拟侧用Spectre、APS跑电路仿真,数字侧用VCS、Xcelium跑RTL仿真,两个团队通过文档或会议对齐接口时序,验证结果很难形成闭环。时间一长,系统的集成问题往往要等到MPW回来之后在实测阶段才暴露,这在现在动辄几千万流片成本的节点上,属于风险极高的操作。
1.2 三个支点:RNM抽象、Verilog-on-Top、网表落地
我后来在实践中梳理出一条相对靠谱的路径,分三个台阶走。
第一层是RNM(Real Number Modeling)抽象。它在数字仿真器里用实数域建模的方式描述模拟模块的核心电气行为,既保留了模拟行为的关键特征,又能跑在数字仿真器的事件驱动机制上,速度比SPICE快几个数量级。
第二层是Verilog-on-Top的验证架构。整个验证环境的顶层用Verilog/SystemVerilog搭建,数字侧的标准UVM验证组件正常使用,模拟模块以RNM模型或行为级模型嵌进去,既能跑定向测试,也能跑大规模回归,覆盖率、断言、UVM sequence这些数字验证的利器全都能用上。
第三层是模型落地成网表。验证通过不等于交付完成,RNM模型只是个抽象产物,真正要交给后端或板级设计团队的是一份能跑的网表。芯片内部,数字模块综合成门级网表、模拟模块从原理图导出SPICE网表,再拼成AMS网表;到了系统级或板级,典型操作就是用OrCAD Capture导出网表、再导入Allegro做PCB设计。这一步衔接得顺不顺,直接决定模型验证的价值能不能兑现。
三个台阶缺一不可。RNM是“验得动”,Verilog-on-Top是“验得对”,网表落地是“交得出去”。
2. RNM建模:用数字仿真器的世界观表达模拟行为
2.1 RNM和Verilog-AMS、SPICE到底差在哪
很多刚接触混合信号验证的工程师会混淆RNM和Verilog-AMS。简单说,Verilog-AMS是模拟与混合信号硬件描述语言标准,它可以描述连续时间行为,需要模拟求解器支撑;而RNM是建立在Verilog/SystemVerilog体系里的实数建模方法,运行的机制是数字事件驱动。
三者的对比如下:
| 建模方式 | 运行平台 | 精度 | 仿真速度 | 适合场景 |
|---|---|---|---|---|
| SPICE/晶体管级 | Spectre、APS、HSPICE | 极高(伏安级) | 极慢 | 模拟模块内部精细验证、PVT角标分析 |
| Verilog-AMS | 混合信号仿真器 | 高(带连续时间求解) | 慢 | 模拟与数字交互较少的小规模验证 |
| RNM | 数字仿真器(VCS/Xcelium) | 中高(实数域行为) | 快数十至数百倍 | 大规模系统级混合信号验证、回归测试 |
RNM的核心类型就是wreal。wreal是一种四态逻辑的实数连线类型,能携带实数值,也能表达高阻、未知等逻辑状态。它走的是数字仿真器的时间调度机制,连续赋值和时序赋值都能用,省去了模拟求解器的开销。用RNM建模一个LDO,它不会去管内部每个晶体管怎么工作,只表达输入电压、负载电流、输出电压之间的函数关系,带一点建立时间和过冲特性,就足够支撑系统级验证了。
2.2 建模细节里面的坑:时间步长、分辨率、状态切换
RNM虽然跑在数字仿真器里,但它的时间语义和普通数字逻辑有一点本质区别:数字逻辑关心的是事件发生的那一刻,而RNM模型关心的是“这个时刻的实数取值”,因此在没有事件驱动的时刻,RNM输出默认保持上一次的值。这个机制看起来简单,实际建模时坑很多。
最典型的坑是时间分辨率问题。SystemVerilog里timeunit和timeprecision直接影响实数模型切换时刻的对齐精度。如果你在一个模块里把timeprecision设成1ns,那么模型中20.3ns时刻发生的电压跳变会被四舍五入到20ns,导致时序偏差在跨越多个模块后累积放大。我的做法是统一在验证环境顶层约定timeunit 1ns / timeprecision 1ps,所有RNM模块都继承这个精度,避免混用导致行为错位。
另一个常见坑是状态切换时的尖峰问题。建模一个比较器输出从高到低时,如果用组合逻辑直接写assign comp_out = (vin_p > vin_n) ? 1.0 : 0.0;,当两个输入电压在阈值附近抖动时,输出会产生高频振荡。这在SPICE里因为存在寄生电容和迟滞效应,实际电路不会出现这么密集的翻转,但RNM模型没有这些物理约束,数字仿真器会诚实地把每次变化都记录下来,结果就是下游数字逻辑被无意义的事件刷爆。解决办法是在模型中显式加入迟滞量或最小脉冲宽度过滤。
2.3 可以拿来即用的RNM模块模板
下面分享一个常用的带迟滞比较器的RNM模块写法,保留端口为wreal,内部用参数控制迟滞宽度和输出摆幅:
module cmp_rnm #( parameter real VTH_H = 0.8, parameter real VTH_L = 0.6, parameter real VOUT_H = 1.8, parameter real VOUT_L = 0.0 )( input wreal vin_p, input wreal vin_n, output wreal vout ); real state; real vin_diff; always @(*) begin vin_diff = vin_p - vin_n; if (vin_diff > VTH_H) begin state = VOUT_H; end else if (vin_diff < VTH_L) begin state = VOUT_L; end // 在迟滞区间内保持上一次输出状态 end assign vout = state; endmodule注意,这里always @(*)块内虽然没有显式else分支,但综合工具不会管它,仿真器的事件触发机制也足够敏感,因为vin_diff的变化会触发条件判断,两侧的比较表达式会重新求值。迟滞区间的保持状态依靠state变量未被重新赋值来达到,这正好对应了实际比较器的迟滞特性。
建模时务必坚持“为验证目标服务”的原则,不要追求模型跟SPICE波形完全一致。RNM的价值是跑得快、抓住关键行为特征,而不是替代模拟仿真。
3. Verilog-on-Top:验证环境搭建的完整实操
3.1 环境架构选型:为什么选择Verilog-on-Top
混合信号验证环境的顶层架构通常有三种:SPICE-on-Top、Verilog-on-Top、以及混合模式。SPICE-on-Top是把模拟求解器作为主仿真器,数字模块以门级或RTL形式嵌进去,这种方式数字侧回归跑不动,适合模拟验证为主的小模块验证。Verilog-on-Top则完全反过来,用数字仿真器做主导,模拟侧通过RNM或行为模型接入。第三种混合模式根据不同场景切换仿真器,工程复杂度较高,除非有专门的AMS验证平台,否则我一般不推荐在小团队里轻易尝试。
Verilog-on-Top的优势非常明确:
- 数字验证的UVM、覆盖率、断言、formal工具全部可以直接复用。
- 支持大规模并行回归,CI流程能跑起来。
- 模拟模型和数字逻辑在同一个仿真器中跑,不存在跨求解器的同步问题。
3.2 连接模拟模型与数字环境的三种方式
实际搭建Verilog-on-Top环境时,模拟模型与数字环境的连接方式决定了环境的灵活性和可维护性。
第一种是纯RNM对接。模拟模块接口全部定义为wreal类型,数字侧通过连接模块将wreal信号转换为bit或logic信号,或者反过来把数字信号的逻辑0/1转换成实数电压。这种方式的优点在于模型跑在纯数字仿真器里,速度极快,适合大规模系统验证。缺点是需要额外处理电平转换逻辑,比如1.8V域的数字输出到3.3V域模拟输入的转换关系,得手动定义好。
第二种是混合信号联合仿真,即数字环境跑在Xcelium/VCS上,模拟模块以spice网表或Verilog-AMS模型通过仿真器的混合信号接口接入。这种方式精度高,但需要配置AMS仿真流程,每个模拟模块都得做模型接口适配,跑起来也慢。
第三种是纯行为级模型加总线接口,适用于IP级别验证。比如验证一个ADC的数字控制逻辑,就用一个行为级ADC模型,配置接口用APB或者SPI,转换结果用实数输出。这种方式与RNM有重叠,但行为级模型偏系统架构层面,通常更关注时序和协议交互。
我在实际项目中采用最多的是综合方案:顶层用Verilog,模拟模块使用RNM模型完成功能验证和回归,抽出一部分关键用例在AMS仿真器里跑真实SPICE网表做精度确认,两头兼顾。
3.3 跨域断言的采样与时序对齐
Verilog-on-Top环境里最容易被忽视的环节是跨域断言。数字侧的信号是离散逻辑,模拟侧RNM输出是实数,两者直接在断言里比较时,最容易出问题的是采样时刻不对齐。
比如你想验证一个电源管理模块在负载跳变时输出电压不能跌破某个阈值,如果你用assert property (@(posedge clk) vout > 0.95);这种写法,当vout在两次时钟上升沿之间瞬间跌破阈值时,这个断言根本捕捉不到。因为断言只在采样时刻评估,错过了真正的事件窗口。这个问题在RNM模型里尤其严重,因为实数信号可以任意时刻变化,数字采样时钟却是有固定周期的。
解决思路,第一是使用$rose、$fell这类边沿敏感断言配合实数比较,但更稳妥的做法是单独在RNM模型内部做比较检查,把结果作为事件信号输出。这样既能捕捉瞬态跌落,又不会给数字断言环境增加额外复杂度。比如在模型里用一个always块实时监控vout,一旦连续跌落超过指定时间窗口,直接拉高一个fail_flag信号。
real vout_monitor; always @(*) begin if (vout < 0.95 && $realtime - last_fall_time > 5ns) begin vout_fail_flag = 1'b1; end end这种方法把模拟域的监控逻辑放在模型内部,输出到环境时已经是布尔事件,数字断言只需要关注flag是否被拉高,跨域协作清爽很多。
4. 模型落地:从RNM验证成果到一份能跑的网表
4.1 芯片级落地:数字综合网表与模拟网表的拼装
验证完成之后,更大的工程量在于“把模型翻译成后端能用的网表”。这里的网表分两条线。
数字侧,验证时用的RTL经过综合工具(Design Compiler、Genus等)映射到标准单元库,产出门级网表(.v或.vg文件),包含每个标准单元的实例化、连线关系以及时序约束信息。综合过程中,验证环境里定义的接口信号、跨模块常量、参数配置都需要与实际设计约束保持一致,任何一个参数失配都会反映在网表里变成悬空引脚或非预期连接。
模拟侧,模拟模块通常不走综合,而是从原理图工具(Cadence Virtuoso、Synopsys Custom Designer等)中直接抽取SPICE网表。抽取时要注意器件的statistics参数、寄生参数是否保留,以及层次化子电路结构是否完整。一个LDO的SPICE网表通常由顶层subckt加上内部的带隙、误差放大器、功率管等子电路构成,导出前必须确认所有子电路都包含在同一个文件内。
最后是AMS网表的拼装。数字门级网表和模拟SPICE网表通过配置文件和connect rule连接起来,在仿真器里做最终精度验证。这一步虽然和“RNM模型”已经相去甚远,但它是模型验证成果真正落到物理实现的关键一跳。RNM阶段确认的接口行为、时序关系、握手协议,会直接决定netlist里模块间怎么连接、仿真配置里需要哪些接口模型。
4.2 板级落地:OrCAD导出网表到Allegro导入手把手流程
芯片内部的网表拼装完成之后,如果芯片要上板,还有一道更接地气的网表流转流程:OrCAD(Capture)导出网表,Allegro导入网表。这也是很多工程师从芯片设计跨到系统设计时最容易卡住的地方。
第一步,原理图检查。在OrCAD Capture中导网表之前,必须先跑一遍DRC(Design Rules Check),确保原理图没有悬空引脚、引脚类型不匹配等问题。这个环节最容易出错的是电源符号的处理,VCC、VSS这类全局电源网络,在导出网表时必须确保所有电源符号的命名一致,否则Allegro导入后会出现“网络断裂”的现象。
第二步,配置封装映射文件。OrCAD导出网表到Allegro,靠的是一个配置文件allegro.cfg,这个文件要提前配置好原理图器件封装名和Allegro PCB封装库的对应关系。很多新手在这里会卡住半天,因为在Capture里器件属性上填的封装名(PCB Footprint),必须和Allegro封装库里的dra名称完全一致,一个字符都不能差。而且封装名不能含空格或特殊字符,否则导入时直接报错。
第三步,执行导出。在Capture中点击Tools -> Create Netlist,在Allegro选项卡里选中Create Allegro Netlist,输出的是pstchip.dat、pstxprt.dat、pstxnet.dat三个文件。这三个文件是Allegro导入网表的输入,包含元件信息、封装信息、网络连接信息。
第四步,Allegro导入网表。打开Allegro,选择File -> Import -> Logic,在Logic Type中选择第三方网表,选中pstchip.dat等文件所在目录,点导入。导入过程中会生成netrev.lst日志文件,凡是报ERROR的,基本都要回到原理图侧去修改再重新导出。
4.3 网表导入后的验证检查清单
导入只是起点,导入完成后必须做一系列检查,否则等板子做出来才发现问题就晚了。
- 元件位移检查:导入后所有元件会堆叠在原点附近,需要解除固定状态才能摆放,但前提是确认每个元件的封装都正确映射,特别是电阻电容这类封装有0603、0402、0805区分的器件,映射错误在摆放阶段很难发现。
- 网络完整性检查:用Allegro的Display -> Highlight功能抽查关键网络,确认电源、时钟、复位网络的连接完整,没有因为导入顺序问题导致的孤岛网络。
- 引脚交换与门交换规划:如果板上有大量BGA封装,建议在导入网表时就做好pin swap、gate swap的规划,这在allegro.cfg里可以配置允许交换的引脚组,后面布线会省很多功夫。
- DRC检查:Allegro里BRD文件就绪后,跑一遍几何DRC和布线DRC,重点检查安全间距、走线宽度、过孔规则是否满足板厂工艺要求。
这些检查项整合成表格可以这样看:
| 检查阶段 | 核心检查内容 | 常见错误 |
|---|---|---|
| 导出前 | 原理图DRC、电源网络命名、封装格式 | 悬空引脚、同名网络冲突、封装名带空格 |
| 导入中 | netrev.lst日志、封装映射 | 封装缺失、引脚类型冲突、器件属性缺失 |
| 导入后 | 元件位置、网络完整性、DRC | 元件重叠、飞线缺失、电源网络悬空 |
5. 常见问题与排查技巧实录
5.1 RNM模型仿真速度慢
RNM用数字仿真器跑,理论上应该很快,但如果你发现RNM仿真依然慢得离谱,多半是模型里写了过于频繁的事件触发。别小看这件事,RNM的速度优势在错误建模方式下会被完全抵消,跑出来的效率甚至不如简化版SPICE。
实例:我给一个Buck转换器建模时,为了追求纹波精度,把开关频率设成了2MHz,又在模型内部用64个谐波叠加的方式生成纹波,结果整个系统仿真实测速度反而比SPICE快不了多少。后来换成了固化的纹波包络模型,只在负载跳变事件点更新输出电压,仿真速度直接提升了30多倍。建模时一定要想清楚哪些细节对整个系统的验证目标是有意义的,哪些细节纯粹是自我感动。
触发频繁的根源往往是组合反馈环。一个信号发生变化,触发模型内多个always块,每个块又更新了更多信号,形成了事件风暴。排查时可以在波形里看某个内部real信号的变化次数,如果远远大于物理上可能出现的变化次数,就要怀疑模型里有组合环或者不必要的精度过度设计。
5.2 Verilog-on-Top环境里连接模拟模型的采样异常
一个常见的怪现象是:RNM模型输出的电压值明明符合预期,但数字侧采样到的逻辑值偶尔会冒出一个毛刺。排查下来发现是RNM输出的实数信号在跨越逻辑阈值时,数字侧连接模块的阈值比较产生了亚稳态时间窗。比如一个从1.8V降到0V的斜坡信号,它在降至逻辑低阈值0.6V的过程中,连接模块内部会产生一次比较事件,如果此时数字域的采样时钟正好在事件窗口内,就可能采到一个不确定的中间值。
解决办法是给连接模块增加去毛刺参数,比较结果至少要稳定一个仿真时间步长以上才允许输出变化。或者更简单,在RNM模型内部把电压输出改成携带明确状态类型的数据结构,数字侧不做电压-逻辑转换,直接读状态字段,从根源上规避跨域阈值比较的模糊性。
5.3 OrCAD导出网表时引脚类型冲突
OrCAD导出时最常见的报错就是“Pin type mismatch”或者“Invalid pin type”。大部分原因是原理图里用的器件符号中引脚类型设置和实际器件不符,比如电源引脚被默认成了Passive,但在另一个元件里又被定义成Power引脚。电源网络的连接在导出网表时对引脚类型很敏感,Power引脚可以连接到全局电源网络,而Passive引脚只能走普通连接,两者一旦混用就会报冲突。
理顺方式是把所有电源引脚统一改成Power类型,并且确保每个电源网络有且只有一个驱动源。如果板上有多个电源域,最好在原理图中用不同的电源符号区分,这样导出网表后网络名才有区分度,Allegro里也方便按电源域加约束。
5.4 Allegro导入网表后飞线缺失
导入成功后,Allegro的飞线(ratsnest)只有一部分显示出来,另外一些网络死活不亮。这个问题十有八九是导入时没有勾选“Allow User Defined Properties”,导致Allegro丢失了网络颜色和显示属性。还有可能是pstxnet.dat里网络名包含非法字符,导入时被静默跳过。
排查技巧是打开netrev.lst日志文件,搜索WARNING关键字。多数情况下日志里会明确指出“Net name contains illegal character”之类的提示。加强策略是,在OrCAD导出时统一把网络名限制在字母、数字、下划线范围内,不要使用点号、斜杠、方括号这些字符。比如命名“VCC_1P8”没问题,但“VCC[1P8]”就会埋雷。
5.5 跑混合信号回归时模型与网表结果不一致
RNM模型验证通过后,在后端网表仿真阶段偶尔会发现行为和模型预期对不上。此时不要急着怀疑数字设计改坏了,先检查RNM模型是否过度理想化。最常见的是手写握手信号宽度的理想化。比如RNM模型里把模拟模块的建立时间建模为固定10ns,但真实SPICE网表在低电压、高温角下建立时间会翻倍到22ns,数字时序约束还是按10ns去收敛,结果就是网表仿真时出现时序违例。
这种情况需要回到RNM模型,把关键时序参数按PVT角标范围建模为区间值,而不是固定值。验证环境里的断言设置就需要按最悲观值来写,确保网表实现留有足够裕量。核心原则始终是:RNM模型负责功能正确和收敛高效,网表负责物理可实现,两者之间必须在抽象层次上清晰划分边界。
6. 收尾之前:几点实操心得
这套MSDV流程做下来,最大的感触是不要一开始就追求模型的绝对精确。RNM模型能跑功能、能跑回归、能暴露系统集成的握手问题,就已经完成了90%的使命。剩下的精度问题交给AMS联合仿真去兜底,如果所有内容都想在同一层验证里做完美,最终结果通常是速度性能被拖垮、模型维护成本爆炸。
我也一直在用一个小习惯:每个RNM模型都配一个自检testbench,里面放上关键电参数的断言。这样每当验证环境有改动,回归一跑就知道哪些模拟行为发生了变化,而不是等到系统级集成时才被动排查。这个方法在多人协作的团队里尤其有效,模拟工程师改模型参数、数字工程师改接口约束,两边都能第一时间知道改动带来的全局影响。
模型落网表这件事,芯片级和板级看似隔得很远,但实际上是对同一份交付物的两种表现形式。芯片级是“模型的电气行为变成底层器件的物理连接”,板级是“原理图的逻辑连接变成PCB上的铜箔走线”。两条路径都吃透了,混合信号项目的交付链路才算真正打通。如果后续有时间,我打算再写一篇关于AMS联合仿真里connect rule配置的实战文章,那个领域同样坑点密集,值得单独梳理。