1. 项目概述:这不是教科书里的DFT,是流片前最后一道实操关卡
你手头有一份RTL代码,模块清晰、功能验证通过、时序收敛良好——但芯片厂的DFT签核邮件还没回。不是因为逻辑不对,而是因为你还没把Tessent Shell里那套Flat Design DFT流程真正跑通。我带过三颗28nm到7nm工艺的SoC做DFT交付,每次流片前最耗心力的,从来不是写testbench,而是把RTL顺利“喂”进Tessent Shell,跑出合格的ATPG pattern,且pattern能真实打到硅片上不报错。这个过程表面看是工具链操作,实则是一场对设计意图、约束完整性、测试结构兼容性、甚至工艺角敏感性的综合校验。标题里“从RTL到ATPG”不是线性步骤,而是一个闭环反馈系统:RTL里一个没加scan enable的寄存器,会在ATPG阶段直接卡死;Tessent Shell里一个没设对的shared bus mode,会让pattern覆盖率掉15%;而所谓“Flat Design”,不是指设计没分层,而是指在DFT插入和ATPG生成阶段,必须以扁平化视角统一看待所有可测单元——哪怕你用了多级子模块复用,Tessent Shell也要求你在DFT视图下把它当一个整体来建模、约束、仿真。关键词RTL、ATPG、Tessent Shell、Flat Design、DFT,每一个都不是孤立概念:RTL是输入源,ATPG是输出目标,Tessent Shell是执行引擎,Flat Design是方法论前提,DFT是贯穿始终的工程目标。适合谁?数字前端工程师刚做完功能验证想交DFT;DFT工程师接手新项目要快速建流程;或者验证工程师被要求补全scan pattern却连Tessent命令都敲不对。别指望点几下GUI就搞定——我见过太多人卡在“tessent shell> read_design -format verilog xxx.v”之后,报错“missing scan chain definition”,翻文档两小时才发现是RTL里assign语句驱动了scan_en信号,而Tessent默认不识别这种组合逻辑驱动方式。这恰恰是当前热词“rtl中assign的作用”背后的真实痛点:assign在功能逻辑里干净利落,在DFT上下文中却可能成为隐性障碍。接下来,我会带你从RTL源头开始,一帧一帧拆解Tessent Shell里Flat Design DFT的完整实操链路,不跳步、不省略、不回避那些文档里不会写的坑。
2. 整体流程设计与思路拆解:为什么必须坚持Flat Design而非Hierarchical?
2.1 Flat Design不是偷懒,而是DFT签核的硬性前提
很多人第一反应是:“我们设计明明是分层的,为什么DFT非得flat?”答案很直接:Tessent Shell的ATPG引擎(尤其是legacy ATPG flow)在pattern生成阶段,对层次化设计的支持存在结构性限制。它需要精确知道每个flip-flop在整个scan chain中的绝对位置、相邻关系、以及所有影响scan shift路径的组合逻辑扇入扇出。如果保留层次,Tessent Shell在读入设计后会自动生成一个flat view用于ATPG,但这个自动生成过程极易丢失关键信息——比如跨层级的shared bus控制信号连接关系、PVT IP内部的scan bypass逻辑、或者某个子模块内部为降低功耗而插入的clock gating cell,其使能端若未在顶层显式暴露,flat化时就会被误判为不可控节点。我去年负责的一颗AI加速IP,就因在RTL中将shared bus dft的enable信号用assign在子模块内生成,未引出到顶层端口,导致Tessent Shell flat化后该信号被优化掉,最终ATPG coverage卡在82%,反复debug三天才发现问题根源不在test logic,而在RTL描述方式。Flat Design在这里不是设计方法,而是DFT交付的强制视图——你必须主动提供一个经过DFT-aware flattening的网表,而不是依赖工具自动处理。这意味着:RTL阶段就要规划好scan enable、scan mode、scan reset等全局DFT信号的驱动方式;所有PVT IP的DFT接口必须在顶层显式例化并连接;shared bus dft的仲裁逻辑必须可被Tessent Shell直接识别,不能藏在黑盒里。
2.2 流程选型:为什么选Tessent Shell而非Innovus或Genus内置DFT?
Tessent Shell是Synopsys专为DFT签核打造的命令行环境,它的核心优势在于“可控性”和“可追溯性”。Innovus或Genus虽然集成了DFT插入功能,但它们更侧重于物理实现与DFT的协同优化,比如自动place & route scan chain、优化scan clock tree。而Tessent Shell则聚焦于DFT逻辑本身:从RTL netlist读入、DFT insertion、constraint定义、ATPG pattern生成、到pattern simulation验证,全程由用户精确控制每一步参数。举个典型场景:当你需要调试一个coverage hole时,Innovus GUI里点几下可能只看到“untestable”,但Tessent Shell里你可以用report_fault_coverage -detailed直接定位到具体是哪个flip-flop的某个stuck-at fault未被激活,再用show_fault -cell xxx -pin yyy查看该fault对应的ATPG stimulus序列,甚至用write_pattern -format stil xxx.stil导出pattern手动注入仿真器单步观察。这种深度调试能力,是图形界面无法替代的。更重要的是,Tessent Shell的脚本化特性让整个流程可版本化、可复现。我把所有Tessent Shell命令写成.tcl脚本,配合Makefile管理,每次RTL更新后只需make dft_flow,就能自动完成从read_design到write_pattern的全流程。而Innovus的DFT flow一旦GUI操作出错,很难回溯哪一步参数设错了。所以,尽管学习曲线陡峭,但Tessent Shell是DFT工程师的“手术刀”,不是“搅拌机”。
2.3 关键决策点:RTL准备阶段的三大不可妥协项
在把RTL交给Tessent Shell之前,有三个动作必须在RTL编码阶段完成,否则后续所有努力都是徒劳:
Scan Enable信号必须由同步逻辑驱动,禁用assign直接赋值
这是当前热词“rtl中assign的作用”在DFT中最致命的应用误区。assign常用于功能逻辑中生成控制信号,但在DFT上下文中,scan_en必须是一个可测试、可控制的同步信号。如果用assign scan_en = (mode == 2'b10) ? 1'b1 : 1'b0;,Tessent Shell在DFT insertion时会将其识别为组合逻辑,无法保证scan_en在scan shift阶段的稳定性和可控性,导致ATPG pattern失效。正确做法是:在顶层always块中用同步逻辑生成scan_en,例如:always @(posedge clk or negedge rst_n) begin if (!rst_n) scan_en_reg <= 1'b0; else scan_en_reg <= (mode == 2'b10); end assign scan_en = scan_en_reg;这样Tessent Shell能明确识别scan_en_reg为可控寄存器,确保其在scan模式下的行为可预测。
所有PVT IP的DFT端口必须显式连接,禁止黑盒推断
PVT IP(Process-Voltage-Temperature monitor)通常由Foundry提供,其DFT接口如pvt_scan_in,pvt_scan_out,pvt_scan_mode等,必须在顶层RTL中显式例化并连接。不能依赖Tessent Shell的auto-recognition,因为不同Foundry的PVT IP命名规则差异极大,Tessent Shell的默认库可能根本找不到匹配项。我遇到过一次,某家Foundry的PVT IP将scan_mode命名为pvt_dft_mode,而Tessent Shell默认只认scan_mode,结果整个PVT模块被当作普通逻辑处理,ATPG coverage直接损失3%。解决方案:在RTL顶层,为每个PVT IP添加标准DFT wrapper,强制重命名端口,并在Tessent Shell中用set_dft_signal -type ScanMode -port pvt_dft_mode显式声明。Shared Bus DFT的仲裁逻辑必须可扫描,且优先级可配置
Shared bus dft是当前高频热词,其核心是多个模块共享同一组scan chain,通过仲裁器动态分配访问权。但很多设计将仲裁逻辑做成纯组合逻辑(如用case语句选择mux),Tessent Shell无法对其施加scan constraint,导致仲裁状态不可控,ATPG pattern无法稳定驱动bus。正确做法:将仲裁状态机用寄存器实现,并暴露arb_state端口;在Tessent Shell中用set_dft_signal -type ScanEnable -port arb_en声明其scan enable信号,并用add_scan_chain -name shared_bus_chain -cells {arb_ff*}将其纳入scan chain。这样ATPG才能生成控制仲裁状态的pattern,确保bus访问的确定性。
3. 核心细节解析与实操要点:Tessent Shell命令链的每一处陷阱
3.1 RTL读入与DFT插入:read_design之后的三道生死关
Tessent Shell启动后,第一步永远是read_design -format verilog your_top.v。但这只是开始,真正的挑战在后续三步:
第一步:link_design必须指定正确的top module name
Tessent Shell不会自动推断顶层模块名。如果你的RTL文件里有多个module,比如top_module,sub_module_a,sub_module_b,而top_module是真正的顶层,你必须显式指定:link_design -top top_module。漏掉这一步,Tessent Shell会默认选择第一个module,导致后续所有DFT操作对象错误。我曾因此浪费一整天——ATPG生成的pattern打在错误的模块上,coverage报告全是0。检查方法:report_design后看Top Module:字段是否为你预期的名称。
第二步:set_dft_signal必须覆盖所有DFT全局信号,一个都不能少
这是最容易被忽略的环节。Tessent Shell需要明确知道哪些信号是DFT专用的,否则无法正确建模scan chain。标准信号包括:
-type ScanMode -port scan_mode-type ScanEnable -port scan_en-type ScanReset -port scan_rst_n-type ScanClock -port scan_clk-type ScanDataIn -port scan_in-type ScanDataOut -port scan_out
但实际项目中,往往还有定制信号,比如shared bus dft的bus_arb_en、PVT IP的pvt_scan_mode。必须全部用set_dft_signal声明,否则Tessent Shell会将其视为普通信号,在DFT insertion时可能被优化掉或连接错误。一个实用技巧:在RTL顶层,用注释标记所有DFT相关端口,例如// DFT: scan_en, scan_mode, scan_clk,然后写个Python脚本自动提取这些端口生成set_dft_signal命令列表,避免人工遗漏。
第三步:insert_dft的选项组合决定成败insert_dft命令看似简单,但参数组合直接影响后续ATPG质量。最关键的三个参数:
-scan_style flat:强制flat scan chain,这是Flat Design的核心。不加此选项,默认是hierarchical,会触发前述的自动flat化风险。-scan_cell_type:必须与工艺库中的scan cell严格匹配。比如SMIC 28nm库中scan cell名为SDFL1P0T28,就必须写-scan_cell_type SDFL1P0T28。写错会导致DFT insertion失败或生成无效netlist。-max_fanout:设置scan chain最大fanout。默认值往往过大(如100),导致scan clock skew严重。根据你的clock frequency和工艺角,应手动计算:假设scan clock period为10ns,cell delay为0.1ns,那么最大fanout ≈ 10 / 0.1 = 100,但实际要考虑布线延迟,建议设为50-70。我通常用report_clock_tree先看原始clock tree,再反推合理fanout值。
提示:
insert_dft执行后,务必运行report_scan_chain。重点检查两项:一是Total number of scan cells是否等于RTL中所有flip-flop数量(允许±1,因某些特殊cell如memory wrapper可能不参与scan);二是Chain count是否合理。如果chain数远大于预期(如设计只有4条chain,报告却显示20条),说明-max_fanout设得太小,导致chain被过度分割。
3.2 Constraint定义:为什么set_atpg_constraint比set_dft_signal更难缠?
ATPG不是无约束的暴力搜索,它需要精确的timing和functional constraint来指导pattern生成。set_atpg_constraint命令就是设定这些“游戏规则”的入口,但它的难点在于:约束必须与RTL功能逻辑完全一致,否则ATPG会生成违反设计意图的pattern。
Timing Constraint:set_atpg_timing的三个致命参数
-launch_clock:指定scan shift阶段的launch clock。必须是你RTL中实际用于scan_en采样的那个clock,通常是scan_clk。写成clk就错了,因为clk是functional clock,其skew和latency与scan_clk完全不同。-capture_clock:指定scan capture阶段的capture clock。这里极易混淆——不是scan_clk,而是functional clockclk。因为ATPG的capture动作,是在functional clock边沿采样被测电路的响应,所以必须用clk作为capture clock。我见过太多人填错这里,导致ATPG生成的pattern在仿真中永远捕获不到fault effect。-scan_shift_period:scan shift的周期。必须与scan_clk的实际period一致。如果scan_clk是10MHz(period=100ns),这里就必须填100。填错会导致ATPG计算的shift时间错误,pattern timing违例。
Functional Constraint:set_atpg_functional_constraint的实战技巧
这是解决shared bus dft和PVT IP测试的关键。例如,shared bus的仲裁逻辑要求:在任意时刻,只能有一个master获得bus access。这个约束必须显式告诉ATPG:
set_atpg_functional_constraint -name bus_arb_exclusive -condition "!(master_a_en && master_b_en)"如果不加此约束,ATPG可能会生成同时激活两个master的pattern,导致bus冲突,仿真失败。同样,PVT IP要求pvt_scan_mode必须在scan shift期间保持稳定,不能在shift过程中变化,否则PVT数据会错乱:
set_atpg_functional_constraint -name pvt_mode_stable -condition "stable(pvt_scan_mode)"注意:
stable()函数是Tessent Shell内置的functional constraint语法,表示该信号在整个ATPG cycle中必须保持不变。这是PVT IP DFT的刚需,漏掉它,ATPG coverage会因PVT模块被标记为untestable而下降。
3.3 ATPG生成与Pattern验证:run_atpg之后的黄金十分钟
run_atpg命令执行后,Tessent Shell会输出大量日志。此时不要急着看coverage report,先做这三件事,能避开80%的后续问题:
第一件事:检查report_fault_coverage中的Untestable Faults明细
Coverage报告里总有个百分比,比如98.5%,但真正重要的是那1.5% untestable faults在哪里。用report_fault_coverage -detailed > coverage_detail.log导出详细报告,重点看Fault Type列。如果是Stuck-at-0或Stuck-at-1,属于正常;但如果是Redundant(冗余fault)或Uncontrollable(不可控fault),就要警惕。Uncontrollable通常意味着某个input pin无法被ATPG控制,根源往往是:RTL中该pin由assign驱动(如assign data_in = {8{1'b0}};),或该pin连接了未声明的DFT signal。解决方案:回到RTL,将该assign改为寄存器驱动,或用set_dft_signal声明该pin为DFT signal。
第二件事:用write_pattern -format stil导出STIL文件,并用simulator做最小化仿真
不要直接拿ATPG生成的pattern去ATE机台。先用Tessent Shell自带的simulator做快速验证:
simulator -input your_top.stil -output sim_result.log检查sim_result.log中的Fault Coverage是否与ATPG报告一致,更重要的是看Simulation Status是否为PASS。如果出现FAIL,说明pattern在仿真中无法激活fault,根源可能是timing constraint设错,或functional constraint未生效。此时,用show_fault -cell xxx -pin yyy定位具体fault,再用write_pattern -format ascii -fault xxx_yyy导出该fault的专用pattern,手动注入仿真器单步调试。
第三件事:report_pattern_statistics确认pattern质量
这个命令输出pattern的物理特性,对ATE机台部署至关重要:
Total Patterns:总pattern数,影响测试时间。Average Bits per Pattern:平均每个pattern的bit数,反映scan chain利用率。Maximum Shift Cycles:最大shift cycles,决定ATE的shift clock频率上限。
如果Maximum Shift Cycles远超你的scan chain length(比如chain length=1000,报告却是5000),说明ATPG在优化时引入了过多dummy cycles,会浪费测试时间。解决方案:在run_atpg前,用set_atpg_option -name max_shift_cycles -value 1000强制限制。
4. 实操过程与核心环节实现:从RTL到Pattern的逐帧记录
4.1 环境准备与Tessent Shell初始化:一个不能少的.tcl模板
Tessent Shell的稳定性高度依赖环境变量和初始化脚本。我从不手动敲命令,而是用一个标准化的.tcl脚本启动整个流程。以下是我在多个项目中验证过的最小可行模板(dft_init.tcl):
# 设置工艺库路径 set search_path [concat $search_path "/path/to/your/process/lib"] set link_library [concat $link_library "/path/to/your/process/lib/stdcell.db"] # 加载DFT库(必须!) load_dft_library -library /path/to/your/process/dft_lib/tessent_dft.db # 设置DFT工作目录 set work_dir "./dft_work" if {![file exists $work_dir]} { file mkdir $work_dir } cd $work_dir # 设置默认DFT选项 set_dft_option -name scan_style -value flat set_dft_option -name scan_cell_type -value SDFL1P0T28 set_dft_option -name max_fanout -value 60 # 设置ATPG默认选项 set_atpg_option -name max_shift_cycles -value 1000 set_atpg_option -name pattern_format -value stil这个脚本的关键点在于load_dft_library——它加载的是Foundry提供的DFT-specific library,包含scan cell的timing model和ATPG behavior model。漏掉这一步,insert_dft会报错“unknown scan cell type”。另外,set_dft_option和set_atpg_option的预设值,避免了每次run_atpg都要重复设置,大幅提升复现性。我习惯把所有项目相关的路径用环境变量$DFT_HOME统一管理,在shell中export DFT_HOME=/project/dft,然后在tcl脚本里用$::env(DFT_HOME)引用,这样换项目只需改一个环境变量。
4.2 RTL到Netlist的转换:Verilog vs. Synthesized Netlist的选择博弈
Tessent Shell支持两种输入:RTL Verilog和Synthesized Netlist(如.v或.db)。选择哪种?我的经验是:前期用RTL,后期用Netlist。
RTL阶段(推荐):当你还在功能验证阶段,RTL尚未综合,用
read_design -format verilog top.v。优势是:DFT insertion发生在RTL层面,可以直观看到scan chain如何插入,便于debug;所有assign、always块的结构清晰可见,方便检查DFT信号驱动方式。劣势是:RTL中可能存在未优化的冗余逻辑,ATPG coverage计算可能偏高(因为未考虑综合后的实际cell delay)。Netlist阶段(必须):当RTL已综合、STA已完成、物理实现即将开始时,必须用
read_design -format db your_top.db。优势是:ATPG基于真实cell和timing,coverage报告与流片后实际测试结果高度一致;能准确反映clock tree、routing delay对scan shift的影响。劣势是:RTL结构被展平,debug困难;如果综合脚本中漏掉了-no_scan_optimization选项,综合工具可能优化掉部分scan logic,导致DFT签核失败。
我的实操流程是:先用RTL跑通基础DFT flow,确认scan chain结构和coverage baseline;再用Netlist跑最终签核flow,对比两次coverage差异。如果Netlist coverage比RTL低超过2%,说明综合或place & route阶段引入了DFT-unfriendly的优化,必须回溯修正。
4.3 Flat Design DFT的完整命令链:一行都不能删的实操清单
以下是我当前项目(7nm AI SoC)正在使用的、经过流片验证的完整命令链。每行都标注了作用和常见错误,可直接复制粘贴执行:
# 1. 初始化(执行dft_init.tcl) source dft_init.tcl # 2. 读入RTL(注意:必须是flatten后的RTL,即所有sub-module已展开) read_design -format verilog -top top_module ../rtl/top_flat.v # 3. 链接设计 link_design -top top_module # 4. 声明所有DFT信号(此处列出全部,一个都不能少) set_dft_signal -type ScanMode -port scan_mode set_dft_signal -type ScanEnable -port scan_en set_dft_signal -type ScanReset -port scan_rst_n set_dft_signal -type ScanClock -port scan_clk set_dft_signal -type ScanDataIn -port scan_in set_dft_signal -type ScanDataOut -port scan_out set_dft_signal -type ScanEnable -port bus_arb_en # shared bus dft set_dft_signal -type ScanMode -port pvt_scan_mode # PVT IP # 5. 插入DFT逻辑(关键:-scan_style flat) insert_dft -scan_style flat -scan_cell_type SDFL1P0T28 -max_fanout 60 # 6. 设置ATPG timing constraint(launch=capture=scan_clk? 错!) set_atpg_timing -launch_clock scan_clk -capture_clock clk -scan_shift_period 100 # 7. 设置functional constraint(shared bus和PVT IP的刚需) set_atpg_functional_constraint -name bus_arb_exclusive -condition "!(master_a_en && master_b_en)" set_atpg_functional_constraint -name pvt_mode_stable -condition "stable(pvt_scan_mode)" # 8. 运行ATPG(-coverage_target 99.5是签核底线) run_atpg -coverage_target 99.5 -timeout 3600 # 9. 报告详细coverage(导出到文件,供review) report_fault_coverage -detailed > coverage_report.log # 10. 导出STIL pattern(ATE机台标准格式) write_pattern -format stil -output ../pattern/top.stil # 11. 仿真验证(黄金十分钟) simulator -input ../pattern/top.stil -output ../sim/sim_result.log注意:第6步的
-capture_clock clk是易错点。clk必须是你RTL中定义的functional clock port name,不是scan_clk。如果RTL中functional clock叫sys_clk,这里就必须写-capture_clock sys_clk。写错会导致ATPG生成的pattern在仿真中无法捕获fault response,coverage报告虚高。
4.4 避坑点实录:那些让我凌晨三点还在改.tcl的深夜
坑1:scan_rst_n极性搞反,导致ATPG coverage归零
RTL中scan_rst_n是active-low,但我在set_dft_signal中误写为-type ScanReset -port scan_rst_n -active high。结果ATPG在reset阶段试图拉高scan_rst_n,而实际电路需要拉低才能reset,所有flip-flop保持原态,scan chain无法初始化,coverage直接0%。修复:-active low。教训:DFT信号极性必须与RTL定义100%一致,不能凭感觉。
坑2:set_atpg_timing的-scan_shift_period单位是ns,不是ps
文档里写“period in time units”,但没说单位。我按惯性填了100000(以为是ps),结果ATPG计算的shift时间是100us,远超实际需求,pattern size爆炸。修复:填100(对应100ns)。教训:Tessent Shell所有timing参数默认单位是ns,必须确认。
坑3:PVT IP的pvt_scan_out未声明为ScanDataOut,导致其输出不可观测
PVT IP的pvt_scan_out是DFT专用输出,但我只声明了pvt_scan_mode,忘了pvt_scan_out。结果ATPG认为该信号不可观测,所有PVT内部fault被标记为Unobservable,coverage损失2.3%。修复:set_dft_signal -type ScanDataOut -port pvt_scan_out。教训:PVT IP的所有DFT端口,无论in/out/mode,必须全部声明。
坑4:run_atpg超时后,report_fault_coverage仍显示旧数据run_atpg -timeout 3600超时中断后,Tessent Shell不会自动清除旧coverage数据。report_fault_coverage仍显示上次成功运行的结果,极具欺骗性。修复:超时后,先clear_atpg_data,再重新run_atpg。教训:任何ATPG命令失败后,必须手动清理数据,否则报告不可信。
5. 常见问题与排查技巧实录:一份可直接抄作业的速查表
5.1 Coverage卡在95%上不去?按此顺序排查
| 现象 | 可能原因 | 排查命令 | 解决方案 |
|---|---|---|---|
Uncontrollablefaults集中于某几个module | 该module的scan_en由assign驱动 | show_design -hierarchy | grep -i "assign.*scan_en" | 修改RTL,用寄存器驱动scan_en |
Unobservablefaults集中在PVT IP | pvt_scan_out未声明为ScanDataOut | report_dft_signal | grep pvt_scan_out | set_dft_signal -type ScanDataOut -port pvt_scan_out |
Redundantfaults占比过高(>5%) | RTL中存在未使用的logic或dead code | report_unused_logic | 清理RTL,删除dead code;或用set_dft_option -name remove_redundant_faults -value true |
| Coverage在RTL和Netlist间差异>3% | 综合脚本漏掉-no_scan_optimization | 检查synthesis log中的optimization report | 在综合脚本中添加set_app_var syn_no_scan_optimization true |
5.2run_atpg报错“Cannot find scan chain”?三步定位法
这是Tessent Shell最让人抓狂的报错之一,表面看是scan chain缺失,实则根源多样。按此顺序排查:
第一步:确认insert_dft是否成功执行
运行report_scan_chain。如果输出为空或Chain count: 0,说明DFT insertion失败。检查insert_dft日志,常见原因是-scan_cell_type名称错误,或工艺库路径未正确设置。
第二步:确认scan_in和scan_out端口是否被优化掉
运行report_port -all \| grep -E "(scan_in|scan_out)"。如果无输出,说明这两个端口在RTL中未定义,或被综合工具优化掉。检查RTL顶层,确保scan_in和scan_out是inout或output端口,且未被ifdef条件编译掉。
第三步:确认set_dft_signal是否覆盖所有必需信号
运行report_dft_signal。重点检查ScanMode,ScanEnable,ScanClock三项是否都有。如果ScanClock缺失,run_atpg必然失败,因为ATPG不知道用哪个clock做shift。
5.3 Pattern仿真失败?仿真器日志里的关键线索
当simulator -input top.stil返回FAIL,不要盲目重跑ATPG。打开sim_result.log,重点关注三类日志:
[ERROR] Cannot resolve signal 'xxx':说明STIL文件中引用了RTL中不存在的信号。根源是set_dft_signal声明的port name与RTL实际port name不一致。例如RTL中叫scan_mode_i,但set_dft_signal写了scan_mode。解决方案:report_dft_signal对比RTL port list。[WARNING] Capture cycle failed for fault xxx:说明ATPG生成的pattern在capture阶段未能捕获fault effect。根源是-capture_clock设置错误,或functional constraint未生效。解决方案:用show_fault -cell xxx查看该fault的ATPG stimulus,手动在仿真器中注入,观察capture clock边沿时的信号状态。[INFO] Simulation completed with 0 faults detected:说明pattern未激活任何fault,coverage为0%。根源是-coverage_target设得过高,ATPG无法满足,但未报错退出。解决方案:降低-coverage_target至95%,先生成可用pattern,再逐步提升。
5.4 Shared Bus DFT的专属排错指南
Shared bus dft因其动态特性,排错逻辑与常规DFT不同:
| 问题现象 | 根本原因 | Tessent Shell诊断命令 | 修复动作 |
|---|---|---|---|
| ATPG coverage中bus相关module coverage为0% | bus_arb_en未声明为ScanEnable | report_dft_signal | grep bus_arb_en | set_dft_signal -type ScanEnable -port bus_arb_en |
| Pattern仿真中bus出现data collision | bus_arb_exclusiveconstraint未生效 | report_atpg_functional_constraint | 确认constraint name拼写正确,且-condition语法无误(如&&不能写成and) |
| ATPG生成大量dummy cycles,测试时间暴增 | bus_arb_en信号在pattern中频繁切换 | write_pattern -format ascii -output bus_debug.pat | 分析bus_debug.pat,找到bus_arb_en切换的cycle,用set_atpg_functional_constraint -name bus_arb_stable -condition "stable(bus_arb_en)"强制其稳定 |
实操心得:Shared bus dft的ATPG constraint必须“双保险”。既要
bus_arb_exclusive保证互斥,也要bus_arb_stable保证仲裁状态在单个ATPG cycle内不变。后者常被忽略,但它是控制pattern size的关键。
6. 后续扩展与工程化建议:让DFT流程真正融入研发主干
跑通一次Tessent Shell Flat Design DFT流程只是起点。要让它真正成为研发流程的一部分,还需做三件事:
第一,把.tcl脚本接入CI/CD流水线
我用Jenkins搭建了一个DFT CI job,每次RTL push到Git,自动触发dft_flow.tcl。job成功标准不是“ATPG完成”,而是coverage_report.log中Testable Faults数量稳定,且Untestable Faults类型符合预期(如仅含Redundant)。这样,DFT问题能在代码提交阶段就被发现,而不是等到signoff前一周才爆发。
第二,建立DFT checklist文档
把本文提到的所有避坑点,整理成一份checklist PDF,发给前端设计工程师。重点标红三条:1)scan_en必须用寄存器驱动;2)所有PVT IP DFT端口必须显式连接;3)shared bus仲裁逻辑必须可扫描。让DFT意识前置到RTL编码阶段,比后期fix cost低十倍。
第三,沉淀pattern validation用例库
针对每种DFT结构(如shared bus、PVT IP、memory BIST),维护一个最小化RTL testbench,包含已知fault的stimulus和expected response。每次ATPG生成新pattern,自动运行这些testbench,确保pattern功能正确。这比单纯看coverage数字更可靠。
最后分享一个小技巧:Tessent Shell的history命令能查看本次session所有执行过的命令。我习惯在流程结束时,用history > session_commands.tcl保存完整命令链。下次遇到类似项目,直接source session_commands.tcl,再微调路径和参数,5分钟就能复现整个流程。DFT不是玄学,它是一门可积累、可复用、可量化的工程实践。你手里的RTL,不是终点,而是DFT签核长征的第一步。