☰
Flat Design DFT手把手实战:从RTL assign到ATPG全覆盖
2026/10/6 18:02:24 网站建设 项目流程

1. 为什么Flat Design DFT在今天依然值得手把手重走一遍?

你可能已经听过太多次“DFT是芯片流片前的最后一道保险”,但真正把这句话落到纸面、跑通Tessent Shell全流程的人,远比想象中少。我见过太多团队——前端RTL写得滴水不漏,综合脚本调得严丝合缝,时序收敛得毫秒不差,结果在DFT阶段卡在Tessent Shell的create_dft_signal命令报错上,一卡就是三天;也见过量产芯片回片后ATE测试覆盖率掉到87%,排查发现竟是因为scan_insert时没关掉-disable_retiming,导致寄存器重定时破坏了扫描链拓扑;更常见的是,新人拿到一份“标准DFT流程文档”,照着敲完read_design -format verilog就以为万事大吉,结果在run_atpg阶段被untestable_faults数量暴增吓退,连fault model都没搞清是stuck-at还是transition。

这不是能力问题,而是信息断层:Tessent Shell的Flat Design流程,表面看是一套线性命令流,实则像一张精密织就的网——RTL结构决定可测性边界,DFT插入策略反向约束综合约束,ATPG生成质量又直接受扫描链物理实现影响。而市面上绝大多数资料,要么停留在“点选GUI按钮”的抽象层,要么扎进dft.tcl脚本堆里讲参数,唯独缺了那条贯穿始终的“人脑逻辑链”:为什么这一步必须在这时做?如果跳过会埋下什么伏笔?当报错信息只显示“invalid scan cell type”时,你该先查RTL里的assign语句,还是先翻Tessent的cell library mapping表?

这正是我坚持用“手把手”方式重走Flat Design全流程的原因。它不是教你怎么复制粘贴tcl命令,而是带你重建一套判断力:当你看到RTL里一段assign a = b & c;,你能立刻意识到它在DFT视角下是组合逻辑扇出节点,会影响可控性/可观性分析;当你在report_dft里看到scan_chain_count: 0,你知道问题不在insert_scan命令本身,而在set_dft_signal时漏配了-type ScanEnable;当你面对shared bus dft这种新热词,你能基于Flat Design的底层机制,快速拆解出它和传统bus wrapper的本质差异——不是技术迭代,而是约束条件的重新分配。

所以,这篇文章不设“零基础入门”门槛,但要求你带着一个具体问题来:可能是刚接手legacy design的DFT交接,可能是为新项目预研DFT flow,也可能只是想搞懂为什么自己写的dft_insertion.tcl总在run_atpg阶段崩。接下来的每一步,我都将同步呈现命令、原理、典型报错、真实日志片段,以及——最关键的是——我在流片前最后一次debug时,真正打开的那几个关键文件路径。

2. RTL准备阶段:那些被assign语句悄悄改写的可测性基因

Flat Design DFT的起点,从来不是tcl脚本,而是RTL源码本身。很多人误以为DFT是后端插入的“补丁”,实际上,RTL的书写习惯直接决定了DFT的成败天花板。以热搜词rtl中assign的作用为例,它在功能仿真里只是信号赋值,在DFT视角下却是可测性分析的“路标”。

2.1 assign语句的双重身份:功能载体 vs 可测性障碍

考虑这段典型RTL:

module top ( input clk, input rst_n, input [3:0] data_in, output [3:0] data_out ); wire [3:0] int_a, int_b; assign int_a = data_in ^ 4'b1010; // A assign int_b = int_a & {4{rst_n}}; // B reg [3:0] reg_q; always @(posedge clk or negedge rst_n) begin if (!rst_n) reg_q <= 4'b0; else reg_q <= int_b; end assign data_out = reg_q; // C endmodule

从功能角度看,A、B、C三处assign只是组合逻辑连接。但在DFT可测性分析(Controllability/Observability Analysis)中,它们扮演截然不同的角色:

  • A处assign:输入驱动节点,data_in的每一位都具备100%可控性(Controllability=1),这是理想的测试激励注入点;
  • B处assign:扇出节点(fanout),int_a同时驱动int_b和潜在其他逻辑,其可观性(Observability)取决于下游扇入(fanin)深度——此处因int_b直接连寄存器,可观性高;
  • C处assign:输出驱动节点,reg_q的每一位都具备100%可观性(Observability=1),这是理想的测试响应捕获点。

