所有关于电路
技术文章

JTAG测试访问端口(TAP)状态机

2020年11月20日通过山姆·加拉格尔

在本文中,我们将详细查看测试访问状态机,甚至查看简单JTAG接口的一些伪代码。

在本系列的第一部分中,我们研究了通用的单片机/FPGA/ASIC接口标准JTAG。但是,尽管我们讨论了很多关于指令和寄存器的内容,我们仍然需要了解如何操作JTAG测试访问端口(TAP)。

正如在前一篇文章中提到的,TAP是通过状态机来控制的,它有两条路径,这取决于我们是在加载指令,还是在读/写数据寄存器。在这一部分中,我们将详细研究状态机,甚至还将看到一个简单JTAG接口的一些伪代码。

TAP状态机

如下面的图1所示,IEEE 1149.1-2013标准中显示了状态机。

状态机很简单,包括两条路径:

  • 数据寄存器(DR)路径(以绿色显示),用于加载指令
  • 指令寄存器(IR)路径(以蓝色表示),用于从数据寄存器读写数据,包括边界扫描寄存器(BSR)

图1所示。TAP状态机,详见IEEE 1149.1-2013标准。点击在这里为了一个更大的版本。

    状态机在测试时钟(TCK)边缘上进行,测试模式选择(TMS)引脚的值控制行为。

    假设状态机从Test-Logic-Reset开始,我们首先对一个TMS = 0进行计时以进入Run-Test/Idle状态,然后对一个TMS = 1进行计时以开始选择路径。

    图2简要总结了不同状态的角色。

    图2。带有状态描述的TAP状态机。点击在这里为了一个更大的版本。

    为了帮助理解这些状态,请再次查看前一篇文章(图3)中的JTAG系统。

    图3。JTAG架构

    TAP控制器管理状态机,根据选择的状态,输出MUX被切换。

    这两条路径分别是:

    • 指令capture-shift路径
    • 数据capture-shift路径

    请注意边界扫描寄存器(包含IO引脚周围的边界扫描单元)是如何成为数据寄存器之一的。数据寄存器是移位寄存器,可以是任意长度的。

    捕获、更新和移位状态

    最“活跃”的状态是捕获,转变,更新州。

    捕获状态可能是最神秘的,与指令路径相比,数据路径执行不同的操作。在这里,捕获指将数据并行装入移位寄存器,而不是将数据串行地装入寄存器。移位意味着将数据移到移位寄存器中。然后,更新阶段锁存寄存器,状态机可以复位。

    具体来说,Capture-DR是一种状态,在这种状态下,如果需要,可以将测试数据并行加载到当前数据寄存器的shift-capture路径中。(当前数据寄存器由之前设置的当前指令设置。)这意味着数据被并行加载到当前指令选择的数据寄存器中,而不是移位。

    Capture-IR用于JTAG系统中的故障隔离,尽管该标准对其用途并不明确。一个固定的逻辑值(必须以{…01}结尾)被并行加载到指令寄存器的移位捕获路径中。这就是说,指令寄存器是用固定的逻辑值并行加载(而不是移位)的。

    Shift-DR和Shift-IR状态是将数据串行加载到数据寄存器或指令寄存器的主要状态。当状态机处于这些状态之一时,TMS保持LOW状态,直到转移操作完成。Update-DR和Update-IR状态将数据锁存到寄存器中,将指令寄存器中的数据设置为当前指令(这样做时,将为下一个周期设置当前数据寄存器)。

    操作TAP状态机的示例通常以时序图的形式给出,但此类图传递信息的能力有限,因此感兴趣的读者可以参考JTAG标准本身以获得更多信息,包括各种逻辑块的实现建议。

    JTAG接口的伪代码

    为了充实上述思想,在本节中,我们将组装一些可能控制JTAG接口(可以像微控制器开发板一样简单)的伪代码。代码实现了最基本的功能,没有任何错误检查或指令的特殊处理。包括一些延迟来管理时间,包括一个短延迟来适应不能保证时间的多任务系统。

    / /定义针

    JTAG_TMS = PA01

    JTAG_TCK = PA02

    JTAG_TDI = PA03

    JTAG_TDO = PA04

    //创建一个由5个1组成的字符串,用于强制重置

    tms_reset_str = {1, 1, 1, 1, 1}

    / / JTAG功能

    //发送一个常量字符串到TAP,不设置TDI或TDO

    transmit_tms_str (tms_str)

    {

    For I = 0: len(tms_str)

    {

    set_pin (JTAG_TMS tms_str[我])

    jtag_short_delay ()

    set_pin (JTAG_TCK、高)

    jtag_clock_delay ()

    set_pin (JTAG_TCK,低)

    jtag_clock_delay ()

    }

    }

    shift_tdi_str (tdi_str)

    {

    set_pin(JTAG_TMS, LOW) //保持TMS LOW,平移

    For I = 0: len(tdi_str)

    {

    set_pin (JTAG_TDI tdi_str[我])

    jtag_short_delay ()

    set_pin (JTAG_TCK、高)

    jtag_clock_delay ()

    set_pin (JTAG_TCK,低)

    jtag_clock_delay ()

    }

    }

    shift_tdo_str(长度)

    {

    //这个函数返回从TDO移出的字符串

    set_pin(JTAG_TMS, LOW) //移动时保持TMS LOW

    Output_str = {}

    对于I = 0: length

    {

    set_pin (JTAG_TCK、高)

    jtag_short_delay ()

    output_str + = read_pin (JTAG_TDO)

    jtag_clock_delay ()

    set_pin (JTAG_TCK,低)

    jtag_clock_delay ()

    }

    返回output_str

    }

    reset_jtag ()

    {

    transmit_tms_str (tms_reset_str)

    }

    load_jtag_instruction (instr)

    {

    //假设我们在运行测试/空闲

    //注意:没有错误检查,早期退出,或暂停

    / /在这里实现

    transmit_tms_str({1,1,0,0}) //使我们处于Shift-IR状态

    shift_tdi_str(instr) //转移指令数据

    transmit_tms_str({1,0,1,1,0}) //返回Run-Test/Idle状态

    }

    read_jtag_register (reg_length)

    {

    //这个函数读取当前数据寄存器(由大多数设置)

    / /最近的指令)

    //假设我们在运行测试/空闲

    //注意:没有错误检查,早期退出,或暂停

    / /在这里实现

    transmit_tms_str({1,0,0}) //使我们处于Shift-DR状态

    reg_str = shift_tdo_str(reg_length) //移出寄存器数据

    transmit_tms_str({1,0,1,1,0}) //返回Run-Test/Idle状态

    返回reg_str

    }

    如果浏览Black Magic Probe源代码,您可以看到JTAG接口编程的一个实际示例,可以在Github上找到。(特别是src/platforms/目录和src/include/目录)。

    结论

    我们现在已经看到了JTAG TAP最重要的部分,即它的状态机。在IEEE 1149.1-2013标准中可以找到本系列前两部分所涉及的材料,以及许多有用的实现提示和细节。

    从这里开始,我们将变得更加实际,看看各种可用的JTAG接口,讨论常用的pinouts和连接器,最后仔细看看Arm调试接口(ADI),作为实践中的JTAG示例。