混合信号验证这几年在业内谈得很多但真正能把 RNMReal Number Modeling抽象、Verilog-on-Top 验证策略、以及最终模型怎么落到一份能跑的网表这三件事串起来讲清楚的人其实并不多。很多团队还停留在把模拟块单独拿出来跑 SPICE再把数字块丢给 UVM 环境两头各玩各的等流片回来才发现接口时序、驱动能力、上下电顺序这些跨域问题烧钱又烧时间。我自己的体会是MSDVMixed-Signal Design Verification的瓶颈从来不是工具不够强而是思路没理顺你到底要验什么、抽象到哪个层级、用什么语言统一描述、最终模型怎么交付给后端和 PCB 设计。这篇文章就围绕这几个问题把我实际跑过的一套流程完整拆开讲一遍从 RNM 抽象开始到 Verilog-on-Top 环境搭建再到模型怎么落地成一份能跑的网表中间会穿插我在项目里踩过的坑和最后找到的解法希望对正在做混合信号验证的朋友有帮助。开头先把话说明白这篇文章不是讲某个 EDA 工具的操作手册而是讲一套可以复用的验证方法论。适合三类人看一是刚接手数模混合芯片项目、需要搭建整体验证环境的验证工程师二是被模拟团队和数字团队来回拉扯、急需一个统一沟通语言的项目负责人三是后端和 PCB 工程师——你们经常拿到一份看不懂的模型文档这篇文章会让你们知道模型是怎么来的、为什么长这样、以及导入网表时哪些坑可以提前避开。1. 内容整体设计与思路拆解1.1 为什么混合信号验证不能只靠 SPICE 和 UVM 各管一段很多团队习惯的做法是模拟工程师用 SPICE 跑自己那一小块电路数字工程师用 SystemVerilog/UVM 验数字逻辑两边在接口处靠文档和口头约定来对齐。这种方式在小规模项目里勉强能转一旦模块多起来问题立刻暴露SPICE 跑一个 PLL 锁定行为可能要几个小时而数字端要等这个结果才能继续跑接口时序两边理解不一致往往要等顶层集成时才发现 bug这时候改一版代价极高。混合信号验证的核心难点在于跨域交互的验证而不在于模拟电路本身的功能对不对。模拟块内部性能可以用 SPICE 精确评估数字块内部逻辑可以用 UVM 充分验证但数模接口处的驱动强度、电平转换时序、上下电顺序、状态切换时的毛刺行为这些只有把两边放在同一个环境里跑才有意义。这就引出了 MSDV 的核心思路需要一种方法让模拟块以足够快的速度参与数字验证同时保留必要的模拟精度让数字块能够感知模拟行为的关键特性。RNM 抽象就是为解决这个问题而建立的。1.2 RNM 抽象和 Verilog-on-Top 是 MSDV 的两个支柱RNM 的核心思想是把连续时间的模拟信号用实数real来表示把数字事件和模拟行为统一到同一个仿真内核里。对比传统 SPICE 的电压电流连续求解RNM 模型不关注具体的晶体管级细节而是描述信号值的变化——比如一个 LDO 的输出电压RNM 模型不关心内部误差放大器的偏置点而是抽象成“给定输入电压范围输出稳定在某个实数电压值”的行为。Verilog-on-Top 则是从验证架构层面解决“谁主导整个仿真”的问题。以数字顶层模块作为仿真顶层模拟模块以行为级模型的形式嵌入到数字环境中整套验证环境用 SystemVerilog/UVM 搭建。这种方式的好处是显而易见的模拟块以数字解算器的速度运行整个 SoC 级别的验证可以跑起来同时验证环境完全复用已有的数字验证基础设施——testbench、sequence、checker、覆盖率收集全部照常工作。这两种思路放在一起整个混合信号验证的框架就清楚了RNM 解决“模拟块怎么抽象、以什么形式与数字逻辑交互”的问题Verilog-on-Top 解决“整体环境怎么组织、谁在顶层控制仿真”的问题。两者结合才能支撑起从模块级到系统级的混合信号验证。1.3 模型落地成网表验证的最后一公里很多时候验证工程师把 RNM 模型写好、仿真跑通了就觉得工作完成了。但实际上模型的价值要传递到后端和 PCB才能对整个产品链条产生作用。这里的网表不单指晶圆厂所需的晶体管级网表还包括从 OrCAD 导出、导入 Allegro 进行 PCB Layout 的板级网表。这个环节最大的断层在于验证环境里的 RNM 模型是行为级的而后端和 PCB 工程师需要的是结构级的连接关系。如何把验证模型的信息映射到网表如何保证模型跑出来的行为与网表实际连接一致这是混合信号验证流程里最容易脱节、也是大家讨论最少的一段。后面我会用一个实际例子详细说明这条链路怎么打通。2. RNM 模型建立与 Verilog-on-Top 环境搭建2.1 RNM 建模的精度分级从功能级到时序级RNM 建模最需要想清楚的一件事每个模拟模块该抽象到什么程度。精度太高仿真速度优势就没了精度太低数字逻辑检测不到关键行为验证等于白做。我通常把 RNM 模型分成三个精度级别按需选择功能级模型只表达模块的输入输出映射关系不关心时序细节。比如一个比较器功能级模型就是“输入大于参考电压则输出高电平”适合在验证早期做架构探索速度最快。时序级模型在功能级基础上增加了关键时序参数——延迟、上升下降时间、建立保持时间约束等。这个级别适合做 SoC 级验证数字逻辑能够感知到模拟模块带来的时序影响同时运行速度依然远快于 SPICE。模拟行为级模型进一步把非线性特性考虑进来比如压摆率限制、噪声容限、温度漂移等。这类模型通常用在数模接口处排查边界问题时需要。再往上就是晶体管级精确模型了一般只留到最终回归时抽检几组关键向量用不会作为主验证模型。实际项目中我建议的做法先所有模块用功能级模型搭出整个 SoC 的验证环境确保数字侧的基本功能正确然后逐个替换关键模拟模块为时序级模型观察时序相关功能是否受到影响最后将风险最高的几个接口模块提升为模拟行为级模型做宿小范围的精确验证。这样把算力集中在刀刃上。2.2 Verilog-on-Top 环境的目录结构与文件组织Verilog-on-Top 环境的搭建有一个容易忽略的重点目录结构是否清晰直接决定了多人协作时的效率。我给自己项目定了一套标准的目录划分分享出来供参考msdv_project/ ├── rtl/ # 数字 RTL 代码目录 │ ├── core/ # 处理器核心等数字逻辑 │ └── peripherals/ # 数字外设 ├── analog/ │ ├── models/ # 模拟模块的 RNM 模型按模块分子目录 │ ├── rnm_lib/ # 通用的实数建模库类型定义、转换函数 │ └── testcases/ # 模拟模块单独的验证用例 ├── tb/ │ ├── top/ # Verilog-on-Top 顶层环境 │ ├── agents/ # 各接口的 driver/monitor/sequencer │ └── sequences/ # 验证序列 ├── tc/ # 测试用例 ├── scripts/ # 编译、仿真、回归脚本 └── out/ # 仿真输出、覆盖率数据库模拟模块的模型用 SystemVerilog 的 real 类型来实现放在 analog/models 下每个模块一个目录里面包括模型文件、说明文档和简单的自测 testbench。这样做的好处是模拟团队可以独立于数字验证环境对这些模型做单元验证确认模型行为正确后再集成到顶层环境减少联调时的调试成本。2.3 搭建一套可复用的 Verilog-on-Top 仿真环境具体到环境搭建我用一个简化但完整的示例来说明。假设我们有一个模拟模块 PLL它给数字核心提供时钟信号。PLL 的 RNM 模型用一个 SystemVerilog 模块实现输出为 real 类型的时钟频率控制参数。// pll_rnm_model.sv module pll_rnm_model ( input logic ref_clk_i, input logic enable_i, input logic [7:0] div_ratio_i, output real clk_period_ns, output logic lock_o ); timeunit 1ns; timeprecision 1ps; real period_ns; int lock_count; // 分频比为零时无效实际分频值 always_comb begin if (div_ratio_i 8d0) period_ns 20.0; // 默认频率 else period_ns 20.0 * real(div_ratio_i); end // 锁定行为使能后经过一定时间完成锁定 always (posedge enable_i) begin lock_count 0; end always (posedge ref_clk_i) begin if (enable_i !lock_o) begin lock_count lock_count 1; if (lock_count 1000) lock_o 1b1; end end assign clk_period_ns enable_i ? period_ns : 0.0; endmodule然后这个模型产生的时钟频率送给数字逻辑侧一个任务用来实时生成时钟信号// 顶层环境中从 RNM 模型的实数输出产生数字时钟 real clk_period; logic clk_gen; always begin if (clk_period 0.0) begin #(clk_period/2.0) clk_gen 1b1; #(clk_period/2.0) clk_gen 1b0; end else begin clk_gen 1b0; #1ns; end end这套环境的好处在于一旦 PLL 的 RNM 模型输出频率参数整个数字 SoC 就能在这个频率下运行无论是功能验证、时序收敛还是软件驱动调试都能在真实频率行为下进行。而如果换成晶体管级 PLL跑这样一段仿真需要的时间是天文数字。环境搭建还有一个很容易忽略的细节RNM 模型的 port 类型定义。模拟模块和数字模块连接处经常出现 real 类型与 logic 类型的混合连接。建议写一套类型转换函数放在 rnm_lib 公共库里避免在模型内部到处写转换逻辑维护起来也方便。3. 核心细节解析RNM 建模的进阶技巧3.1 实数信号与数字信号的交互跨域转换的常见坑RNM 建模过程中最容易被忽视的地方是跨域信号交互。real 类型的模拟信号如何转换成数字逻辑能够识别的 0/1 信号以及数字信号如何转换成 real 值供模拟模型使用这里面的细节决定了模型能不能真实反映硅片行为。一种常见做法是使用阈值判定。下面是模拟比较器模块 RNM 模型的实现module cmp_rnm_model ( input real vin_p, input real vin_n, input logic en_i, output logic out_o ); real threshold 0.0; real histeresis 0.005; // 5mV 迟滞 always_comb begin if (!en_i) begin out_o 1bz; end else if (vin_p vin_n histeresis) begin out_o 1b1; end else if (vin_p vin_n - histeresis) begin out_o 1b0; end // 在迟滞区间内保持原值 end endmodule迟滞效应的建模往往被初学者忽略。如果没有迟滞区间当输入信号在阈值附近上下波动时输出会高频翻转这在真实器件里不会发生却会在仿真里给后面接的数字逻辑带来大量无意义的翻转事件拖慢仿真速度还可能导致功能误判。另一个常见问题是 real 信号和 logic 信号之间的位宽匹配。SystemVerilog 中 real 类型是 64 位双精度浮点数模转换器DAC的输出值是离散的比如一个 12 位 DAC 输出 0 到 4095对应的电压范围可能是 0 到 3.3V。RNM 建模时需要在模拟侧输出 real 值然后加一个迟滞函数处理量化误差否则会引入大量因为浮点比较导致的随机行为。3.2 上电复位和上下电顺序RNM 模型最容易出错的地方混合信号芯片的上电复位和上下电顺序问题是流片后最容易出现、但验证时最难发现的 bug 类型。这是因为传统验证方式中纯数字环境会假设电源始终稳定而 RNM 模型如果只关注模块功能不关注电源依赖关系就会在电源时序相关验证上留下巨大的盲区。我在 RNM 建模时会要求每个模拟模块都带上电源相关的行为描述。即使是最简单的 vdd_i 和 vss_i 输入也要在模型内部建立“电源未稳定时输出无效”的行为。例如模拟模块的输出驱动能力应随 VDD 变化而变化module ana_block_rnm ( input real vdd_i, input real vin_i, output real vout_o ); real vout; real vth_supply 0.8; // 最小工作电压 always_comb begin if (vdd_i vth_supply) begin vout 0.0; // 欠压时输出无效 end else begin // 正常工作输出跟随输入但受电源电压限制 vout vin_i vdd_i ? vdd_i : vin_i; end end assign vout_o vout; endmodule上电顺序验证还需要在 testbench 中定义合理的电源序列场景。有些团队喜欢在 UVDUnified Verification Dashboard里把电源序列写成单独测试用例每次回归都跑一遍我建议把这个动作放在 nightly regression 里不要只在流片前的最终验证阶段才做。实际经验是电源时序相关的 bug 发现越晚修起来越痛苦因为它往往不在单一模块内部而是跨模块交互产生的问题。3.3 从模型到行为如何量化 RNM 模型与 SPICE 的差异RNM 模型再精细也是抽象与 SPICE 晶体管级仿真必然存在误差。关键问题是这个误差会不会影响验证结论的可靠性我一般会定义“校准测试用例”把典型的激励向量同时用 SPICE 仿真和 RNM 模型仿真对比输出量化误差水平。比如一个电压调节器模块SPICE 仿真 100us 的时间可能需要 20 分钟RNM 模型只要 2 秒。校准的做法是对比不同负载跳变下输出电压的响应时间和跌落幅度如果两者相差在 5% 以内就认为这个抽象级别对当前验证任务足够。如果超过这个范围就需要考虑提高模型精度或者在关键路径上增加修正因子。这件事一定要做而且要留文档记录。因为别人在用你的模型时需要知道模型的适用范围和精度限制。我见过一些项目模型写得很漂亮但精度指标严重偏离真实电路数字侧的行为验证完全失真最后 debug 时浪费了整个团队好几周的精力。4. 实操过程从 RNM 模型到网表落地的完整链路4.1 模拟模型如何走向门级和晶体管级网表模型落地成网表首先要听清楚“网表”在这里指哪个层面。对芯片设计而言通常是数字网表门级网表、模拟网表晶体管级 SPICE 网表、以及顶层的混合信号网表。对板级设计而言则是 OrCAD 导出的 PCB 网表再导入 Allegro 做 Layout。这两条线在同一个产品里都存在而 RNM 模型对它们的作用方式不同。芯片设计侧RNM 模型最大的价值在于验证阶段形成的行为预期。当设计迈向综合和物理实现时RTL 被综合成门级网表模拟模块被替换成自家的真实电路网表。此时需要做 LEC逻辑等价性检查数字侧是 RTL vs 门级网表模拟侧是行为模型 vs 晶体管网表。这里 RNM 模型可以作为参照基准把模拟模块接口的行为描述提取成断言在混合信号网表仿真时做在线检查。实际流程走下来我的建议是建立“模型证据链”初版行为模型建立时用 SPICE 仿真结果校准模型精度数字验证阶段所有用例的模拟部分固定使用校准过的模型版本确保可复现后端网表生成后对关键模拟模块做有限的混合信号仿真将 RNM 模型输出与真实电路输出对比确认后端实现没有改变模块行为最终回归时统一采用后端网表完成签核验证。这样每一步都有对照依据出了问题也知道是哪个环节引入的偏离。4.2 OrCAD 导出网表与 Allegro 导入网表板级验证的衔接在板级混合信号设计中验证工程师的交付物除了仿真报告往往还包括一份指导 PCB 设计的接口文档。而 PCB 工程师手里的工具链通常是 OrCAD 做原理图、Allegro 做 Layout这两个工具之间传递的就是网表文件。从 RNM 验证的角度看这里有个关键点验证环境里的模块连接关系需要与原理图的连接关系一致。我踩过一次特别深的坑芯片顶层验证时某个模拟模块的电源引脚是 vdd_a而板级原理图里对应的网络名是 VDDA大小写不同、后缀不同导致 Allegro 导入网表后网络完全对不上Layout 到一半才发现返工成本非常高。规范的做法是在项目启动之初就统一网络命名规范。验证环境里的顶层接口信号名、原理图里的网络名、PCB Layout 里的 net class三处必须保持一致的命名规则。建议在项目 kickoff 时做一次命名对齐评审而不是等网表导入了再各改各的。实际操作流程大致如下OrCAD 原理图完成 → 生成网表文件.net 格式 → Allegro 导入网表 → 检查 DRC设计规则检查 → 与验证团队核对网络命名映射表 → 确认无误后开始布局布线这个流程中验证工程师能介入的是“网络命名映射表”这一步。我在项目中会写一份自动化的网表扫描脚本把 OrCAD 导出的网表网络名与验证顶层环境里的接口列表做比对自动输出不一致项。不要小看这个动作它能提前拦截掉非常多的低级错误。4.3 一个完整的实操案例SoC 级混合信号验证到网表交付用一个实际跑过的案例把整条链路串起来。项目是一颗 MCU 类芯片内部有 LDO、POR上电复位、时钟 PLL、ADC、比较器、若干数字外设采用数模混合设计。验证目标是在流片前确认整个 SoC 在正常和异常电源条件下的行为符合规格书。第一步搭建 Verilog-on-Top 环境。数字 RTL 作为顶层LDO、POR、PLL、ADC 用 RNM 模型接入。模拟团队提供模型数字验证团队负责集成到 UVM 环境。第二步校准。对 LDO 和 PLL 分别做 SPICE 与 RNM 模型的响应对比。LDO 关注负载瞬态响应PLL 关注锁定时间和抖动特性。校准结果显示PLL 锁定时间 RNM 模型比 SPICE 快约 3%在可接受范围LDO 的跌落幅度误差需要修正通过修改模型参数收敛到 2% 以内。第三步功能验证。在统一环境下跑数字功能用例其中用到模拟模块的场景包括ADC 采集、比较器中断、POR 后的启动时序、LDO 过流保护触发时数字系统的响应。这个阶段发现了一个真实 bugPOR 释放后数字核心立即开始读 Flash但 LDO 输出电压还没来得及建立到稳定值导致首次读 Flash 失败。这个问题在传统分离验证中极难被发现——因为数字验证环境里 LDO 一直被视为“已稳定”而模拟验证环境里根本不会跑 Flash 读取这种数字场景。第四步网表交付。芯片物理实现后用门级网表替换数字 RTL模拟模块用真实电路网表。对 POR 上电、时钟切换等关键场景做混合信号回归与 RNM 模型结果对比确认后端没有破坏行为。与此同时板级原理图设计启动OrCAD 导出网表、Allegro 导入、DRC 通过网络命名映射表扫描无异常PCB Layout 得以顺利启动。整个过程跑下来从环境搭建到网表交付大约用了 6 周时间。相比以往项目在流片前多发现了两类典型问题电源时序相关 bug 和跨域接口噪声问题而这两类恰恰是竞品芯片流片后最常见的失效模式。5. 常见问题与排查技巧实录5.1 RNM 模型仿真速度慢于预期怎么办RNM 模型最大的卖点就是快但实际项目中经常会遇到模型跑起来比想象中慢的情况。排查优先级我建议按以下顺序第一检查是不是 real 类型被用在了高频信号上。real 类型的运算和赋值比 logic 类型要慢很多。如果有一个 1GHz 的时钟信号用 real 类型传递仿真器会比较吃力。对策是对于明显的数字信号该用 0/1 的用 logic 类型只有真正的模拟连续量才用 real。第二检查有没有无意义的毛刺事件。之前提到的迟滞缺失会引发高频翻转正确做法是给比较器、开关电容等模块加足够大的迟滞区间或者在输出级加一个数字滤波器过滤掉小于若干个纳秒的事件。第三检查仿真器的 real 事件调度配置。主流仿真器对 real 信号的调度策略是可选配置的默认值往往不是性能最优的。记得查证并调整仿真器的 delta-cycle 处理策略实测下来有时候能把速度提升一倍以上。给一个典型经验值同一个 SoC 环境如果 RNM 模型全部使用功能级抽象仿真速度大约是 50K cycles/s升级到时序级模型后降到 10K cycles/s如果误把 real 类型用在所有端口上可能跌到 1K cycles/s 以下——这个速度对 SoC 验证来说基本不可用。5.2 Verilog-on-Top 环境里模拟模型连接失败的常见原因连接失败是搭环境时最容易卡住的环节我总结了三类高频原因第一类类型不匹配。真实模拟模块的模拟端口如果定义为 real 类型但数字环境给的是 logic 信号编译时可能通过隐式转换但仿真时行为完全不对。对策是在顶层的连接处显式使用转换函数强制类型匹配。第二类位宽不匹配。数字侧有的信号声明为 32 位但模拟侧的实数模型只用了低 12 位对应真实 DAC 的精度赋值时容易产生未定义的高位值。对策是使用截断函数显式处理位宽。第三类浮点比较的边界问题。RNM 模型里用 real 做相等比较在仿真里可能永远等不到精确相等。我在两个项目里都遇到这种情况最后统一把所有 real 相等判断改成“差的绝对值小于 epsilon”的形式。5.3 网表导入 Allegro 后网络对不上的排查方法从 OrCAD 导出网表、再导入 Allegro 后出现网络对不上是最常见也最让人头疼的问题。按照我的经验排查顺序应该是第一步确认网表生成选项。OrCAD 导出网表时有一个“创建 PCB 编辑用的网表”选项很多人默认勾选的是老版本兼容格式导致 Allegro 识别错误。建议确认使用当前工具链匹配的网表版本。第二步核对网络命名映射表。这一步最容易出问题的是非 ASCII 字符、斜杠、空格被网表格式转义。比如信号名A[3:0]在网表里可能变成A3_0_这样的形式如果不做映射Allegro 就会认为网络不存在。第三步检查连接关系。用诺泰CSACross Section Analysis或者直接看网表文本检查有没有因为原理图里悬空引脚导致的未连接网络。我这边实操时写过一个快速检查脚本读取 OrCAD 导出的网表文件提取网络列表再和原理图里定义的连接关系做 diff输出的差异内容直接定位到具体页号和器件位号排查效率提高了很多。5.4 混合信号验证中需要避开的三个坑最后分享三个容易忽视但代价极高的坑。第一个坑是忽略模型版本管理。RNM 模型会随着校准结果不断迭代如果数字验证团队用的模型版本和模拟团队的最新版不一致整个验证结果都会失真。建议把模型文件纳入版本管理且验证环境编译时打印模型文件的 MD5 值回归报告自动带上版本信息。第二个坑是忽略跨域接口的断言。很多团队在纯数字验证时会用断言覆盖协议但在混合信号环境里接口引脚的 level 和时序却被遗漏了。建议至少覆盖电源与地之间不能短路、模拟输出上升到设定阈值的时间窗口、时钟稳定前的复位信号保持有效这几类核心断言。第三个坑是网表交付前不做模型到网表的交叉检查。数字网表往往通过逻辑综合自动生成而模拟部分可能还是手焊网络的拼接方式。不做交叉检查的后果是仿真里功能全过的设计到了最终网表仿真时因为接口连接不一致大量报错不得不返工修网表。这类问题发现得越晚修复成本越呈指数上升。根据我个人的经验混合信号验证流程的建立最重要的不是工具链多先进而是把抽象层级、连接规范和交付标准定清楚。RNM 模型怎么写、Verilog-on-Top 怎么建、网表怎么落地这三件事在每个项目启动时花一周时间立好规矩后续几个月的验证工作会顺利得多。最后分享一个小技巧把网表命名映射表作为项目交付物之一每次网表更新后自动运行一次映射检查这个动作不起眼却能在关键时刻替你省掉一整周的 debug 时间。