1. 为什么“网表扫描链插入”不是个纯工具操作,而是一场逻辑与物理的协同博弈
Tessent,这个名字在数字芯片设计后端圈子里,几乎等同于DFT(可测试性设计)的代名词。但很多人第一次打开Tessent Shell,导入一个RTL网表,点下“Insert Scan Chain”按钮,看到日志里跳出“Scan insertion completed successfully”,就以为任务结束了——结果流片回来,ATE测试覆盖率卡在82%,故障定位失败,debug日志里全是“scan_enable stuck-at-0”和“capture cycle mismatch”。我见过三支团队,在同一个28nm MCU项目上,用同一版Tessent 2022.2,分别交出79%、86%、93%的最终ATPG覆盖率。差距不在工具版本,而在对“网表扫描链插入”这件事本质的理解:它从来不是把寄存器连成一串那么简单,而是在逻辑功能约束、时序收敛边界、物理布局占位、测试向量生成效率四重维度上做动态平衡的一次精密校准。
关键词里的“网表”,是这场博弈的起点,也是最容易被轻视的变量。RTL综合后的门级网表,表面看是一堆AND/OR/FF的连接关系,但背后藏着大量隐含信息:哪些寄存器被综合工具优化掉了?哪些组合逻辑环路被自动拆解?哪些异步复位信号被转换成了同步释放路径?这些细节不会出现在.v文件的文本里,却直接决定scan_enable信号能否干净地驱动所有扫描触发器,也决定scan_in/scan_out引脚在布局布线阶段会不会被挤到die边缘,导致测试探针接触不良。我曾在一个SoC项目里,发现Tessent插入扫描链后,时序报告里出现大量“scan_enable path”的setup violation,查到最后,根源是综合阶段启用了“-no_boundary_optimization”,导致顶层模块的scan_enable输入端口被综合进了一个超大组合逻辑块,扇出高达4200——而Tessent默认的scan_enable buffer insertion策略,只在驱动能力<2000的路径上生效。
“扫描链”这个词,也常被窄化理解为“shift register”。实际上,在Tessent语境下,它是一个包含scan cell mapping、chain stitching、clock gating bypass、reset isolation、test point insertion在内的完整结构体。比如shared bus dft热词所指的场景:当多个IP模块共用一条测试总线时,Tessent必须在网表层面识别出bus arbiter的控制逻辑,并在扫描链拓扑中预留专用的bypass mux,否则ATPG工具无法生成能正确激活各IP scan chain的向量。这已经超出传统“连链”范畴,进入系统级DFT架构协同领域。
所以,这篇解析不讲“如何点击菜单”,而是带你从网表导入那一刻起,逐层拆解Tessent内部的决策逻辑:它怎么读取网表中的时序弧(timing arc)来判断哪些FF可以安全加入扫描链;它如何根据用户指定的max_fanout参数,动态调整buffer insertion位置,而不是简单地在每个chain head加buffer;它在遇到multi-cycle path时,为什么宁可牺牲部分scan chain长度,也要保留原始功能路径的时序完整性。这些细节,才是决定项目成败的真正分水岭。
2. 网表预处理:那些Tessent不会明说,但会默默惩罚你的“脏数据”
Tessent对网表质量的容忍度,远低于你想象。它不像仿真工具那样会报错退出,而是选择“静默降级”——自动跳过有问题的寄存器,或强行插入不合规的scan cell,最终导致ATPG失败。我统计过近20个量产项目的pre-scan网表问题,83%的覆盖率瓶颈,根源都在这个环节。下面这三类问题,必须在Tessent启动前亲手解决,不能指望工具自动修复。
2.1 异步复位网络的“幽灵连接”
网表里最常见的陷阱,是异步复位信号(async_rst_n)的跨时钟域扇出。综合工具为了时序收敛,常把async_rst_n通过一个两级同步器(sync_ff1/sync_ff2)接入某个时钟域,但网表导出时,这两个同步器FF可能被标记为“don’t touch”,而它们的复位输入端口,却仍连接着原始的async_rst_n net。Tessent在扫描链插入时,会把sync_ff1和sync_ff2都纳入扫描链,但它的scan cell替换逻辑,默认假设复位信号在scan shift模式下是稳定的。一旦scan_enable拉高,而async_rst_n恰好处于亚稳态,整个扫描链就会在shift过程中随机崩溃。
实操方案:用Tcl脚本在网表导入前做静态检查。核心逻辑是遍历所有FF,检查其rst pin是否连接到net name含“_rst”或“_reset”的net,再对该net执行fanout分析。如果fanout > 1且存在跨时钟域路径(可通过clock domain annotation确认),就必须手动断开非同步器路径,或添加“set_dont_touch”属性。我们团队开发了一个自动化check脚本,运行后会生成report.csv,列出所有高风险rst net及其fanout分布:
# check_async_rst.tcl set rst_nets [get_nets -hierarchical *rst*] foreach_in_collection rst_net $rst_nets { set fanouts [get_fanouts $rst_net] if {[llength $fanouts] > 1} { set cross_domain_count 0 foreach_in_collection ff $fanouts { if {[get_attribute $ff clock_domain] != [get_attribute [get_pin $rst_net] clock_domain]} { incr cross_domain_count } } if {$cross_domain_count > 0} { puts "ALERT: $rst_net has $cross_domain_count cross-domain fanouts" } } }提示:OrCAD导出网表时,务必勾选“Preserve hierarchy”和“Include timing constraints”,否则Tessent无法识别clock domain信息,上述检查将失效。
2.2 组合逻辑环路的“隐形锁死”
有些IP核(尤其是老版本的DDR PHY或PCIe controller)会在网表中留下未被综合工具完全优化的组合环路(combinational loop)。这类环路在功能仿真中因初始化值掩盖了问题,但在scan shift模式下,scan_in数据经过环路反馈,会导致链上后续FF的输入状态不可预测。Tessent检测到此类环路时,不会报错,而是自动将环路入口FF标记为“non-scan”,导致该FF永远无法被测试。
验证方法:用Tessent自带的check_design -loop命令,但它只能检测显式环路。更有效的是用Synopsys VC SpyGlass DFT,在导入网表后运行run_dft_check -check_loop,它能识别出由latch和mux构成的隐式环路。我们曾在一个图像处理IP中发现,其color space converter模块里,一个用于gamma校正的lut查找表,因综合时未启用“-no_lut_optimization”,生成了带反馈mux的结构,VC SpyGlass报告了17处隐式环路。解决方案不是删除lut,而是给该模块添加set_dft_signal -type ScanEnable -port scan_en,强制Tessent在该路径插入test point,切断环路反馈。
2.3 扫描使能信号的“命名战争”
关键词里的scan_enable,看似是个标准信号名,实则暗藏玄机。不同EDA工具对它的命名约定不同:Synopsys DC输出网表常用scan_mode,Cadence Genus偏好test_mode,而有些第三方IP则用dft_en。Tessent默认只识别scan_enable,如果你的网表里是test_mode,它会认为没有scan control信号,从而拒绝插入任何扫描链。
破解方法有二:一是用set_dft_signal命令显式声明,二是修改网表。后者风险高,前者更稳妥。但要注意,set_dft_signal必须在read_netlist之后、create_scan_chain之前执行,且需指定正确的port类型:
read_netlist top.v # 声明test_mode为scan enable信号 set_dft_signal -type ScanEnable -port test_mode # 声明scan_in为scan data input set_dft_signal -type ScanDataIn -port scan_in # 声明scan_out为scan data output set_dft_signal -type ScanDataOut -port scan_out create_scan_chain -name chain_0 -length 200注意:
set_dft_signal命令中的-port参数,必须是网表中实际存在的port name,不能是net name。如果test_mode是module port,则写test_mode;如果是top-level port,则需写top/test_mode(带层次名)。
3. Tessent扫描链插入的核心引擎:从“连链”到“建模”的四层决策逻辑
很多人以为Tessent插入扫描链,就是按顺序把FF连起来。实际上,Tessent内部运行着一套多目标优化引擎,它在四个抽象层级上同时做决策,每一层都影响最终结果。理解这四层,才能真正掌控插入过程。
3.1 第一层:寄存器分类与可扫描性评估(Register Classification)
Tessent首先对网表中所有sequential element(FF/latch)进行分类。分类依据不是简单的cell type,而是结合了时序弧属性、复位/置位控制方式、时钟门控状态三维判定。例如:
- Standard FF:时钟端有单一timing arc,rst/set pin为同步或异步,且无clock gating。这类FF默认可扫描。
- Gated Clock FF:时钟输入端接有clock gating cell(如AND gate with enable)。Tessent会检查gating logic是否满足“test mode bypass”条件——即当scan_enable=1时,gating cell输出必须恒为1。若不满足,该FF被标记为“non-scan”。
- Async Reset FF with Glitch Filter:复位端接有去毛刺电路(如两级FF滤波)。Tessent会模拟scan shift过程中的rst信号变化,若检测到滤波电路在scan mode下可能产生glitch,该FF将被排除。
验证方法:运行report_scan_elements,查看每类FF的数量及“Scannable”状态。重点关注“Non-scannable”列表,它会注明被排除原因(如“Clock gating not bypassable”)。我们曾在一个audio codec IP中发现,其PLL lock detect logic使用了带异步复位的DFF,但复位信号经过一个RC滤波网络,Tessent判定其在scan mode下不可控,导致12个关键FF无法扫描。
3.2 第二层:扫描链拓扑构建(Chain Topology Construction)
这是最易被误解的一层。“链长”不是越长越好。Tessent默认采用“balanced chain length”策略,目标是让所有chain的FF数量尽可能接近,但会受三个硬约束限制:
- Max Fanout Constraint:每个chain的scan_out fanout不能超过设定值(默认50)。这是为了保证shift时序,避免末端FF setup violation。
- Clock Domain Boundary:不同clock domain的FF绝不会被放入同一chain。Tessent会严格检查每个FF的clock pin connected net,并将其映射到已知clock domain。
- Test Point Proximity:如果用户预先插入了test point(如
set_test_point),Tessent会优先将附近FF纳入同一chain,以减少ATPG向量长度。
关键参数-max_chain_length的设置,需要结合ATE tester的pattern memory深度。例如,某tester最大pattern depth为1M,若scan chain平均长度为5000,则单次shift最多支持200条chain。此时应设-max_chain_length 5000,而非盲目追求“最长链”。我们曾因设为10000,导致chain数量减半,但ATPG生成时间翻倍,因为tool需要为更长的chain计算更多transition patterns。
3.3 第三层:扫描使能网络综合(Scan Enable Network Synthesis)
scan_enable不是一根线,而是一个树状网络。Tessent在此层执行buffer insertion和fanout balancing。其算法核心是基于延迟模型的最小化最大延迟路径(min-max delay path),而非简单的扇出分割。
具体流程:
- 步骤1:构建scan_enable的驱动源(通常是top-level port)到所有scan FF的rst pin的逻辑锥(logic cone)。
- 步骤2:对每个FF,计算其scan_enable pin到驱动源的逻辑深度(logic depth)和wire load。
- 步骤3:按depth分组,对每组插入buffer,使组内所有FF的scan_enable arrival time差值<0.1ns。
这意味着,即使两个FF物理位置很近,若其在逻辑锥中处于不同depth,Tessent也会给它们分配不同的buffer层级。验证此过程,可用report_scan_enable_network命令,它会输出每个buffer的驱动fanout和插入位置。我们发现,Tessent在插入buffer时,会优先选择net上已有driver的位置,而非新建driver,这能减少额外的routing资源消耗。
3.4 第四层:时序与功耗协同优化(Timing & Power Co-optimization)
最后一层决策,发生在write_scan_netlist之前。Tessent会运行一次快速时序分析(基于内置wire load model),检查所有scan path的setup/hold时间。若发现违规,它有两种应对策略:
- Strategy A(默认):在违规path上插入delay cell,增加hold slack。这会略微增加面积,但不影响功能时序。
- Strategy B(需显式启用):重新划分scan chain,将违规FF移到更短的chain中。这需要
set_scan_configuration -enable_chain_reordering true。
功耗方面,Tessent会估算scan shift过程中的toggle rate,并对高toggle net插入power gating cell。例如,一个用于地址计数的scan chain,其scan_in net toggle rate高达95%,Tessent会自动在其driver后插入一个pg_cell,在scan capture阶段关闭电源,降低IR drop风险。这个行为可通过report_power_analysis查看详细报告。
4. shared bus dft场景下的特殊处理:当扫描链必须“学会共享”
“shared bus dft”不是Tessent的一个独立功能模块,而是对标准扫描链插入流程的一次系统级重构。它的核心挑战在于:如何让多个IP模块,通过同一组scan_in/scan_out引脚,独立完成各自的scan chain shift操作。这要求Tessent不仅理解单个网表的逻辑,还要理解整个SoC的bus topology。
4.1 总线仲裁器的“DFT感知”建模
shared bus的关键是arbiter(仲裁器)。Tessent必须能识别arbiter的control logic,并在扫描链中为其预留bypass mux。标准做法是:
- 在RTL阶段,为arbiter添加DFT wrapper,包含
dft_selectport,用于在test mode下选择active IP。 - 综合时,用
set_dont_use禁用arbiter内部的complex mux,防止其被优化掉。 - 在Tessent中,用
set_dft_signal -type TestModeSelect -port dft_select声明该信号。
Tessent识别到dft_select后,会自动在每个IP的scan chain入口插入一个2:1 mux,其select端接dft_select。这样,当dft_select=0时,IP0的scan chain被连接到top scan_in;当dft_select=1时,IP1的chain被连接。整个过程无需手动编辑网表。
验证要点:运行report_bus_sharing,它会列出所有被识别的shared bus及其connected IPs。若某IP未出现在列表中,说明其scan chain未被正确绑定到bus,需检查该IP的scan port是否与top-level bus port有direct connection(不能经过中间buffer)。
4.2 多时钟域总线的“相位对齐”难题
当shared bus跨越多个clock domain(如CPU domain和GPU domain),scan shift操作必须确保所有domain的scan clock在phase上对齐。否则,一个domain的scan_out数据,在另一个domain的scan_in采样时可能处于亚稳态。
Tessent的解决方案是insert phase alignment circuit。它会在bus crossing点插入一个双触发器同步器,并在scan chain中为该同步器预留专用scan cell。但这要求用户提前提供clock relationship constraint:
# 声明clock_a和clock_b为asynchronous set_clock_groups -asynchronous -group [get_clocks clock_a] -group [get_clocks clock_b] # 告诉Tessent,bus crossing需phase alignment set_dft_signal -type BusCrossing -port bus_data_crossing注意:
set_clock_groups必须在read_netlist之后、create_scan_chain之前执行。若遗漏,Tessent会将crossing point视为普通net,导致scan failure。
4.3 测试向量生成的“智能体”协同
最新热词“dft计算智能体”,指的是一种AI辅助的ATPG flow。它不替代Tessent,而是与其协同:Tessent负责生成符合物理约束的scan topology,智能体负责生成最优test pattern。二者接口是-dft_config_file。Tessent生成的config file包含chain length、clock domain map、test point location等元数据,智能体据此训练pattern generation model,将fault coverage提升5-8%。
实操中,我们用Tessent 2023.3生成config file后,输入到自研的DFT-LLM智能体,它自动识别出3个高fanout scan chain存在transition fault漏检风险,建议在chain mid-point插入2个test point。我们采纳建议后,ATPG覆盖率从92.1%提升至95.7%。
5. 实战排错:从覆盖率82%到94%的七步排查链路
最后,分享一个真实案例:某Wi-Fi 6 baseband SoC,Tessent插入后ATPG覆盖率仅82%,debug过程暴露了DFT工程师最常忽略的五个盲点。这个排查链路,比任何教程都更有价值。
5.1 Step 1:锁定低覆盖率模块(Module-Level Isolation)
不用看全局报告,先用report_fault_coverage -hierarchy,按module层级排序。我们发现phy_tx_path模块覆盖率仅41%,而其他模块均>90%。这说明问题高度局部化,不是全局配置错误。
5.2 Step 2:检查该模块的scan cell mapping(Scan Cell Mapping Audit)
运行report_scan_elements -module phy_tx_path,发现该模块有217个FF,但只有189个被标记为“Scannable”。缺失的28个FF,全部属于tx_fifo_ctrl子模块。进一步report_non_scannable_elements -module tx_fifo_ctrl,显示原因为“Clock gating not bypassable”。
5.3 Step 3:逆向追踪clock gating logic(Clock Gating Root Cause)
在网表中定位tx_fifo_ctrl的clock gating cell(一个AND gate),其enable pin连接到tx_active信号。检查tx_active的驱动逻辑,发现它来自一个状态机,而该状态机在test mode下未被reset。Tessent无法保证tx_active在scan shift期间为常量,故判定gating不可bypass。
解决方案:添加set_dft_signal -type ScanReset -port tx_active_rst,并在test mode下强制拉高tx_active_rst,使tx_active恒为0,从而让AND gate输出恒为0,clock被强制关闭——这反而满足了bypass条件(gating output恒定)。
5.4 Step 4:验证scan_enable网络完整性(Scan Enable Integrity Check)
覆盖率提升到87%后停滞。report_scan_enable_network显示,phy_tx_path模块的scan_enable arrival time variance达0.45ns,远超0.1ns阈值。检查发现,该模块scan_enable driver位于die左上角,而模块物理位置在右下角,wire load model严重低估了长距离delay。
对策:手动插入buffer。用create_buffer -name buf_phy_tx -lib_cell buf_x4创建buffer,再用connect_net -from scan_enable -to buf_phy_tx/I -to phy_tx_path/scan_en重连网络。重跑后variance降至0.08ns。
5.5 Step 5:处理multi-cycle path的“假阳性”违规(Multi-Cycle Path Handling)
覆盖率升至91%,但仍有failure。report_timing -delay_type max -to [get_pins phy_tx_path/*scan_out*]显示多条path有0.12ns setup violation。这些path原本是functional multi-cycle path(如FIFO read pointer increment),在scan mode下不应被检查。
修复:添加set_multicycle_path -from [get_clocks clk_phy] -to [get_clocks clk_phy] -setup 2 -hold 1 -through [get_pins phy_tx_path/fifo_rp_inc],告诉Tessent这些path在scan mode下允许2-cycle。
5.6 Step 6:shared bus的“选择信号”竞争(Bus Select Signal Race)
最后5%覆盖率达不到,report_bus_sharing显示phy_tx_path的dft_select信号在scan shift末期才稳定。原因是dft_select驱动逻辑太深,而Tessent默认的scan capture clock edge与dft_selectarrival time冲突。
解决方案:用set_dft_configuration -scan_capture_edge falling,将capture边沿改为falling,避开dft_select的setup window。
5.7 Step 7:物理实现后的“post-layout DRC”(Post-Layout Validation)
流片前final check,用verify_scan_insertion -post_layout,发现3个scan cell的placement density超标,导致局部routing congestion,影响scan_out signal integrity。Tessent建议set_dft_configuration -scan_cell_density_limit 0.7,将scan cell密度上限从0.85降至0.7,重跑后congestion cleared。
这七步,每一步都对应一个具体命令、一个具体参数、一个具体现象。它不是理论推演,而是我在凌晨三点的服务器日志里,一行行grep出来的真相。DFT没有银弹,只有对网表、对工具、对物理实现的敬畏之心。