
先说一个容易被新人绕晕的事DFT里的DRC和你在版图、FPGA实现里看到的DRC完全是两码事。前阵子群里还有人拿着Vivado报的“drc rtstat-6 partial route conflicts”来问我是不是scan chain插错了我当时哭笑不得——那是布局布线阶段的物理DRC告警跟Tessent的DFT规则检查不在一个维度。这篇笔记我会把用Tessent做Scan Chain插入、跑通ATPG到输出pattern的完整流程捋一遍重点放在DRC错误怎么查、怎么解尽量把我在项目里踩过的坑一次说清。这篇东西的目标读者是刚接触DFT的芯片设计工程师、后端想补DFT知识的同学以及那些被Tessent海量report逼到怀疑人生的兄弟。你不需要是DFT专家只要懂点数字电路基础、见过综合后的门级网表跟着往下走就行。1. 先把流程全貌装进脑子Tessent在DFT里到底管哪一段1.1 Scan Chain是什么为什么非要插它Scan Chain扫描链本质上是把设计里成千上万个D触发器换成带MUX的可扫描触发器Muxed-D scan cell然后用一条或几条链把它们串起来。普通模式下scan_enable拉低走正常功能路径测试模式下scan_enable拉高所有触发器变成一串移位寄存器测试数据从scan_in口一粒一粒灌进去等灌满之后拉低scan_enable打一拍捕获再把内部状态从scan_out口倒出来。这套机制解决的核心问题是可观测性和可控制性。一颗芯片几百万个触发器内部节点状态你根本没法从引脚直接看到更没法直接置成想要的初始值。有了scan chain每个触发器的状态可以被“移位”出去观测也可以被“移位”进来控制。ATPG生成的那些pattern本质就是在干这件事算好一组输入激励和期望响应灌进扫描链、捕获、再移出来比对。没有scan chainDFT等于零没有好的scan chain结构ATPG覆盖率会惨不忍睹。这就是为什么Tessent里第一步往往是DRC先把扫描结构的设计规则查清楚再谈插入和生成。1.2 Tessent工具链里各个成员的分工Tessent这个平台下挂了一堆工具我们最常用的几块是Tessent Shell统一命令行环境几乎所有操作都在它里面完成。你可以把它理解成一个DFT专用的“总控台”读网表、设约束、跑DRC、做插入、写协议文件全程不换工具。Tessent Scan负责扫描链的规划、分组、平衡和插入。Tessent ATPG读入扫描后的网表和测试协议生成测试向量并计算故障覆盖率。Tessent Diagnosis主要用于良率分析时的失效诊断不是每个项目都会跑。后面还有Tessent BoundaryScan、Tessent MemoryBIST、Tessent LogicBIST这些但本篇只涉及Scan和ATPG这段主线其他的先不展开。有一点值得提前说Tessent的command体系跟Synopsys的DFT Compiler差别挺大它更强调先定义完整的DFT约束时钟、复位、scan enable、scan mode再统一跑规则检查。你要是刚从DC切过来别急着敲insert_scan先把Tessent Shell的思维方式适应了再动手否则后面全是在改约束的死循环。1.3 DRC这个缩写在不同阶段的不同含义既然热词里一堆DRC这里顺手给你做个区分上下文DRC含义典型工具查什么物理版图Design Rule Check版图设计规则检查KLayout、Calibre金属线间距、宽度、通孔重叠等工艺规则FPGA实现布局布线后的设计规则检查Vivado如drc rtstat-6这类局部拥塞、路由冲突、时钟资源异常PCB/原理图电气规则检查OrCAD等网络连接、引脚冲突、未连接引脚DFT可测性设计规则检查Tessent、DFT Compiler时钟可控、扫描单元合法、异步复位可控等Tessent里的DRC查的是你的设计能不能被可靠地扫描测试而不是版图上的几何规则。搞清楚这个概念以后你搜“Tessent DRC报错”就知道搜出来的东西跟Vivado那堆报错不是一码事了。2. 输入准备库、网表、约束一个都不能少2.1 你要准备的输入文件全家桶跑Tessent Scan链插入之前先把下面这些东西备齐门级网表综合后的Verilog网表通常来自DC或Genus。注意网表必须已经映射到可用的标准单元库而且最好不要带未映射的RTL残留。标准单元库文件一般给.db或.libTessent是从库里识别哪些单元是可扫描触发器的。没有正确读入库后续DRC全是幽灵报错。时序约束文件SDC或Tessent支持的约束描述主要用来定义时钟、复位这些关键信号。Tessent对SDC的解析有自己的规则不是所有SDC写法它都吃。UPF可选但有更好如果有功耗意图比如多电压域、isolaton cell最好一并读入避免DRC把电源关断相关的逻辑误报成violation。已有的DFT约束比如扫描端口定义、扫描模式信号这些在你前期DFT规划时就应该定好。我遇到过最难受的情况是版图前综合的网表没处理好异步复位导致Tessent DRC一跑几百条violation全是复位可控性问题。后来学乖了前端RTL阶段就要求所有异步复位统一走DFT约束里的复位信号管理后端DRC瞬间干净。2.2 Tessent Shell里的读入命令和坑Tessent Shell启动后核心命令大致如下read_verilog -format verilog ./rtl2gate/top_netlist.v read_db /path/to/stdcell.db read_parasitics -format spef ./rc/top.spef常见的问题是库文件顺序和网表引用不一致。Tessent不是每次都会提醒你库里的cell和网表里实例化的cell不匹配读完了照样能往下走等你跑DRC才发现一堆“unknown cell type”之类的诡异问题。所以读完之后我习惯用一条命令快速验证# 检查当前设计中所有instance的数量和类型 report_area -instances如果不读到几十万级实例数或者实例里混进了一堆库外的黑盒先回头查库和网表别急着往下走。还有一点读入多份Verilog文件时顺序很重要。Tessent对后读入的文件覆盖先读入的同名模块定义一不小心就会把父模块里的子模块引用搞乱。我的习惯是底层库里的标准单元单独放一个目录先读RTL门级网表后读模块间的依赖关系由工具自动解析。2.3 时钟、复位、扫描信号的定义方式Tessent里所有DFT信号都要通过set_dft_signal或add_clock这类命令显式描述。这一步是DFT DRC能否干净通过的分水岭。# 定义时钟 add_clock -period 10 -name clk -port clk # 定义扫描使能 set_dft_signal -view spec -type ScanEnable -port scan_en # 定义扫描时钟 set_dft_signal -view spec -type ScanClock -port clk # 定义复位信号 set_dft_signal -view spec -type Reset -port rst_n -active_state 0 # 定义扫描输入/输出端口 set_dft_signal -view spec -type ScanDataIn -port scan_in set_dft_signal -view spec -type ScanDataOut -port scan_out我自己的习惯是先定义标准扫描时钟ScanClock和普通功能时钟Clock因为后续ATPG阶段对时钟的分类会直接影响pattern生成方式。扫描使能信号属于ScanEnable复位信号标注active_state 0还是1必须跟网表里实际的极性和连接一致这块错了DRC会直接以“uncontrolled pin”的形式骂你。另外一个总被忽略的点scan mode信号。设计中如果有ICG门控时钟、多路选择器在功能模式下会切时钟路径那你必须在Tessent里把scan mode信号也约束出来让它把时钟路径锁定到确定的测试拓扑上。没有这个约束DRC会报一堆时钟不可控。# scan mode信号定义 set_dft_signal -view spec -type ScanMode -port scan_mode首次接触Tessent的人容易漏掉-view spec这个参数。Tessent把信号分为spec和existing_dft两种视角spec表示你希望插scan之后形成的DFT结构existing_dft表示设计中已经存在的DFT逻辑。后续跑DRC时这两个视角的信号会同时参与检查漏定义任何一个都可能导致报错。3. Scan Chain插入实操从run_drc到insert_scan3.1 先把DRC跑一遍再谈插入这一步是很多从Synopsys流程转过来的工程师最不适应的Tessent要求在插入scan链之前先跑run_drc。原因很简单扫描链插入是在已有设计基础上修改网表、新增测试结构如果原设计本身存在不可测的逻辑比如锁存器、不受控异步复位、内部三态总线冲突插了scan也白搭还会把问题放大。典型的DRC流程# 设置DFT约束完成后运行DRC run_drc -spec # 查看DRC报告 report_drc -summary report_drc -violations-spec参数告诉工具按你设定的spec视角来检查。跑完之后工具会生成.drc文件和一个报告文件。合格的DFT DRC应当是0 violation但实际上第一天就跑出0的情况非常少大部分时候你会看到几十条错。版本不同Tessent输出报告的命令略有差异有的版本用report_dft_violations有的用report_drc -violations。如果命令不存在直接打开工作目录下的.drc和.log文件看原始内容不纠结命令名。3.2 扫描链分组、平衡和端口的取舍DRC干净之后就要规划scan chain了。先想清楚这几个问题**配多少条链**这取决于芯片的测试引脚数量和ATE测试时间。链越少每条链越长shift时间越长链越多占用的scan_in/scan_out引脚越多但shift节奏更快。通常大芯片会选32条、64条甚至更多像我们做的一颗SoC就配了96条链。**每条链长度是否均匀**链长不均测试时间会被最长链拖死。Tessent有自动平衡工具也可以在add_scan_groups里显式指定。# 添加一个scan group并指定链的数量和端口 add_scan_groups -name chain_group_0 \ -scan_in {pin_a pin_b pin_c} \ -scan_out {out_a out_b out_c} \ -chain_count 3 # 或者让工具自动分配 add_scan_groups -name auto_group -auto_chain_count 64**哪些扫描单元不进链**比如某些带特殊模拟功能的IO单元、PLL里的分频触发器如果工具把它们识别成不可扫描单元会报告并跳过。但如果你希望某些明确可测的单元强制进链需要手动添加add_scan_cell约束。扫描链的起点和终点一般放在顶层或特定子模块的端口上这样后端布线时可以在边界上统一处理。每次插入scan链之前建议先看一眼get_pins的层级路径确认你要用的扫描端口是真实的物理端口而不是某个模块内部的软端口。3.3 执行insert_scan并检查输出网表DRC干净、扫描链分组搞定了就执行插入insert_scan write_verilog -replace -output ./scan_output/top_scan.v write_test_protocol -replace -output ./scan_output/top.spfinsert_scan做完之后不要急着写网表先确认几条关键信息report_scan_chains看每条链的长度、起始单元、结束单元。report_scan_groups看分组是否均衡。随机抽查几条链的第一个和最后一个单元确认确实连接到了对应的scan端口上。write_test_protocol生成的SPF文件或STIL是给后续ATPG用的里面包含了完整的扫描结构定义、时钟、IO约束。这个文件相当于“ATPG怎么操作你的扫描链”的操作手册一旦网表有变动SPF必须重新生成不能复用旧的否则后面ATPG会莫名其妙报一堆时序violation。还有个大坑写出的scan网表必须重新做形式验证。扫描插入改了网表结构但功能逻辑应当等效。Tessent可以在插完后用verify_scan做内部一致性检查但更可靠的是拿形式验证工具跑一遍功能等价性。我们团队内部的规矩是scan网表和原网表必须过formal否则不往后端release。这一步能挡住大量因为工具设置不当导致的网表异常。4. ATPG流程从scan网表到测试向量4.1 读入scan网表与协议文件重建测试环境ATPG阶段可以直接在同一个Tessent Shell会话里继续也可以新开一个会话。如果是新会话流程是这样# 新会话中读入scan后的网表和库 read_verilog -format verilog ../scan_output/top_scan.v read_db /path/to/stdcell.db # 读入扫描协议文件 read_test_protocol -format spf ./scan_output/top.spf # 或者读STIL格式 # read_test_protocol -format stil ./scan_output/top.stil # 构建ATPG环境 build_modelbuild_model会根据网表和协议构建一个内部故障模拟模型。这一步如果报错大多数是SPF和网表不匹配比如链上某个单元名字对不上或者时钟定义和网表实际连接不一致。TP到这一步回头比对比对网表和SPF里的实例名基本能定位。4.2 故障模型怎么选stuck-at优先transition跟上ATPG不是凭空生成向量而是针对特定故障模型去算。最常见的两类stuck-at故障假设某节点的信号固定为逻辑0或逻辑1。这是制造缺陷中最基础、覆盖率最容易做高的模型。跑一次full stuck-at ATPG覆盖率一般能做到95%以上很多成熟工艺甚至98%、99%。transition故障假设节点从0跳变到1或从1跳变到0失败。这类故障测的是时序问题对shift频率、捕获时序有要求生成pattern数量比stuck-at多不少覆盖率也相对难做高。还有path delay、bridging等但一般项目不会默认全上。我的习惯是第一轮只跑stuck-at先把基础覆盖率拉起来第二轮加上transition按客户或质量目标决定要不要继续加压。你非要在第一轮就把所有故障模型全打开运行时间会翻几倍排错时还分不清是哪个模型带来的问题。Tessent里设置和运行ATPG大概长这样# 设置故障类型 set_fault_type stuck_at # 或者 set_fault_type transition # 设置覆盖率目标 set_patterns -limit 10000 set_coverage_target 98 # 开始生成 run_atpg -autorun_atpg -auto会先做fault collapsing故障合并、然后动态压缩pattern、再产出一份覆盖率报告。如果覆盖率达不到预期Tessent会提示你哪些故障没测到并给出未覆盖故障列表这时候可以去查是不是某些逻辑被exclude了或者时钟/复位约束导致捕获路径有问题。4.3 pattern生成、仿真验证与格式转换的完整链路ATPG跑完后你需要把生成的pattern写出来验证和交付# 写出pattern文件格式可选 write_patterns ./atpg_output/top.stuck_at.pattern -format stil # 或者WGL格式 write_patterns ./atpg_output/top.stuck_at.wgl -format wgl # 查看覆盖率总结 report_summaries输出pattern后我强烈建议先做一次门级仿真。把pattern文件、scan网表、库的仿真模型Verilog/VHDL模型放进仿真器里跑一遍看有没有mismatch。很多DRC和ATPG层面看着没问题的情况到仿真阶段会暴露时序违例、X态传播、仿真模型缺少初始值等问题。仿真这一步能拦住大约两成的“假好pattern”。格式转换方面Tessent输出STIL/WGL只是中间格式通常还要转成ATE厂商的最终格式比如Teradyne的UltraFlex格式、Advantest的T2000格式等。这类转换一般用Tessent的配套工具或脚本完成转换时注意检查pattern header里的时钟定义和ATE测试台的配置是否一致。5. 常见DRC错误排查实录从报错到定位5.1 第一次看到DRC报告别慌先分级Tessent的DRC报告一般会按严重程度分三档Error必须解决的硬错误不修就没法插scan或无法做ATPG。Warning不一定会卡流程但大概率影响覆盖率应该重视。Info提示信息告知某些单元被排除、某些约束被自动继承等。我拿到一份DRC报告第一件事不是逐条去读错误内容而是先看每个类别的数量。如果某个类别数量特别大比如“uncontrolled reset pin”报了500条那通常是根因只有一个——复位控制逻辑没配好而不是500个独立问题。把这个根因找到并修掉500条会一起消失。5.2 高频DRC错误类型与排查方法我带过的项目里以下DRC错误出现频率最高每一项后面附上排查思路DRC错误方向典型报错特征排查思路时钟不可控clock pin is not controllable / clock not stable during shift确认时钟定义是否完整检查内部生成的时钟、门控时钟路径确保scan_mode下时钟路径固定。异步复位/置位不可控reset/set pin is not controllable检查复位信号是否由外部端口或已约束的DFT信号驱动必要时对复位树增加scan mode下与门处理。扫描单元非法non-scan cell / instance is not in scan list确认库文件是否完整检查该单元是否被显式exclude或尺寸过小/带特殊属性无法替换。三态总线冲突bus contention / multiple drivers on net找出总线上的多个三态驱动确认扫描模式下是否会有多个驱动同时使能。锁存器latch detected in scan path确认锁存器是否故意保留若是需配置成transparent mode或在约束中显式处理。组合逻辑环路combinational loop detected检查网表中的组合回环通常需要前端修改设计或在约束中添加break。内部生成时钟internally generated clock on data path在扫描模式下将内部时钟通过MUX切换为外部测试时钟或在约束中把该节点声明为时钟。黑盒/未建模单元black box / unknown model补全库或添加仿真模型避免ATPG把该单元当作黑盒导致覆盖率下降。再补一个最容易忽略的坑多时钟域边界上的跨时钟路径。Tessent的DRC在检查时钟交叉路径时如果两个时钟之间没有同步器或者scan_mode下时钟关系没定义清楚会报出类似“unstable clock relationship”的错误。这种情况先在约束里把异步时钟域显式声明出来set_clock_group -asynchronous -group {clk_a clk_b}然后再跑DRC多半就能消掉。5.3 用层次化定位法快速锁定问题根因实际排错时我习惯用三步定位法第一步看单个violation的详细报告。Tessent的DRC报告会带instance路径。复制路径到网表里看这条路径上到底连了什么。比如一条“uncontrolled clock”的violation顺着路径查到源头是一个PLL的输出那问题就清楚了PLL在扫描模式下没被旁路。第二步归类并回溯根因。把几百条violation按涉及的信号线或模块路径归类通常归到最后就两三个根因。修根因而不是修症状这很重要。第三步修改约束或网表重跑DRC验证。约束修改后重跑确认violation数量从三位数降到0。如果只降了一半说明根因不止一个继续归类和排查。5.4 一些平时搜不到但极其好用的排查技巧下面这几个技巧是文档里不太起眼、但实际特别省时间的善用set_dft_signal的active_state。复位信号极性反了工具不会主动告诉你DRC会报成“uncontrollable”。清空一下约束里复位极性的定义重新跑确认一下网表里实际连接的是rst_n还是rst。排查DRC前先跑一次report_constraints。这个命令会列出Tessent当前认到的所有DFT约束和信号分类一眼就能发现有没有信号被自动归到了错误类别。很多时候DRC错就是因为你以为约束了、其实没约束上。针对特定violation用get_drc_violations和get_cells配合过滤。比如只关心所有“clock”相关的DRCset vio [get_drc_violations -filter severity error message ~ *clock*] puts clock related DRC errors: [sizeof $vio]不要一上来就改网表。大多数DRC问题都能通过约束解决只有少数需要动网表。改网表容易引入新问题能不动就不动。6. 实操心得与避坑总结用Tessent做Scan Chain插入和ATPG核心就四个字约束先行。约束不干净后面每一步都在还债。我见过太多团队在run_drc阶段花了整个DFT周期的一半时间最后发现只是某个扫描时钟没定义好、或者复位极性弄反了。磨刀不误砍柴工Tessent这套东西前期的DFT约束梳理越细致后期越省心。另一个心得是版本管理要到位。Tessent版本升级命令和报告格式都会有细微变化。我们曾因为服务器上同时存在多个Tessent版本导致同一个脚本在不同机器上跑出不一样的结果。后来统一在Makefile里显式指定工具版本和安装路径再没出过这种幺蛾子。最后分享一个所有人都用得上的小技巧DRC报告一定要保留原始log并归档。跑完ATPG或者整个DFT流程之后如果客户或后端来问某个覆盖率为什么是99.1%而不是99.5%你翻出当时的DRC报告就能解释清楚——是因为某条链上有一个不可扫描的模拟单元导致那部分逻辑覆盖率上不去。没有这份原始记录事后查起来真的很被动。Tessent这套流程说实话不难难的是耐下心来把每一步的约束和检查做扎实。希望这篇实战笔记能帮你少走点弯路尤其是DRC报错那一片遇到类似问题的时候能有个参考。后面我再写一篇关于Tessent跟Vivado物理DRC联调的记录如果你正好也在做FPGA原型验证可能会用得上。