1. 这件事得从一个“看似正常”的block级DFT讲起
做DFT的兄弟应该都有这种体会:在block level用DFTC(DFT Compiler)插OCC(On-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到底在做什么
OCC(On-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。也就是说,当测试模式切换到capture,OCC打算把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插了一个OCC,top 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,不插入OCC,OCC统一在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在低温下随机fail | PLL饿死,参考时钟被OCC门控 | 检查PLL ref时钟路径上的gating cell |
| PLL lock信号在仿真中反复跳变 | PLL参考频率突变,lock判定窗口抖动 | 检查测试模式下pll ref时钟是否稳定 |
| block level DFT DRC clean,top 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版本差异的一些提醒
我在不同工艺节点上用过多个版本的DFTC,OCC相关行为有差异,主要体现在对时钟门控单元的处理策略上。
较新的版本对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 edge,capture 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位置回归问题。