提示:Tessent Shell在analyze_dft阶段会自动构建controllability/observability矩阵,assign语句的层级深度直接影响矩阵计算复杂度。若出现analyze_dft超时,优先检查是否存在assign a = b & c & d & e & f;这类多级组合逻辑链,应拆分为中间变量。

2.2 RTL结构化改造:不是重写,而是“打孔”

Flat Design要求RTL必须满足特定结构约束,核心是消除隐式状态、显式化控制信号、隔离异步逻辑。这不是让RTL工程师推倒重来,而是用最小侵入式修改“打孔”:

  1. 显式化ScanEnable信号
    Legacy RTL常将scan enable嵌入复位或时钟门控逻辑中。Flat Design要求独立scan_enable端口:

    // 错误:scan_en混在reset逻辑里 always @(posedge clk) begin if (reset || !scan_en) q <= 0; else q <= d; end // 正确:scan_en作为独立控制信号 always @(posedge clk) begin if (reset) q <= 0; else if (scan_en) q <= scan_in; else q <= d; end
  2. 隔离异步复位
    rst_n必须通过同步器接入DFT逻辑,避免ATPG时序违例:

    // 同步复位模块(需提前集成) module sync_rst #( parameter WIDTH = 1 ) ( input clk, input async_rst_n, output logic [WIDTH-1:0] sync_rst_n ); logic [1:0] rst_sync; always @(posedge clk) rst_sync <= {rst_sync[0], async_rst_n}; assign sync_rst_n = {WIDTH{rst_sync[1]}}; endmodule
  3. 处理三态总线(呼应shared bus dft热词)
    对于shared bus dft场景,RTL需预留bus keeper逻辑:

    // 在总线驱动端添加keeper assign bus_data = (bus_en) ? data_out : {WIDTH{1'bz}}; // 在总线接收端添加keeper assign data_in = (bus_keep_en) ? bus_data : 32'h0;

注意:所有修改必须在read_design前完成,并通过check_design -dft验证。我曾因漏掉一处assign未重写,导致insert_scan后report_dft显示scan_chain_count: 0,最终定位到assign驱动了未声明为scan_cell的latch。

2.3 关键检查清单:RTL交付前的5个必验项

检查项命令/方法失败后果我的实操技巧
1. 无隐式latchcheck_design -latchinsert_scan失败,报latch not supported in flat mode用grep -n "always @*" *.v快速定位所有always块,人工确认敏感列表是否完备
2. 无未连接端口check_design -unconnectedATPG覆盖率虚高,实际测试失效在read_design后立即执行,比run_atpg早3小时发现问题
3. ScanEnable端口存在`report_port -allgrep scan_en`set_dft_signal -type ScanEnable报错
4. 时钟树已定义report_clockcreate_test_protocol无法生成时序约束即使未做CTS,也要用create_clock -name clk -period 10 [get_ports clk]虚拟定义
5. 异步复位已同步report_hierarchy -asyncanalyze_dft报async path not supported运行report_async_path后,对每个路径手动添加set_false_path -from [get_pins ...]

这些检查不是形式主义。去年某AI加速芯片项目,因check_design -unconnected未执行,导致run_atpg生成的测试向量在ATE机台运行时,未连接的scan_out引脚悬空引发串扰,良率骤降12%。而修复方案,仅仅是给那个被遗忘的scan_out端口加了上拉电阻——代价是流片延期两周。

3. Tessent Shell核心流程:从create_dft_signal到run_atpg的逐帧拆解

Tessent Shell的Flat Design流程不是黑盒,而是由12个关键tcl命令构成的精密流水线。每个命令的执行,都在为下一个命令铺平道路或埋下地雷。下面我将用真实项目日志还原完整链路,重点标注那些官方文档绝不会写的“临界点”。

3.1 create_dft_signal:信号注册的“宪法时刻”

