混合信号验证实战:从RNM建模到Verilog-on-Top网表仿真的完整指南
说来惭愧我在混合信号验证这条路上交过不少学费。最开始接触混合信号验证时我天真地以为只要把模拟模块打包成一个黑盒写好数字Testbench再拖上SPICE跑一遍就能完事。结果第一次回归就把仿真时间跑到了三天三夜还没跑完一个用例。后来被前辈点醒才明白真正的混合信号验证不是把两个世界硬怼在一起而是要在抽象层次和精度需求之间找到那个平衡点。这篇东西我想用一次实际的RNM建模、Verilog-on-Top环境搭建到最终落到网表仿真验证的经历来聊聊这条路上必须搞清楚的思路、工具和坑。这套方法论适合所有做数模混合芯片验证的工程师无论你是在做ADC、PLL、PMIC还是Sensor接口只要你的项目里同时存在数字逻辑和模拟电路这篇文章都值得你花十分钟看完。它的价值在于不是教你背一条命令而是让你理解为什么选RNM、为什么用Verilog-on-Top、以及模型和网表之间那条最后一段路到底该怎么走。1. 混合信号验证到底在验证什么1.1 从一颗芯片的两种脸说起一颗数模混合芯片比如一个带SAR ADC的SoC本质上同时生活在两个世界里。数字世界看的是0和1讲究的是时序、状态机、协议模拟世界看的是电压、电流、噪声讲究的是精度、带宽、噪声底。最麻烦的是这两个世界在芯片上不是割裂的——数字电路要控制模拟前端模拟前端要把结果喂给数字后端。一旦放到真实硅片上任何一方的非理想特性都会传递到另一方。混合信号验证要做的就是在仿真环境里提前验证数字模拟协同工作的行为。这件事难在哪难在一个仿真器很难同时高效地模拟两个世界。SPICE类仿真器对模拟电路精度高但跑数字逻辑慢得离谱我在一个PLL项目里用晶体管级网表跑了1ms仿真时间整整花了36个小时。反过来Verilog的数字仿真器跑逻辑飞快但压根不认识模拟电路里的电阻、电容、差分对。于是就有了抽象层次的概念在架构级验证时用行为模型在模块级验证时用晶体管或网表在SoC级验证时用RNM。每一层抽象都对应不同的速度和精度取舍。RNM之所以能在混合信号验证里站稳脚跟是因为它提供了一个中间地带——用数字仿真器的速度去逼近模拟信号的连续行为。1.2 全SPICE仿真为什么跑不动我见过太多团队一上来就全SPICE仿真的场景。不是说全SPICE不行而是你得算笔账。比如一个带数字校准的16位SAR ADC模拟部分可能就几百个晶体管但校准逻辑、控制时序、寄存器状态机加起来几万门。如果你把这段模拟前端和数字后端一起丢进SPICE里跑整个数字部分会被转换成一个巨大的非线性方程组每个时钟周期都要迭代求解。举个例子一个10MHz的校准时钟SPICE仿真跑1ms需要10000个时钟周期。每个周期里数字逻辑的每个节点都要做牛顿-拉夫森迭代假设有10万个数字节点每次迭代涉及大规模矩阵运算这算力开销你感受一下。结果是一个本应在几分钟内跑完的数字验证用例被拖成了几天的SPICE仿真任务而且中途还容易出现不收敛、时间步进过小等问题。RNM的出发点恰恰是避开这个泥潭。它把模拟信号的连续值用一个实数变量来表示而不是用晶体管级节点电位。仿真器的数字引擎处理实数变量速度比处理模拟节点快几个数量级同时又能表达出模拟信号会慢慢爬升带有纹波受负载影响下降变缓这类连续行为。这是全数字仿真做不到的也是全SPICE仿真跑不动的空间。1.3 RNM、Verilog-on-Top、网表三者如何串起来很多人对这三个概念的关系是模糊的。我自己的理解是RNM是建模方法论Verilog-on-Top是环境架构网表是落地验证的最终形式。三者不是竞争关系而是一条流水线上的不同阶段。RNM负责解决模拟信号怎么用数字语言描述的问题。它不关心晶体管长什么样只关心信号的数值、方向、负载效应。Verilog-on-Top负责解决验证环境怎么组织的问题它把整个芯片的顶层用Verilog写出来模拟模块以RNM模型或行为模型的身份参与仿真这样整个环境就能跑在数字仿真器上。网表则是最终的真相——当你的RNM模型通过了系统级验证模拟模块的真身晶体管级网表必须替代模型再跑一遍确认模型和现实之间的差距没有大到让系统失效。我用一句话总结这套流程先用RNM把模拟模块变成能跑的数字演员用Verilog-on-Top把整台戏搭起来最后请出真正的模拟网表来彩排上市。2. RNM抽象让模拟信号在数字世界里活起来2.1 RNM的本质实数信号 vs 逻辑信号RNMReal Number Modeling最简单的说法就是用SystemVerilog的real类型变量来表征模拟信号。传统数字信号只有0、1、X、Z四个逻辑值但real类型可以表示1.234V、0.876V这种任意精度的电压值。这还不够RNM还支持带方向的连续驱动、电阻分压效应、甚至复杂的分段线性行为。举个例子一个LDO的输出电压在传统Verilog里你可能只能写成高电平或者低电平但真实LDO是一个渐进的、带纹波的、受负载影响的曲线。如果数字仿真器里只有一个1/0那下游的ADC采样逻辑可能根本测不到电源纹波对采样精度的影响。RNM就能表达出来// LDO输出行为的简化RNM模型 module ldo_rnm #( parameter real V_NOMINAL 1.8, parameter real V_RIPPLE 0.02 )( output wreal vout, input wreal vin, input wreal load_current ); real vout_value; always (vin or load_current) begin vout_value V_NOMINAL - V_RIPPLE * load_current / 0.05; vout vout_value; end endmodule这段代码里vout的每个赋值都可能是一个连续电压值而且驱动关系里带上了负载电流对电压的影啊这在纯逻辑仿真里是无法表达的。RNM的另一个关键点是驱动强度和决议。一个net上可能有多个驱动源比如LDO的输出节点同时被LDO模型和外部电容模型驱动。RNM需要定义决议函数来决定最终电压。SystemVerilog里wreal类型的变量如果没有指定决议函数按默认规则是最后赋值获胜这在多个always块竞争时就会出问题。所以我建议在项目一开始就定义一套标准的resolution function。2.2 wreal和两个wreal多驱动怎么办我实际用的最多的是wreal类型。单驱动场景下够用但混合信号验证里大量场景是多驱动的——一个节点既有内部驱动又有外部负载注入甚至测试bench里还可能欠一个激励源。这时候单wreal就不够了。SystemVerilog支持wire wreal多驱动决议需要你自己写决议函数。决议函数的规定是这样的系统会收集net上所有驱动的值然后调用你定义的function返回一个最终值。比如在一个电流求和节点上三个模块各自贡献一个电压值决议函数要决定最终节点电压是取平均、取最大值还是按某种权重合并。我常用的是一个带优先级的决议函数function real resolve_vout(input real driver[]); real max_val; int i; max_val driver[0]; for (i 1; i driver.size(); i) begin if (driver[i] max_val) max_val driver[i]; // 取最大值 end return max_val; endfunction这种决策必须写在验证计划里不能到了DUT对接时才发现两个模型的决议行为不一致。否则等你在网表阶段发现电压值不对再回头查模型代价就大了。2.3 连接模块与决议函数模拟到数字的桥梁RNM模型再高级最终要跟普通数字信号对接。在SystemVerilog的MSMixed Signal仿真环境里这个对接通过connect module完成。connect module负责把wreal电压值转成logic值或者把logic值转成wreal电压值。connectmodule wreal_to_logic(input wreal a, output logic b); assign b (a 0.5) ? 1b1 : 1b0; endconnectmodule这个看似简单的东西实际工程里坑不少。最常见的问题是connect module的实例化方向以及多个connect module之间的耦合。比如一个外部引脚既作为输入又作为输出它既需要从wreal转logic也需要反向从logic转wreal。这时候connect module的方向设置必须和net的方向约束一致否则仿真器会报方向冲突或者结果完全不对。我一般会在环境里建一个统一的connect module库明确规定每个引脚的方向和阈值电压。阈值电压的选择也很有讲究数字逻辑要把一个模拟电压判断为0还是1这个阈值不能随意设要看芯片内部定的是TTL门限还是CMOS门限通常用0.5*VDD作为门限最稳。2.4 RNM精度控制的几个坑RNM的第一个坑是精度丢失。有些工程师把real类型当浮点数到处用但RNM模型的精度最终也取决于你仿真的时间步长以及你用的仿真器对实数运算的处理方式。如果在RNM里做非常灵敏的时序比较比如两个边沿到达时间的差在皮秒级而仿真器的精度只到纳秒级那结果就是不稳定的。第二个坑是实数信号的初始值。real类型在仿真启动时往往默认是0但很多模拟信号在复位状态并不是0。比如一个振荡器的输出在复位阶段也可能是VDD/2的共模电平。如果RNM模型的initial块不把信号驱动到正确初值后面所有依赖该信号的判断都会跑偏。我在几个项目里都会强制给所有wreal信号在initial块里赋初值。第三个坑是RNM模型和SPICE网表混仿时的接口不匹配。RNM模型工作在数字引擎里网表工作在模拟引擎里连接处的精度、步长、事件传递都要精心配置。很多仿真器有专门的计算引擎接口设置不要贸然用默认参数。3. Verilog-on-Top以数字为主体的验证环境搭建3.1 SPICE-on-Top vs Verilog-on-Top为什么选后者搭建混合信号验证环境顶层文件的选择直接决定了整个仿真的运行机制和使用体验。两种主流方案SPICE-on-Top和Verilog-on-Top。SPICE-on-Top把整个token用SPICE网表包起来模拟模块是网表数字模块通过数字子电路或行为源接入。它的好处是模拟视角更真实模拟模块之间的连接完全按电路方式处理但劣势也明显顶层是个SPICE文件你得用模拟仿真器去跑数字部分同样被模拟引擎拖累速度上不去。Verilog-on-Top反过来顶层是纯Verilog模拟模块用RNM模型表示数字模块用RTL或门级网表。整个仿真由数字仿真器主导模拟行为模型只是演员。这种方式最大的价值是速度。我在一个电源管理芯片项目里同样的回归用例SPICE-on-Top需要40分钟Verilog-on-Top只需要5分钟而且后者还能跑更多场景。所以我的倾向很明确能用Verilog-on-Top解决的问题就不要上SPICE-on-Top。除非你在验证模拟模块自身的行为特性否则系统级、功能级验证都应该以数字顶层为主。3.2 顶层怎么搭数字DUT、模拟行为模型、接口Verilog-on-Top环境里的顶层模块一般长这样module chip_tb_top; // 时钟和复位 logic clk, rst_n; // 数字侧接口 logic [7:0] config_data; logic [1:0] mode_sel; // 模拟侧接口用wreal类型 wreal vout_ldo; wreal vref; wreal vout_amp; // 时钟生成 always #5 clk ~clk; // 模拟模块的RNM模型实例 ldo_rnm u_ldo ( .vin (vdd_supply), .load_current (load_est), .vout (vout_ldo) ); // 数字DUT实例 digital_core u_dig ( .clk (clk), .rst_n (rst_n), .config_data (config_data), .mode_sel (mode_sel), .vout_monitor (vout_sampled) // 这个信号来自connect module转换 ); endmodule从这段代码里能看到几个关键点模拟模块的接口全是wreal类型数字DUT的接口是logic类型而两个模块之间通过connect module自动转换信号类型。数字DUT看到的vout_sampled是一个logic信号实际上它的值来自RNM模型的wreal输出经过阈值判断后的结果。如果你是第一次搭这个环境我建议先把接口信号列一张表格明确每个信号的类型、方向、连接的模块然后照着表格写顶层避免后面排错时对着连线发懵。3.3 激励与断言把模拟指标变成可检查的断言Verilog-on-Top的好处不仅是速度快还在于你能利用SystemVerilog强大的断言机制来检查模拟行为。传统SPICE仿真里检测一个电压是否稳定在1.8V附近你得写一堆measure语句然后人工翻波形。但在Verilog-on-Top里你可以直接写一条SVA断言property p_ldo_settle; (posedge en_ldo) ##[1:100] $rose(vout_ldo V_NOMINAL * 0.95) (vout_ldo V_NOMINAL * 1.05); endproperty assert property (p_ldo_settle) else $error(LDO未在100个时钟周期内稳定);为了能在断言里比较wreal值你可能需要先把wreal转成实数变量再比较。有些仿真器支持直接在断言里比较wreal但为了兼容性我更倾向在环境里预留一个专门取实时电压值的函数。断言的价值在于把模拟指标变成自动化可检查的标准。以前你要打开波形、量电压、对比规格书现在断言帮你干了这件事。在回归测试里断言失败会自动标记用例失败这样大规模跑回归时就能快速定位问题。3.4 回归测试怎么组织Verilog-on-Top环境跑回归最大的优势是速度快但要注意回归策略。我的经验是分三层第一层全RNM模型跑回归。每个模拟模块都是行为模型仿真速度最快跑所有数字逻辑功能用例覆盖控制逻辑、寄存器、协议流程。这一层的目的不是验证模拟精度而是确保数字逻辑没有接错线、状态机没有死锁。第二层关键模拟模块换成晶体管级网表其他保持RNM。这种混仿模式适合验证模拟模块和数字逻辑的接口时序。比如ADC模块用真实网表其他都用RNM模型检查采样时序和数据输出是否正常。第三层全网表回归。在tape-out前跑把所有RNM模型替成真实网表验证最后的系统行为。这层跑得慢但它是木已成舟前的最后验证。这三层回归各有分工千万别拿第三层当第一层用否则效率会低到让人崩溃。4. 从RNM模型到网表落地成一份能跑的网表4.1 网表这个词在IC验证里到底指什么先说清楚概念因为网表这个词在不同语境下含义差别很大。如果你接触过PCB设计你可能知道OrCAD导出网表、Allegro导入网表那个网表描述的是元件和元件之间的连线关系用于PCB布局布线。而IC验证里的网表指的是晶体管级网表SPICE netlist或者门级网表gate-level netlist描述的是一个个晶体管或逻辑门的连接关系用于仿真验证。在混合信号验证里我们说模型落地成一份能跑的网表通常指的是把RNM模型替换成真实的SPICE晶体管级网表然后在仿真环境里跑网表仿真。这一步是必经之路因为RNM模型再精确也是抽象出来的不代表硅片上的真实行为尤其是工艺偏差、寄生效应、温度影响这些只有真实网表和工艺库才能反映出来。4.2 RNM模型怎么替换成晶体管级网表替换过程不是简单地换个模块实例而是涉及两层操作。第一层是网表格式的适配SPICE网表文件和RNM模型的端口定义往往有差异你需要在顶层环境里做一个wrapper模块把RNM模型的wreal接口映射到SPICE网表的模拟端口上。例如一个LDO的RNM模型有三个端口vin、vout、gnd而SPICE网表可能是.subckt ldo_netlist vin vout vgnd vdd M1 n1 vin vdd vdd pch W1u L0.18u M2 n1 vout n2 0 nch W1u L0.18u ... .ends你要写一个SystemVerilog wrapper里面实例化这个subckt同时把wreal信号转接到SPICE节点上。这个过程叫transistor-level model wrapper或者analog interface。第二层是仿真引擎的切换。RNM模型跑在数字引擎上SPICE网表跑在模拟引擎上。当环境里同时存在RNM模型和SPICE网表时仿真器需要同时用数字和模拟两个引擎并把两个引擎的事件同步起来。这一步最考验工具配置不同仿真器的配置方式差异很大但核心参数无非是模拟引擎的时间步长上限、接口处的收敛容差、事件同步方式。我在Cadence环境下用的命令大概是这个思路# Xcelium混合信号仿真RNM模型用数字引擎网表用的模拟引擎 xrun -ams \ -timescale 1ns/1ps \ -xmvlog top_file.sv \ -xmas sim_config.cfg \ -access rwc \ -cleansim_config.cfg里指定模拟引擎步长、连接模块方式等参数。这个配置需要按项目实际情况调别照抄网上的模板。4.3 网表仿真的关键步骤从LVS到后仿真网表仿真不是从零开始的它前面还有一连串流程。我梳理一下从版图到仿真网表的必经之路。首先是LVSLayout vs. Schematic版图与原理图一致性检查。这一步确保版图画出来的连线关系和你设计的原理图一致。如果LVS不过那你拿到的网表本身就是有问题的仿真跑出来的结果毫无意义。我做过的项目里LVS最常见的问题就是电源地的网络名不统一比如有的模块叫VDD有的叫VCCLVS工具就会认为它们是两个不同的网络导致很多器件断开。LVS过了之后如果做后仿真还要做寄生参数提取PEXParasitic Extraction。这一步会把版图上的导线电阻、电容寄生参数提取出来附加到网表上。后仿真和前仿真的差别就是这些寄生参数——它反映了真实芯片上的导线延迟和耦合。前仿真没有这些参数所以后仿真更接近真实但也更慢。后仿真网表的格式一般是带寄生参数的SPICE网表可能高达几万行。仿真器加载这种网表时内存占用和仿真时间都会显著上升。我建议按模块做后仿真别一下子全芯片跑后仿真不然一次仿真跑几十个小时验证效率会非常低。最后一步把后仿真网表替换RNM模型跑系统级回归。这一步的目的是验证真实的模拟电路数字逻辑在系统层面的行为是否符合预期。到这里RNM模型才真正完成它的历史使命被真实网表取代。4.4 网表仿真环境配置的细节和检查项网表仿真比RNM模型仿真麻烦得多光环境配置就能拦住不少人。我整理了一份检查清单每次搭建网表仿真环境时逐项确认第一仿真器能不能正确识别网表中的模拟组件。SPICE网表里有MOS管、电容、电阻、二极管仿真器需要加载对应的工艺模型库model library。如果模型库路径配错仿真器会直接报找不到模型或者参数错误而且这个报错往往很隐晦不是直接告诉你路径错误而是假装某个器件不存在。第二接口处的connect module必须正确配置。RNM模型和网表混合仿真时数字侧的wreal信号和网表侧的模拟电压节点之间需要连接模块。方向一旦配反就会出现数字端以为看到了LDO输出实际看到的是高阻节点这种情况。排查方式很简单打印节点电压对比一下波形。第三仿真时间步长的控制。网表仿真的默认最大步长可能太大导致模拟信号变化被跳过数字侧采样到的电压值错误。我习惯把接口处的最大步长限制在信号周期的十分之一以内宁慢勿错。第四初值问题。SPICE网表的初始电压取决于仿真器的DC工作点分析如果网表仿真没有做DC初始化直接跑瞬态很多节点可能从0V开始爬升导致上电瞬间数字逻辑看到错误的电压值。通常需要在瞬态分析前加一个初始DC工作点计算这一步别省略。5. 我踩过的坑混合信号验证常见问题与排查5.1 connect module方向冲突这是我第一次搭Verilog-on-Top环境时遇到的第一个大坑。当时我写了一个连接模块想同时处理输入和输出方向的转换结果仿真器直接报方向冲突整个环境起不来。后来才发现connect module的方向必须跟net的方向声明严格一致。比如一个信号声明为inout那么连接模块里必须有inout方向处理如果声明为output却去做input方向转换系统就会报错。解决方案是把每个连接模块按方向分成独立的module输入归输入、输出归输出在connect module库里按需实例化不要写一个万能模块处理所有情况。这种做法看着冗余实际上排查问题非常方便。5.2 环路时序和初值问题混合信号验证的环路问题往往比纯数字验证更头大。模拟信号经过阈值判决变成logiclogic再驱动数字状态机状态机又反过来控制模拟模块的使能信号穿过RNM模型又影响模拟电压。这个环一旦初始状态不对就会形成错误初值—错误判决—错误控制—更错初值的恶性循环。有一次我遇到一个ADC校准使能信号一直变来变去怎么查都查不到原因。最后用force把校准使能信号强制拉低波形才稳定。后来检查代码发现RNM模型里有个控制寄存器的默认值为0但在Verilog-on-Top环境里它的初始值是X导致状态机在X和0之间反复切换。从那以后我对所有模拟接口信号做严格的初值检查一旦发现高阻状态或X态立刻处理。5.3 现实信号和Verilog类型不匹配wreal类型在SystemVerilog里不是万能的它跟logic类型交互时有一些限制。比如wreal信号不能直接作为普通Verilog模块的input端口除了connect module之外也不能用于某些需要整型运算的表达式里。我经常写的$display(vout %f, vout_ldo)是可以的但如果在赋值语句里logic_v wreal_v在部分仿真器上会提示类型不匹配编译失败。处理方式是先转成real类型变量再操作或者在connect module里完成转换。我建议养成一个习惯在RNM模型内部所有计算都用real类型中间变量只在端口处使用wreal类型。这样既满足了RNM对端口类型的要求又避免了类型不匹配的问题。5.4 精度不足导致收敛问题网表仿真跑着跑着仿真器突然提示timestep too small这是经典的不收敛问题。如果RNM模型和网表混仿接口处的信号变化非常剧烈比如阶跃变化数字引擎和模拟引擎在同步事件时会产生极小的时间步长导致仿真停滞。我在一个带斜坡信号的ADC输入项目里就遇到过每次斜坡电压快速变化时仿真就卡成了蜗牛。解决思路有两个一是把斜坡信号的斜率做平滑处理让信号变化不至于触发模拟引擎的最小步长限制二是在仿真器配置里调整接口处的time step控制参数适当放宽时间步长下限。但后者要谨慎放宽太多会丢掉信号细节反而影响精度。6. 一些实在的建议6.1 工具选型与学习路线混合信号验证的主流工具商业环境里常见的是Cadence Xcelium、Synopsys VCS AMS、Siemens Questa Advanced Simulator开源方案有Verilator配合SPICE仿真器做混合仿真的尝试但成熟度还不如商业工具。我个人的推荐是如果团队基础设施扎实优先选Cadence或者Synopsys的成熟工具链它们对RNM和网表混仿的支持是经过大量项目验证的。初学者重点看两本参考资料SystemVerilog语言参考手册里和real/wreal相关的章节以及你所用仿真器的混合信号仿真用户指南。别一上来就啃语言手册先用官方example跑通一个小环境再逐渐加模块。6.2 渐进式验证策略回头看我做过的那几个项目最大的教训就是一步到位验证是行不通的。正确的方式是渐进式推进先全RNM跑通数字功能再混仿加入真实网表最后全网表回归。每往前走一步都要先确认前一步的结果是干净的否则问题互相缠绕排错成本会呈指数级上升。我还建议在项目初期就定义好RNM模型和真实网表之间的接口协议包括信号名称、方向、电平阈值、时序约束。这样后期替换网表时基本只改模块实例不用大改环境效率会高很多。6.3 最后分享一个小习惯在每次跑网表仿真之前我会先把RNM模型环境快速跑一个smoke test确认数字部分行为正常然后再切换到网表跑同样的用例。这个小习惯帮我省掉了很多明明网表替换了结果连数字部分都跑挂的排查时间。毕竟网表仿真的调试成本比RNM模型仿真高一个量级能在模型阶段发现的问题就不要留到网表阶段。混合信号验证是一个抽象和现实不断斗争的过程。RNM让你看得快网表让你看得准Verilog-on-Top让你能把两者高效地组织起来。模型怎么落地成一份能跑的网表说到底就是这句话用正确的抽象层次解决对应阶段该解决的问题。