3、扫描链设计实践:扫描链插入流程、扫描链综合、扫描链验证
好,咱们今天聊聊扫描链的实战环节。说实话,很多同学学DFT时,理论背得滚瓜烂熟,一到动手就懵了。我当年也是这样,看了无数遍扫描链的原理,结果第一次跑综合脚本时,连set_scan_configuration该放哪都搞不清楚。嗯,今天我就把这块掰开了揉碎了讲给你听。
3.1 扫描链插入流程——别急着跑脚本,先理清步骤
扫描链插入,说白了就是把普通寄存器换成带扫描功能的寄存器,再把这些寄存器串成一串。但流程上,我习惯分成三步走:
- 准备设计:确保RTL代码风格符合DFT要求。比如,避免异步复位、避免锁存器(除非你特别清楚自己在干嘛)。
- 配置扫描链:告诉工具哪些寄存器要进链,链多长,时钟怎么处理。
- 插入与验证:工具自动替换寄存器,然后我们检查替换结果。
我在项目中遇到过最坑的事,就是有人把时钟门控单元也当成普通寄存器塞进了扫描链。结果呢?测试时时钟根本传不过去,整个链都废了。所以,插入前一定要先做DFT检查,看看哪些单元不能碰。
核心原则:扫描链插入不是“一键搞定”的事。你得先想清楚,哪些寄存器必须进链,哪些可以跳过(比如小规模的状态机寄存器,我有时会单独处理)。
3.2 扫描链综合——工具替你干活,但你要告诉它怎么干
扫描链综合,通常用Synopsys的DFT Compiler或Cadence的RTL Compiler来做。我个人习惯用DFT Compiler,因为它的脚本更直观。下面是一个典型的综合脚本片段:
# 设置扫描链配置
set_scan_configuration -chain_count 4 \
-clock_mixing no_mix \
-style multiplexed_flip_flop
# 插入扫描链
insert_dft
# 查看结果
report_scan_path -view existing
这里有几个关键点:
- 链的数量:
-chain_count 4表示分成4条链。链越多,测试时间越短,但IO引脚占用也越多。我一般根据芯片的IO数量来定,比如一个128引脚的芯片,我最多分8条链。 - 时钟混合:
-clock_mixing no_mix表示不同时钟域的寄存器不能混在同一条链里。为什么?因为扫描时时钟必须同步,混了容易出时序问题。我曾经试过允许混合,结果后仿真时数据老对不上,查了三天才发现是跨时钟域的问题。 - 扫描风格:
multiplexed_flip_flop是最常用的,每个寄存器前加一个MUX。还有lssd风格(电平敏感扫描设计),但那个功耗大,现在用得少了。
小技巧:综合完成后,一定要看report_scan_path的输出。它会告诉你每条链上有多少个寄存器,起点和终点是什么。我习惯把这个报告存下来,后面验证时对照着看。
3.3 扫描链验证——别以为插进去就完事了
扫描链插完了,综合也过了,是不是就万事大吉?当然不是。你想想看,如果链里有个寄存器没连上,或者时钟没给到,那整个测试就废了。所以验证这一步,我从来不敢马虎。
验证分两个层面:
- 功能验证:用仿真工具跑扫描链的测试向量。比如,往扫描链里灌一串“1010...”,然后看能不能原样吐出来。如果吐出来的不对,说明链有问题。
- 时序验证:检查扫描模式下,时钟能不能满足建立时间和保持时间。扫描链的时钟频率通常比功能模式低,但也不能太低,否则测试时间太长。
我举个例子。有一次,我在验证一个芯片的扫描链时,发现第3条链的输出总是少一位。查了半天,原来是综合时工具把某个寄存器优化掉了,因为它觉得那个寄存器“没用”。但实际上,那个寄存器是扫描链的一部分。从那以后,我每次综合前都会加一句:
set_dont_touch [get_cells -hier *scan_reg*] true
告诉工具:这些寄存器你别动,它们有特殊用途。
注意:扫描链验证时,别忘了检查扫描使能信号(scan_enable)的时序。这个信号在功能模式下是低电平,扫描模式下是高电平。如果切换时机不对,可能导致数据错乱。我见过有人因为这个信号没处理好,流片回来芯片测试时,扫描链时好时坏,最后只能降频使用。
3.4 知识体系总览
下面这张图,是我自己总结的扫描链设计核心逻辑。你可以把它当成一个检查清单,每次做扫描链时对照着看一遍:
这张图里,我把流程分成了三个阶段。每个阶段下面都有具体的检查项。你照着这个做,基本不会出大问题。
3.5 避坑指南——我踩过的那些坑
最后,分享几个我亲身经历过的坑,希望能帮你省点时间:
- 坑1:忘了加扫描使能引脚。有一次,我设计的芯片有64个引脚,我为了省引脚,把scan_enable和某个功能引脚复用了。结果测试时,功能模式和扫描模式切换不过来,芯片直接罢工。后来我学乖了,scan_enable必须单独拉一个引脚出来,哪怕多花一个封装成本。
- 坑2:扫描链长度不均匀。比如,一条链上有1000个寄存器,另一条只有100个。测试时,短的链很快就跑完了,长的链还在跑,导致测试时间被长链拖死。我现在的做法是,综合前先估算一下每个模块的寄存器数量,尽量平均分配到各条链上。
- 坑3:忘了做后仿真。综合后的网表跟RTL不一样,因为工具会做优化。如果不跑后仿真,你根本不知道扫描链在真实门级电路里能不能工作。我见过有人只跑了前仿真就投片,结果回来发现扫描链时序不满足,整个芯片只能当废品。
我的习惯:每次做完扫描链插入,我都会写一个简单的测试脚本,自动灌入“1010”模式,然后检查输出。这个脚本虽然简单,但能帮我快速定位问题。你也试试看?
好了,扫描链的实践部分就聊到这。记住,DFT不是“做完就行”,而是“做对才行”。每一步都认真验证,流片回来才能睡得着觉。