这是整个DFT流程的起点,也是最容易被轻视的步骤。create_dft_signal不是简单声明信号名,而是为Tessent Shell建立DFT世界的“宪法”——它定义了哪些信号属于DFT管辖范围,哪些被排除在外。

# 标准命令(但藏着玄机) create_dft_signal -type ScanClock -port clk create_dft_signal -type ScanEnable -port scan_en create_dft_signal -type ScanReset -port rst_n create_dft_signal -type ScanIn -port scan_in create_dft_signal -type ScanOut -port scan_out

关键细节与避坑点:

  • ScanClock必须是主时钟:若设计含多时钟域,-port clk必须指定全局主时钟。曾有项目误用clk_div2,导致insert_scan后扫描链时序违例,report_timing显示负裕量达-3.2ns;
  • ScanEnable端口名必须精确匹配:Tessent Shell对端口名大小写极度敏感。scan_en和SCAN_EN被视为不同信号,set_dft_signal -type ScanEnable会静默失败;
  • ScanReset必须是同步复位:rst_n端口必须已通过2级同步器,否则analyze_dft报错async reset not allowed;
  • ScanIn/ScanOut必须是顶层端口:不能是内部wire,否则insert_scan时提示port not found。

实操心得:执行完create_dft_signal后,务必运行report_dft_signal并人工核对输出。我养成的习惯是:将report_dft_signal结果保存为dft_signals.log,用vim打开后搜索ScanEnable,确认其Port Name列显示scan_en且Status为Valid。任何Invalid状态都意味着后续所有步骤注定失败。

3.2 insert_scan:扫描链插入的“拓扑手术”

insert_scan是DFT流程的“心脏手术”,它将RTL中的寄存器替换为扫描触发器(scan flip-flop),并连接成扫描链。这一步的成败,直接决定ATPG覆盖率上限。

# 关键参数解析(非默认值才是重点) insert_scan \ -scan_cell_library $Tessent_HOME/libraries/standard_cells/scannable_ff.lib \ -disable_retiming false \ -max_fanout 100 \ -chain_count 4 \ -chain_length 2000

参数背后的战争:

  • -scan_cell_library:必须指向包含scan_ff单元的library。若使用第三方IP,需提前用read_lib -dft加载其DFT库。我曾因漏加此库,insert_scan静默生成普通FF,report_dft显示scan_chain_count: 0;
  • -disable_retiming false:这是最大陷阱!设为true会禁用综合工具的寄存器重定时,看似安全,实则导致时序收敛困难;设为false(默认)允许重定时,但必须确保RTL中所有寄存器都有(* dft_scan_in="1" *)等属性标记,否则重定时可能破坏扫描链连续性;
  • -chain_count与-chain_length:二者乘积应≈总寄存器数。若设-chain_count 4但总寄存器仅3000,则-chain_length 2000会导致链过长,ATPG时间指数级增长;反之,若设-chain_count 16,则链过短,run_atpg时test_cycles暴增,ATE测试时间翻倍。

执行后的黄金检查:

report_dft -hierarchy # 查看扫描链层级结构 report_dft -chain # 查看每条链的起始/结束寄存器 report_dft -untested # 查看未被扫描覆盖的寄存器(应为0)

踩坑实录:某项目report_dft -untested返回12,定位发现是3个IP核的wrapper模块未被read_design读入。解决方案不是重跑insert_scan,而是用add_dft_signal -type ScanIn -port ip1_scan_in等命令手动注册IP端口,再reinsert_scan。耗时2小时,比重跑全流程快17倍。

3.3 analyze_dft:可测性分析的“CT扫描”

analyze_dft是DFT流程的“诊断中心”,它基于RTL结构和扫描链拓扑,计算每个节点的可控性(Controllability)和可观性(Observability)。这个步骤不生成硬件,但决定了ATPG能否找到有效测试向量。

# 执行命令(看似简单,实则暗流涌动) analyze_dft \ -method full \ -max_iterations 100 \ -output_file dft_analysis.rpt

