ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

多时钟域Scan Chain设计实战:从时钟梳理到DFT配置的完整指南

2026/10/7 9:14:52 拓冰建站 浏览量
多时钟域Scan Chain设计实战:从时钟梳理到DFT配置的完整指南 多时钟域scan chain最气人的一点是单时钟域的流程你跑得再熟跨到两个以上时钟域依然会翻车而且故障通常不会在DFT阶段立刻暴露而是等到后端做完时序收敛、甚至流片回来测试时才集中爆发。我第一次独立做一颗带三个异步时钟域芯片的DFT时insert_dft和dft_drc全绿TetraMAX报的测试覆盖率也能看结果后端做完时钟树综合shift测试在波形里直接乱套扫描链上相邻的两个registerlaunch和capture完全对不上整个pattern变成一锅粥。后来复盘问题根子几乎都出在移位阶段时钟关系、异步时钟域的处理策略和工具默认配置这三件事上。这篇文章把我用Synopsys DFT Compiler做多时钟域scan chain设计的实战经验完整梳理了一遍读者定位是正在做DFT、或者刚接手多时钟域芯片后端与验证的工程师内容偏向能直接落地的细节时钟梳理、dft信号定义、命令参数含义、真实翻车案例和对应排查链路最后附一张长期沉淀下来的自查清单。你可以把这篇当作多时钟域scan chain的“实战笔记”来用不必按教科书从头啃。1. 多时钟域scan chain为什么总在最后关头翻车三个绕不开的矛盾1.1 移位阶段谁在驱动数据功能时钟与测试时钟的冲突scan chain的移位本质上是一个时钟周期一个时钟周期地把数据从scan_in推到scan_out。单时钟域里所有触发器被同一个时钟沿驱动只要保持时间足够链上数据就像传送带一样稳定前进。多时钟域一出现问题就来了每个寄存器在功能模式下受自己的功能时钟控制这些时钟频率不同、相位不同、上升沿到达时间也不同。如果让功能时钟直接参与shift跨在两个时钟域边界的相邻寄存器之间数据到达时刻和时钟到达时刻完全没有对齐关系hold violation几乎是必然的。所以真实项目的标准做法是在每个时钟的根部做测试时钟mux把功能时钟切到统一的测试时钟上让全链在shift阶段用同一个低频时钟沿驱动。但这里面有一个非常容易被忽略的点测试时钟本身的频率、占空比以及DFT阶段被识别为ScanClock的view决定了STA阶段这条链以什么样的时钟关系去做时序检查。如果你在DFT脚本里只定义了功能时钟没有把测试时钟通过set_dft_signal -view existing_dft的方式描述清楚工具会默认拿功能时钟的沿来推断shift关系这对异步时钟域来说几乎等于没切。我个人习惯是在任何多时钟域项目里先统一约定shift阶段全芯片只存在一个有效时钟沿。这个约定写进DFT脚本、写进后端约束、写进STA检查条目比任何一条命令都重要。1.2 异步时钟域之间的寄存器链条功能上的伪路径在测试里变成了真实路径功能模式下两个异步时钟域之间通常不需要做时序收敛SDC里用set_clock_groups -asynchronous一划就完事跨时钟域的握手逻辑、同步器链在时序分析时都可以当伪路径处理。但在scan chain的shift阶段物理连接关系完全变了链上相邻的两个触发器不管它们之间在功能上有多少异步逻辑测试时它们就是一条真实的数据通路。那层“异步伪路径”的保护伞在移位模式下是不存在的。这个问题最典型的表现就是后端用功能模式SDC跑STA时跨时钟域路径被当作false path一点问题都没有可一旦切到shift模式工具开始检查扫描路径上的时序跨域边界立刻冒出一堆hold violation。很多工程师第一反应是“是不是scan cell选得不对”“是不是后端修hold的buffer没插”但真正的根因往往在更早的环节——DFT阶段有没有想清楚跨时钟域寄存器之间以什么方式互联有没有在移位模式下给这条“伪路径”补上真实路径该有的时序保护。1.3 工具默认配置距离多时钟域最优解还有不少距离Synopsys DFT Compiler的默认配置是保守的。老实说这个保守设计对单时钟域、单边沿的设计是安全的但遇到多时钟域场景默认配置往往不是最合适的选择。比如set_scan_configuration默认的clock mixing策略偏保守会严格限制哪些时钟的寄存器可以进同一条chainchain数量默认取值也不一定适合你的供电、面积和测试时间约束。工具的思路是“宁可少干也不犯错”很多跨时钟域优化需要你自己明确告诉它“这里可以mix”“这里需要lockup”“这里允许edge混用”。这里想强调一个观念DFT工具不是自动化的终点而是把设计者的测试策略落地的手段。多时钟域scan chain设计里真正干活的是你提前规划好的时钟关系、测试时钟方案和链分配策略工具只负责执行得更精细。把锅甩给工具之前先检查自己有没有把规则喂清楚。2. 动手之前先把时钟家族梳理清楚从RTL时钟树到测试时钟定义2.1 一张纸画出时钟关系源时钟、衍生时钟、门控时钟我拿到RTL后不会马上打开工具而是先在代码或者示意图上把时钟家族画出来。要标清楚这几类主时钟芯片输入端口进来的原始时钟比如PLL之前的参考时钟、外部接口时钟。衍生时钟由主时钟分频、倍频、门控得到的时钟比如div2寄存器输出的时钟、AND门控出来的模块时钟。测试时钟与测试模式信号scan_en、test_clk这些在DFT阶段要用的端口。每个时钟对应的触发器集合哪些模块的寄存器是吃这个时钟的。画完这张图你基本就知道这个设计的scan chain会有哪些天然的“分界”。时钟域边界越多链分配越碎片化就越需要决定这些域允许不允许串在同一条chain里。如果允许必须用lockup latch和测试时钟对齐来兜底如果不允许chain数量至少要覆盖这些域的分组需求。这张图也是后续和前端、后端对齐的公共语言功能验证的人看功能时钟后端的人看物理时钟树DFT的人看的其实是“哪些触发器可以按测试逻辑组合在一起”三者的信息流全部从这张图开始。2.2 SDC里的时钟分组与DFT的测试时钟定义必须对同一件事说同一种话多时钟域DFT最隐蔽的问题之一是SDC里功能模式的时钟分组和DFT脚本里的测试时钟定义彼此脱节。举个例子SDC里你已经用set_clock_groups -asynchronous分好了A、B、C三个异步时钟域但DFT脚本里做set_dft_signal时只定义了顶层test_clk作为ScanClock没有把功能时钟和测试时钟的关系明确建模工具就会自己“脑补”功能时钟的沿关系。一旦脑补的方向和SDC不一致dft_drc可能仍然能过但后端STA时必然露馅。我的做法是把时钟定义集中在一个公共的setup脚本里SDC资源和DFT资源共用。至少包含三类信息功能时钟的周期和端口、异步时钟分组、测试时钟和scan_en的定义。下面是一个简化骨架工具版本不同命令格式有小差异但思路通用。# 功能时钟定义 create_clock -name clk_a -period 10 [get_ports clk_a] create_clock -name clk_b -period 20 [get_ports clk_b] create_clock -name clk_c -period 5 [get_ports clk_c] # 异步时钟分组功能模式下跨这些域的路径不做时序收敛 set_clock_groups -asynchronous \ -group { clk_a } \ -group { clk_b } \ -group { clk_c }# DFT相关信号定义 set_dft_signal -view existing_dft -type ScanClock \ -port [get_ports test_clk] -timing { 30 60 } set_dft_signal -view existing_dft -type ScanEnable \ -port [get_ports scan_en] -active_state 1 set_dft_signal -view existing_dft -type Reset \ -port [get_ports scan_rst_n] -active_state 0这里面有一个细节-timing { 30 60 }填的是测试时钟上升沿/下降沿时刻对应的占空比信息具体数值要根据实际测试时钟频率来定义。不管填多少核心目的都是让工具和后续STA以同一个时钟沿为基准去计算扫描路径的时序而不是各拿各的时钟沿乱算一气。2.3 一套可以直接复用的多时钟域DFT脚本骨架把上面这些拼起来我通常会在项目里维护一个DFT流程脚本按顺序完成环境加载、时钟定义、dft信号定义、dft_drc和insert_dft。下面是一个简化但完整的参考骨架命令和选项以常见版本为基准使用前建议对照你手上的工具版本再查一遍help。# 加载设计、库和约束 read_verilog rtl_top.v current_design rtl_top link source common_clocks.sdc source dft_signals.tcl # 扫描配置8条链允许跨时钟混合开启lockup自动插入 set_scan_configuration -chain_count 8 \ -clock_mixing mix_clocks \ -add_lockup true # 先做DRC检查 dft_drc # 预览插入后的链结构不改变设计 preview_dft # 正式插入 insert_dft # 报告检查 report_scan_path report_dft_signal注意一个容易被忽略的顺序dft_drc要先跑。很多人图省事配置完直接insert_dft结果DRC问题被插入动作一次性带出来报告里的错误信息混杂在一起很难快速定位。DRC阶段就把时钟问题、单元问题、扫描配置问题暴露出来远比插入后回头排查省时间。遇到大规模设计时这一步的差别可能是半天和两天的区别。3. DFT Compiler插入扫描链那些决定跨时钟域命运的命令参数3.1 set_scan_configuration中的clock mixing选项到底在管什么事多时钟域scan chain的核心配置基本都落在set_scan_configuration里。其中-clock_mixing是决定“不同时钟域的寄存器能不能串进同一条chain”的关键开关。常见值有这几个选项行为多时钟域场景下的适用性no_mix不同时钟域的寄存器不允许进同一条chain最保守链数量往往偏多跨域边界少但chain利用率可能低mix_clocks允许不同时钟域的寄存器混合到同一chain最常用能提高chain利用率链数量和IO压力降低但必须配合lockup latch保证跨域时序mix_edges在mix_clocks基础上允许跨越时钟边沿适用于存在下降沿采样寄存器的设计跨边沿时对时序要求更细当你选了mix_clocks工具就有了“把不同域的触发器拼在同一条链里”的权限但拼的时候它会自己判断哪些跨域连接是安全的不安全的会尝试插入lockup latch。这里要划一个重点clock mixing不是百分比越高越好。跨时钟域混用的链对测试时钟的skew要求非常严格skew稍微大一点lockup latch也救不回来。所以我的习惯是异步时钟域之间能用独立chain的就尽量独立只有chain数量受IO限制时才允许mix_clocks同属一个主时钟的衍生时钟域之间则可以放心用它来提升利用率。3.2 preview_dft插入之前免费检查一次结构风险preview_dft这个命令很多人不常用我强烈建议在insert_dft之前养成跑一下的习惯。它不会真的改设计只是按你当前的配置做一次预演输出每条扫描链的预期结构、时钟域分布、链长度、可能的DRC问题。对于多时钟域项目preview_dft报告里我最关注三个信息。第一每条chain上有没有跨异步时钟域的连接。如果出现了而脚本里没有设置mix_clocks那你需要回去重新审视配置否则insert_dft要么报错要么以某种保守方式把链拆开。第二chain长度是否均衡。多时钟域设计里某个小时钟域只有几十个触发器如果单独成链整条链短得离谱不仅浪费扫描IO还让pattern时间被这条短链拖累。看到这种失衡就该考虑把相邻安全域合并。第三lockup latch的预期插入点。preview_dft如果显示某些跨域连接没有插入lockup你就要去追问为什么——是不需要还是工具认为那里是安全的同沿连接这个判断直接关系后续STA结果。3.3 insert_dft之后的产物怎么看chain报告、lockup数量与跨域连接insert_dft跑完别急着导出网表先看report_scan_path。多时钟域设计里这份报告的价值远高于单时钟域它详细列出了每条链上的寄存器分组、时钟关系、插入的lockup latch。我一般会重点核对三件事。一是lockup latch数量。只要用了mix_clocks跨域连接处都应能看到lockup。如果报告里lockup为0而设计里确实存在异步域相邻寄存器的连接那就说明工具认为没有跨域或者你的时钟定义有漏洞这需要回到第2章去查。二是chain与时钟域的映射关系。每条chain里都有哪些时钟域的触发器这个信息直接决定后端在时钟树综合时对测试时钟的约束结构。如果一条链里混了3个异步域后端看到这样的物理连接就知道测试时钟树必须覆盖这3个域否则hold问题无处可藏。三是每个时钟域是否都有对应的scan output可观测。多时钟域设计容易出现某个小域的触发器被分散在几条链里但每条链的观测点又落在别的域出问题的时候定位困难。我会建议在小时钟域至少保留一个独立的scan output方便测试向量生成和良率分析时单独看这个域的状态。4. 多时钟域scan chain三个真实翻车现场从现象到根因的完整排查链路4.1 翻车现场一dft_drc红灯一片根因是分频时钟定义不完整有一次处理一颗带内部div2时钟的设计dft_drc跑出来一大片和时钟识别相关的错误具体表现是大量寄存器被报告无法归入任何有效时钟组扫描配置怎么调都插不满链。我当时第一反应是scan cell库没配好换库、换流程折腾了半天都没用。后来静下心来看RTL才意识到那个div2寄存器输出的时钟在SDC里压根没有create_generated_clock工具只能靠网表结构猜测这个时钟的存在。猜出来的结果时好时坏一部分触发器被识别为吃div2时钟一部分又因为组合逻辑太深被当成“无时钟器件”整个clock group七零八落DRC自然红灯一片。把分频关系用create_generated_clock定义清楚之后DRC瞬间干净链也顺利插完。这个案例让我养成了一个习惯脚本报错之前先把设计里所有时钟的定义完整程度检查一遍。DFT工具对时钟关系的推断能力远没有你想象中那么强一旦它需要“猜”结果往往就是DRC里那些莫名其妙的错误码。多时钟域设计尤其如此衍生时钟多、门控链深只要有一个时钟定义不完整工具后续的所有推演都是建立在沙子上的。4.2 翻车现场二post-route大量跨时钟域hold violation根因在shift mode的STA约束另一个项目更隐蔽。dft_drc全绿insert_dft顺利ATPG coverage也达标结果后端完成时钟树综合和绕线之后post-route STA报告里跨时钟域边界的scan路径上冒出一堆hold violation。一开始大家都以为是lockup latch没插结果我打开report_scan_pathlockup数量是正常的跨域连接处确实有latch保护。真正的问题出在STA的shift mode约束上。功能模式SDC里set_clock_groups -asynchronous把三个域划开了shift mode做时序检查时工程团队偷懒直接复用了这份SDC只额外加了测试时钟的时钟定义没有删除异步分组。结果就是shift模式下跨域路径在STA眼里依然是异步路径工具根本不对它们做launch-capture对齐检查但测试pattern实际执行时所有寄存器都被测试时钟统一驱动这些路径上是有真实时序要求的。等到了post-route测试时钟树skew稍大一点hold violation就在这些“没人检查”的路径上集中爆发。修复的办法分两层。DFT层面跨域连接处保留lockup latch这是对时钟skew的硬件兜底STA层面shift mode必须使用独立的constraint把测试时钟当作唯一的有效时钟所有扫描路径都按同步路径去做setup/hold检查同时给测试时钟树设置合理的uncertainty。这两件事一件都不能少少了任何一个问题只是换一个阶段暴露而已。这次之后我在项目里强制要求shift mode的SDC单独维护禁止复用功能模式的异步分组。4.3 翻车现场三同步器链进链后X态污染观察点覆盖率死活上不去第三个案例发生在ATPG阶段。芯片里有一批双触发器同步器属于典型的跨时钟域接口逻辑。insert_dft后这些触发器都正常进了扫描链ATPG生成pattern时工具也从它们身上抓到了不少fault coverage但就是有一组观察点始终测不到覆盖率卡在一个尴尬位置怎么都提不上去。查了几天才定位到是X态传播问题。功能模式下同步器的作用是把异步输入端来的信号同步到本地时钟域输出是稳定的但scan shift模式下同步器链两级触发器作为普通扫描寄存器被移位异步输入端的X态会沿着同步器链一路传播通过组合逻辑冲到某些观察点上把本来应该清晰捕获的值全部污染了。工具不是没做处理而是这类跨时钟域接口上的X源很难在ATPG阶段自动识别干净。最终的解决方案是从DFT阶段就介入对同步器链做分组约束避免把容易产生X态的异步输入直接串入关键观察路径同时在测试约束里把同步器链的输入阶段设置为可预测的值对确实无法处理的X源通过测试模式信号把它们置成固定状态。这个案例给我的教训是多时钟域DFT不是插完链就结束的ATPG阶段的可控性和可观测性一定要在DFT阶段就同步考虑尤其是跨时钟域接口这种X态高发区域。5. 长期沉淀下来的多时钟域scan chain自查清单5.1 RTL与DFT准备阶段要确认的事所有主时钟、衍生时钟、门控时钟是否都已定义完整的时钟关系分频时钟有没有对应的generated clock定义。SDC里的异步时钟分组和DFT脚本里的dft signal定义是否来自同一个公共文件两者对时钟域的划分是否一致。测试时钟和scan_en在RTL里是否已经规划好端口有没有被综合工具优化掉。5.2 工具运行与结果检查阶段要确认的事set_scan_configuration的chain_count和clock_mixing是否基于第2章的时钟分组图决定而不是随手填的默认值。dft_drc是否在insert_dft之前单独跑过错误清单里有没有时钟定义不完整的痕迹。preview_dft报告里每条chain的时钟域混合情况是否符合预期lockup latch的插入点是否合理。insert_dft后report_scan_path的chain长度是否均衡小时钟域有没有独立的观测出口。5.3 与STA、ATPG和后端PR需要对齐的信息shift mode下必须使用独立的约束文件测试时钟是唯一的有效时钟扫描路径全部按同步路径检查异步分组在shift mode下要谨慎使用。测试时钟树在后端实现阶段的skew目标要按scan chain跨域连接的实际物理范围来设定不能拿着功能时钟树的指标套用。ATPG阶段的X态处理策略要反馈到DFT阶段同步器链、跨域接口这些X态高发区域最好在设计阶段就预留测试模式下的可控信号。最后再分享一个我自己的实操习惯每颗多时钟域芯片的DFT我都会在项目启动时先做一次“全芯片只用一个测试时钟”的假设推演把所有时钟域的寄存器按这个假设映射一遍。如果映射结果能接受说明设计本身的测试结构是健康的如果某个域怎么都映射不过去那这个域多半就是后期所有时序和覆盖率问题的源头趁早单独设计方案比等后端报错再返工划算得多。这个习惯帮我避开了不少坑也推荐你试试。