拓冰建站拓冰建站
首页 / 资讯中心 / 正文

级联PLL下OCC时钟控制的DFTC配置与“饿死”问题排查

做OCC时钟控制这些年我最怕遇到一种问题ATPG仿真跑起来shift阶段一切正常一到capture阶段波形上明明看到了预期的捕获沿采回来的数据却整片都是X态或者完全不变。刚开始我以为是约束问题反复查set_dft_signal查时序余量折腾了一整天才定位到根因——不是OCC本身写错了而是级联PLL的第二级在测试模式下被硬生生“饿死”了。这个标题里的“饿死”不是比喻是字面意思PLL的参考时钟丢了。级联场景里PLL_B的ref_clk来自PLL_A的输出如果DFTC做OCC控制时只盯着PLL_B的输出时钟没管PLL_A的参考时钟是否在测试模式下可见那PLL_B根本锁不出来OCC产生再漂亮的capture脉冲也没用下游全是无效数据。这篇文章把我踩过的坑、DFTC配置的关键点、以及Hierarchy Flow下的落地建议都梳理一遍希望对做DFT和低功耗集成的朋友有参考价值。1. OCC时钟控制到底在控什么1.1 shift和capture的本质区别要理解OCCOn-Chip Clock Controller的职责得先看at-speed测试的两种工作阶段。Shift阶段用的是低速测试时钟把测试向量逐位移进扫描链这个阶段对时钟频率几乎没要求只要满足DRC规则、保证建立保持时间即可。真正麻烦的是capture阶段测试向量已经装载完成这时候需要产生一个或多个高速时钟脉冲让被测路径上的数据像功能模式一样真实翻转才能在捕获沿到来时把结果打进扫描单元。问题来了——扫描链里的时钟不是功能时钟而是经过测试MUX切换过来的测试时钟。测试时钟本身通常是低频的如果直接用测试时钟做capture那测的就只是低速路径完全达不到at-speed覆盖的目的。这时候必须把时钟源切换回功能时钟路径用PLL输出的高速时钟作为捕获沿。但所有扫描单元都挂在同一根功能时钟树上直接切换会产生毛刺、竞争和不确定的捕获行为。OCC就是干这个的它像一个训练有素的交通警察在shift阶段让测试时钟畅通无阻在capture阶段用精确的时序打开功能时钟产生干净、可控的高速捕获脉冲。1.2 DFTC在OCC流程中的角色在实际项目中OCC不一定是全手工搭的Synopsys的DFTCDFT Compiler可以自动插入clock controller逻辑。DFTC会识别你定义的测试时钟和功能时钟在时钟汇聚点插入OCC结构默认生成标准的安全切换逻辑——通常包含一个锁存器或触发器以及对应的时钟门控。这个自动插入非常方便但也埋了不少雷。DFTC终究是“工具”它按照你的约束和声明来行事。你说清楚了它就给你办得明明白白你没说的部分它不做任何假设或者直接按照最保守的方式处理。我见过最多的坑就是定义了PLL_B的输出作为测试时钟源也定义了OCC enable信号DFTC兴高采烈地在PLL_B输出端插好了控制器报告里一片绿色。结果仿真一跑capture失败。原因是PLL_B根本就没输出时钟它自己还饿着肚子呢。2. 级联PLL为什么会“饿死”2.1 什么是级联PLL先明确概念。所谓级联PLL就是一级PLL的输出时钟作为另一级PLL的参考时钟输入。低功耗SoC里非常常见比如主PLL_A从外部晶振得到26MHz参考时钟输出48MHz这个48MHz再喂给PLL_BPLL_B倍频到2.4GHz供无线子系统使用。这样做的原因是面积和功耗优化——高精度低频晶振通常只有一颗多个高速PLL共享同一个参考时钟源中间加一级PLL做分频或倍频灵活调整各子系统的时钟需求。功能模式下这套方案完全没问题但DFT测试模式下就引入了额外的约束链。PLL_B能否正常工作完全依赖于PLL_A的输出是否稳定。一旦PLL_A的输出在测试模式下被关断、被门控、或者PLL_A本身因为参考时钟丢失而失锁整条链路就断了。2.2 “饿死”的物理机制“饿死”的本质是PLL的参考时钟或者反馈路径在测试模式下不可见。归纳起来有以下几种典型场景第一种上游PLL参考时钟被测试模式门控。很多低功耗芯片在测试模式下会关掉不必要的振荡器或时钟源以此来降低动态功耗缩短测试时间或满足峰值电流要求。如果在UPF或时钟控制逻辑里没有明确把PLL_A的参考时钟设置为“测试模式保持开启”那它很可能在capture阶段就消失了。第二种上游PLL的输出被isolation cell隔离。芯片做了电压域划分PLL_A所在域与PLL_B所在域之间插了isolation cell。功能模式下isolation是透明的但测试模式下如果isolation控制信号被置为clamp值上游PLL_A的输出时钟就被固定成常数。时钟变成了常数下游PLL_B自然锁不出来这就是最典型的“饿死”。第三种PLL的lock信号在测试复位下被清掉。DFTC插入OCC时通常会用PLL的lock信号作为安全切换的条件之一——lock有效才允许从测试时钟切换到功能时钟。有些设计的lock信号受全局复位控制测试模式下一复位就把lock拉低。DFTC看到lock恒为0就认为PLL不可用OCC永远停留在测试时钟状态capture脉冲根本不会产生。2.3 踩坑现场一次典型的capture fail我遇到的一个真实案例是这样的一颗IoT SoC包含两个PLLPLL_A输出48MHz作为PLL_B的参考时钟PLL_B输出2.4GHz作为射频子系统的工作时钟。DFTC插入OCC时我定义了PLL_B的输出作为功能时钟源DFTC也顺利报了OCC controller生成成功。ATPG仿真时shift正常capture异常。打开波形看到PLL_B的时钟输出在capture窗口内完全没有翻转——不是频率不对是根本没有沿。再往上游看PLL_A的输出时钟也是平的。继续追发现PLL_A的输入端ref_clk电压一直是0。顺着这条线查最终定位到一根时钟门控控制线有个HCG硬件时钟门控单元在测试模式下被错误地关闭了它控制的恰好是PLL_A的参考时钟路径。这个HCG在UPF里归属某个低功耗域测试模式的isolation策略把它当成“不需要工作”的模块处理了。这就是典型的“级联PLL饿死”——第二级PLL的参考时钟丢了而DFTC插入的OCC毫不知情。工具管的是OCC怎么生成它管不了PLL上游的电源和时钟门控配置是否合理。3. DFTC配置级联OCC的实操要点3.1 定义清楚DFT时钟拓扑使用DFTC做OCC插入第一步是把DFT时钟拓扑定义完整。这不仅仅是定义测试时钟还要明确告诉工具哪些时钟是测试模式下的源时钟哪些时钟是功能模式下的PLL时钟哪个信号是PLL的锁定指示哪个信号是OCC使能。我在做级联PLL项目时一定会做以下这些声明# 定义测试时钟用于shift阶段 set_dft_signal -view existing_dft -type ScanClock -port test_clk_in -timing {45 55} # 定义OCC enable信号 set_dft_signal -view existing_dft -type OCCEnable -port occ_enable # 定义PLL_B的锁定信号作为OCC切换的安全条件 set_dft_signal -view existing_dft -type PllLock -port pll_b_lock # 定义PLL_A的锁定信号级联场景必须显式声明 set_dft_signal -view existing_dft -type PllLock -port pll_a_lock # 定义PLL_B输出的功能时钟DFTC会在该时钟路径上插入OCC set_dft_signal -view spec -type OCCClock -port pll_b_clk_out -timing {45 55} # 定义PLL_A输出的中间时钟级联节点需要标记为non-test source set_dft_signal -view existing_dft -type ClkSource -port pll_a_clk_out这里有个容易忽略的点PLL_A的lock信号在级联场景下同样必须声明为PllLock并且关联到PLL_B的参考时钟路径上。DFTC只有知道这条依赖关系才会在生成OCC控制逻辑时把PLL_A的lock状态纳入切换条件。否则它只会看PLL_B自身的lock一旦PLL_A失锁导致PLL_B的lock永远拉不起来OCC就卡死在测试时钟状态。3.2 时钟穿透与依赖关系的处理级联PLL还有一种常见形态PLL_A的输出不只是一根简单的时钟线它会经过一系列功能MUX、分频器再进入PLL_B的参考时钟输入。DFTC默认只吃标准时钟网络连接碰到这种经过组合逻辑透传的时钟路径容易报“clock not identifiable”或者直接把路径断掉。我的做法是在DFT约束文件里用create_test_clock配合set_dft_signal把这条路径显式告知工具。更稳妥的方式是在RTL里为级联参考时钟加一个专用的测试旁路MUX——测试模式下PLL_B的参考时钟直接连接到晶振或者片上RC振荡器绕过PLL_A。这样做的额外好处是测试可靠性大幅提升因为capture阶段不依赖PLL_A是否锁定PLL_B只要有稳定的参考时钟就能工作。如果项目不允许改RTL那就必须保证DFTC把PLL_A的输出识别为有效的时钟源节点。我常用的命令是set_dft_signals -view existing_dft -type ClkSource -port pll_a_clk_out -disable false这条命令的意图是告诉工具PLL_A的输出是一根真实的、测试模式下必须保持正常工作的时钟源不允许被优化掉或者被当作普通信号处理。3.3 OCC插入后的验证检查DFTC插入OCC后不能只盯着report_dft_registers里OCC controller的数量就收工。我强烈建议做三件事第一跑一遍report_dft_clock确认所有功能时钟都能与对应的测试时钟建立映射关系。如果PLL_B的时钟在报告里显示“no associated test clock”说明DFTC根本没把它当成可OCC控制的时钟后续ATPG只会在shift工作capture阶段就没这个时钟的戏。第二检查OCC controller的使能逻辑链。打开生成的逻辑确认PLL_A的lock信号确实参与到了OCC的安全切换条件里。如果只在功能时钟门控的AND门里看到了PLL_B的lock而没有PLL_A的任何条件那就要警惕——这说明工具没理解级联关系。第三仿真跑起来后除了看capture出来的数据还要看OCC内部锁存器的状态。OCC切换瞬间的毛刺往往在数据上是看不出来的但抓锁存器的输出波形就能看到。有一个很实用的检查点在OCC锁存器的enable端加断言验证在capture脉冲产生前enable至少稳定了一个完整PLL时钟周期。级联场景下这个周期可能比预期长因为PLL锁定时间可能达到上百微秒测试向量里必须预留足够的时间窗口。4. 常见问题与排查技巧实录4.1 问题速查表实际操作中我把级联PLL相关的OCC问题整理过一张速查表按现象、根因、解决思路归类现象可能根因解决思路capture期间PLL_B无时钟输出PLL_A参考时钟被门控或isolate检查UPF隔离策略测试模式排除ref_clk路径PLL_B的lock信号恒为低lock信号被测试复位清掉测试模式旁路复位或者用lock的extend逻辑DFTC报“clock not controllable”参考时钟经过功能MUX/分频器透传声明existing_dft ClkSource或加测试旁路MUXOCC一直停留在shift时钟PLL_A lock未参与OCC切换条件级联场景显式声明PllLock关联关系capture结果全X态OCC使能时序不满足引入毛刺在OCC锁存器输出加约束检查时钟门控setup/hold功耗过高导致测试失败PLL_A和PLL_B同时运行评估是否必须同时工作改用独立参考源4.2 一条高效的排查路径遇到capture fail我建议先别急着看数据按这条路径逐级查先看PLL_B的时钟输出是否有沿。如果没沿奥卡姆剃刀原则先怀疑参考时钟链路。从PLL_B的ref_clk引脚开始往上游一级一级追。每经过一级逻辑就确认它是否在测试模式下是透明的。这一步能快速定位是物理上的“饿死”还是逻辑上的“锁死”。再看PLL_B的lock信号在capture窗口前是否已经拉高。这里要注意PLL的锁定时间不是瞬时的从参考时钟稳定到lock拉高可能需要几十甚至上百微秒。如果ATPG pattern里推进得太快测试向量还没给够时间PLL自然锁不上。这种情况不是逻辑错误是时序等待不足我经常在pattern开头加足够长的PLL settle时间来解决。第三步查OCC的切换条件确认在capture窗口开始之前OCC enable已经被正确置位且没有其他信号把它拉低。这步可以借助report_dft_registers查看OCC controller内部的寄存器连接关系。4.3 一个容易被忽略的细节反馈时钟路径我以前踩过一次很隐蔽的坑就是PLL的反馈时钟。某些PLL设计里反馈时钟不是在PLL内部短接的而是从外部走一圈再回来。这种设计下测试模式如果把这个反馈路径切断了PLL的输出频率会完全不对甚至VCO都起振不了。排查时只盯着参考时钟忽略了反馈时钟很容易绕弯路。建议在DFTC约束里把反馈时钟路径也声明清楚。尤其是在Hierarchy Flow里反馈路径的时钟可能被block级的隔离逻辑挡住需要特别留意。5. Hierarchy Flow下如何避免级联PLL陷阱5.1 弄懂Hierarchical DFT的基本诉求大芯片做DFT几乎都会用Hierarchy Flow原因很简单一个模块几百万门全平铺做综合和DFTC插入工具跑不动迭代也慢。按模块先做DFT插入再在顶层做连接和复用是标准做法。但Hierarchy Flow在级联PLL场景下有一个天然缺陷PLL_A在Block A里PLL_B在Block B里Block B做DFTC插入时工具只能看到Block B内部的东西。PLL_B的参考时钟在Block B的视角里就是一个来自边界的普通输入端口。如果做Block B的工程师没有意识到这个参考时钟在上层连接着另一个PLL他没有把PLL_A的lock信号与PLL_B的OCC逻辑建立关联那插入的OCC就只是个“半成品”——结构看起来正确实际上切换条件缺了一环。5.2 跨层次约束的三个关键动作做Hierarchy Flow时我建议至少在三个地方做好协同第一Block级约束文件里明确展示外部时钟源的依赖关系。即使PLL_A不在Block B内部也要在Block B的DFT约束中声明一个虚拟的PLL节点。# Block B的约束 set_dft_signal -view existing_dft -type PllLock -port pll_a_lock_from_top set_dft_signal -view spec -type OCCClock -port pll_b_clk_out -timing {45 55} set_dft_capture_signal -view spec -type OCCEnable -port occ_enable -active high第二顶层做时钟连接时一定要把PLL_A的lock信号作为重构OCC依赖关系的输入。换句话说顶层收敛的时候不能只是把Block B的OCC原样搬进来而要把PLL_A的lock和PLL_B的OCC使能逻辑做一次正式的连接检查。第三UPF里为级联PLL设定专门的测试模式隔离策略。在block级UPF里默认的isolation策略可能是对所有输入端口clamp到0这在功能模式下没问题。但是在测试模式下必须让PLL_A的输出时钟端口绕过isolation规则或者至少把clamp值设为1——时钟信号不能clamp到静态值否则下游PLL立刻“饿死”。5.3 Hierarchy Flow的落地建议清单基于这些经验我整理了一份清单每次做级联PLL的Hierarchical DFT时都会逐条确认芯片级的DFT测试模式信号scan_mode, shift_mode需要在使用早期就定义并贯穿到所有子block建议在顶层定义后统一做约束分发。每个block的DFTC插入脚本都需要包含外部PLL口径约束如果block内部没有PLL但存在接收外部PLL时钟的寄存器域建议不做OCC插入把OCC留给顶层统一处理。顶层做OCC连接时优先例化统一的OCC控制模块不要依赖block内auto-insert的OCC结构。UPF里PLL相关域的isolation策略尤其是ref_clk和lock信号要单独列出来review。芯片级DFT仿真时不仅要跑function pattern和scan pattern还要专门跑一个“PLL时钟可见性”检查pattern把所有PLL的参考时钟在测试模式下是否翻转作为检查点。RTL freeze之前跑一遍clock domain crossing检查重点看PLL_A的lock信号跨域到PLL_B的OCC逻辑这一段的同步处理。5.4 一个提升可调试性的好习惯还有一个小技巧我在做Hierarchy Flow时会在PLL链路的关键节点手动插入测试观察点。比如在PLL_B的ref_clk上插入一个always-on的观察寄存器测试模式下把它的值串到扫描链尾部。这样一旦出问题通过scan dump就能看到ref_clk在capture窗口内有没有沿不用反复开波形抓信号。这个观察点面积开销极小但调试效率提升不是一点半点。特别是大芯片一次netlist仿真开机和跑完都要好几个小时如果没有观察点光靠猜和试几轮下来人就麻了。根据我个人经验设计一个级联PLL的OCC方案不管用什么工具流最核心的一点就是提前把所有时钟链路画出来然后把每条链路上的关键信号参考时钟、lock信号、反馈时钟在测试模式下的可见性逐一确认。DFTC能帮你生成OCC结构但生成得对不对、能不能解决级联依赖最终靠的还是对整个时钟拓扑的理解深度。先把拓扑理顺再来谈工具配置这条路最稳妥。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门