3、扫描链设计规则:扫描链结构规则、时钟域规则、复位规则、三态规则
好,咱们今天聊聊扫描链的设计规则。说实话,这部分内容在DFT里属于“基础但容易翻车”的环节。我见过不少项目,功能仿真跑得飞起,结果一上ATE测试机,扫描链就是进不去数据。为什么?多半是规则没吃透。
我个人习惯,在写扫描链的RTL之前,先把这几条规则在脑子里过一遍。你想想看,扫描链说白了就是把一堆寄存器串起来,但怎么串、能不能串、串了之后会不会打架,这里头门道不少。
3.1 扫描链结构规则
先讲结构规则。这是最基础的,也是EDA工具检查的第一关。
核心要求:扫描链上的每个寄存器,必须能正常工作在扫描模式下。什么意思?就是当scan_enable拉高时,数据能从scan_in进来,经过寄存器,再从scan_out出去。
具体来说,有这几个硬性指标:
- 寄存器必须可扫描替换:每个触发器都要有对应的扫描触发器(SFF)。不能有普通D触发器混在链里,否则数据根本传不过去。
- 时钟必须可控:扫描链上的所有寄存器,时钟必须来自同一个或同源的时钟域。嗯,这里要注意,如果混了不同时钟域的寄存器,工具会报错。
- 扫描路径不能有组合逻辑环路:我曾经在项目中遇到过,一个组合反馈环路把扫描链堵死了,查了三天才找到原因。
避坑指南:我曾经在某个项目里,为了省面积,把几个非扫描寄存器硬塞进了扫描链。结果ATE测试时,扫描链移位就是不对。后来老老实实全换成SFF,问题解决。所以,别在这上面省。
下面给个简单的扫描链结构示例:
// 扫描链结构示意
module scan_chain_example (
input clk,
input rst_n,
input scan_enable,
input scan_in,
output scan_out
);
reg q1, q2, q3;
// 扫描触发器1
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
q1 <= 1'b0;
else if (scan_enable)
q1 <= scan_in; // 扫描模式下,数据来自scan_in
else
q1 <= d1; // 功能模式下,数据来自功能逻辑
end
// 扫描触发器2
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
q2 <= 1'b0;
else if (scan_enable)
q2 <= q1; // 串接前一级
else
q2 <= d2;
end
// 扫描触发器3
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
q3 <= 1'b0;
else if (scan_enable)
q3 <= q2;
else
q3 <= d3;
end
assign scan_out = q3;
endmodule
3.2 时钟域规则
时钟域规则,说白了就是“跨时钟域的信号怎么处理”。在扫描链里,这个问题尤其突出。
我建议你记住一句话:一条扫描链,只能在一个时钟域里跑。为什么?因为扫描移位需要时钟同步。如果链上混了两个不同频率的时钟,移位时序根本没法收敛。
具体规则如下:
- 同频同相时钟可以混用:比如同一个PLL出来的两个分支,相位对齐,可以放在一条链里。
- 异步时钟必须分链:不同PLL出来的时钟,或者同PLL但不同分频比的,必须分开成独立的扫描链。
- 门控时钟要小心:如果寄存器用了门控时钟,扫描模式下必须绕过门控,直接给时钟。否则门控一关,数据就卡住了。
个人经验:我习惯在综合脚本里,对每个时钟域单独声明一个scan_chain。这样后期调试时,一眼就能看出哪个时钟域出了问题。
这里有个常见的时钟域划分表格,供你参考:
| 时钟源 | 频率 | 相位关系 | 能否同链 |
|---|---|---|---|
| PLL0_CLK | 100MHz | 同相 | 可以 |
| PLL0_CLK_DIV2 | 50MHz | 同源但分频 | 不建议 |
| PLL1_CLK | 200MHz | 异步 | 不可以 |
| EXT_CLK | 25MHz | 完全异步 | 不可以 |
3.3 复位规则
复位规则,嗯,这里要注意。很多工程师觉得复位很简单,不就是拉低清零嘛。但在扫描链里,复位处理不好,会直接导致测试失败。
核心原则:扫描模式下,复位信号必须可控。你不能让复位在移位过程中乱跳。
具体来说:
- 同步复位 vs 异步复位:我个人更倾向于在扫描链里用同步复位。异步复位在扫描模式下容易产生毛刺,导致寄存器状态不确定。
- 复位信号必须被scan_enable屏蔽:当scan_enable为高时,复位信号应该被强制拉无效(比如高电平有效复位就拉低)。否则,移位过程中复位一触发,链上数据全丢了。
- 复位树也要测试:别忘了,复位树本身也是需要测试的。我建议在扫描链里专门加一个复位测试模式,用来验证复位树有没有断路。
警告:我曾经遇到过一个案例,复位信号在扫描模式下被一个组合逻辑误触发,导致整条链上的寄存器全部清零。ATE测试时,扫描链移位结果全是0,还以为芯片坏了。后来加了复位屏蔽逻辑才解决。
复位屏蔽的代码示例:
// 复位信号屏蔽逻辑
assign rst_n_scan = rst_n & (~scan_enable); // 扫描模式下,强制复位无效
// 或者
assign rst_n_scan = rst_n | scan_enable; // 取决于复位极性
3.4 三态规则
最后说说三态规则。三态总线在芯片里很常见,但扫描链遇到三态,容易出问题。
问题本质:三态总线在扫描模式下,如果多个驱动同时使能,就会产生总线冲突。轻则电流过大,重则烧毁芯片。
我建议的规则如下:
- 扫描模式下,三态总线必须被强制拉成非高阻态:通常的做法是加一个扫描专用的三态控制信号,在扫描模式下把所有三态门都打开或都关闭。
- 避免多个驱动同时使能:如果一条总线上挂了多个三态驱动,扫描模式下只能有一个驱动是使能的,其他必须关闭。
- 三态控制逻辑必须可测试:三态控制信号本身也要能通过扫描链测试。否则,你没法知道控制逻辑有没有坏。
避坑指南:我曾经在项目中,因为三态总线没处理好,导致ATE测试时电流异常大。后来一查,是扫描模式下两个三态门同时打开了,总线直接短路。从那以后,我每次都会在扫描链里加一个三态强制控制信号。
三态控制的示例:
// 三态总线扫描控制
assign bus_drive_en = scan_enable ? 1'b0 : func_drive_en; // 扫描模式下,关闭所有三态驱动
// 或者
assign bus_drive_en = scan_enable ? 1'b1 : func_drive_en; // 扫描模式下,强制打开一个驱动
好了,扫描链的四大规则就讲到这里。你想想看,结构规则保证链能串起来,时钟规则保证链能跑起来,复位规则保证链不乱跳,三态规则保证链不打架。把这四点吃透了,扫描链设计基本就稳了。
下一章,咱们聊聊扫描链的时序约束和ATPG。到时候我会分享一些实际项目里的调试经验,保证让你少走弯路。