级联PLL场景下DFTC插入OCC导致PLL饿死的根因与规避方法
1. 这件事得从一个“看似正常”的block级DFT讲起做DFT的兄弟应该都有这种体会在block level用DFTCDFT Compiler插OCCOn-Chip Clock Controller时工具跑完一切正常drc也过了pattern也生成了眼瞅着就要signoff。结果到了top level或者到了ate自动测试机上跑shmoo的时候发现只要是涉及到PLL链路的at-speed pattern良率掉得离谱。查到最后问题往往就出在“OCC把级联PLL的参考时钟给切断了”PLL直接饿死在半路上。这个坑我踩过不止一次查起来是真的折磨。因为从DFTC的log、报告、甚至仿真波形上看一开始都“正常”——pattern能跑capture能采但就偏偏在某些电压/温度角落下PLL的lock信号迟迟不来或者中途掉锁导致launch沿和capture沿的频率、相位全不对出来的结果自然是天上一脚地上一脚。这篇文章就围绕一个核心场景来拆多级PLL级联也就是第一个PLL输出时钟作为第二个PLL参考时钟的设计在这条链路里DFTC插OCC时稍有不慎就会让后面的PLL无参考可用。全文会讲清楚OCC的工作机制、级联PLL“饿死”的根因、DFTC里的设置细节以及Hierarchy Flow下面怎么合理地规划OCC插入的位置。2. OCC和级联PLL的基本盘先对齐一下2.1 OCC到底在做什么OCCOn-Chip Clock Controller是at-speed测试的核心。所谓at-speed测试就是让芯片在接近正常工作频率下跑扫描链检查setup/hold是否有问题。测试机提供的时钟频率往往只有几十MHz根本达不到芯片内部的GHz级工作频率所以必须依赖芯片内部的PLL产生高速时钟。但扫描链移位阶段shift要用慢速、稳定、最好是直接由测试机控制的时钟capture阶段才需要切到高速PLL时钟这个过程就靠OCC来完成。OCC本质上就是一个“时钟源切换器”加“沿控制器”它一般包括一组MUX负责在功能时钟来自PLL和测试时钟来自测试机/扫描时钟之间做切换一个launch clock generation逻辑负责产生特定的沿上升沿、下降沿、或者两个沿一组clock gating cell用来精确控制输出给被测逻辑的时钟脉冲数量。DFTC做插入时会识别设计里的时钟结构自动把OCC挂到对应的时钟通路上。默认情况下工具倾向于把OCC插在你指定的“测试主时钟”和“功能时钟”交汇的位置而这个位置选得对不对直接决定PLL会不会被饿死。2.2 级联PLL的时钟结构什么叫级联PLL就是一个PLL的输出再作为另一个PLL的reference clock。典型场景有两类第一类前级PLL负责把低频输入比如25MHz晶振倍频到一个中间频率比如1GHz后级PLL再基于这个1GHz生成多个高频输出比如3.2GHz、2.4GHz用作不同模块的时钟。第二类前级PLL在低速下做相位锁定和滤波输出一个干净的低相噪频率后级PLL做频率综合输出GHz级时钟。这样做的好处是能把整个时钟树的抖动控制得更好。不管哪类前级PLL的参考时钟如果断了后级PLL就相当于“哑火”。这个概念不难但麻烦就麻烦在DFT工具不会替你考虑这层逻辑的物理依赖关系。3. 级联PLL“饿死”的根因与DFTC的默认行为3.1 DFTC插OCC时的时钟路径识别逻辑DFTC判断插OCC的位置依赖的是SDC里定义的时钟约束。它一般把时钟分成三类看你定义的功能时钟create_clock、测试时钟set_dft_signal或者create_clock搭配test mode以及由PLL输出衍生出来的时钟create_generated_clock。在单级PLL场景下功能时钟就是PLL的输出时钟OCC插在PLL输出和被测逻辑之间这是标准做法完全没问题。但到了级联PLL场景如果你把一个PLL输出衍生出来的时钟定义成另一个PLL的输入参考时钟事情就会变得微妙。DFTC在识别这条通路时有可能会把OCC插进参考时钟通路上。举个例子xtal 25MHz - PLL1 - clk_1GHz - PLL2 - clk_3p2GHz你在SDC里写了create_clock -name xtal_clk -period 40 [get_ports xtal_in] create_generated_clock -name clk_1GHz -source [get_ports xtal_in] \ -divide_by 40 [get_pins pll1/clk_out] create_generated_clock -name clk_3p2GHz -source [get_pins pll1/clk_out] \ -multiply_by 32 [get_pins pll2/clk_out]DFTC在插OCC时识别到PLL2的源时钟是pll1/clk_out它可能就会沿着这条路径找交汇点。如果这条通路上没有任何保护逻辑工具很容易把OCC的clock mux直接串在pll1/clk_out到pll2/clk_ref之间。这样带来的后果是只要进入了测试模式或者capture模式OCC切到测试时钟pll1/clk_out到pll2/reference就被切断了PLL2因为长时间没有参考时钟从锁定状态掉出来。3.2 所谓“饿死”的具体表现PLL“饿死”不是一个比喻它是一个实打实的失效过程。PLL要维持输出时钟的频率和相位靠的是参考时钟和反馈时钟之间的相位比较。当参考时钟消失时PLL的鉴频鉴相器PFD没有输入环路滤波器上的电压会逐渐飘掉VCO输出频率会漂移直到最终停振或者掉到某个不稳定的自由振荡频率。这个过程的典型时序特征是PLL lock信号在几十微秒到几百微秒内从高变低即使lock信号还没来得及掉输出时钟的jitter也会明显恶化在pattern的capture窗口内时钟沿的位置是不可预测的所以测试结果表现为随机性fail而不是稳定fail电压越低、温度越高PLL饿死越快。所以你在ATE上看到的现象可能是同一个pattern换个电压温度点就挂挂的fail bit每次还不一样这种“幽灵式失败”查起来非常痛苦。3.3 为什么功能模式没问题测试模式就挂这是最让人迷惑的一点。功能模式上电PLL一直有参考时钟从头到尾都工作得好好的。一到测试模式pattern加载完成scan enable切换OCC介入PLL2的参考就被干掉了。其实根子就在OCC插入位置错误。DFTC默认会把OCC插在它认为的“功能时钟与测试时钟的汇聚点”。如果你的SDC里没有明确把PLL的参考时钟路径保护起来工具就按照纯拓扑逻辑去选点。在单PLL设计里这个汇聚点通常就是PLL输出到逻辑的第一级mux/门控没毛病。但在级联PLL设计里它可能选到pll1输出到pll2参考输入之间的某个节点上——因为在工具的拓扑图上这里也满足“功能时钟源头”的定义。4. 实际操作用DFTC做级联PLL场景时怎么避免踩坑4.1 插入前必须做的检查在跑insert_dft之前先花十分钟把下面的检查做掉能省下后面一周的调试时间。第一列出所有PLL的参考时钟路径确认路径上没有DFT插入的mux或gate cell。可以用如下命令检查# 查看PLL ref clock路径上有没有clock gating get_cells -quiet -hier -filter ref_name ~ *CLK_GATE* \ [get_pins -of_objects [get_nets -of_objects [get_pins pll2/clk_ref]]]第二确认SDC里create_generated_clock的source定义。PLL2的generated clock source一定不能是pll1的clk_out再经过任何DFT逻辑来找而应该是pll1/clk_out直接到pll2/clk_ref这条纯净路径上的节点。第三检查PLL的lock信号在测试模式下是否可控可见。如果lock信号在top level被某些test mode信号强制拉低或者做冗余那PLL饿死后的现象会被mask掉一部分给调试增加难度。4.2 在DFTC里正确设置OCC的插入点这里推荐一个稳妥的做法OCC统一插在后级PLL输出之后不要插在前级PLL输出的参考路径上。当然DFTC不会自动这么干需要你通过约束来引导。如果使用DFTC的的插入方式关键指令大致是这样set_dft_signal -view existing_dft -type ScanClock \ -port test_clk -timing [list 0 25] set_dft_signal -view existing_dft -type Constant \ -port test_mode -active 1 set_dft_signal -view spec -type OCCObserve \ -port occ_observe_0 set_scan_clock_configuration -clock_domain clk_3p2GHz \ -launch_capture_same_domain然后为了避免DFTC把OCC插到pll1的输出上需要用一个属性或时钟排除声明明确PLL1的输出不作为OCC的候选位置set_dft_signal -view spec -type Clock \ -port test_clk set_multicycle_path -from [get_clocks xtal_clk] \ -to [get_clocks clk_3p2GHz] -setup 4 # 告诉DFTC这条路径上的时钟不参与OCC mux set_dft_path -from [get_pins pll1/clk_out] \ -to [get_pins pll2/clk_ref] -type false_path -test这种约束能让工具在分析OCC插入候选点时跳过pll1到pll2的参考路径只保留pll2输出作为功能时钟插入OCC。我刚才提到-type false_path -test在实际项目里这个约束不一定被所有版本的工具正确识别更稳妥的替代方案是把PLL参考时钟的路径用set_clock_gate或者set_dft_signal -view spec -type Reset前后的逻辑隔离起来。4.3 PLL bypass mode是另一个必须考虑的环即使OCC插对了位置级联PLL在测试模式下还有一个坑PLL本身在shift阶段要不要旁路掉很多PLL都会有bypass模式就是把PLL输出直接旁路到参考/分频时钟绕过内部的VCO和反馈环路。在扫描模式shift下我们一般希望时钟尽量简单、可控、低抖动所以会启用PLL bypass或者直接用测试机时钟。如果PLL没有bypass模式那至少也要保证PLL在shift阶段保持锁定不然shift到capture转换的瞬间时钟沿会乱跳。级联PLL场景里两个PLL的bypass控制信号最好独立可控。因为前级PLL可能在bypass下输出一个粗时钟这个粗时钟仍然能给后级PLL做参考如果两个PLL被绑成一个信号控制前级bypass后后级参考跳到另一个频率后级锁相条件突变失锁概率大增。实操建议在DFTC里把PLL bypass信号声明为一个test control signal并且在SDC约束里确保bypass信号不被DFT逻辑吞掉同时让这两个PLL的bypass选择信号分别可观测可控制set_dft_signal -view spec -type TestMode -port pll_bypass_1 set_dft_signal -view spec -type TestMode -port pll_bypass_2 set_dft_signal -view spec -type TestMode -port pll_div_sel当然具体端口名因项目而异核心是让这两路control井水不犯河水。5. 实操案例这个坑我们是这么填上的5.1 问题背景我经手过的一个无线收发芯片项目时钟系统就是典型的两级PLL级联外部26MHz晶振经过PLL_A倍频到416MHz作为中频本振同时这个416MHz又作为PLL_B的参考时钟PLL_B输出3.328GHz的射频本振。DFT部分要求在block level用DFTC做OCC插入支持AC scan。第一版DFTC流程跑完block level的DRC是clean的也没报任何OCC相关的warning。结果上到top level做了几片工程样片实测发现射频本振在AC scan pattern下失锁严重具体表现是射频本振的频偏能达到几百kHz以上而spec只允许±10kHz。一开始还以为是模拟PLL IP的建模问题后来在仿真里抓PLL_B的lock信号才发现在capture窗口的前几十纳秒lock就彻底掉下去了。5.2 定位过程我的定位步骤大致是这样第一步把DFTC生成的deliverable拿出来跑report_dft_configuration和report_dft_signal确认OCC的时钟通路选点。第二步仿真里拉出PLL_B参考时钟端的波形看它在ATPG pattern下是不是被切掉了。第三步用report_clock_gating检查pll_A输出到pll_B ref之间有没有插入gating cell。果然在PLL_A的clk_out到PLL_B的clk_ref之间DFTC插入了一个OCC的gating cell。也就是说当测试模式切换到captureOCC打算把PLL_B的输出时钟替换成测试时钟时连PLL_B的参考时钟也被门控了。PLL_B的参考时钟停顿几个微秒lock自然掉。dfx口的兄弟查了好几天最后是在波形里一眼看到ref clk被gate才定位到这个gating cell然后顺着DFT report找到这个cell是在block level DFT插入时被加进去的。5.3 修复方案修复并不复杂复杂的是找出这个问题的过程。修复时做了三件事第一在PLL_A到PLL_B_REF的路径上加set_dft_path -type false_path让DFTC在插入OCC时直接把这个路径排除。第二把OCC的插入位置显式指定到PLL_B输出时钟树的leaf cell级别汇聚点上也就是靠近scan flop的clock root位置不让工具自己选。第三增加PLL_B lock信号的观测点。在OCC controller附近加一个observable flop专门用来在测试模式下采样PLL_B的lock状态这样如果在ATE上再出现失锁不需要靠现象猜而是直接在shift out的数据里看到lock信号跳变的时间点。修复后的DFTC报告里OCC的clock逻辑只出现在clk_3p328GHz路径上不再出现在clk_416MHz_path上PLL_B的参考时钟在任何测试向量下都不再受OCC控制。6. OCC时序控制细节launch捕获沿与锁相环稳定时间的关系插对位置只是第一步。级联PLL场景里还有一个常见问题是OCC的launch和capture脉冲之间的间隔跟PLL的重新锁定时间根本对不上。常规的at-speed测试OCC在capture窗口内产生两个高速时钟沿一个launch沿一个capture沿两个沿之间的间隔就是一个功能时钟周期。这个过程中PLL必须保持稳定输出。如果PLL因为参考时钟波动发生了锁相环环路调整输出时钟的瞬时频率就会变化launch和capture之间的实际时间间隔就不再等于设定的一个周期。在级联PLL里这种风险是双倍的。只要其中一个PLL对参考噪声的容忍度不足另一个输出端就会被波及。这就涉及到一个关键参数PLL的环路带宽。如果前级PLL的环路带宽较低对输入参考的瞬间变化响应比较钝那么当后级PLL对参考未做充分去耦时整个锁定状态会变得脆弱。实际经验是在create_generated_clock里把PLL输出定义成ideal network如果在DFT阶段需要保持ideal或者None-ideal之前先确认后级PLL的参考在测试模式下的jitter预算。关于OCC本身的时序约束有三组时序你必须单独检查shift clock到capture clock切换时PLL的输出要稳定这个窗口由PLL lock时间决定一般是几十到几百微秒由test protocol保证OCC的launch到capture间隔必须小于PLL的失锁时间否则capture沿采到的数据可能来自失锁后的乱掉时钟OCC的控制信号一般是scan_enable的派生信号在PLL输出的时钟域上要有setup/hold余量。这里最容易出问题因为scan_enable是测试机慢速时钟域的进入PLL高速时钟域后如果没有做同步处理OCC很容易出现亚稳态导致launch沿丢失。一个工程上稳妥的做法在OCC内部的launch/capture沿控制flop上加一组约束把scan_enable的释放时刻release time相对于PLL时钟沿做固定设置set_dft_signal -view spec -type ScanEnable \ -port scan_enable -timing [list 0 10] set_scan_enable_configuration -hierarchical_reuse false \ -shared_scan_enable false这样至少保证scan_enable在测试模式下的时序是可预估的。7. Hierarchy Flow建议DFTC做OCC时的分层策略7.1 分层设计的三个典型问题做Hierarchy Flow时OCC的插入问题会被再次放大。因为每个block独立做DFT做完后提到top level拼接以下三个问题几乎必然遇到第一大问题重复插入。block level插了一个OCCtop level在做reuse的时候工具又发现了一个“更好”的插入点结果插了两个OCC链路多了一级mux时钟路径延迟明显变大。第二大问题跨block的PLL参考时钟路径被意外门控。比如PLL_A在block A里PLL_B在block B里top level之间连接用的是普通信号线。如果block A的DFT边界条件处理不好进入block B的ref clk路径会在top level被某些test mode信号强制拉低。第三大问题OCC的control信号在不同block之间不同步。每个block各自插入的OCC如果它们共用同一个scan_enable信号但从top到两个block的到达时间差异过大两个OCC的launch/capture时序就会错开导致跨block路径的at-speed测试完全没法做。7.2 推荐的Hierarchy Flow做法基于我多次踩坑的教训建议的顺序是“先定边界再插OCC后做优化”不要反过来。第一步在block level做DFT规划时就明确哪些时钟路径属于“PLL参考通路”这类路径一律不允许插入任何DFT逻辑。可以通过在SDC里把这部分时钟设成-dont_touch来实现。第二步在插入OCC时把OCC controller的位置固定在block的leaf cell级别。也就是让OCC尽量靠近sink flop的clock root不要安排在block的port上。这样后续在top level做时序修复时还有一定的余量可以插buffer不会因为OCC位置太靠前导致后面一长串clock tree全部要重跑。第三步top level做DFT时对来自不同block的OCC统一做约束统一。Hierarchy Flow里还有一个推荐的做法——block level只做测试时钟的prepare不插入OCCOCC统一在top level插入。我理解有些团队会担心block level的clock routing会丢失OCC对时序的影响但实践中现代流程的抽象化水平已经足够好。block level先把测试时钟树做成“可测试的”OCC留到top做这样能最大程度避免跨block的PLL参考通路被误伤。当然这是个流量落地决策没有一个绝对正确的答案。如果项目要求每个block单独出pattern那你必须做block level的OCC插入如果所有pattern都在top生成那么top level插OCC是更稳妥的选择。7.3 Hierarchy Flow下的PLL lock信号处理这是很多人容易忽略的细节。PLL的lock信号在block level可能只有一个端口到了top level如果这个信号被DFT逻辑使用比如用来gating时钟那它必须被正确约束。在级联PLL的Hierarchy Flow里我建议把PLL lock信号当作一个独立的测试观测信号而不是一个时钟门控信号。什么意思就是lock信号可以用于simulation里的检查和ATE上的判断但不要用它去gating时钟。因为PLL lock信号本质上是一个模拟电平转换到数字域的信号它的建立时间、毛刺特性、在不同电压温度下的翻转点都不像数字标准单元那么干净。用它去gating任何时钟永远是DFT里最脆弱的路径之一。如果芯片规格确实要求用lock信号来gating时钟那么至少要在lock信号进入数字逻辑之后先做两拍同步再去做gating且在DFT插入时明确这个同步链不属于scan chain的一部分或者把同步链的第一级flop排除在scan chain之外避免测试模式下lock信号路径被注入不相关的逻辑值。7.4 时钟域交叉CDC视角下的OCC与PLL级联PLL场景天然会引出CDC问题。因为PLL A输出的时钟和PLL B输出的时钟是两个异步时钟域。OCC在测试模式下会在这两个域之间做某种形式的同步/切换。举个例子OCC观察来自PLL_A时钟域的信号然后用PLL_B的时钟去采样它这就要在测试模式下考虑这个跨域路径的稳定性。在功能模式下这条路径可能根本不存在或者经过了严格的双触发器同步。但在DFT模式下OCC会旁路掉这些同步器直接把两个域的数据路径串起来。在插入OCC后必须检查OCC内部控制逻辑的CDC路径是否都被正确处理了。最简单的方法是看OCC的RTL模型如果OCC内部控制信号都来自被测时钟域本身那相对安全如果有跨域信号就要查该信号是否经过同步。实践中我用过的一个方法是在insert_dft之后跑一下report_clock_domain_crossing如果工具支持或者用formality做逻辑等价性检查时专门核对OCC控制逻辑在不同clock domain下的连接。8. 常见问题与排查技巧实录8.1 问题排查速查表现象可能原因排查手段AC pattern在低温下随机failPLL饿死参考时钟被OCC门控检查PLL ref时钟路径上的gating cellPLL lock信号在仿真中反复跳变PLL参考频率突变lock判定窗口抖动检查测试模式下pll ref时钟是否稳定block level DFT DRC cleantop level fail跨block的测试时钟边界处理不一致检查top level的复用OCC是否和block OCC重复功能模式PLL输出正常测试模式PLL输出频率偏移PLL参考时钟在测试模式下被bypass或gating对比功能/测试模式下PLL参考时钟波形OCC插入后setup time恶化严重OCC的clock mux和gating插得离sink太远把OCC位置调整到leaf cell级别同一个pattern重复跑fail bit每次不同时钟沿位置不确定大概率是PLL失锁或jitter超差在ATE上抓PLL lock和ref clk看时序Shift阶段正常capture瞬间挂OCC的launch/capture沿控制有问题或者PLL稳定时间不够调整test protocol里的PLL lock time级联PLL场景后级PLL失锁但前级正常后级PLL参考时钟被OCC截断重点检查前级PLL输出到后级PLL ref的路径8.2 我自己的习惯性排查步骤因为我吃过太多这种亏后来总结了一套“五步定位法”专门用来处理OCC和PLL相关的DFT问题。第一步复现并确认现象。在仿真或者ATE上确认问题只在at-speed pattern下出现shift pattern完全正常。这能快速排除scan chain结构性问题。第二步抓PLL相关信号。把每个PLL的ref clk、lock、输出时钟全部拉出来看。重点不是看有没有而是看时间关系。PLL饿死和老化的特征区别在于饿死时ref clk会有明确的“截至”时刻输出频率漂移是渐进的。第三步检查DFTC插入日志。搜occ、clock controller、clock gating这些关键字看工具在哪里插了gating cell。如果插入点出现在“PLL输出到另一个PLL参考时钟”的路径上基本就实锤了。第四步反标SDC约束。有时候问题不在DFTC而在SDC本身。如果SDC里把PLL的ref clk定义成了某个衍生时钟的source工具的路径分析就会自动关联然后选了一条不想要的通路。这种情况要先把SDC简化到最小复现条件再逐步加约束。第五步做设计层面的验证。改完约束后不要只跑DRC要用实际pattern做仿真确认尤其是把PLL的模拟行为模型带上。8.3 关于DFTC版本差异的一些提醒我在不同工艺节点上用过多个版本的DFTCOCC相关行为有差异主要体现在对时钟门控单元的处理策略上。较新的版本对set_scan_clock_configuration的支持更细可以按clock domain分别指定launch/capture关系。但版本越新工具对“PLL参考时钟”的自动推断能力不一定越强。它依然不理解什么叫“这个PLL的ref必须一直在线”。所以不要因为是新版本就放松对SDC的检查。还有一个容易忽略的点DFTC在某些版本下会根据时钟周期自动推导OCC的pulse模式。比如你定义了-multiply_by 32的generated clock工具可能认为capture需要32个周期才能完成。当测试机的clock资源不够时OCC会自动插入额外的“等待周期”。这些等待周期里PLL的参考时钟如果被门控同样会导致饿死。所以在report里看到OCC的pulse序列时多看一眼它有没有在中间插入等待周期以及这些周期内PLL ref是否在线。9. 关于设计本身的一点延伸能不能绕开OCC绕开OCC当然可以有些低功耗设计会要求用功能路径直接做capture。但at-speed测试基本绕不开OCC除非你改用BIST或者完全依赖外部高速测试机的时钟这在实际量产中成本过高且频率受限。如果你真的想减少OCC对PLL的影响可以考虑用下面的思路第一PLL的bypass功能要设计得足够完整尤其要支持“参考时钟直通”模式。也就是PLL在bypass下输出的不是VCO频率而是参考频率分频后的时钟。这样测试模式下整个时钟网络都统一到慢速时钟域不涉及PLL锁定的依赖。第二如果芯片有多个PLL尽量让每个PLL都有独立的旁路和锁定状态输出。千万不要把多个PLL的bypass信号做成同一个管脚控制除非你有非常充分的理由。第三OCC的功能可以进一步简化。很多OCC问题出在launch/capture沿选择逻辑太复杂。如果你的设计只要求launch on rising edgecapture on rising edge那就不建议开一些高级的OCC功能。越简单的OCC越少出幺蛾子。10. 量产调度视角不要忽略ATE上的PLL settling time哪怕你在设计阶段把所有OCC和PLL逻辑都弄对了ATE上还有一道坎——PLL的settling time。测试机往芯片加载pattern第一步是进入shift模式然后是切换capture模式中间有一段PLL lock time。这个时间在test protocol里一般是通过pulse_clock或者timeplate设置的。如果设置得太短PLL还没锁定就开始capture那前面所有OCC的努力都白搭。在级联PLL场景里这个settling time要按“最慢的那个PLL”来算。也就是前后两个PLL的lock时间之和甚至还要留出余量因为后级PLL的参考在前级稳定之前是不准的。我见过一个项目测试工程师为了跑量把PLL lock time从200us压缩到80us结果良率掉了3个百分点。改回150us后良率恢复。这就是典型的为时间牺牲性能的教训。给个建议在test protocol里PLL lock time这个参数一定要跟DFT工程师确认不要自己拍脑袋定。DFT工程师至少要在仿真里验证过PLL lock信号在vgg/tj 最差角落下的建立时间再给出一个安全窗口。另外如果pattern支持repeat功能可以在上电初始化阶段重复多次“复位PLL - 等待lock - 检查lock”的流程确保PLL已经稳定进入锁定状态再开始真正的测试。这招对PLL饿死的排查也能用——如果重复上电流程后良率明显改善那问题基本就在PLL锁定相关的时序上。11. 最后分享一个调试小技巧做OCC相关调试时我强烈建议在流片前的仿真环境里至少留一组“最坏情况PLL模型”的仿真用例。所谓最坏情况不是指PLL仿真模型本身而是指把PLL的lock时间、VCO起振时间、ref clk丢失后的掉锁时间都放到极限值。为什么要这样做因为留到流片后在ATE上排查PLL饿死问题的成本高得离谱——每一轮实验都得烧片、上机、跑pattern、抓波形一天下来可能就只验证了一个假设。而在RTL仿真里改一个模型参数、跑一轮回归成本微乎其微。如果项目处于早期阶段还可以考虑让DFT工程师和模拟工程师共同参与PLL相关DFT方案的评审。很多PLL饿死的问题模拟工程师一眼就能看出来因为他们比任何人都清楚PLL对参考时钟丢失的恢复时间以及lock信号掉落后的行为特征。而DFT工程师则更清楚OCC会在哪条路径上做文章。两者之间多聊一聊比事后调试省太多时间。我在实际项目中还有一个小习惯在DFTC插入完OCC后把report_clock_gating的gating cell清单导出到CSV再用脚本把是否落在PLL参考路径上这一列标记出来。这个脚本逻辑不复杂但能帮我在每次flow改版后快速发现回归问题。这个做法不值钱但确实帮我避过好几次大改版引入的OCC位置回归问题。