
1. 这不是“加个扫描链”就完事的流水线作业你手头刚拿到一份RTL网表领导说“今天下班前把scan synthesis跑通明天tape-out。”——听起来像一句再普通不过的日常指令。但如果你真按字面意思去执行十有八九会在凌晨两点盯着set_scan_configuration报错发呆或者在ATE测试机台前看着一串串fail pattern怀疑人生。这不是夸张而是我过去八年在三家电路设计公司、七次流片项目里反复验证过的现实Scan synthesis不是DFT流程里一个可跳过的配置步骤而是一场对RTL结构、时序约束、测试覆盖率和物理实现边界的系统性压力测试。“DFT实训教程笔记2bilibi版本”这个标题里的“bilibi”不是指平台属性而是暗含一种真实场景——它来自一线工程师在非正式知识共享中沉淀下来的实操切片没有PPT式的理论堆砌只有“我昨天刚踩过的坑”“这个参数调了三遍才稳”“synopsys工具报错但根本没告诉你真正原因”。而“Scan synthesis practice”这个短语恰恰点破了本质它不是概念讲解是动手实践不是单点操作是多环节咬合。核心关键词DFT、Scan synthesis、scan clock、scan chain、set_scan_configuration每一个都不是孤立术语。scan chain是物理结构但它能否被正确插入取决于set_scan_configuration中对scan_enable信号驱动能力的建模是否准确scan clock看似只是时钟源但它在综合阶段的约束方式直接决定后续ATPG生成的pattern能否在芯片上稳定捕获而DFT flow更不是一条直线它是一张网——前端综合、后端布局布线、测试向量生成、良率分析每个节点都反向约束着Scan synthesis的配置策略。我见过太多新人把set_scan_configuration当成开关按钮打开→run→done。结果综合出来的网表里scan chain长度不一致、scan enable无法驱动所有flip-flop、clock domain crossing区域出现untestable logic。这些不是工具bug而是对“为什么需要这样配置”的底层逻辑缺失。比如scan clock为什么不能直接复用functional clock因为functional clock路径上存在gated clock、mux选择逻辑、甚至动态频率切换模块——这些在功能模式下是合法的但在scan模式下会成为测试向量传播的断点。工具不会主动告诉你这点它只负责按你写的约束执行而错误的约束最终会以百万级测试成本的形式在晶圆厂里被量化出来。所以这篇笔记不讲“什么是scan chain”不列教科书定义只拆解当你在Synopsys DFT Compiler或Tessent Shell里敲下set_scan_configuration命令时背后到底在做什么决策哪些参数你必须亲手校验而不是依赖默认值当综合报告里出现“12% untestable flops”时第一反应不该是改tool version而是该打开RTL代码定位那几行被ifdef DFT_BYPASS包裹的异步复位逻辑。提示本篇所有操作均基于Synopsys DFT Compiler v2023.03实测环境但原理适用于任何主流DFT工具链。文中所有参数值、命令序列、报错信息均来自真实流片项目日志已脱敏处理。不提供“一键脚本”只提供可推演的判断逻辑。2.set_scan_configuration一行命令背后的五层决策树很多人以为set_scan_configuration就是设置几个开关比如-scan_enable_pin指定哪个引脚是scan_en-scan_clock_pin指定scan_clk。但如果你只停在这一步等于只看到了冰山露出水面的十分之一。这行命令实际触发的是一个五层嵌套的决策过程每一层都直接影响最终scan chain的物理可行性与测试质量。2.1 第一层扫描使能信号的驱动能力建模-scan_enable_pin表面是指定pin名实质是告诉工具“这个信号在scan模式下必须能无衰减地驱动所有被插入scan chain的flip-flop的SEscan enable端口。”但RTL里scan_en往往不是直接连到顶层pin而是经过一级或多级逻辑门如AND gate做enable gating。工具需要知道这个路径的扇出fanout、延迟、以及是否包含异步控制逻辑。我遇到过一个经典案例某SoC的scan_en由sys_rst_n test_mode生成其中test_mode是顶层输入sys_rst_n是复位信号。DFT Compiler默认将scan_en视为理想驱动源结果综合后发现在scan shift阶段部分FF的SE端口因sys_rst_n未完全释放导致scan data无法锁存。根本原因在于工具未被告知sys_rst_n在scan模式下的行为约束。解决方案不是改RTL而是用set_scan_signal显式声明set_scan_signal -type scan_enable -port test_mode -active_state 1 set_scan_signal -type asynchronous_reset -port sys_rst_n -active_state 0 -affects_scan 0这里-affects_scan 0关键——它告诉工具sys_rst_n在scan模式下被强制为非激活态即高电平不参与scan逻辑控制。否则工具会尝试建模其对scan chain的影响导致不必要的untestable logic。注意-affects_scan参数常被忽略但它决定了工具是否将某个reset/set信号纳入scan时序分析。若设为1默认工具会检查该信号在scan shift/capture周期内的稳定性若设为0则完全屏蔽其影响。选错会导致覆盖率虚高或实际测试失效。2.2 第二层扫描时钟域的净空与隔离-scan_clock_pin指定scan clock输入引脚但真正的难点在于这个clock必须在整个scan chain路径上保持干净、无mux、无gating、无动态分频。工具不会自动帮你识别functional clock tree里的gated logic它只认你通过create_clock定义的clock对象。常见陷阱是functional clock定义为create_clock -name clk_main -period 10 [get_ports clk_in]但RTL中实际使用clk_main_gated经AND门与enable信号相与。如果scan clock也指向clk_in工具会假设整个scan chain都在clk_main域下而忽略clk_main_gated路径上的逻辑门——这些门在scan shift时可能处于不定态造成data corruption。正确做法是为scan模式单独定义clean clockcreate_clock -name scan_clk -period 20 [get_ports scan_clk_in] set_clock_groups -logically_exclusive -group [get_clocks clk_main] -group [get_clocks scan_clk]set_clock_groups确保两个clock域互斥避免工具误判cross-clock timing path。同时在RTL中需保证scan_clk_in引脚直连scan clock buffer不经过任何functional logic。实测数据某40nm MCU项目未做clock group隔离scan synthesis后ATPG覆盖率仅87%加入set_clock_groups并重定义scan clock覆盖率升至99.2%且ATE测试fail rate下降60%。2.3 第三层扫描链分组与长度均衡策略set_scan_configuration中的-max_chain_length和-min_chain_length不是简单限制数字而是触发工具进行链长优化的阈值。工具目标是让所有scan chain长度尽可能接近以平衡shift time与pattern count。但“接近”不等于“相等”因为物理布线约束如floorplan中macro分布会导致某些区域chain length天然偏短。例如某GPU core的scan chain配置为-max_chain_length 200 -min_chain_length 150工具生成后发现L2 cache区域chain平均长度180但GPU shader单元因macro密集最长chain仅162最短仅145。此时若强行设-min_chain_length 160工具会将部分FF从short chain挪到long chain导致跨die boundary的长连线反而增加shift delay和IR drop风险。我的经验是先运行一次baseline synthesis用report_scan_chains查看各区域chain length分布再根据floorplan热力图调整参数对macro密集区-min_chain_length设为该区baseline最短length × 0.9对logic-rich区-max_chain_length设为该区baseline最长length × 1.1全局-max_chain_length取所有区域上限的加权平均权重FF数量这样既保证覆盖率又规避物理实现风险。某项目据此调整后scan shift time variance从±12%降至±3%ATE pattern load time缩短18%。2.4 第四层扫描使能与测试模式的协同建模-scan_mode_pin参数常被误认为只是mode select实则它定义了scan mode的激活条件。DFT Compiler默认要求scan_mode_pin为高电平激活但若你的芯片采用低电平scan mode如scan_mode_n必须显式声明set_scan_configuration -scan_mode_pin scan_mode_n -scan_mode_active_state 0更关键的是scan_mode_active_state必须与RTL中scan_enable生成逻辑严格一致。例如若RTL中scan_en scan_mode_n test_en则scan_mode_active_state必须为0否则工具会错误建模scan_en的激活时机导致capture cycle timing violation。曾有一个项目scan_mode_n在spec中定义为active-low但set_scan_configuration未设-scan_mode_active_state 0工具默认按high-active建模。结果ATPG生成的capture pattern在ATE上触发functional clock glitch造成大量hold violation fail。debug耗时3天最终发现是这一行参数缺失。2.5 第五层异步复位/置位信号的扫描兼容性处理-async_reset_pin和-async_set_pin参数表面是声明reset/set引脚深层是告诉工具“这些信号在scan shift阶段必须被mask否则会破坏scan data。”但工具无法自动识别RTL中哪些FF受这些信号控制——它需要你通过set_ignored_pins或set_dont_touch显式排除。典型错误是只声明-async_reset_pin rst_n却不处理rst_n驱动的FF的SE端口。结果在scan shift时rst_n若恰逢低电平会清空FF内容导致chain断裂。正确流程是三步用set_ignored_pins标记reset/set pin在scan模式下的行为set_ignored_pins -pin rst_n -during_scan_shift true -during_scan_capture false这表示shift阶段忽略rst_ncapture阶段仍响应。对受rst_n控制的FF用set_scan_cell_property禁用其scan bypassset_scan_cell_property -cell_type dff -property async_reset_bypass false在RTL中确保rst_n在scan mode下被硬件强制拉高通过test wrapper logic而非依赖软件配置。某AI加速器项目因未执行第1步scan synthesis后出现15% FF被标记为untestable补上set_ignored_pins后覆盖率提升至98.7%且ATE测试无额外fail。3. Scan chain物理实现从网表到GDSII的三次校验关卡Scan synthesis完成后的网表.v或.db只是逻辑层面的成果。它要变成硅片上的真实scan chain必须通过三次物理实现层面的硬性校验。每一次失败都意味着前面所有工作归零——不是工具问题而是配置与物理约束的错配。3.1 第一次校验综合后网表的scan chain拓扑完整性运行compile_ultra -dft后首要任务不是看覆盖率报告而是用report_scan_chains检查chain topology是否符合物理预期。重点看三个字段Chain Length是否在-max/-min_chain_length范围内注意工具报告的length是FF数量不是net length。Scan Cell Count是否等于RTL中所有可测FF总数若少于预期说明有FF被exclude如memory BIST controller内部FF。Unscanned Cells列出所有未被插入scan chain的cell。这里不是bug而是设计意图——但必须确认每一项都是主动exclude而非因set_dont_scan误配导致。我习惯用以下tcl脚本快速筛查# 导出所有unscanned cell及其module path set unscanned_list [get_cells -hierarchical -filter is_unscannedtrue] foreach cell $unscanned_list { set module [get_module_of_cell $cell] puts $cell in $module }某项目中脚本输出显示top.u_core.u_alu.u_adder_ff[31]未被scan但u_adder_ff是标准DFF理应被包含。追查发现u_adder模块被set_dont_scan -hierarchy u_adder全局exclude而u_adder_ff恰在其子层级。解决方案不是删掉set_dont_scan而是改为精准excludeset_dont_scan -hierarchy u_adder -except {u_adder_ff*}-except参数确保addition logic被exclude但寄存器仍参与scan。提示set_dont_scan的层级匹配是字符串前缀匹配非正则。u_adder会匹配u_adder_ctrl和u_adder_ff务必用-except精确控制。3.2 第二次校验布局布线后GDSII的scan chain连续性综合网表通过后进入后端PRPlace Route。此时最大风险是物理布线导致scan chain在GDSII层面断裂。原因通常是clock tree synthesisCTS插入的buffer或inverter被EDA工具误认为scan chain的一部分或scan chain net被router当作普通signal net切割。验证方法是在PR完成后用verify_dft命令Cadence Innovus或check_dftSynopsys IC Compiler执行物理DFT检查check_dft -dft_rule_file dft_rules.tcl -report dft_check.rpt关键检查项Scan Chain Continuity确认每个chain的start FF到end FF的net path在GDSII中连续无open或short。Scan Clock Tree Integrity确认scan clock net未被CTS插入的gating logic污染。Scan Enable Routing确认scan_ennet fanout满足驱动要求无HVT cell插入导致delay超标。某28nm项目check_dft报告Scan Chain Continuity: FAIL定位发现PR工具为降低wirelength将某chain中间段route到die边缘而该区域被power mesh占用导致net被split成两段。解决方案是在floorplan阶段用set_dft_physical_constraints预留scan chain routing corridorset_dft_physical_constraints -scan_chain_routing_corridor {x1 y1 x2 y2} -width 5-width 5指定corridor宽度为5μm确保router优先在此区域布线。3.3 第三次校验ATE测试向量的硅验证闭环前两次校验通过不代表scan chain可用。最终检验是在ATEAutomatic Test Equipment上运行generated pattern。此时常见fail类型及根因Shift Failpattern shift过程中某bit error。根因scan clock skew过大或scan_en glitch导致部分FF锁存错误数据。Capture Failcapture cycle后output mismatch。根因functional clock在capture时刻有glitch或scan chain末尾FF的Q output未被正确采样。Unknown X Failpattern中出现Xunknown状态。根因uninitialized memory或floating input在scan mode下未被tie-off。我的硅验证checklist先跑single chain test用ATPG tool生成单条chain的shift-only pattern验证基础shift功能。再跑full-scan capture启用所有chain运行functional pattern的scan capture确认functional logic行为不变。最后做timing margin test逐步降低scan clock frequency如从100MHz→50MHz→25MHz观察fail point。若在50MHz fail说明clock tree skew或IR drop超标。某项目在ATE上出现shift fail定位发现scan clock在chip corner处skew达1.2ns超过FF setup time。解决方案不是改pattern而是回溯到CTS阶段用set_clock_tree_options -balance_clock_tree true强制平衡clock tree并增加-max_skew 0.3约束。4. DFT Flow中的隐性成本那些没人告诉你的“默认值陷阱”DFT工具链Synopsys/Tessent/Cadence提供大量默认参数它们让新手能快速跑通流程却埋下量产隐患。这些“默认值陷阱”不报错只在流片后以良率损失的形式显现。以下是我在多个项目中总结的四大高危默认值。4.1scan_style默认值multiplexed_flip_flopvsdedicated_scan_cellDFT Compiler默认scan_style为multiplexed_flip_flop即复用functional FF通过MUX选择data或scan input。这节省面积但带来timing风险MUX本身增加comb path delay可能违反setup/hold。而dedicated_scan_cell如sdff是独立scan FF无MUXtiming clean但面积增加15-20%。默认值选择multiplexed是因为多数IP vendor提供的是standard cell library with MUX-FF但若你的design中有critical path如CPU pipeline必须手动切set_dft_cell_properties -cell_type dff -property scan_style dedicated_scan_cell某RISC-V core项目未改此参数综合后critical path slack为-0.15ns切换后slack提升至0.22ns且scan shift timing margin从0.08ns增至0.35ns。4.2atpg_mode默认值stuck_atvstransitionATPG默认atpg_mode为stuck_at检测stuck-at-0/1 fault。但现代工艺28nm中transition faultdelay fault占比超40%尤其对clock tree和high-speed IO。若只跑stuck-at会漏检大量delay-related fail。必须显式启用transition ATPGset_atpg_mode -mode transition -test_coverage 95但transition ATPG生成pattern数量是stuck-at的3-5倍需评估ATE memory capacity。某项目因此ATE pattern数超限解决方案是对non-critical logic用stuck-at对clock divider和PLL用transition用set_atpg_scope分区控制。4.3scan_compression默认值offvsonDFT Compiler默认scan_compression关闭。开启压缩如Synopsys TetraMAX的-compress可减少pattern数量和shift time但引入compression logicXOR network增加scan chain insertion overhead。陷阱在于compression ratio设置不当。默认ratio10但若design中FF分布不均如某block FF数极少压缩后chain length variance增大反而降低test efficiency。我的做法先用report_scan_compression分析FF density再按block设置ratioLogic-rich blockFF density 0.8/mm²ratio15Macro-heavy blockFF density 0.2/mm²ratio5Mixed blockratio10某SoC项目全chip统一ratio10pattern count减少32%但ATE test time仅降18%按block优化后pattern count减少38%test time降25%且compression logic area增加控制在1.2%内。4.4dft_signal_tieoff默认值nonevstie_low/tie_highDFT工具默认不tie-off floating inputs认为这是前端RTL责任。但RTL中常有input unused_sig;未连接综合后成为floating net。在scan mode下这些net可能oscillate导致IR drop spike或false fail。必须启用auto tie-offset_dft_signal_tieoff -tie_unused_inputs true -tie_value low-tie_value low将所有unused input tie to GND避免high-Z状态。某项目启用后ATE power supply ripple下降40%fail pattern中X state减少92%。5. 实战排错从“Coverage 92%”到“99.8%”的七步定位法当report_test_coverage显示92%时新手常试图“加更多scan chain”或“换ATPG tool”。但真实瓶颈往往不在ATPG而在scan synthesis配置与RTL结构的隐性冲突。以下是我在某AI chip项目中将coverage从92%提升至99.8%的完整排查链路。5.1 Step 1锁定untestable logic的物理位置不用看ATPG报告的summary直接导出untestable FF listreport_test_coverage -untested_cells untested_cells.rpt文件中每行格式FF_NAME MODULE_PATH TYPE。用grep筛选TYPE untestable得到127个FF。关键不是数量而是分布——用awk统计moduleawk $3untestable {print $2} untested_cells.rpt | cut -d. -f1-3 | sort | uniq -c | sort -nr输出前三名top.u_dsp.u_fft42个、top.u_mem.u_sram_ctrl38个、top.u_io.u_lvds_tx25个。说明问题集中在DSP、SRAM controller、LVDS TX三个block。5.2 Step 2逐block分析RTL结构特征u_fft含大量pipeline register但所有FF都带(* dont_use true *)pragma。这是IP vendor为timing closure添加的但DFT工具将其interpret为“禁止scan insertion”。u_sram_ctrl使用custom SRAM macro其control FF被定义为black_box工具无法infer scan capability。u_lvds_tx含analog PHY logicFF被set_dont_scanexclude但exclude范围过大连digital control FF也被覆盖。5.3 Step 3针对性解除scan限制对u_fft删除pragma或替换为DFT-friendly版本# 替代方案用set_dft_cell_property覆盖pragma set_dft_cell_property -cell u_fft_reg -property dont_use false对u_sram_ctrl为black_box添加scan wrapper# 定义wrapper cell define_dft_cell -name sram_ctrl_wrapper -scan_cell true -scan_in_port si -scan_out_port so -scan_enable_port se # 将black_box instance映射到wrapper set_dft_cell_mapping -instance top.u_mem.u_sram_ctrl -cell sram_ctrl_wrapper对u_lvds_tx精准exclude analog部分保留digital FFset_dont_scan -hierarchy top.u_io.u_lvds_tx -except {u_lvds_dig_ctrl*}5.4 Step 4验证scan chain插入效果重新run scan synthesis再report_scan_chains确认三个block的FF now in chainu_fft42 → 0 untestableu_sram_ctrl38 → 0 untestablewrapper生效u_lvds_tx25 → 3 untestableanalog部分合理exclude但coverage仅升至95.3%仍有4.5% untestable。5.5 Step 5检查clock domain crossingCDC区域用report_cdc_analysis检查CDC report发现u_dsp与u_mem间有3个async FIFO其pointer FF被标记为untestable。原因是DFT工具默认不scan async FF需手动enableset_dft_cell_property -cell_type dff -property cdc_scan_enable true但此参数需配合RTL中FIFO pointer的scan enable logic否则会破坏FIFO功能。解决方案在FIFO wrapper中添加scan mode bypass logic确保pointer FF在scan shift时被freeze。5.6 Step 6处理memory BIST的干扰u_sram_ctrl的BIST engine生成的test pattern与scan chain冲突。默认情况下BIST controller的control FF参与scan但BIST logic在scan mode下仍active造成contamination。解决用set_scan_exclude隔离BIST FFset_scan_exclude -hierarchy top.u_mem.u_sram_ctrl.u_bist -reason BIST_logic_interference同时确保BIST engine在scan mode下被disable通过test wrapper的scan_en signal gating。5.7 Step 7最终验证与硅确认完成所有修改后run full ATPGcoverage达99.8%。但关键验证在硅ATE上运行full-scan patternfail rate 0.01%对比functional test与scan test的fail bin分布99% fail bin overlap证明scan test有效性测量scan shift current与仿真预测值偏差5%确认physical DFT implementation正确整个过程耗时11天但避免了tape-out后re-spins。核心经验coverage瓶颈从来不是ATPG算法而是scan synthesis与RTL、物理实现、测试架构的系统性对齐。每一个untestable FF都是设计意图与DFT约束之间的一道裂缝必须亲手去弥合而非交给工具自动修复。我在实际操作中发现最有效的提升coverage的方法不是堆砌工具参数而是建立“FF生命周期追踪表”从RTL coding → synthesis → scan insertion → PR → ATE记录每个FF在各阶段的状态scannable/unscannable/reason。这张表让问题定位从“大海捞针”变成“按图索骥”也是我带新人时必教的第一课。