PFD仿真实战:从Testbench搭建到死区盲区定量提取 📅 发布时间:2026/9/20 9:15:42 👁 浏览次数: 搞PLL的人没有谁绕得开PFD这个模块。很多工程师第一次跑PFD鉴频鉴相器仿真时都会有一种“这么简单的电路有什么好仿”的错觉——两个D触发器加一个与门无非是看UP和DN谁先拉高然后等复位脉冲下来。可真等你在Spectre里把testbench搭起来开始定量观察死区宽度、盲区边沿、复位延迟这些参数时你会发现这个“简单电路”的仿真一点都不简单。脉冲宽度可能只有皮秒级仿真步长稍微给大一点就什么都看不出来运气不好还会撞上瞬态仿真不收敛波形直接飞掉如果你中途换成数字仿真器还可能被一堆红线折腾半天。这篇文章我会以Cadence Spectre为主完整梳理一遍PFD仿真的流程从测试平台搭建、激励构造到死区、盲区、鉴相增益这些指标的定量提取再到仿真发散和异常波形的排查链路最后把晶体管级PFD仿真结果和整环PLL仿真需要的行为级模型串起来。无论你是刚接触锁相环的学生还是正在调PLL的工程师这篇内容应该都能直接帮上忙。1. 为什么PFD值得单独拉出来仿真1.1 三态状态机UP/DN到底在比什么PFD比较的是两路输入的时钟边沿典型的三态PFD由两个D触发器和一个复位与门构成输出端通常还挂一个电荷泵。CLKREF的上升沿先到UP就被置1CLKFB的上升沿先到DN就被置1当UP和DN同时为1时与门产生复位脉冲把两个触发器一起清零。整个过程就是一个三态状态机正向充电状态、负向充电状态、中性状态。用一个生活化的类比来记这个逻辑两个人面前各有一个按钮谁先按下谁的灯亮两个人同时按下时裁判把灯全灭。这里的“同时按下”区间就是复位时间。这个时间窗口看着不起眼实际直接决定PFD的盲区大小和最高工作频率。PFD之所以能同时鉴频和鉴相是因为它比较的是边沿顺序而不是电平高低。早期的异或门鉴相器只能锁定同频信号频率不对时输出没有明确的牵引信息PFD在频率差很大时也能输出一个向正确方向牵引的净占空比所以锁相环几乎都用PFD来做前端。仿真时的“鉴频”和“鉴相”两种维度也正是从这个状态机行为衍生出来的。1.2 单独仿真要抓住的三个核心问题在整环PLL仿真里如果PFD被换成理想行为模型很多非理想效应会被直接隐藏掉。要做低噪声或者高可靠性的PLLPFD必须单独拿出来验证三个点。第一是死区。锁定状态下相位误差很小UP和DN输出的脉冲都很窄窄到这个脉冲不足以让电荷泵正确开启或者关闭时环路就会对微小误差“视而不见”误差一点点积累成周期性的抖动反映到输出就是带内相位噪声恶化。死区是PFD单测里最容易被忽略、又最影响相噪的指标。第二是盲区。复位窗口期间PFD对新的时钟边沿不敏感如果参考沿或反馈沿恰好落在这个窗口里就会被直接吞掉造成漏检。漏检会导致周期跳变cycle slip带外杂散变差锁定时间也会拉长。盲区反映的是PFD“看不见”的区域和死区完全是两码事。第三是复位延迟和最高工作频率。复位延迟决定了盲区宽度又和触发器的tco、建立时间共同决定PFD的最高工作频率。设计时要在盲区宽度和可工作频率之间做折中这个折中点必须在单测阶段量化出来。1.3 死区、盲区两个经常被搞混的指标我见过不少人把死区和盲区当成同一件事其实它们出现的相位差区间完全不同产生的物理机制也完全不同。列一张表把区别定死对比项死区Dead Zone盲区Blind Zone出现位置相位误差接近0的锁定附近相位误差接近±2π即复位窗口内产生根源UP/DN脉冲太窄电荷泵来不及开关复位期间边沿检测被屏蔽可观察现象小相差下输出平均电压基本不变大相差下偶发漏检、脉宽突变对系统影响带内相位噪声恶化周期跳变、参考杂散、锁定时间变长仿真观察手段扫描小相差测输出脉宽差在复位窗口注入边沿看是否响应一句话概括死区是“看见了但没力气响应”盲区是“干脆看不见”。设计PFD时通常是先保证死区足够小再想办法压缩盲区两个指标常常互相牵扯不能只看其中一个。2. 仿真工具与测试环境的搭建思路2.1 Spectre/HSpice/ADS怎么选仿真PFD的主流工具大致分三类Cadence Virtuoso环境里的Spectre、Synopsys HSpice以及ADS这类偏系统级的仿真工具。选择逻辑其实很简单你要看的是晶体管级的边沿和开关瞬态就用SPICE级别工具只是验证逻辑功能可以用ADS或者纯数字仿真器。我个人优先用Cadence Spectre。原因有三个PLL周边的PFD、电荷泵、VCO、分频器基本都是模拟模块放在同一个Virtuoso工程里联调最方便Spectre对数字门和状态节点初始化的设置比较直观跑corner和蒙特卡洛时和PDK的配合也更顺滑。HSpice的收敛算法非常成熟而且脚本驱动能力强适合做自动化回归。ADS的优势在系统预算分配PFD通常用行为级模型代替做不了太细的晶体管验证。这里多提一句纯数字仿真器的局限。ModelSim、VCS这类工具用标准单元库跑PFD逻辑功能没问题但SPICE仿真里能看到的电荷泵开关瞬态、输出摆幅限制、复位路径毛刺在纯数字仿真里完全没有。所以功能验证可以用数字仿真性能指标必须回到模拟域两者结合才是完整验证。2.2 testbench的基本连接以Spectre为例PFD的测试平台一般这样搭电源VDD接到标准电压同时在电源节点加一个去耦电容比如100pF到地避免数字翻转激励起电源网络振铃。输入时钟CLKREF和CLKFB各用一个脉冲源设置合理的上升沿和下降沿时间。上升沿一般取时钟周期的1%左右太陡会恶化收敛太缓又测不出真实的边沿灵敏度。复位信号PFD通常有RST_N输入仿真启动时先拉低一段比如5ns然后再拉高确保触发器初始状态确定。输出负载UP和DN节点不要空载。最简做法是各挂一个fF级电容模拟后级栅电容比如20fF。想更贴近实际就接电荷泵简化模型或者直接接实际CP电路。内部节点做死区或盲区测量时把PFD内部关键节点也保存下来包括两个D触发器的Q端和复位与门的输出。为什么要保存内部节点因为只看UP和DN很多时候不够。复位信号实际在什么时刻拉低、复位脉冲宽度多少这些在输出端不能直接看出来而它们恰恰是死区和盲区的关键参数。你总不想为了看一个内部信号重新跑一遍仿真。2.3 transient仿真参数怎么设才不至于“看不到”脉冲Spectre瞬态仿真有几个参数直接决定你能不能看到PFD的细节脉冲。errpreset建议设成conservative。PFD输出包含大量快速上升沿和窄脉冲默认的moderate模式为了省时间会加大时间步长窄脉冲容易直接被磨平看起来波形很干净实际上把关键信息抹掉了。maxstep是这里最关键的参数。如果要观察几纳秒级的复位脉冲maxstep至少要小于脉冲宽度的1/10如果要分辨皮秒级的脉宽差异需要把maxstep压到0.1ps量级。当然步长越小仿真越慢建议先跑一次常规仿真看看复位脉宽大概是多少再针对性地设置步长。仿真时长至少覆盖几个完整的参考时钟周期。如果要做鉴相增益提取需要跑足够长让平均测量稳定通常几十个周期起步。初始条件方面Spectre默认节点电压是0V但这不保证所有数字门处于有效状态后面的章节会专门展开讲。一句话先弄清楚自己要看的脉冲有多窄再去定步长。看不到波形时九成情况是步长给太大了。3. 激励构造与关键时序处理3.1 频率偏置法和相位跳变法测PFD最核心的激励就是让CLKREF和CLKFB之间存在频率差或相位差。实际操作中我常用两种方法各有适用场景。方法A频率偏置法。CLKREF给100MHzCLKFB给100.0001MHz跑一个足够长的时间窗口。观察UP和DN的脉冲宽度差会发现它随两个时钟的相位关系周期性变化整个过程从负到正再回到负正好覆盖-2π到2π的相位差范围。这个方法适合宏观验证PFD能不能正确鉴频也适合提取KPD的整体线性趋势。方法B相位跳变法。两路时钟同频但给CLKFB的脉冲源设置一个固定的delay比如500ps等效于给CLKFB一个固定相位滞后。然后逐步改变delay就能得到任意精确相位差下的PFD响应。这个方法适合做定点测量比如扫描死区时需要精确控制0.5ps级别的相位差。实操时我一般先用A确认PFD大致工作状态再用B做定量扫描。两种方法在Spectre里都能用参数扫描完成不需要一遍遍手动改网表。给一个HSpice风格的示意写法Spectre里逻辑一致* 参考时钟, 100MHz VREF clkref 0 PULSE(0 1.8 0 50p 50p 4.9n 10n) * 反馈时钟, 100.0001MHz, delay5.001ns VFBK clkfb 0 PULSE(0 1.8 5.001n 50p 50p 4.8999n 9.99999n)这个方法的好处是直观你改delay参数就能精确控制两个时钟的相位差。3.2 初始状态与复位第一步必须做对我踩过很多次坑之后总结出一条经验PFD仿真里八成以上的异常波形根源在初始状态而不是电路本身。PFD的D触发器如果没有复位上电瞬间内部节点可能处于一个既不完全是0、也不完全是1的中间态。在SPICE仿真里这个中间态会导致与门输出出现奇怪的中间电平甚至直接让瞬态仿真不收敛。所以testbench里必须做一个明确的复位动作启动后0到5nsRST_N保持低电平5.01ns之后再拉高时钟源最好也从5ns之后才开始起振避免在复位释放的同时出现时钟边沿造成时序竞争。如果你的PFD还有预充电或预置功能那么预充电信号的时序也要一并处理。还有一点容易被忽略复位路径延迟本身就是PFD设计的一部分仿真时别为了省事把复位信号做成理想零延迟。那样做会低估复位路径上的毛刺和竞争问题最后在实测时打你个措手不及。3.3 输出负载挂什么才能还原真实场景PFD在芯片里通常不会直接驱动很大负载它的输出连的是后续电荷泵的开关管栅极。所以UP和DN节点上的负载应该体现几个部分栅电容电荷泵开关管的栅极总电容大概几fF到几十fF仿真时用理想电容替代就行。连线寄生先用一小段RC网络近似等版图出来再通过后仿提取精确值。如果有测试焊盘还要加pad电容。不过这个通常留到整芯片验证阶段再考虑单独跑PFD时不必加。还有一个容易忽视的点UP和DN两条路径的负载要尽量保持一致。如果一边挂了很大的电容另一边不挂PFD会表现出非对称延迟反映在输出上就是锁定点出现相位偏移而这个偏移在真实版图里可能根本不存在。这种人为不平衡比实际失配还要误导人搭testbench时务必注意对称性。4. 从波形中把四个关键指标抠出来4.1 死区宽度的扫描测量死区测量的本质是扫一个很小的相位差看输出脉冲宽度差是否还保持线性。具体步骤把CLKREF和CLKFB设成同一个频率例如100MHz周期10ns。给CLKFB加一个小的delay从0开始按0.5ps、1ps、2ps、5ps、10ps、20ps逐步增加。每个delay下分别测UP和DN的高电平时间在Virtuoso Calculator里可以用pulseWidth函数或者直接测量波形时间差计算Δt tUP - tDN。画出Δt随相位差变化的曲线。理想PFD中Δt应该正比于相位差。现实PFD在相位差小于某个阈值时Δt会固定在复位脉宽附近不发生变化这一段就是死区。举个例子某工艺下测得相位差小于3ps时UP和DN的宽度差始终等于复位脉宽超过3ps后开始线性增加那么死区宽度就是3ps。死区仿真有一个非常容易踩的坑maxstep必须设到足够小小于你希望分辨的最小脉宽差异建议0.1ps级别。不然波形精度不够死区会直接被数值误差抹平看起来一切都好实际上你什么都没测出来。4.2 盲区边沿的注入测试盲区测起来比死区更麻烦因为它带偶发性不是每个周期都出现。直观的方法是把两个时钟源的delay调成接近0让它们几乎同相观察UP和DN的脉冲形态。当PFD进入复位窗口时如果第二个时钟沿来得稍微晚一点会被复位窗口吞掉那么波形上就能看到输出少了一个本应出现的脉冲或者UP/DN出现异常窄的毛刺。更精确的注入测试方法是让两个时钟在某个时刻几乎同时上升进入复位状态然后在复位脉冲还没有结束时人为插入一个额外的参考边沿用一个很窄的脉冲源叠加到CLKREF上观察PFD对这个插入边沿有没有反应。预测结果通常是边沿落在复位窗口前半段PFD几乎不响应落在窗口之外才恢复正常鉴相。盲区宽度近似等于复位路径总延迟。这个值直接决定PFD在接近2π相位误差处的线性范围对低杂散设计来说盲区越短越好但它受触发器复位时间和与门延迟的限制不能无限压缩。所以仿真时测到的盲区宽度就是给复位路径设计提要求的那把尺子。4.3 鉴相增益KPD与平均输出计算PFD的线性增益KPD定义为平均输出电压或输出电流随相位差变化的斜率。如果是PFD直接挂电阻负载看电压理想情况下KPD VDD/(2π)。举例VDD1.8V那么KPD约为286mV/rad。如果测量到tUP - tDN 100ps时钟周期10ns平均电压差是1.8V × 100ps/10000ps 18mV对应的相位差是2π × 100ps/10ns 62.8mrad两者相除确实得到286mV/rad。如果是PFD加电荷泵的结构增益就变成KPD Icp/(2π)。比如电荷泵电流Icp100μAKPD约为15.9μA/rad。仿真提取时用频率偏置法跑一段较长的瞬态对UP和DN做时间积分得到占空比差再除以对应的相位差范围就能拟合出实际KPD。如果测出来的KPD在中间某个区段偏离理想值说明PFD已经进入非线性区通常就是死区或者盲区造成的。对低噪声设计来说KPD的线性范围越大越好。4.4 最高工作频率与复位延迟的关系PFD的最高工作频率不是一个绝对数值而是“性能还能接受”的临界点。它的理论最小周期大致可以写成T_min ≈ tcoD触发器时钟到输出 复位路径延迟 tsu建立时间在仿真里我习惯这样验证设一个固定相差比如1ns把CLK频率从100MHz逐步提到200MHz、400MHz、800MHz观察UP/DN是否还能输出等比例宽度的脉冲。当出现下面任一现象时说明频率已经接近或超过上限UP/DN出现缺失脉冲脉宽差与预期偏差超过10%复位窗口占整个周期的比例接近50%盲区问题开始显著。举个例子某0.18μm工艺下PFD复位路径延迟约1.5ns实际能稳定工作的最高频率大概在100到150MHz把复位路径优化到500ps之后最高频率可以推到300MHz以上。这就解释了为什么PLL的应用频率范围往往被PFD的复位延迟卡住而不只是看VCO能不能振荡到那么高。这个指标必须在PFD单测里量化留到整环再去排查就晚了。5. 仿真发散与异常波形的排查链路5.1 先分清数值震荡还是电路振荡仿真发散这类问题在很多搜索热词里都排在前面说明大家普遍遇到过。遇到“跑着跑着波形飞了”的情况第一步不是急着改求解器参数而是先判断这到底是数值问题还是电路本身在振荡。数值发散的特征很典型节点电压变成NaN或接近无穷大时间步长被自动压到极小仍然报No convergence波形在某个时间点之后变成一团随机噪声。电路振荡则不同它通常有固定的振荡周期幅度有限而且和外部时钟边沿相关。快速判断的一个办法在一个可疑节点挂一个大电阻到地比如1kΩ或10kΩ。如果波形瞬间恢复正常那很可能是节点缺直流通路或初始值不对属于数值问题如果挂电阻后波形只是形状变了但依然自激那才是电路本身的振荡问题。这个判断看似粗糙实际非常高效能帮你少走很多弯路。5.2 初始条件与复位时序导致的X态和PFD这种数字类电路最相关的坑就是X态也就是未知态。在Virtuoso的Spectre里X态表现为某些节点电压停在VDD和GND之间的奇怪值在ModelSim这类数字仿真器里就是波形上扎眼的红线。两者本质相同触发器或锁存器的初始状态没有确定。处理手段有三个在testbench里加入合理的复位时序前面已经强调过对DFF内部关键节点用.ic语句或者Spectre的set命令做初始化如果复位信号本身有组合逻辑延迟仿真器可能在一个时间步内无法收敛可以在复位路径上插一个buffer级模拟物理延迟。还有一个实际使用中的细节Spectre跑瞬态时默认只保存某些输出端口如果你想在波形数据库里看某一个内部节点必须显式地save这个节点否则“看起来没有这个信号”很容易误判成X态。这个问题我至少帮别人排过十几次每次都是先查save列表再查初始化。5.3 常见报错和对应处理把PFD仿真里出现频率最高的几类异常整理成一张表格方便直接对照排查报错现象常见原因处理方式No convergence in transient节点缺初始条件、步长过大、数字门在中间电平翻转设IC、加nodeset、减小maxstep、PULSE边沿设缓Singular matrix / DC converge fail某个节点没有直流通路浮空在悬空点挂高阻到地如1GΩ或加fF级电容Timestep too small电路存在极快时间常数模型过硬用$bound_step限制步长检查PULSE边沿有没有0sOutput voltage beyond supply复位路径竞争或悬空输入导致门输出到错误电平恢复DFF初始状态检查复位时序Waveform all flat时钟源没起振或testbench没加激励检查激励源的delay/period参数有没有填错一个经验之谈在SPICE里做数字电路仿真时“给悬空节点挂个大电阻”几乎能解决一半的收敛问题但要记住这只是仿真里的权宜之计不是电路修复方案。真正的原因多半是复位策略不完整或者仿真状态没有初始化。挂电阻解决问题之后还是要回头把根本原因找出来。6. 从晶体管级到行为级PFD仿真如何为整环PLL服务6.1 行为级模型要保留哪些参数单测PFD是必要的但一个PLL如果每次都做晶体管级全环仿真时间成本高到不现实。工程上常见的做法是先用晶体管级仿真把PFD的关键参数测出来再把这些参数灌进行为级模型用行为级模型做整环验证。行为级模型必须保留的参数至少有这四项复位延迟t_rst决定盲区宽度和最高工作频率输出摆幅通常等于VDD但如果输出级有压降需要修正输出阻抗或驱动能力影响和电荷泵接口处的时序死区宽度如果模型要做带内相噪估算死区绝对不能省。这四个参数如果不保留整环仿真的意义就大打折扣——你等于拿着一个没有缺点的PFD去评估一个有缺点的PLL最后看到的性能一定偏乐观。很多团队整环仿真和实测对不上问题往往就出在PFD行为模型太理想上。6.2 一个可用的行为级模型雏形与校准方法下面给一个Verilog-A风格的PFD行为模型示意思路是把复位延迟和输出高电平保留下来供整环仿真使用。具体语法建议按所用仿真器Virtuoso ADE、HSpice或AMS稍作调整。include constants.vams include disciplines.vams module pfd_va(clkref, clkfb, up, dn, vdd); input clkref, clkfb; output up, dn; electrical clkref, clkfb, up, dn, vdd; parameter real vth 1.8; parameter real trst 500p; // 复位路径延迟由晶体管级实测标定 integer up_state, dn_state; analog begin (cross(V(clkref) - vth/2, 1)) begin if (!dn_state) up_state 1; end (cross(V(clkfb) - vth/2, 1)) begin if (!up_state) dn_state 1; end (cross(V(up) - vth/2, 1) or cross(V(dn) - vth/2, 1)) begin if (up_state dn_state) begin #(trst); up_state 0; dn_state 0; end end V(up) vth * (up_state ? 1 : 0); V(dn) vth * (dn_state ? 1 : 0); end endmodule校准方法很直接把行为级模型放到和晶体管级一模一样的testbench里跑同一个死区和盲区测试用例对比UP/DN波形。如果上升沿时刻、复位脉冲宽度、输出高电平都对得上模型就基本可用如果差异大优先调整trst再看输出摆幅和压摆率。最后多提醒一句如果你在PLL整环仿真里只想快速过功能直接用理想PFD模型没问题但一旦要评估锁定后的相噪和杂散请务必用标定过的模型。我自己的习惯是把“死区宽度”做成模型里的可配置项留一个变量给系统级仿真这样系统工程师可以快速看到死区从1ps变成10ps对杂散的影响有多大。多做几次这种对比你对PFD在PLL里到底扮演什么角色会比单纯看波形有更深的体感。