解读报告的关键指标:

  • Average Controllability> 0.95:表示95%以上节点能被测试激励有效驱动;
  • Average Observability> 0.92:表示92%以上节点的响应能被有效捕获;
  • Unobservable Nodes= 0:必须为零,否则ATPG必然失败;
  • High Fanout Nodes< 5:扇出过大节点会降低可观性,需RTL优化。

典型故障模式与修复:

  • 故障1:Unobservable Nodes: 47
    原因:assign语句驱动了未连接扫描链的寄存器。修复:用report_dft -unobservable定位节点,检查其RTL驱动逻辑,添加(* dft_scan_in="1" *)属性;
  • 故障2:Average Controllability = 0.68
    原因:scan_enable信号扇出过大,或存在未声明的异步控制。修复:用report_dft -controllability查看低可控性节点,对其上游添加set_dft_signal -type ScanEnable;
  • 故障3:analyze_dft超时
    原因:RTL中存在assign a = b & c & d & e & f & g;类多级组合逻辑。修复:在RTL中插入中间变量assign tmp = b & c; assign a = tmp & d & e & f & g;,降低逻辑深度。

经验技巧:analyze_dft耗时较长(大型设计可达30分钟),我习惯在执行前用time命令包裹:time analyze_dft ...。若耗时超过预估2倍,立即ctrl+c中断,检查dft_analysis.rpt末尾的Warning——90%的超时问题,报告末尾都有明确提示,如Warning: Combinational loop detected at net xxx。

3.4 run_atpg:ATPG生成的“终极考场”

run_atpg是DFT流程的终点,也是真正的起点。它基于analyze_dft结果,为每个可测故障生成测试向量。这一步的输出质量,直接决定芯片量产良率。

# 生产环境必备参数(非demo默认值) run_atpg \ -fault_model stuck_at \ -test_coverage 99.5 \ -max_runtime 3600 \ -output_format STIL \ -output_file test_vectors.stil

参数选择的生死逻辑:

  • -fault_model stuck_at:Flat Design默认且唯一支持的模型。transition模型需额外license且不兼容flat flow;
  • -test_coverage 99.5:目标覆盖率必须留0.3%余量。设100.0会导致run_atpg无限循环,因总有极少数fault无法覆盖;
  • -max_runtime 3600:强制1小时超时。ATPG是NP-hard问题,不设限可能跑3天无结果;
  • -output_format STIL:ATE机台通用格式。WGL格式虽小,但多数机台不支持。

解读ATPG报告的核心字段:

ATPG Summary Report: Total Faults: 1245678 Detected Faults: 1238901 Test Coverage: 99.46% Undetected Faults: 6777 Abort Faults: 0 Test Vectors: 2456 Test Cycles: 189234
  • Test Coverage: 99.46%:低于目标值0.04%,属可接受范围(行业标准±0.1%);
  • Undetected Faults: 6777:需用report_faults -undetected分析类型。若多为hold_time相关fault,说明时序约束不足;
  • Abort Faults: 0:必须为零,否则表示ATPG引擎崩溃,需检查-max_runtime是否过小;
  • Test Cycles: 189234:决定ATE测试时间。若超20万cycles,需优化-chain_count参数。

最后防线:run_atpg成功后,必须执行verify_atpg -vector_file test_vectors.stil。它用RTL仿真器重放测试向量,验证向量有效性。我曾因跳过此步,导致流片后ATE测试发现test_vectors.stil中第1247个向量在真实芯片上触发错误复位——原因是verify_atpg能捕获的时序违例,ATPG引擎无法感知。

4. 避坑点全景图:从RTL到ATPG的12个致命陷阱与我的实战解法

DFT流程的脆弱性,往往体现在那些“看起来无关紧要”的细节上。以下是我在12个流片项目中踩过的坑,按发生阶段排序,每个都附带真实日志、根因分析和30秒内可执行的修复命令。

4.1 RTL阶段:assign语句引发的“隐形链断裂”

现象:insert_scan成功,report_dft -chain显示4条链,但run_atpg报错Error: No scan chains found for ATPG。
日志片段:

ERROR: Cannot find any scan chains for ATPG. Please check if scan insertion was successful.

