
简介Tessent® Shell 用户手册2018.3版是一份面向数字与混合信号集成电路测试领域的专业英文原版资料适合EDA与半导体行业的设计验证工程师系统学习。手册深入阐述了Tessent Shell的安装配置、自动测试向量生成、故障注入与检测、测试结果分析及故障诊断等核心功能并针对PDF在浏览器中查看时部分链接无法正常工作的问题给出了明确提示。压缩包仅含1个PDF文件大小5.68MB便于离线查阅目前已有556人学习下载。手册对应2018年8月发布的软件版本内容章节围绕实际测试流程展开既涵盖命令行操作与参数配置的说明也包含故障诊断的思路。读者通过这一手册不仅能建立Tessent Shell的整体使用框架还可对照功能模块快速查阅所需细节适用于数字与混合信号IC测试项目的方案设计、问题排查及流程优化是一份实用性较强的案头参考文档。1. Tessent Shell 是什么一份手册背后的 DFT 总控环境跑 DFT可测性设计流程的工程师多半有过这种经历读网表是一套命令设约束是另一套命令生成 pattern 又是一套工具命令散在好几个脚本里换个项目就要重新拼。Tessent Shell 就是来解决这个问题的——它是 Siemens EDA原 MentorTessent 工具族的主控环境一个基于 Tcl 的命令行 shell。它把设计读入、可测性约束、DFT 规则检查、扫描链配置和 pattern 生成收进同一个会话风格上和 Synopsys 的 dc_shell 非常接近。适合做 DFT 的工程师、做前后端衔接的芯片设计工程师以及需要批量回归测试结果的人。这份手册的 PDF 只是说明书真正值钱的是把它当成脚本引擎来用而不是当交互台敲命令。2. Tessent Shell 的启动与交互从命令行到 dofile 批处理2.1 Tessent Shell 在 Tessent 工具族里的定位Tessent Shell 是 Tessent 工具族里的“总控台”。Tessent 家族里有负责扫描链插入的 Tessent Scan、负责测试向量生成的 Tessent ATPG、负责失效分析的 Tessent Diagnosis 等模块Shell 是它们的公共入口——你先进 Shell读好网表、设好约束、跑完规则检查再在同一个会话里调度这些引擎。这和 Synopsys 的 dc_shell 的地位很像dc_shell 是 Design Compiler 的交互外壳Tessent Shell 是 Tessent 全流程的交互外壳。如果你从 Synopsys 流程转过来看到这些命令会觉得很眼熟但又不完全一样。dc_shell 里用create_clock建时钟Tessent Shell 里是add_clock读设计都是read_verilog之后link这点一致。差异集中在 DFT 命令上因为 Tessent 的定位就是测试不是综合。这种相似有两面性上手快但也容易把 dc_shell 的约束习惯带过来比如敲create_clock然后报错找不到命令。遇到这种情况别硬背进 Shell 敲一下help看看命令分类。为什么不是直接跑tessent scan再跑tessent atpg因为那样每个工具都要重新读网表、重新解库、重新挂约束时间翻倍不说约束在两套脚本之间不一致的坑肉眼很难发现。用 Shell 统一会话设计只读一次约束只写一份规则检查的结果可以在生成 pattern 之前就反馈出来。这就是它存在的核心价值。2.2 启动方式与三种运行模式先把命令写出来# 交互模式进 Shell 后逐条敲命令 tessent -shell # 批处理模式把命令写在 dofile 里一次跑完 tessent -shell -dofile run_scan.dofile # 后台跑批处理console 和 tool 日志分开存 tessent -shell -dofile run_scan.dofile -log run_scan.log run_console.log 21 参数拆开讲。-shell是显式进入 shell 的开关有些版本不加也能进但加上可以避免误启动别的工具模块。-dofile指定批处理脚本Tessent 惯例的后缀是.dofile内容本质是 Tcl 脚本所以也有人直接写.tcl再 source效果一样。-log是工具自己记录会话日志的文件 run_console.log 21是把终端输出重定向适合后台跑完再看。这里的“后台跑”和普通 Linux shell 的后台任务是一个道理适合那些一次要跑几个小时的 ATPG 任务。交互模式进去之后Shell 会打一个提示符常见的是tessent。先敲三件事version看工具版本help看命令分类pwd确认工作目录。很多脚本问题都出在启动目录和预期不一致。下面这张表是交互模式下最常用的内建命令相当于 Linux shell 里cd、ls、history的地位命令作用类比version打印工具版本无help \[命令\]列出命令或查询单个命令用法manpwd显示当前工作目录bashpwdls列出当前目录文件bashlshistory查看历史命令bashhistoryexit退出 Shellbashexit这套内建命令和 Tcl 的puts、open、read不冲突前者管理会话后者处理数据。新手阶段不用记太多把help和pwd用熟踩坑率能降一半。2.3 与 Tcl 的融合变量、列表、循环够用就行Tessent Shell 内嵌了一个 Tcl 解释器所以写 dofile 就是在写 Tcl。不需要成为 Tcl 专家但下面这几个必须会# 变量与字符串拼接 set design top set clk_period 10.0 puts Design: $design, period: ${clk_period}ns # 列表操作 set lib_paths [list /libs/stdcells /libs/io] lappend lib_paths /libs/mbist foreach p $lib_paths { puts LIB: $p } # 条件与循环 if {$clk_period 8.0} { puts Slow clock mode } else { puts Fast clock mode } for {set i 0} {$i 3} {incr i} { puts Iter $i }注意几点。第一Tcl 里变量替换靠$但如果你要在字符串中间插变量最好用${clk_period}ns这种写法否则ns会被当成变量名的一部分。第二foreach遍历列表时循环体里改列表不会影响迭代本身这跟 bash 的for有区别别指望在循环里lappend还能把新元素也遍历到。第三if后面的{}必须同行这是 Tcl 的换行规则跟 C 语言习惯不一样我第一次写就栽在这上面。用 Linux shell 写脚本的人看到set以为是 bash 的set -x看到$design以为是环境变量其实 Tcl 里set就是赋值。真正要记的只有三点命令求值、变量替换、方括号执行。puts [expr 1 2]这种写法方括号里的内容会先被求值。这在生成文件名时很有用set logfile run_[clock format [clock seconds] -format %Y%m%d].log把 dofile 当成“套着 Tcl 外壳的 shell 脚本”来理解就顺了。这一章解决的是“Shell 是什么、怎么启动、用什么语法写脚本”下一章开始进入正题——用 Shell 把一条最小 DFT 流程完整跑起来。3. 在 Tessent Shell 里跑通一条 DFT 流程读网表、设约束、生成 Pattern3.1 读库、读网表、设置顶层设计写一个最小可跑的 dofile 骨架。第一步是把“设计”这件事在 Shell 会话里立起来# 设置库搜索路径和目标库 set search_path [list /pdk/stdcells /pdk/io] set link_library [list stdcells.db io.db] set target_library $link_library # 读入门级网表扫描插入前的网表或已插完链的网表都可以 read_verilog netlist/top_preroute.v # 链接把网表里的单元引用指向库中的具体 cell link # 指定当前要操作的顶层模块 set_current_design top逻辑说明set_search_path不是必须项但强烈建议写否则每次read_verilog都要拼绝对路径。read_verilog读门级网表Tessent Shell 也支持读.v、.vhd、以及.db形式的设计数据。link的作用是把网表里引用的 cell 名解析到库文件这一条漏了后面所有对 cell 的操作都会报 unresolved reference。set_current_design告诉后续的 DFT 命令你操作的是谁——一个网表里可能有多个模块不指定的话命令会不知道作用对象。参数说明路径尽量写成绝对路径或相对启动目录的稳定路径。新手最容易犯的是把set_search_path当成 bash 的PATH以为 netlist 也能在里面找到——不是的search_path 只对库查找生效网表路径要靠read_verilog里的路径来保证。提示不同版本的 Tessent Shell 在具体 DFT 命令名上存在差异比如规则检查命令有的版本叫dft_drc有的叫check_dft_rules。动手前先敲help确认本版本文档里的命令名。3.2 DFT 信号约束时钟、复位、扫描使能设计读进来之后典型操作是告诉 Shell 这设计里哪些信号是时钟、复位、扫描使能。这步直接决定后面的规则检查结果# 定义时钟周期、波形、端口 add_clock -name clk -period 10.0 -waveform {0.0 5.0} -port clk # 定义已有的扫描信号网表已经插过链或者要复用已有 DFT 逻辑 set_dft_signal -view existing_dft -type ScanClock -port clk -period 10.0 set_dft_signal -view existing_dft -type ScanEnable -port scan_en set_dft_signal -view existing_dft -type ScanMasterClock -port clk set_dft_signal -view existing_dft -type Reset -port rst_n -active 0参数说明add_clock是给工具做时序推导用的period 单位是纳秒还是皮秒取决于你的库设置-waveform {0.0 5.0}表示时钟在 0ns 拉高、5ns 拉低形成周期 10ns、占空比 50% 的方波。set_dft_signal是 DFT 专用约束-view existing_dft的意思是“这些信号在网表里已经存在”如果网表还没有扫描逻辑、要靠工具插入就要用-view spec来定义期望的信号。-type ScanClock、ScanEnable、ScanMasterClock、Reset的区别在于它们在 ATPG 时扮演的角色不同——ScanClock 驱动扫描移位时钟ScanEnable 控制移位/捕获模式Reset 在捕获阶段需要保持非激活。复位信号这里标记-active 0表示低有效复位。这部分几乎没有标准答案每个设计的时钟方案都不一样。我一般会先把时钟和复位定义完整再跑 DRC因为漏了复位时报出来的 violation 会误导排查方向。另外如果设计里有多个时钟域记得把每个时钟都add_clock一遍只定义主时钟会让跨时钟域的故障全部变成不可测。3.3 规则检查、扫描配置与 pattern 生成约束齐了进入检查和生产阶段# 检查 DFT 规则verbose 参数打印完整 violation 列表 dft_drc -verbose # 查看当前扫描配置 report_scan_configuration # 设置扫描链数量与插入风格如果还没插链 set_scan_configuration -chain_count 8 -style muxed_scan insert_scan # 重新做规则检查确认插入后没有引入新问题 dft_drc -verbose # 运行 ATPG 生成测试图形 run_atpg -auto_compression # 报告测试覆盖率与 pattern 数量 report_coverage reports/coverage.rpt # 输出多种仿真器格式的 pattern write_patterns patterns/top.wgl -format wgl write_patterns patterns/top.stil -format stil命令逻辑拆开看。dft_drc是全流程里第一道质检它检查时钟是否可控制、复位是否会影响捕获、扫描链是否完整报出来的 violation 要先清零再往下走。set_scan_configuration里的chain_count决定扫描链条数链越少每条链越长ATPG 压缩率通常更高但测试时间也变长muxed_scan是最常见的结构在功能模式和扫描模式之间用 mux 切换。insert_scan只对还没有扫描结构的网表做插入如果输入网表已经是插完链的这步就不需要否则会重复插入报错。run_atpg -auto_compression是调用 Tessent 的 ATPG 引擎做测试生成-auto_compression是常见的压缩模式目标是减少 pattern 数量但不牺牲覆盖率。跑完之后report_coverage给覆盖率write_patterns把 pattern 导出成仿真器要的格式。WGL 是 Tessent 的波形格式STIL 是 IEEE 1450 标准格式两种都导出是最稳妥的——前后端仿真工具可能只认其中一种。跑完这四步一条典型的最小 DFT 流程就通了。但流程通不等于结果对第 5 章专门讲那些让脚本挂到半夜的坑。在那之前先把手动流程升级成可复用的脚本引擎。4. 把 Tessent Shell 当脚本引擎批处理、参数解析与日志榨取4.1 dofile 不只是命令列表第 3 章的骨架解决“跑通一次”。但真实项目里没有哪个设计是一次跑完就再也不碰的——ECO 换一版网表、加一条 scan 链、改一个时钟频率都要重跑。这时候把 dofile 当成脚本写收益比交互模式大多了。dofile 本质就是 Tcl 脚本意味着你可以用循环一次处理几十个模块用条件语句跳过缺失文件用 proc 封装自己的命令。一个最简单的批量处理例子# 批量读入多个模块的网表 set designs [list ctrl dsp mbist_wrap] foreach dsn $designs { set netlist netlist/${dsn}.v if {![file exists $netlist]} { puts WARN: $netlist not found, skip $dsn continue } read_verilog $netlist link set_current_design $dsn puts Loaded $dsn OK }这里file exists是 Tcl 的文件检查命令作用相当于 bash 里的test -f。把跳过逻辑写进脚本比每次缺文件时手工改脚本要稳。continue和 bash 里的 continue 一样跳到下一次循环。这个模式在跑多模块回归时几乎每天都用。更进一步可以把一段固定的处理流程封装成 proc。比如把“读网表 link 设顶层”三步封装成load_design后面每个模块调用一行。这样 dofile 结构会从 200 行缩到几十行排查问题时定位也快。封装的原则很简单重复出现三次以上的命令序列就该变成函数。4.2 用类似 shift 的风格解析入口参数很多工程师把参数写死在 dofile 里换模块就改脚本三个模块改成三份脚本改完还怕漏改。更省心的做法是让 dofile 接受命令行参数。Tessent Shell 启动时会把用户在命令行里额外带的内容存进全局变量argv我们可以写一个解析函数proc parse_args {} { global argv set design set period 10.0 for {set i 0} {$i [llength $argv]} {incr i} { set arg [lindex $argv $i] switch -- $arg { -design { incr i set design [lindex $argv $i] } -period { incr i set period [lindex $argv $i] } -h { puts Usage: tessent -shell -dofile run_flow.tcl -design top -period 20.0 exit 0 } } } if {$design eq } { puts ERROR: -design is required exit 1 } return [list $design $period] } set params [parse_args] set design [lindex $params 0] set period [lindex $params 1] puts Running DFT with design$design, period${period}ns这个写法借鉴了 Linux shell 脚本里shift处理参数的思路每遇到一个-xxx就用incr i把指针移到下一个位置拿到对应的值。switch在 Tcl 里支持多分支匹配--告诉 switch 后面都是模式不是选项。写完之后启动命令就变成tessent -shell -dofile run_flow.tcl -design top -period 20.0一条命令控制设计名和时钟频率脚本本体一份就够了。这就是从“敲交互命令”到“写工具”的分水岭。4.3 日志榨取不退出 Shell 也能做 grep跑完几十个模块最常见的动作是打开 log 文件用 grep 过滤关键字看每个模块的 violation 和 coverage。Linux shell 的 grep 当然能做但如果场景是“在 Tessent Shell 里跑完任务、马上根据结果决定下一批参数”退出 Shell 再 grep 再回来就很打断。可以在 dofile 的末尾直接读日志、统计、输出汇总# 跑完后自动摘出所有 violation 行 proc summarize_log {logfile} { set fh [open $logfile r] set data [read $fh] close $fh set lines [split $data \n] set violations [list] foreach line $lines { if {[string match *Violation* $line]} { lappend violations $line } } puts Violation Summary puts Total violation lines: [llength $violations] foreach v $violations { puts $v } } summarize_log run_scan.logopen、read、close、split、string match都是标准 Tcl 命令string match里的*通配符用法和 bash 里的 grep 模式很接近。比起用 shell 的 grep这种做法的好处是结果可以直接在同一个 Tcl 会话里参与判断比如“violation 数超过阈值就标记该模块 failed”进而不需要人工介入。把这段再封装一下还能顺便生成一个汇总文本留作回归记录。4.4 循环里的隐藏坑写到这里有一个反复坑人的点必须单独讲Tcl 的循环变量替换发生在每次迭代开始前但如果你在循环体里用set修改了迭代计数变量行为会和 bash 里一样危险。另一个更隐蔽的是foreach与引用传值——在 Tcl 8.5 之前foreach 不支持对列表元素的直接修改你改$item只是改了副本# 错误示范在 foreach 里试图改列表元素 set items [list a b c] foreach item $items { set item X$item ;# 只改了副本items 不变 } puts $items ;# 输出 a b c不是 Xa Xb XcTessent Shell 内嵌的 Tcl 版本通常较新但写脚本时我仍然避免在 foreach 里修改列表元素而是先收集到新的 list循环结束后再统一处理。这样逻辑清楚也不依赖 Tcl 版本。把 dofile 写成参数化脚本之后运行回归就是一条命令的事。但跑得多踩坑也多下一章是我最想留给你的部分。5. Tessent Shell 避坑指南5 个让脚本挂到半夜的常见问题这些坑都是实际跑流程时高频出现的每条按现象、原因、解决的顺序写可以直接对照排查。说白了没有一条是工具设计缺陷全是脚本习惯问题。5.1 现象dofile 里路径不对工具静默退出或报一堆 not found现象read_verilog netlist/top.v在某个目录下跑得好好的换到另一个项目目录同样的 dofile 直接报 cannot open file甚至更隐蔽——工具不报错但后续命令链接出来的设计是空的到 ATPG 才炸。原因read_verilog的相对路径基于启动 Shell 时的工作目录dofile 放在哪个目录不影响文件查找。很多脚本套模板时把路径写成相对路径换个启动位置就全废了。这是所有坑里出现频率最高的一个。解决在 dofile 开头先把工程根目录固定下来用file dirname拼出绝对路径再使用set script_dir [file dirname [info script]] set netlist_dir [file join $script_dir netlist] set LIB_ROOT /pdk/stdcells set search_path [list $LIB_ROOT] read_verilog [file join $netlist_dir top.v]info script是 Tcl 里返回当前脚本路径的命令file join按平台规则拼接路径。这样 dofile 无论放在哪里都能稳稳找到自己的兄弟目录。我一般还会在开头加一段puts WORK DIR: [pwd]跑挂了看第一行日志就知道当前工作目录是什么省得猜。5.2 现象时钟约束写错pattern 数量暴涨或覆盖率掉 3 个点现象同一个设计上个月跑了 2000 个 pattern这个月换了个人写 dofile同样覆盖率下 pattern 变成 4000 个或者覆盖率直接掉了。原因最常见是add_clock只写了-period没写-waveform工具按默认波形推导和实际时钟偏移不匹配导致 ATPG 把很多本该检测到的 fault 当成不可检测。另一个常见是把时钟 port 写错比如用了clk_in而不是系统时钟clk整个时序路径全部偏移。解决每次写完时钟约束先report_clocks看一遍工具解析出来的周期和波形再跑 DRC。手感上我是把时钟定义单独抽到一个clocks.tcl里所有项目统一维护不散落在各个 dofile 里。换时钟频率时只改一个文件diff 也干净。5.3 现象Tessent Shell 内存持续增长跑到第 N 个模块直接 OOM现象dofile 里用 foreach 循环处理 20 个模块前 10 个模块正常第 12 个模块时机器开始疯狂 swap最后进程被 OOM killer 杀掉。这个现象在跑多模块回归时特别常见。原因循环里每次read_verilog后没有释放上一个设计的数据。Shell 会话为了性能会缓存设计对象循环里反复读设计又反复set_current_design旧设计没有清掉内存随迭代线性增长。解决每个模块处理完后显式释放设计foreach dsn $designs { read_verilog ${netlist_dir}/${dsn}.v link set_current_design $dsn # ... 约束、DRC、ATPG ... remove_design -all ;# 释放当前设计的内存占用 }注意remove_design -all会把当前会话里所有设计都清掉如果后面的循环还需要前面某个设计的引用就不能这么干。另一种做法是每个模块单独启动一个 Tessent Shell 进程用批处理方式串行跑虽然启动有开销但内存边界最干净。我自己倾向后一种尤其是在机器上同时挂多个回归时。单独进程还有额外好处一个模块挂了不会拖垮整批任务。5.4 现象write_patterns 输出的文件格式和仿真器对不上现象write_patterns成功生成了.wgl文件但仿真器加载时报格式不支持换成.stil后仿真器又说 stil 版本不对。这属于那种“工具没报错但下游全是错”的坑。原因WGL 和 STIL 都有版本和选项差异仿真器支持的是子集。比如 STIL 的 WFTWaveform Table里的时序定义如果 Tessent 导出时用了仿真器不认的语法就会报解析错误。另一个常见问题是 pattern 文件里包含了 compressed 数据仿真器不支持压缩 pattern。解决写 pattern 前先确认目标仿真器支持哪种格式和版本。一般做法是输出时指定格式参数并关闭压缩或使用仿真器兼容模式write_patterns patterns/top.stil -format stil -no_compress write_patterns patterns/top.vcd -format vcd -event vector_change-no_compress在部分版本里默认关闭压缩但显式写出来能让阅读脚本的人一眼知道意图。如果两种格式都仿真不了退一步检查 ATPG 生成的report_coverage里有没有大量 unclassified 的 fault那往往是约束问题而不是格式问题。格式问题好解决约束问题才是根子。5.5 现象catch 到了错误脚本却继续跑最后产出一堆废结果现象dofile 里用catch包住 ATPG 命令原意是“出错就记录然后停”结果脚本继续往下跑基于残缺的设计生成了 pattern覆盖率 0%还白白跑了两个小时。原因Tessent Shell 对 error 的处理并不是“一碰就退出”。catch捕获错误后Tcl 会继续执行后续命令除非你在 catch 块显式调用exit或者error。很多人把 catch 当成 bash 的set -e这是完全不同的语义。这是血泪经验里最贵的一条因为废结果会浪费掉整个通宵。解决在 catch 里做显式退出或者干脆用全局的 error 处理策略if {[catch {run_atpg -auto_compression} err]} { puts ERROR: ATPG failed: $err puts Check: $logfile exit 1 }另一层保险在 dofile 开头加全局错误陷阱任何未捕获的 error 都结束脚本proc global_exit_on_error {msg} { puts FATAL: $msg exit 1 } bgerror global_exit_on_errorbgerror是 Tcl 的全局错误处理器入口。改掉“catch 了就等于安全”的习惯之后半夜被废结果叫醒的次数明显少了。脚本宁可挂得早不能错得远。6. 进阶验证save_session 回归调试与覆盖率核对的实用技巧6.1 用 save_session 存现场改参数不用全部重跑一个大的 SoC 设计光是读网表和 link 就要二三十分钟。如果只是改一个扫描链数量从头跑一遍太浪费。Tessent Shell 支持保存会话# 第一次流程跑完约束和 DRC存一个 setup 现场 save_session -design top -file session/top_setup.session # 下次进来直接恢复跳过读网表和 link restore_session session/top_setup.sessionsave_session保存的是设计对象、约束、库映射等内存状态恢复之后可以直接改set_scan_configuration再跑 ATPG。注意session 文件和网表不是一回事网表 ECO 了 session 就失效了恢复之后先跑一次report_current_design确认对象还在再动手改参数。我自己习惯在 ATPG 跑之前存一个 session这样覆盖率不达标时恢复现场改约束只要几分钟。6.2 回归结果核对看哪些数字数字怎么对齐跑完一轮回归不要只看“过没过”。至少要核对四项指标期望异常信号Fault Coverage目标值如 95%掉点先查时钟约束Total Patterns与设计规模匹配暴涨查 waveformViolations0 或已知白名单新增 violation 查网表版本Runtime和规模正相关异常久查内存配置验证方法上我是把每次回归的report_coverage重定向到一个固定文件然后写一个小脚本对比两次运行的 coverage 和 pattern 数差值超过阈值就把具体模块名列出来。Tessent Shell 的report_coverage输出是文本的用第 4 章的日志榨取方式可以自动汇总。没有自动化的回核对 DFT 流程来说就是一场灾难因为你根本不知道哪一版网表把覆盖率悄悄带崩了。最后说一个我的习惯每次跑流程先在 dofile 里加一行puts START: [clock format [clock seconds]]跑完再看一遍日志头部的时间戳。别小看这行字它能在你同时跑三四个回归时准确告诉你哪次跑的是哪版脚本。工具跑挂不可怕可怕的是挂了你不知道是为什么挂的。希望这些从实际流程里磨出来的用法和排查习惯能帮你在自己的 DFT 环境里少走几段弯路希望帮到你。本文还有配套的精品资源点击获取