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。到时候我会分享一些实际项目里的调试经验,保证让你少走弯路。