ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Tessent Shell 设计内省与编辑:DFT 工程师的扫描链排查实战指南

Tessent Shell 设计内省与编辑:DFT 工程师的扫描链排查实战指南 先说清楚这篇是从哪里来的。我一直在系统整理 Tessent Shell 用户手册前面已经写完了基础命令和设计读入的部分这篇对应的是手册第三章Design Introspection and Design Editing。做 DFT 的同行应该都有体会Tessent Shell 是所有 Tessent 流程的入口不管后面跑 ATPG、做压缩还是 BIST第一步都是在这个交互环境里把设计摸清楚、把约束配对。字面上看Introspection 和 Editing 一个是“看”一个是“改”但这两个动作在真实项目里是缠在一起的看不清楚就不知道往哪儿改改错了又得靠内省命令把问题拉回来。这篇不打算泛泛讲概念我会结合项目里的实际场景把最常用的命令套路、参数选择和踩过的坑一起过一遍。适合刚接触 Tessent Shell 的工程师照着操作也适合已经用过一段时间但没系统性研究过手册的同行查漏补缺。1. 先搞清楚Design Introspection 和 Design Editing 到底在解决什么问题1.1 内省不是“查网表”那么简单很多人刚接触 Tessent Shell 的时候会觉得内省这个说法太玄了不就是查网表吗直接打开门级网表文件用文本编辑器搜一搜不就行了如果设计只有几千个标准单元这么干确实可以。但实际项目里百万门级的网表压缩成文本打开来就是几十万行光靠 grep 找一条扫描链的连接关系眼睛基本就看花了更别提还要确认每个端口的方向、每个单元的类型、时钟树的走线、复位信号的扇出范围。Tessent Shell 做内省的思路完全不一样。它会把设计读入之后在内存里建一套完整的结构化数据模型端口、单元、网络、层次结构、属性、时序信息全部索引起来。在这个模型上做查询本质上不是“找字符串”而是“问语义”。比如 report_ports 拿到的不只是端口名列表还包括方向、总线定义、与库单元的连接关系report_scan_chains 拿到的不仅是一条链的名字还包括链上每个单元的 instance 路径和它们在链中的顺序。这中间的差别就跟你去图书馆查一本书一样——用全馆书目系统检索和在一堆书里一页页翻效率和准确性完全不在一个量级。内省命令还有一个很实用的特性——支持局部查询。很多工程师习惯一上来就整个设计全量 report输出几千行到屏幕上费眼睛又不好过滤。其实这类命令基本都支持指定 instance、指定层次、指定对象类型做定向查询比如只想看 top/u_core 下面的扫描单元就加一个 -instance 参数输出立刻收敛很多。这个习惯越早养成后面处理大设计越省力。1.2 编辑的边界改的不是功能逻辑而是 DFT 约束Design Editing 这个词非常容易让人产生误解。我第一次看到手册这一章的时候以为 Tessent Shell 可以像文本编辑器一样直接修改功能网表比如改某个逻辑门的连接、加一个 buffer 之类的。实际不是这样或者说至少不是它的主要用途。Tessent Shell 的“设计编辑”对象不是功能逻辑而是与测试相关的属性、约束和扫描结构定义。可以把它理解成在网表旁边放了一张“配置单”哪些引脚被当作 scan enable哪些单元是 black box 不需要插扫描逻辑扫描链怎么分组测试模式怎么定义某些信号是否需要固定为常数。所有这些 . 都是通过命令写进设计对象上的属性里。真正动网表结构发生在后面 insert_dft 的阶段工具会依据这些配置去插入 MUX、串接扫描单元、生成测试协议。换句话说Design Editing 是在“告诉工具应该怎么做”而不是自己动手去改电路。搞清楚这层边界很重要因为不少新手会把大量时间花在试图用 set_attribute 去改逻辑连接上方向找错了自然折腾很久都得不到预期结果。我看到过有人在论坛里问“为什么我设了属性网表输出没变化”其实就是没分清约束配置和逻辑修改的区别。这篇后面讲的编辑操作也全部是围绕 DFT 属性配置这点展开的。2. 设计内省把库、端口、属性和扫描信息一次看清2.1 从空白 Shell 到进场设计读入设计的第一步每次面对一个新设计我习惯先跑一遍完整的读入流程确认工具和设计库之间没有沟通障碍再做任何查询。这里说的障碍最常见的就是库单元缺失或者端口方向信息丢失。Tessent Shell 的启动和读入步骤大致是这样不同版本命令名会有一点差异但不影响整体流程# 1. 启动 Tessent Shell tessent -shell # 2. 读取库不同版本命令名可能不同 read_cell_library ./lib/slow_vdd1v8.lib # 3. 读入门级网表 read_verilog ./netlist/top_routed.v # 4. 读入之后先做一次整体概览 report_design这里有几个细节值得展开说。read_cell_library 这一步很多从 DC 或 PT 过来的人容易忽视。Tessent Shell 需要知道设计中每个实例对应的标准单元库信息比如单元类型是触发器还是组合逻辑、有没有扫描输入端口、时序上怎么定义。如果没有正确加载库后面 report_scan_cells 的结果基本是空的工具根本识别不了哪些是可扫描单元。read_verilog 结束后我会立刻跑一次 report_design这个命令会输出设计的顶层名称、端口数量、层次结构、单元总数这些基础信息。它的作用相当于进场后的第一次“点名”——确认设计确实加载进来了规模跟预期一致没有出现读入一个空设计这种低级错误。如果设计规模显示异常或者顶层端口和期望不符趁早排查别等做完一堆约束才发现读错了文件。还有一个很容易踩的坑读入的网表如果包含 IP 或 memory这类子模块在单纯的门级网表里通常没有完整实现。工具在读入时可能会输出一堆 warning这时候不能直接忽略。比较稳妥的做法是提前准备好 IP 的 behavioral model 或者设置 black box不然后续 DRC 检查和扫描链插入阶段会冒出来一堆来源不明的错误。2.2 端口、时钟和复位内省命令里最高频的三件套设计读进来之后第一波要查的必然是端口、时钟、复位这三类信息。它们是所有后续 DFT 约束的基础也是新人最容易翻车的地方。端口查询用 report_ports这条命令的输出包含端口名、方向、所在层、总线属性等信息。如果需要看总线定义配合 report_buses 使用。很多设计里会混着单 bit 端口和总线端口单看 report_ports 列表容易漏掉总线成员用 report_buses 按总线分组看会更清晰。时钟和复位的情况稍微复杂一点。Tessent Shell 在加载设计后会根据网表连接关系自动识别一部分约束但自动识别不是万能的。实际项目里经常出现某个时钟域因为特殊连接方式没被认出来或者某个异步复位信号被错误的当初普通数据信号处理。这时候就需要主动跑 report_clocks 和 report_resets确认工具的理解和设计意图一致Tessent report_clocks Clock Name Period Source ----------------------------------------------- clk_func 10.0ns top/clk_func clk_test 100.0ns top/clk_test Tessent report_resets Reset Name Type Polarity -------------------------------------------------- rst_n async active_low我自己的习惯是在跑 DRC 之前一定先把这两份报告过一眼。DRC 报出来的时钟相关错误很多时候根源并不是 test 逻辑有问题而是功能时钟的定义在 Tessent Shell 里和设计本意不一致。提前发现了后面能省一大半排查时间。这里额外提一个通用技巧所有 report 命令的输出建议在启动脚本里统一重定向到 log 文件。Tessent Shell 的交互界面输出滚屏非常快等你想回头翻某个结果早就滚没了。写个简单的 wrapper 脚本每次启动自动记录全部会话输出排查问题的时候直接 grep log 文件效率比盯屏幕高得多。2.3 扫描结构与 DFT 信号内省的重头戏端口、时钟、复位都是开胃菜Tessent Shell 里真正体现内省价值的地方是扫描结构和 DFT 信号的查询。这也是第三章最核心的内容。先说 report_scan_cells。这条命令用来确认设计中哪些触发器或者锁存器被工具识别为可扫描单元。输出的重点不是看有多少个而是确认扫描单元的类型映射是否正确——D 触发器映射成了带 scan_in/scan_out 的 sc 单元还是被识别成了普通 D 触发器映射正确与否直接关系后面的扫描链插入质量。然后是 report_scan_chains。如果你的设计是从上一级流程带过来的可能存在已经定义好的扫描链如果是全新设计这一步通常是空的。检查已经存在的扫描链时重点看三样东西链的数量和长度是否平衡、链上单元的连接顺序是否符合预期、时钟和 scan enable 信号是否分配正确。工具输出大概长这样Tessent report_scan_chains Scan Group Name: group1 ---------------------------------------- Chain Name Length Clock Enable chain_0 128 clk_test test_se chain_1 127 clk_test test_se chain_0 instances: 0: top/u_core/u_flop_128 1: top/u_core/u_flop_127 2: top/u_core/u_flop_126 ...chain 的长度差异太大通常意味着扫描链平衡策略需要调整enable 信号不一致往往会导致 DRC 报 scan enable 冲突。这些信息在内省阶段越早暴露越好。report_dft_signals 用来查看当前已经定义的 DFT 信号。它和 report_clocks 的区别在于DFT 信号关注的是每个信号在测试模式下的角色比如 ScanClock、ScanEnable、ScanMode而 report_clocks 更偏重功能时钟的定义。设置完 DFT 约束后我习惯立刻跑一遍这条命令确认 set_dft_signal 的配置全部生效。另外还有 report_scan_style 和 report_scan_structures。前者确认当前的扫描风格muxed-D、LSSD、clocked-scan 这类后者查看整体的扫描结构分组信息。这两个命令在大规模设计里尤其重要因为扫描风格不同后面约束命令的参数写法差异非常大。3. 设计编辑六个你必须掌握的核心操作3.1 set_dft_signal告诉工具哪些信号是拿来测试的如果把设计内省比作“检查身体”那 set_dft_signal 相当于给医生开处方——告诉工具哪些信号在测试时要扮演什么角色。这是设计编辑里最高频、也最容易出错的一条命令。看一个实际例子# 定义测试时钟 set_dft_signal -name clk_test -view existing -type ScanClock -port clk_test # 定义 scan enable set_dft_signal -name test_se -view existing -type ScanEnable -port test_se # 定义测试模式信号 set_dft_signal -name test_mode -view existing -type TestMode -port test_mode这里有几个关键参数必须理解到位。-type 是指定信号角色ScanClock、ScanEnable、TestMode、ScanDataIn、ScanDataOut 等等。新手最容易犯的错是把 ScanClock 和功能时钟混为一谈。一个设计里时钟可能非常多但真正在扫描移位时使用的测试时钟往往只有少数几个乱定义会把整个扫描链的时序搞乱。-view 参数区分的是 existing 还是 insertion。existing 表示这个信号已经在网表顶层存在insertion 表示需要工具在插入 DFT 逻辑时自己创建这个信号。如果你告诉工具一个不存在的端口是 existing后面 DRC 大概率会报错反过来一个应该 existing 的信号你声明成 insertion工具就可能在环境里额外加一个莫名其妙的 pin。我自己的经验是所有 DFT 信号的定义尽量集中写在脚本头部用变量统一管理信号名不要散落在各个配置文件里。项目后期换 pin、换端口名的时候只需改一处避免全局替换带来的遗漏风险。3.2 set_attribute / get_attribute属性和约束的读写Tessent Shell 本质上是一个 Tcl 解释器所以它处理属性的方式也很 Tcl——通过 get_attribute 和 set_attribute 来读写设计对象上的属性。它们是设计编辑里最通用的两个命令几乎做任何定制化操作都会用到。先养成一个好习惯任何 set_attribute 之前先 get_attribute 看一下当前值。属性可能已经存在也可能还带着从库文件里继承来的默认值。不看清楚就直接覆盖有时候会误伤之前流程设置的约束。实际使用中比较常见的属性场景包括# 查看某个 instance 上的所有属性 get_attribute top/u_core/u_flop_128 # 设置某个单元不参与扫描 set_attribute -instance top/u_core/u_flop_128 -name DoNotScan -value true # 给黑盒单元打标 set_attribute -instance top/u_macro_sram -name ScanBlackBox -value true这里要注意属性名在不同 Tessent 版本里可能有差异。比如 DoNotScan 在某些版本里叫 do_not_scanScanBlackBox 也有不同的拼法。最靠谱的方式是先用 help set_attribute 或者 complete 一下属性名的前缀看工具当前版本到底认哪个。因为属性名写错了工具未必会报错它可能只是默默不生效这种问题排查起来最费时。还有一点Tcl 的作用域问题在设置属性时非常坑。如果你在一个 proc 里调用了 set_attribute而这个 proc 的作用域或者参数传值处理不当属性设置可能只在局部生效退出 proc 之后就看不到了。排查方法很简单——set 完之后立刻用 get_attribute 在同一脚本环境里验证一遍。这个习惯能帮你筛掉一大半“为什么设置了没反应”的疑问。3.3 从约束到插入insert_dft 前后的设计状态变化前面做了那么多内省和配置目的都是为了这一刻insert_dft。这个命令会根据你设置好的 DFT 信号、扫描属性、黑盒约束真正开始修改设计把可测试性逻辑插进去。这次修改不是直接在原网表上即时生效的Tessent Shell 的内存模型会先发生变化你需要把变化后的设计写到磁盘上才能拿到新的网表。典型动作是这样的# 插入 DFT 逻辑 insert_dft # 插入后立刻检查扫描链结果 report_scan_chains # 确认无误后写出新网表 write_netlist ./output/top_dft.v这里我强烈建议insert_dft 之前先跑一遍完整的 DRC 检查。原因很简单insert_dft 是批量操作如果前面有遗漏的规则问题插入完再去查错误信息会交织在一起非常难定位。而插入前就把 DRC 清干净insert_dft 报出来的问题基本就是你这次新增配置引入的定位范围一下子小了很多。insert_dft 成功之后不要急着写网表。先跑 report_scan_chains确认扫描链的数量、长度、时钟和 enable 挂载情况都符合预期。这一步看着多余但实际价值巨大——我有一次漏配了一个 scan enableinsert_dft 并没有报错但 report_scan_chains 里有两组链明显挂错了 enable当场发现省去了后端返工的麻烦。最后写网表时推荐用 write_netlist 或者对应的 write_verilog 命令并确认输出文件中包含新的扫描链连接关系。输出完拿这个网表回去跑一遍 DRC 和 ATPG才算真正闭环。4. 常见问题与排查技巧实录4.1 读入时一堆单元不认识怎么办现象read_verilog 之后终端刷出来一长串类似 “Cannot find cell type ...” 或者 “Unresolved module ...” 的 warning。原因无外乎两种一是库文件没加载或者加载路径不对二是网表里引用了一些行为级模型或者 IP 单元在 target library 里根本没有物理实现。排查路径也很直接。先 check 一下 read_cell_library 的路径再看库文件里是否包含对应单元。如果确认物理库确实没有那这些单元大概率需要设置为 black box并提供 behavioral model 供工具做逻辑识别。在脚本里提前处理这些单元能避免后面扫描链插入阶段连环报错。4.2 时钟/复位没被自动识别现象report_clocks 里看不到预期的时钟或者 report_resets 里某个复位信号没有出现。最常见的原因是端口方向定义问题。比如某个时钟端口在网表里是 inout 或者是内部生成的时钟Tessent Shell 自动识别时可能会漏掉。另一个常见原因是为了做 ATPG 约束时钟被设置了一些特殊属性工具默认不好判断。处理手段是手动补充定义。用 set_dft_signal 加上 -view existing 参数把时钟角色补上或者用时钟约束命令明确创建一棵测试时钟树。关键是补完之后一定要重新 report_clocks 验证别补完了就当没事了。4.3 属性写了没反应Tcl 作用域的小坑现象set_attribute 执行没有任何报错但随后 get_attribute 查出来的结果却不是你设置的值。这种问题十有八九是 Tcl 作用域搞的鬼。Tessent Shell 的脚本本质上还是 Tcl 解释器如果你在某个 proc 里写 set_attribute变量和属性设置的作用域就会受到限制。另一个常见原因是 object 路径写错了比如少了一个层次前缀工具没有匹配到任何对象但 Tcl 语法层面完全合法所以不报错。我的习惯是给这类操作写一个简单的封装函数在函数内部强制打印执行日志包括操作对象、属性名、属性值。这样即使后面脚本跑飞了打开 log 也能快速定位是哪一行、哪个对象出了问题。4.4 常见问题速查表典型现象可能的根本原因处理建议读网表时大量单元不识别库未加载、库路径错误、IP 缺 model检查 read_cell_libraryIP 设置 black boxreport_scan_cells 结果为空库映射失败触发器类型未被识别确认库版本与网表匹配检查扫描单元映射时钟没被自动识别时钟端口方向不对或内部生成时钟未声明手动用 set_dft_signal 补充定义属性设置后无效果Tcl 作用域问题或对象路径写错set 后立即 get 验证日志打印操作信息insert_dft 后扫描链异常前面约束配置遗漏或 DRC 未跑干净插入前完整跑 DRC插入后立即 report_scan_chains5. 我个人实际操作中的体会这一章整理下来我自己最大的感受是Design Introspection 和 Design Editing 从来不是两个割裂的阶段而是同一件事的两面。看得越细改得越准改完必须马上用内省命令验证形成“查询—修改—再查询”的闭环。很多时候项目里出现的“DFT 约束搞了半天结果网表不对”的问题根源都是跳过了中间某次验证。另外有两件事我想单独强调一下。第一所有配置脚本必须版本化。Tessent Shell 里设置的 DFT 信号、属性、黑盒约束都是一行行命令堆出来的如果你在交互界面里手敲完之后就关掉窗口那这些配置就全没了。正确的做法是从一开始就把所有约束写进一个 .tcl 文件放到项目仓库里管理。后端迭代网表版本时脚本还能跟着一起维护。第二遇到不懂的命令第一反应应该是 help。Tessent Shell 的命令很多不同版本之间还有细微差异网上找到的老例子未必能直接用。工具自带的 help 输出虽然枯燥但包含的正是当前版本最准确的语法说明。我写这篇的过程里也频繁翻 help确认了一些参数在最新版本里的写法。到这里关于第三章的 Design Introspection and Editing最核心的部分算是讲完了。后面我还想针对压缩逻辑和 BIST 场景下的内省与编辑单独展开那些场景里 set_dft_signal 和属性配置的复杂程度会比这里高出一截。等整理得差不多继续往下写。
返回列表