ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

多时钟域Scan Chain设计实战:从DFT规划到ATPG覆盖率提升

多时钟域Scan Chain设计实战:从DFT规划到ATPG覆盖率提升 做芯片验证和DFT这些年经手过的多时钟域项目一只手数不过来。每次聊到Scan Chain设计总有人觉得“不就是把寄存器串起来嘛有什么难的”。真踩过坑的人才知道多时钟域下把链排好只是第一步让链在测试模式和功能模式都稳定工作才是真正考验功力的地方。所以这篇东西我不打算给你背一堆手册原文而是用我自己在Synopsys工具链上做多时钟域Scan Chain的实际流程讲清楚前期怎么规划、DFT Compiler里怎么配、TetraMAX怎么跑、覆盖率不达标该查哪里。文末附一份踩坑清单都是拿项目教训换来的。适合刚接手DFT工作的工程师以及前端设计和后端集成偶尔要碰DFT的朋友。1. 拿到多时钟域芯片时我先想清楚这几件事1.1 这项目里的“时钟域”到底有多少种玩法现在的SoC已经很少有单一时钟域了。举一个我手里很典型的项目例子CPU子系统一个时钟域大概800MHz的核时钟总线互联一个时钟域AHB/AXI跑100MHz外设模块又一组UART、SPI、I2C各自由PLL分频出来的25MHz、50MHz时钟驱动还挂着一个由外部32.768kHz晶振直驱的RTC时钟域。这几个时钟域之间的关系很不一样核时钟和总线时钟可能是同源的由同一个PLL分频得到相位关系确定。外设时钟可能来自独立的PLL和总线之间是异步关系。RTC时钟更是完全独立不受芯片内部PLL控制。如果不把这些关系理清楚就急着穿链后面DRC会教你做人——工具报一堆“clock not controllable”或“clock relationship undefined”的错你只能一层层解开重来。我自己的习惯是项目一开始就拉着前端和验证的同事把时钟树结构画清楚标好每个时钟域的来源、频率、相位关系、以及测试模式下能否统一切到测试时钟。这个表后面写SDC约束、配ATPG都直接依赖别偷懒。1.2 为什么scan chain设计必须提前介入Scan Chain的插入虽然发生在综合阶段但它牵扯到的东西远远不止“把触发器串起来”。最典型的例子RTL里如果大量使用门控时钟测试模式下如果不旁路移位时一半寄存器收不到时钟脉冲整个链就是死的。异步复位、异步置位信号在测试模式下如果没有统一处理链状态就是未知的ATPG覆盖率会非常难看。跨时钟域路径的约束方式直接决定后面测试向量能不能收敛。这些都需要在RTL阶段就定好设计规则。我自己在项目中会坚持这么做所有时钟门控单元ICG在test_mode有效时强制穿透所有异步复位在测试模式下统一拉有效或统一释放所有跨时钟域路径在test mode下按异步路径约束。这样后面DFT Compiler跑DRC时能省掉大半的warning。1.3 工具链准备Synopsys全家桶怎么搭做多时钟域Scan Chain我常用的工具组合是DFT Compiler也可以理解为Design Compiler NXT里的DFT flow负责在综合时插入scan chain、处理时钟混合、插入lockup latch、做DFT DRC。TetraMAX在网表基础上做ATPG生成测试向量输出覆盖率报告。VCS插入scan chain之后用仿真确认移位正常、capture正常。Formality做DFT插入前后的形式验证确保逻辑等价性没有被破坏。这四件套在我这里缺一不可。尤其Formality这步很多人觉得没必要但DFT插入强行改了电路结构不验证等价性就直接交网表流片回来出了问题根本没法定位。版本上我的建议是尽量用同一release下的DC和TetraMAX。不同大版本之间的SDC、工具间接口脚本、netlist格式细节有时候会有兼容性小坑排查起来很费时间。另外Synopsys工具基本都是跑在Linux环境下的。如果用的是自己搭的服务器注意一下tcl/tk版本和图形库依赖DFT Compiler的GUI和DVE调试器在tcl/tk版本不匹配时会出现启动失败或者界面卡死的问题我曾经在这个环境问题上浪费了小半天后来直接改用命令行批处理模式跑稳定很多。2. 多时钟域Scan Chain的关键细节从结构到时钟策略2.1 scan chain中的“时钟混合”与划分策略Scan chain的原理不复杂测试模式下把散布在芯片各处的触发器连成一条或几条移位寄存器链通过shift-in把测试向量灌进去capture一拍再shift-out把结果移出来和期望值比对。但一旦涉及多个时钟域问题就来了——链上相邻两级的触发器如果工作时钟不同移位阶段谁先更新谁后采样完全没法保证数据会错乱。DFT Compiler提供了一个关键参数set_scan_configuration -clock_mixing。它控制链里允不允许混合不同时钟域的触发器no_mix每个时钟域的触发器各自成链链之间不混时钟。mix_clocks允许多个时钟域的触发器串在同一条链里工具自动在时钟域边界插入lockup latch来缓冲。我的习惯是能不用mix_clocks就不用。链数量允许的时候强制no_mix让每个时钟域单独成链测试时序是最干净的。为什么这么说一方面纯同步链时序收敛容易不太容易产生race问题。另一方面链的移位频率可以尽量拉高而不受其他慢速时钟域拖累测试时间也能缩短。毕竟ATPG的测试时间和最长那条链的长度直接挂钩。如果因为IO端口有限、链条数目受限必须混链那也尽量少混而且混的边界要单独做DRC和时序检查确认lockup latch都插到位了再往下走。链条划分上我一般按“时钟频率物理位置”双维度来分。比如两个都跑在100MHz的模块如果物理上离得近尽量分到同一条链一个跑800MHz、一个跑25MHz的模块不要硬凑在一起差太远绕线的延迟也容易出问题。2.2 跨时钟域path在测试中如何收敛跨时钟域CDC路径在功能模式下通常用同步器处理最简单的就是两级寄存器。但在scan测试模式下问题来了同步器里的两个寄存器也会被当作普通触发器串进链里。ATPG工具默认把每一条寄存器到寄存器的路径都当作可测路径来生成向量。但两个异步时钟域之间的寄存器capture阶段同时采样时结果是不确定的——因为功能上两个时钟本来就不同步你怎么知道哪个沿先到这种情况下ATPG生成的向量即使仿真通过了也只能靠运气谈不上确定性。所以标准做法是在测试约束里把不同时钟域之间的路径声明为false path或者用set_clock_groups -asynchronous把它们隔开不让ATPG在这些路径上生成向量。注意一点这不代表CDC逻辑不测试了。CDC功能对不对是功能验证和形式化验证的职责。DFT要保证的是每个时钟域内部的组合逻辑能够被充分测试。约束跨时钟域路径恰恰是为了让测试结果可重复、可预测避免因为亚稳态导致测试误判。真正危险的是约束写得不对导致某些本该测的路径被误判为false path覆盖率掉下去或者反过来该约束的路径没约束ATPG为了测到它反复报错还拖慢收敛。我个人的经验是时钟域划分的约束宁可一开始保守一点先把覆盖率跑出来再逐步松开边界观察哪些路径被工具“吃进去”了。上来就把所有异步边界全放开后面排查问题更大。2.3 lockup latch链上不同时钟域之间的粘合剂这一小节是理解多时钟域scan chain的核心。当一个时钟域的触发器Q要接到另一个时钟域的触发器D时如果两个时钟的延迟、相位不完全一致shift阶段可能出现这样的场景第一级已经更新了第二级还没采样或者反过来第二级的采样窗口已经过了第一级的新数据才到。结果就是一个hold violation数据直接错掉。经典解法是插入lockup latch。这是一颗时钟控制的锁存器用前级时钟或者后级时钟的反相来控制放在两级触发器中间让数据在时钟沿的间隙里被“暂存”一下隔开竞争窗口。Synopsys DFT Compiler在mix_clocks模式下会自动插入lockup latch但工具不是万能的。我的习惯是插入之后在网表里grep一下lockup latch实例确认数量、位置、时钟接法都符合预期然后还要跑STA确认跨时钟域连线没有setup/hold问题。还有一个小坑对于同源反相时钟比如CLKA和CLKB由同一个PLL产生但相位差180°有些工具会认为不存在race而不自动加lockup latch。理论上的确没有但硅片上的实际延迟和仿真模型总有偏差我会在这个场景下也强制保留lockup选项。多一颗latch的面积损耗换来的是流片后的稳定性这笔账怎么算都划算。3. DFT Compiler与TetraMAX完整实操流程3.1 RTL阶段定义测试端口与时钟规划在RTL阶段我通常就会把测试端口定义在顶层。最基础的一组是test_mode切换功能模式和测试模式的总开关。scan_enscan链移位使能信号。scan_clk测试时钟所有时钟域的scan移位统一用它。scan_in[0..N-1]和scan_out[0..N-1]每一条scan chain的输入输出端口。这些端口在综合阶段会被连接到各模块内部所以RTL里不一定要把这些端口穿到每个子模块但顶层必须预留。DFT Compiler环境里的配置脚本我贴一个简化版基本思路是这样的# 读入RTL设计设定顶层模块 read_file -format verilog rtl_top.v current_design top # 定义测试时钟和测试控制端口 set_dft_signal -view spec -type ScanClock -port scan_clk -timing [list 45 55] set_dft_signal -view spec -type ScanEnable -port scan_en -active_state 1 set_dft_signal -view spec -type TestMode -port test_mode -active_state 1 set_dft_signal -view spec -type ScanDataIn -port scan_in set_dft_signal -view spec -type ScanDataOut -port scan_out # 设置scan链的划分策略 set_scan_configuration -chain_count 4 -clock_mixing no_mix set_scan_configuration -style multiplexed_flip_flop set_scan_configuration -clock_domain max # 设计规则检查 dft_drc这里有几个参数我说明一下-clock_mixing no_mix让每个时钟域严格独立成链这是我最推荐的初始配置。-clock_domain max让工具尽量按时钟域的最大粒度来划分减少链与链之间的混接。-timing [list 45 55]告诉工具测试时钟的上升沿在45ns、下降沿在55ns。别小看这个参数它会影响工具决定lockup latch插在哪个相位。如果这个时序和你实际波形对不上后面仿真会暴露出来。dft_drc是初步的DRC检查可以提前发现时钟门控未旁路、异步信号未约束等问题。这一步我会反复跑直到warning数量降到可控范围才往下走。接下来做综合和scan插入。用Design Compiler的话我习惯在compile_ultra的时候加上-scan选项让工具在综合阶段就把scan逻辑一并规划好比先综合后插入DFT更高效compile_ultra -scan insert_dft dft_drc -postdft_drc -post是插入scan链之后的复检重点确认所有门控时钟在scan模式下能正常穿透、异步复位被正确禁用、lockup latch已插入、每条链的IO连通到顶层端口。3.2 insert_dft之后的检查与flowinsert_dft之后不是直接扔给TetraMAX就完事了。我坚持要做三件检查第一是Formality形式验证。DFT插入必然修改电路——加了MUX、加了lockup latch、改了触发器的连接但功能逻辑必须保持等价。如果Formality跑不过多半是DFT约束里某个信号端口定义错了或者测试模式信号不小心接进了功能逻辑。这时候改脚本重新插入不要硬来。第二是DFT DRC复检。dft_drc -post报错的项目逐条看特别是“clock not controllable”、“async signal not disabled”这几类。多时钟域设计里这类问题90%出在门控时钟和异步复位上。第三是导出测试协议文件。TetraMAX运行需要这个协议即CTL文件或test protocol描述每个测试时钟的沿、scan enable的时序、scan chain的拓扑。用DFT Compiler导出write_test_protocol top.spf然后在TetraMAX里读进来后面才能正确跑ATPG。这里有个很容易踩的坑多时钟域下不同时钟沿的先后顺序在test protocol里体现为具体的timing描述。如果你的测试时钟是外部统一给的那还好如果测试时钟是内部TAP或PLL产生的协议文件里非常容易写错时钟沿顺序。我有一回就是没仔细检查导出的SPF导致TetraMAX跑出来的向量在VCS仿真里有一堆X态查了好久。3.3 TetraMAX跑ATPG的步骤与指标解读TetraMAX的流程我习惯这么走# 读入网表和标准单元库 read_netlist top_scan.v read_netlist /path/to/lib/stdcells.v # 建立模型 run_build_model top # 添加时钟和时钟沿 add_clocks 0 scan_clk # 定义scan chain拓扑 add_scan_chain chain0 scan_in[0] scan_out[0] add_scan_chain chain1 scan_in[1] scan_out[1] # 故障模型选择 set_faults -model stuck_at add_faults -all # 运行ATPG run_atpg -pattern 1000 -auto_compress # 输出报告 report_summary report_faults -class report_patterns跑完之后重点看三个数字Test Coverage目标通常干到95%以上。低于这个数先别看pattern数量回去查约束和故障分类。Fault Coverage这个是可检测故障占总故障的比例。注意它和Test Coverage的区别有部分故障虽然已检测但被归类为“测试不可用”覆盖率就会有差异。Pattern Count测试向量数量。向量越多测试时间越长测试成本越高。auto_compress会做压缩但多时钟域约束复杂时压缩率不一定理想。多时钟域项目里覆盖率不达标最常见的原因有这几个异步路径被过度约束导致一整片逻辑变成“不测试”。某些信号在测试模式下无法置成特定值比如一条链被长使能信号卡住后面的寄存器永远没法capture。RAM和模拟IP周围的shadow logic缺乏可观测点这部分逻辑覆盖率很难提上去。TetraMAX可以生成多种格式的测试向量write_patterns top_pattern.verilog -format verilog给VCS仿真用也可以输出STIL或WGL格式给ATE机台。流片之前我至少会用仿真器把生成的pattern完整过一遍确认没有X态传播导致误判。3.4 仿真验证scan chain是否真正可工作跑完ATPG只是纸上谈兵。真正要确认scan chain能工作我必做几步仿真。最简单的“冒烟测试”是scan shift测试在scan_en拉高的情况下把一串已知数据比如“1010...”从scan_in灌进去打若干个scan_clk再从scan_out读出来看是否原样出现。如果数据对不上链上肯定有问题。initial begin scan_en 1; for (i 0; i 10; i i 1) begin scan_in pattern[i]; #10 scan_clk 1; #10 scan_clk 0; end scan_en 0; // 检查 shift_out 是否与 pattern 一致 end这一步能快速暴露移位上的问题链有没有断、clock gating有没有挡住时钟、lockup latch有没有插对地方。然后跑TetraMAX生成的pattern做串行仿真。仿真过程里如果出现X态优先检查两点第一跨时钟域路径是否被正确约束了第二异步复位的时序是不是把链的初始状态搞乱了。这两个问题在纯工具流程里不一定报错但仿真一定兜得住。4. 避坑指南我在多时钟域DFT上踩过的坑4.1 典型问题速查表我把这几年多时钟域DFT项目里遇到的典型问题整理了一张表排查效率提升不少问题现象可能原因排查与解决思路DFT DRC报“clock not controllable”时钟门控在test_mode下未被旁路检查ICG单元确认test_mode能强制打开ATPG覆盖率低于90%异步路径被过度约束重建clock groups只约束真正异步路径scan shift仿真数据错位lockup latch缺失或时钟接错检查网表中的lockup latch核对时钟相位TetraMAX报“constraint conflict”scan_en与test_mode约束冲突在SDC里统一两个信号的时序关系Formality验证不通过DFT脚本把信号接进了功能逻辑检查set_dft_signal定义重新插入DFT测试覆盖率够但仿真有X态跨时钟域路径捕获结果不确定检查clock group约束是否漏了异步边界4.2 复盘一次覆盖率卡在88%的项目去年一个多时钟域项目带PLL分频出来的一个慢速时钟域ATPG覆盖率死活卡在88%。当时试了很多办法都上不去。最后翻来覆去查发现是慢速时钟域的寄存器在功能模式下由门控时钟驱动test_mode虽然声称旁路了门控但DFT Compiler仍然把整个时钟域识别为“非可控时钟域”导致链上这一片寄存器组件根本没法正常移位。解决方案是把慢速时钟域的测试时钟路径改走统一的scan_clk通过时钟MUX切换而不是让它沿用原本的功能时钟路径。改完之后覆盖率直接上到97%。这个案例让我记住一个关键经验多时钟域设计里测试时钟的可到达性比功能时钟的合理性更重要。你需要确保每个要被串进链的寄存器在测试模式下都能被同一个清晰、确定的时钟沿驱动。否则DRC不报覆盖率也会说话。4.3 四条在实战中一直好用的铁律这么多年做下来有四条原则我一直在用也建议你刻在脑门上第一条DFT规则在RTL阶段定死不要等网表出来了再改。特别是test_mode旁路逻辑、时钟门控处理、异步信号策略越早统一后面越轻松。第二条clock group约束宁可少建不要乱建。多建false path会白白损失覆盖率少建顶多ATPG跑得慢一点。先保守再根据覆盖率报告逐步松开。第三条每条scan chain都要做独立的shift测试。多时钟域下移位测试是最快最直接的DFT功能验证务必确保每条链都能一次通过。第四条CTL和test protocol文件要勤导出、勤检查。多时钟域的时钟沿顺序太容易写错多用TetraMAX导出protocol然后在仿真里交叉确认。别嫌麻烦这步能帮你挡掉后面一长串问题。写到最后做多时钟域Scan Chain设计这几年我最深的体会是Synopsys的工具能帮你解决大部分机械工作但真正拉开差距的是前期规划的判断力。哪些路径该约束、哪条链用哪种时钟混合方式、覆盖率不达标先查哪里——这些靠的是对设计本身的深刻理解而不是工具操作熟练度。如果你正被多时钟域的DFT DRC或者覆盖率问题折磨建议先把时钟域关系图、测试约束、协议文件这三样东西摆到桌面上逐项过一遍。多数问题在这个层面就能找到答案。实际操作中我还会把一个习惯保持到底每个项目结束之后把当年踩过的坑、改过的脚本、梳理过的排查流程整理成内部文档归档到团队知识库里。DFT这个方向坑都是相似的经验是可复用的。希望这篇内容也能成为你的“归档材料”之一帮你省点时间少走点弯路。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进