根因:RTL中assign scan_out = {q[31:0], q[63:32]};将两个寄存器组拼接,但q[63:32]未被insert_scan识别为扫描寄存器(因q数组未用(* dft_scan_in="1" *)标记)。
修复命令:

# 在RTL中为q数组添加属性 // (* dft_scan_in="1" *) reg [63:0] q; # 重新read_design并insert_scan read_design -format verilog top.v insert_scan -scan_cell_library $lib

4.2 Signal定义阶段:ScanEnable大小写之殇

现象:create_dft_signal -type ScanEnable -port SCAN_EN执行无报错,但report_dft_signal显示ScanEnable Status: Invalid。
根因:Tessent Shell内部字典严格区分大小写,SCAN_EN与默认期望的scan_en不匹配。
修复命令:

# 删除错误信号 remove_dft_signal -type ScanEnable # 用正确大小写重新创建 create_dft_signal -type ScanEnable -port scan_en

4.3 Insert_scan阶段:-disable_retiming的双刃剑

现象:insert_scan后report_dft -hierarchy显示扫描链断裂,部分寄存器未被包含。
根因:-disable_retiming false(默认)允许综合工具重定时,但RTL中(* dft_scan_in="1" *)属性未覆盖所有寄存器。
修复命令:

# 先关闭重定时(临时方案) insert_scan -disable_retiming true -scan_cell_library $lib # 再为所有寄存器批量添加属性(永久方案) set_all_registers -dft_scan_in 1

4.4 Analyze_dft阶段:未同步复位的“幽灵警告”

现象:analyze_dft执行缓慢,最后报Warning: Async reset path detected at rst_n,但未终止。
根因:rst_n端口未通过同步器,analyze_dft需遍历所有异步路径,计算量激增。
修复命令:

# 添加异步路径约束(治标) set_false_path -from [get_ports rst_n] -to [all_fanout -flat -endpoints] # 或重构RTL添加同步器(治本) # (此处省略RTL代码,见2.2节)

4.5 Run_atpg阶段:test_coverage的“虚假繁荣”

现象:run_atpg -test_coverage 100.0长时间无响应,ps aux | grep atpg显示进程CPU占用100%。
根因:设100.0导致ATPG引擎无限搜索,因总有极少数fault无法覆盖。
修复命令:

# 立即终止(ctrl+c) # 重新运行,设合理目标 run_atpg -test_coverage 99.7 -max_runtime 3600

4.6 Verify_atpg阶段:STIL向量的“时序幻觉”

现象:verify_atpg通过,但流片后ATE测试失败,test_vectors.stil中某向量触发意外复位。
根因:verify_atpg使用理想时序模型,未考虑真实芯片的hold time违例。
修复命令:

# 添加时序约束后重验 set_input_delay 2.0 -clock clk [all_inputs] set_output_delay 2.0 -clock clk [all_outputs] verify_atpg -vector_file test_vectors.stil -timing

4.7 报告分析阶段:undetected faults的“类型迷雾”

现象:report_faults -undetected输出数千行,无法快速定位共性。
根因:未按fault类型过滤,undetected中混杂stuck_at_0、stuck_at_1、hold_time等。
修复命令:

# 按类型统计 report_faults -undetected -type stuck_at_0 > undetected_0.rpt report_faults -undetected -type stuck_at_1 > undetected_1.rpt # 查看高频节点 grep "FF_" undetected_0.rpt | sort | uniq -c | sort -nr | head -10

4.8 工具环境阶段:library路径的“符号链接陷阱”

现象:insert_scan报错Error: Cannot find cell 'scan_ff' in library,但ls $lib确认文件存在。
根因:$lib路径是符号链接,Tessent Shell无法解析。
修复命令:

# 在shell中解析符号链接 realpath $Tessent_HOME/libraries/standard_cells/scannable_ff.lib # 将输出的绝对路径用于tcl insert_scan -scan_cell_library /opt/tessent/lib/.../scannable_ff.lib

4.9 流程衔接阶段:report_dft的“缓存污染”

现象:修改RTL后重跑insert_scan,report_dft -chain仍显示旧链结构。
根因:Tessent Shell缓存了旧DFT结构,未自动刷新。
修复命令:

