Cadence AC/STB仿真避坑指南:PLL死区调试与蒙特卡洛分析实战
1. 从一次PLL失锁说起为什么AC/STB仿真总在关键时刻掉链子做模拟IC这行的估计没人没被Cadence的仿真坑过。尤其是当你辛辛苦苦搭好一个PLL跑完瞬态发现锁定时间对不上或者环路滤波器输出一直在那抖回头去查AC和STB仿真结果发现相位裕度看着有60度实际流片回来就是振。这种“仿真通过、实测翻车”的事我踩过的坑比走过的路还多。这篇笔记不打算给你讲教科书上的稳定性判据那些东西随便翻本Razavi或者Allen的书都比我说得全。我想聊的是在Cadence Virtuoso Spectre这套环境里做AC/STB仿真时那些工具本身给你埋的雷以及PLL调试中死区、鉴相器非线性这些让人头大的问题到底怎么一步步定位和解决。关键词就几个Cadence、AC/STB、PLL、Spectre、蒙特卡洛。适合已经能跑通基本仿真、但结果总跟预期对不上的朋友。如果你还在纠结怎么装Cadence那这篇可能不太适合你建议先去找吴川斌的博客补补课。先说说为什么AC和STB仿真在PLL里这么容易出问题。PLL本质上是个离散采样系统鉴相器PFD在每个参考时钟周期才比较一次相位但你在Cadence里跑AC仿真时Spectre默认把它当连续时间系统处理。这就好比你用分析水管流量的方法去分析一个每秒开关一次的水阀模型本身就不对。STB仿真虽然专门为环路稳定性设计但它依赖你正确断开环路、正确设置probe稍有不慎得到的结果就是错的。更麻烦的是很多时候仿真报错不收敛你根本不知道是电路问题还是设置问题。我见过太多人STB仿真跑出来相位裕度70度高兴得不行结果流片回来PLL直接自激。后来一查probe放错位置了断在了参考时钟路径上而不是反馈路径上。这种错误Cadence不会给你任何警告它只会老老实实按你给的断点算算出一个漂亮但毫无意义的结果。所以这篇笔记的第一部分我想先把AC/STB仿真中那些“看起来对但实际错”的设置讲清楚。2. AC/STB仿真设置里的那些隐形陷阱2.1 为什么你的AC仿真结果和STB对不上先问一个问题你在PLL里跑AC仿真时输入源加在哪很多人习惯性地在参考输入端加一个acm1的电压源然后看输出。但PLL的AC响应跟普通放大器完全不是一回事。普通放大器的AC响应是开环增益随频率变化而PLL的AC响应取决于你断环的位置和方式。如果你在闭环状态下直接加AC源得到的是闭环响应那个东西看相位裕度是没有意义的。STB仿真之所以更靠谱是因为它用了Middlebrook的双注入法或者单注入法在环路内部注入小信号然后计算环路增益T(s)。但这里有个关键probe必须放在信号单向流动的地方。什么叫单向流动就是信号从A到B不会从B倒流回A。在PLL里参考时钟路径和反馈路径在PFD处汇合PFD的输出是单向的所以probe应该放在PFD输出到电荷泵之间或者电荷泵输出到环路滤波器之间。如果你把probe放在VCO输出到分频器之间那也能用但要注意分频器是数字电路Spectre在处理时可能会引入额外的延迟。我个人的习惯是STB probe放在电荷泵输出和环路滤波器输入之间。这个位置信号是电流形式单向性最好而且环路滤波器是线性网络Spectre算起来最准。具体操作是在Virtuoso原理图里在电荷泵输出和环路滤波器之间插入一个iprobe来自analogLib库然后STB仿真设置里选这个iprobe作为probe。注意iprobe的方向箭头要从电荷泵指向环路滤波器反了的话相位会差180度你看到的相位裕度就完全错了。注意iprobe插入后直流工作点会受影响。因为iprobe在DC时相当于短路所以DC分析没问题。但如果你用的是vprobeDC时相当于开路工作点就全乱了。所以STB仿真一律用iprobe别用vprobe。2.2 STB仿真参数设置别让默认值骗了你STB仿真在Cadence ADE里的设置项不多但每一个都关键。打开ADE选Analyses - stb你会看到几个参数Start Frequency、Stop Frequency、Sweep Type、Points Per Decade。默认值通常是1Hz到1GHz每十倍频程10个点。对于PLL来说这个默认值完全不够用。PLL的环路带宽通常在几十kHz到几MHz之间相位裕度最关心的频段就在环路带宽附近。如果你每十倍频程只取10个点在100kHz到1MHz之间只有10个点根本看不出相位曲线的细节。我的习惯是Start Frequency设10HzStop Frequency设100MHzPoints Per Decade设100。这样在关键频段有足够的采样点相位裕度的读数才准。代价是仿真时间变长但STB是频域仿真多几百个点也就多几秒完全值得。还有一个参数叫“Sweep Type”默认是Logarithmic。这个别动PLL的环路增益本来就是按对数频率轴看的。如果你改成Linear在低频段点太密、高频段点太疏结果没法看。另外STB仿真需要正确的DC工作点。如果DC不收敛STB直接报错。PLL的DC收敛问题通常出在电荷泵和环路滤波器上。电荷泵的上下电流源如果匹配不好DC时输出电流不为零环路滤波器就会一直积分导致VCO控制电压跑到电源轨。这时候Spectre会报“DC convergence failed”。解决办法是在环路滤波器节点加一个很大的电阻比如1G欧姆到地给DC提供一条泄放路径。这个电阻对AC响应的影响可以忽略因为它的阻抗远大于环路滤波器本身的阻抗。2.3 AC仿真在PLL里的正确打开方式虽然STB更准但AC仿真也不是不能用。关键是你得知道自己在看什么。在PLL里跑AC通常是为了看闭环传递函数比如参考时钟到输出的传递函数或者VCO控制电压上的噪声传递函数。这时候输入源要加在参考输入端输出看VCO输出或者分频器输出。但这里有个坑PLL的AC响应是调制响应不是简单的线性放大。参考时钟频率变化时PFD输出的相位差是积分关系所以整个环路的传递函数里有一个1/s因子。如果你在AC仿真里直接看增益曲线会发现低频增益是无穷大因为积分器这跟普通放大器完全不一样。所以看AC结果时别去读相位裕度那个东西在闭环AC里没有意义。要看的是闭环带宽、峰值增益、以及在不同频率下的抑制能力。我一般用AC仿真来验证环路滤波器的参数是否合理。比如把环路滤波器单独拿出来跑AC看它的零极点位置对不对。然后再把整个PLL闭环跑AC看闭环带宽是不是跟设计值一致。如果闭环带宽比设计值大很多说明环路增益太高可能需要调电荷泵电流或者分频比。实操心得AC仿真时把VCO当成一个压控振荡器模型来用别用实际电路。实际VCO的AC响应很复杂而且Spectre在AC分析时会把VCO当成一个非线性器件线性化结果可能不准。用behavioral model或者Verilog-A写的VCOAC结果更干净也更容易收敛。3. PLL死区调试从波形上看出问题3.1 死区到底是什么为什么它让PLL输出抖动变大PLL里的死区指的是PFD鉴频鉴相器在输入相位差很小时输出脉冲宽度太窄导致电荷泵的开关来不及完全打开或关闭实际注入环路滤波器的电荷量与理论值不符。这个现象在CMOS工艺里特别常见因为电荷泵的开关管有寄生电容驱动能力也有限。当PFD输出的UP和DOWN脉冲窄到几百皮秒甚至几十皮秒时电荷泵的电流可能只流了一部分甚至根本没流。死区的直接后果是PLL在锁定状态下相位误差会在零附近来回晃但PFD有时候输出脉冲、有时候不输出导致环路增益在零点附近变得非线性。表现出来就是VCO控制电压上有低频抖动频谱上出现参考杂散和相位噪声恶化。更严重的是如果死区太大PLL可能根本锁不住或者锁定时间变得很长。在Cadence里怎么看死区最直接的方法是跑瞬态仿真看PFD的UP和DOWN信号以及电荷泵输出电流。把时间轴放大到参考时钟周期级别看UP和DOWN脉冲的宽度。如果脉冲宽度小于电荷泵开关的响应时间通常看电荷泵输出电流的上升/下降时间那就是死区了。我一般会做一个简单的测试在PLL锁定后用Cadence的calculator或者WaveScan测量UP和DOWN脉冲的宽度然后跟电荷泵的开关时间对比。如果UP脉冲宽度只有200ps而电荷泵的开关时间是500ps那死区肯定存在。这时候要么加大PFD的输出脉冲宽度比如加延迟单元要么提高电荷泵的开关速度。3.2 用瞬态仿真定位死区的具体步骤第一步搭好PLL的瞬态仿真环境。参考时钟用vpulse频率设成你实际用的值比如10MHz。VCO用behavioral model输出频率设成比如2.4GHz。分频比设成240。环路滤波器用实际电路电荷泵也用实际电路。第二步设置瞬态仿真参数。Stop Time要足够长让PLL锁定。通常锁定时间是环路带宽倒数的几十倍。如果环路带宽是100kHz锁定时间大概几十微秒Stop Time设1ms足够了。但要注意瞬态仿真的步长要足够小才能看到PFD的脉冲。Maxstep设成参考时钟周期的1/100比如10MHz参考时钟周期是100nsMaxstep设1ns。这样UP和DOWN脉冲的宽度才能看清楚。第三步跑完仿真后在WaveScan里看UP和DOWN信号。把时间轴缩放到锁定后的几个参考周期比如从900us到901us。你会看到UP和DOWN脉冲交替出现。测量每个脉冲的宽度特别是当相位误差很小时的脉冲宽度。第四步同时看电荷泵的输出电流。如果UP脉冲宽度是200ps但电荷泵输出电流的上升时间是500ps那实际注入的电荷量只有理论值的40%左右。这就是死区的证据。第五步如果确认有死区可以尝试在PFD输出加延迟单元。具体做法是在UP和DOWN路径上各加两个反相器调整反相器的尺寸来改变延迟。延迟增加后PFD的输出脉冲宽度变大电荷泵有足够时间完全打开。但延迟也不能太大否则会引入额外的相位误差甚至导致PLL不稳定。一般延迟设在电荷泵开关时间的1.5到2倍比较合适。注意加延迟单元后要重新跑STB仿真确认相位裕度没有恶化。因为延迟单元会引入额外的极点可能影响环路稳定性。3.3 死区调试中的常见误区很多人一看到PLL输出抖动大就以为是死区然后拼命加延迟。结果延迟加太多PLL反而振了。其实抖动大不一定就是死区也可能是环路滤波器参数不对、电荷泵电流失配、或者VCO本身的相位噪声大。怎么区分看抖动频谱。死区引起的抖动通常集中在参考频率的整数倍附近表现为参考杂散。而环路滤波器问题引起的抖动是宽带的频谱上是一个隆起的包。VCO相位噪声引起的抖动在高频段更明显。还有一个误区是以为死区只在锁定后才出现。实际上在锁定过程中相位误差大的时候PFD输出脉冲很宽没有死区问题。死区只在相位误差接近零时才显现。所以如果你在锁定过程中看波形可能看不到死区。必须等PLL完全锁定后再看UP和DOWN脉冲。另外有些人用AC仿真去看死区这是不对的。死区是非线性效应AC仿真基于线性化模型根本看不到。必须用瞬态仿真而且要看时域波形。4. Spectre收敛问题与蒙特卡洛分析实战4.1 瞬态仿真不收敛的排查思路Cadence瞬态仿真不收敛是仅次于安装问题的第二大坑。报错信息通常是“Trouble with node XXX”或者“Time step too small”。PLL里最容易出问题的节点是VCO控制电压和电荷泵输出节点。原因通常是节点上有很大的电容和很小的电阻导致时间常数极大或者节点上有非线性器件工作点跳变。排查思路是这样的先看报错信息里提到的节点在原理图里找到它看它连接了什么。如果是VCO控制电压节点检查环路滤波器的电阻电容值。如果电阻是1M欧姆电容是1nF时间常数是1ms而你的仿真Stop Time是1us那Spectre会一直用小步长去追这个慢变节点导致仿真时间极长甚至不收敛。解决办法是要么减小电阻电容值但会改变环路带宽要么在仿真设置里加初始条件。用ic语句给VCO控制电压设一个初始值比如设成VDD/2这样Spectre不用从零开始慢慢爬。如果是电荷泵输出节点检查电荷泵的上下电流源是否匹配。如果DC时输出电流不为零节点电压会一直积分到电源轨Spectre在电源轨附近找不到收敛点。解决办法是在节点上加一个大的电阻到地给DC提供泄放路径。或者用Spectre的“gmin stepping”选项让Spectre在DC分析时先加一个大的并联电导然后逐步减小到零。还有一个常见原因是仿真精度设得太高。ADE里默认的reltol是1e-3abstol是1e-12。对于PLL这种大动态范围的电路可以适当放宽。reltol设1e-2abstol设1e-9仿真速度会快很多结果也不会差太多。但要注意放宽精度后小信号细节可能丢失比如PFD的窄脉冲可能被平滑掉。所以如果是在调死区精度不能放太宽。实操心得如果瞬态仿真一直不收敛可以先用DC分析跑一下看DC工作点是否正常。如果DC都不收敛瞬态肯定不收敛。DC收敛了瞬态还不收敛再检查瞬态设置里的Maxstep和Stop Time。Maxstep太大Spectre可能跳过关键跳变Maxstep太小仿真时间太长。一般Maxstep设成最小时间常数的1/10比较合适。4.2 蒙特卡洛分析在PLL里的正确用法蒙特卡洛分析是用来评估工艺偏差对电路性能影响的。在PLL里最关心的偏差是电荷泵上下电流的失配、环路滤波器电阻电容的偏差、VCO增益的偏差。这些偏差会导致环路带宽变化、相位裕度变化、锁定时间变化。在Cadence里跑蒙特卡洛首先要确保你的工艺库支持蒙特卡洛模型。通常PDK里会有mc或者stat的模型库。在ADE里选Tools - Monte Carlo然后设置采样次数。一般跑200次左右结果就有统计意义了。采样次数太少比如只跑10次结果波动很大看不出真实分布。蒙特卡洛分析的类型有两种工艺偏差process和器件匹配mismatch。工艺偏差是所有器件一起偏比如所有电阻都偏大10%。器件匹配是每个器件独立偏比如两个电阻一个偏大一个偏小。在PLL里电荷泵的上下电流源失配主要是mismatch环路滤波器的电阻电容偏差主要是process。所以两种都要跑。跑完蒙特卡洛后看结果的直方图。比如看相位裕度的分布如果均值是60度标准差是5度那最差情况可能只有45度这就危险了。如果标准差是2度最差情况还有54度那就比较安全。根据这个结果你可以决定要不要加大设计余量比如把标称相位裕度设成70度这样即使偏了也有60度以上。注意蒙特卡洛分析很吃仿真时间。跑200次STB仿真每次几秒总共也就十几分钟。但如果跑200次瞬态仿真每次几分钟那就是十几个小时。所以蒙特卡洛一般只跑STB和AC不跑瞬态。锁定时间的偏差可以用行为级模型来评估速度快很多。4.3 蒙特卡洛结果解读与设计余量分配蒙特卡洛跑完后Cadence会生成一个统计报告里面有均值、标准差、最小值、最大值。但别只看这些数字要看分布形状。如果分布是正态的那均值加减三倍标准差就是99.7%的覆盖范围。如果分布是偏的比如相位裕度的分布往低处偏那说明有些工艺角下相位裕度特别差需要重点关注。我一般会把蒙特卡洛结果和工艺角仿真结合起来看。工艺角仿真跑TT、SS、FF、SF、FS五个角蒙特卡洛跑统计分布。如果某个工艺角下相位裕度已经接近临界值那蒙特卡洛里肯定有更差的情况。这时候就要回去改电路比如加大电荷泵电流、调整环路滤波器零极点。设计余量怎么分配我的经验是相位裕度标称值至少留10度余量比如设计目标60度标称值要做到70度。环路带宽的偏差控制在正负20%以内。锁定时间的偏差可以放宽到正负50%因为锁定时间对很多应用来说不是特别关键。电荷泵电流失配控制在1%以内这个对参考杂散影响很大。5. 那些Cadence使用中的零碎坑5.1 器件未定义与库设置问题“cadence仿真器件未定义”这个报错通常是因为原理图里用了某个器件但仿真模型库没加载。比如你从别的项目拷贝了一个原理图里面用了某个工艺库的MOS管但你的ADE里没加载那个库的模型。解决办法是在ADE的Setup - Model Libraries里把对应的.scs或者.lib文件加进去。注意路径要写对别用相对路径用绝对路径最稳。还有一种情况是器件是behavioral model比如Verilog-A写的但你没编译。Verilog-A模型需要先用compiler编译成Spectre能识别的格式。在ADE里选Setup - Simulator - Spectre然后选Verilog-A编译选项把模型文件加进去编译。另外如果你用的是Cadence自带的analogLib库里面的器件比如vcvs、vccs、res、cap一般不需要额外加载模型。但如果你用了ahdlLib里的器件可能需要加载对应的模型文件。5.2 瞬态仿真中的初始条件设置PLL瞬态仿真最头疼的是锁定时间太长。如果环路带宽是10kHz锁定时间可能几百微秒仿真起来很慢。这时候可以用初始条件来加速。在VCO控制电压节点上加一个ic语句设成你估计的锁定电压。比如VCO调谐范围是0.5V到1.5V锁定电压大概在1V那就设ic1V。这样Spectre不用从零开始积分直接从这个电压附近开始锁定时间大大缩短。但要注意ic语句只在瞬态仿真的初始时刻有效。如果设得不准PLL还是会慢慢调到正确的锁定电压只是快一点。如果设得太离谱比如设成0V而实际锁定电压是1V那PLL还是要花时间爬上去。所以ic值要尽量准可以通过先跑一次短时间的瞬态仿真看控制电压大概稳定在多少然后再设ic。还有一个技巧是用“nodeset”而不是“ic”。nodeset是给Spectre一个初始猜测值但不强制固定。ic是强制固定初始值。对于PLL用nodeset更安全因为如果猜测值不对Spectre可以自己调整。用ic的话如果初始值太离谱Spectre可能报错。5.3 铜皮优先级与版图相关仿真“cadence铜皮优先级”这个热搜词其实跟PLL仿真关系不大但既然提到了就顺带说一句。在版图里铺铜时不同网络的铜皮优先级会影响寄生电容。电源和地的铜皮优先级最高信号线次之。如果信号线的铜皮优先级设得太高可能会跟电源铜皮重叠导致寄生电容增大。在PLL里VCO控制电压节点对寄生电容很敏感所以这个节点的走线要尽量短铜皮优先级要设低避免跟其他网络重叠。仿真时可以用Cadence的寄生提取工具比如Quantus提取版图寄生然后反标到原理图里跑后仿。后仿的STB结果跟原理图可能差很多因为寄生电容会改变环路滤波器的零极点。我一般会在版图完成后跑一次后仿STB确认相位裕度还有足够余量。如果后仿相位裕度掉到50度以下就要回去改版图减小寄生电容。6. 从仿真到流片一些个人经验PLL这个东西仿真跑通只是第一步流片回来能工作才是真的。我做过几个PLL项目总结下来有几个经验第一STB仿真的相位裕度至少留10度余量因为后仿和实测还会有偏差。第二电荷泵的匹配性比什么都重要上下电流失配超过2%参考杂散就会很明显。第三VCO的相位噪声在仿真里通常比实测好因为仿真模型没包含衬底噪声和电源噪声所以设计时要留够余量。第四死区问题在仿真里可能看不出来因为仿真模型太理想实际流片后电荷泵的开关速度可能比仿真慢死区更严重。所以PFD输出延迟要留够宁可大一点也别小。蒙特卡洛分析一定要跑而且要看最差情况。我见过一个设计标称相位裕度65度蒙特卡洛跑出来最差只有40度流片回来果然有几颗芯片锁不住。后来回去改电荷泵电流把标称相位裕度提到75度蒙特卡洛最差也有55度流片就没问题了。最后说一句Cadence的仿真工具很强大但也很容易给你假象。仿真结果漂亮不代表电路没问题仿真报错也不代表电路一定不行。关键是要理解每个仿真设置背后的物理意义知道自己在看什么才能从波形里读出真正的问题。