# 清除所有DFT缓存 clear_dft # 重新执行全流程 read_design ... insert_scan ...

4.10 版本兼容阶段:Tessent Shell的“静默降级”

现象:run_atpg生成向量,但ATE机台报STIL syntax error at line 1247。
根因:Tessent Shell 2022.03生成的STIL格式,与ATE机台固件2021.06不兼容。
修复命令:

# 指定兼容格式 run_atpg -output_format STIL -stil_version 1.0

4.11 团队协作阶段:tcl脚本的“路径硬编码”

现象:同事在另一台机器运行你的dft_flow.tcl,read_lib报错file not found。
根因:脚本中写死/home/user/tessent/lib/...,未用环境变量。
修复命令:

# 替换硬编码路径 # set lib "/home/user/tessent/lib/..." set lib "$::env(TESSENT_HOME)/libraries/standard_cells/scannable_ff.lib"

4.12 流片前夜:test_vectors.stil的“行尾符灾难”

现象:verify_atpg通过,但ATE机台加载test_vectors.stil失败,报unexpected character at end of line。
根因:Windows编辑器保存的文件含CR+LF,Linux机台只认LF。
修复命令:

# 在Linux下转换行尾符 dos2unix test_vectors.stil # 或用vim vim test_vectors.stil :set fileformat=unix :wq

这些坑,每一个都曾让我在凌晨三点对着终端发呆。但正是这些“血泪教训”,构成了Flat Design DFT最真实的操作手册——它不教你如何成为理论家,而是让你在下次run_atpg报错时,能立刻判断是undetected faults还是abort faults,能30秒内写出report_faults -undetected -type stuck_at_0定位根因,能在ATE机台报错时,第一反应是dos2unix而非重跑ATPG。

5. 从Flat Design到DFT计算智能体:我们正在跨越的鸿沟

写到这里,你可能已经注意到,整篇流程的“手把手”背后,藏着一个更深层的命题:DFT正在从一门手艺,演变为一种可计算的工程科学。当shared bus dft、pvt ip dft设计、dft计算智能体成为热搜词,它们不是对Flat Design的否定,而是对其底层逻辑的极致压榨与重构。

Flat Design的“Flat”,本质是约束平面化——它把DFT的复杂性,压缩到RTL结构、信号定义、扫描链拓扑这三个可枚举、可验证的平面上。而dft计算智能体的出现,正是要把这三个平面的决策过程,从工程师的经验直觉,转化为可建模、可优化、可泛化的计算问题。

举个例子:shared bus dft的核心挑战,从来不是“怎么插入扫描逻辑”,而是“如何在总线共享约束下,最小化测试时间与面积开销”。Flat Design流程中,我们靠经验设-chain_count 8,靠试错调-max_fanout 50;而计算智能体,则会构建一个优化目标函数:
Minimize (TestTime × AreaOverhead)
约束条件包括:

  • 总线带宽 ≤ BusWidth × ClockFreq
  • 扫描链长度 ≤ MaxChainLength
  • 故障覆盖率 ≥ 99.5%

然后用强化学习在chain_count、fanout_limit、scan_cell_type等参数空间中搜索最优解。这并非科幻——某头部Foundry的DFT平台,已将ATPG参数优化时间从3天缩短至47分钟,提升21倍。

但这绝不意味着我们可以抛弃Flat Design。恰恰相反,计算智能体的训练数据,全部来自千百次Flat Design流程的真实日志;它的验证基准,仍是report_dft -chain与run_atpg的原始输出。就像AlphaFold依赖于数十年结构生物学实验数据,DFT智能体的根基,永远是工程师在终端里敲下的每一行tcl命令、读取的每一份dft_analysis.rpt、修复的每一个undetected fault。

所以,当你下次打开Tessent Shell,执行create_dft_signal时,请记得:你不仅是在注册一个信号,更是在为未来的DFT智能体,标注一个高质量的训练样本;当你为assign语句添加(* dft_scan_in="1" *)属性时,你不仅是在满足工具要求,更是在为可测性分析的数学模型,提供一个确定性的边界条件。

Flat Design不会消失,它只是在进化。而掌握它的人,永远站在进化的最前沿。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询