在本系列的第一部分中,我们研究了JTAG,无处不在的微控制器/ FPGA / ASIC接口标准。但是,尽管我们讨论了很多关于指令和寄存器的内容,我们仍然需要了解如何操作JTAG测试访问端口(TAP)。
如前一篇文章所示,点击通过状态机控制,该状态机具有两个路径,具体取决于我们是否正在加载指令,或读取/写入数据寄存器。在这部分中,我们将详细介绍状态机,我们甚至会看到一个简单的JTAG接口的一些伪码。
龙头状态机
如下面的图1所示,IEEE 1149.1-2013标准中显示了状态机。
状态机很简单,包括两条路径:
- 数据寄存器(DR)路径(以绿色显示),用于加载指令
- 指令寄存器(IR)路径(以蓝色显示),用于从/向数据寄存器读取/写入数据,包括边界扫描寄存器(BSR)
图1所示。TAP状态机,详见IEEE 1149.1-2013标准。点击这里为了一个更大的版本。
状态机在测试时钟(TCK)边缘进行,测试模式的值选择(TMS)引脚控制行为。
假设状态机从测试逻辑复位开始,我们开始通过时钟TMS = 0来输入运行测试/空闲状态,然后时钟TMS = 1开始选择路径。
图2简要总结了不同状态的角色。
图2。点击状态机具有状态描述。点击这里为了一个更大的版本。
为了帮助理解这些状态,再次从上一篇文章中查看JTAG系统,图3。
图3。JTAG架构
Tap Controller管理状态机,并且根据所选状态,切换输出MUX。
这两条路径分别是:
- 的指令捕获换档路径
- 的数据capture-shift路径
注意,边界扫描寄存器如何包括IO引脚周围的边界扫描单元,是数据寄存器之一。数据寄存器是移位寄存器,并且可以是任意长度。
捕获、更新和移位状态
最“活跃”的状态是捕获,转变, 和更新州。
捕获状态可能是最神秘的,与指令路径相比,数据路径执行不同的操作。在这里,捕获意味着将并行加载数据进入移位寄存器,而不是将数据转换为串行寄存器。转换装置可能期望,将数据转换为移位寄存器。然后,更新阶段锁存寄存器,并且状态机可以重置。
具体地,Capture-DR是其中的状态,如果需要,测试数据可以并行加载到当前数据寄存器的移位捕获路径中。(当前数据寄存器由先前设置的当前指令设置。)这意味着数据并行加载到当前指令选择的数据寄存器中,而不是转换。
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)
{
对于i = 0:len(tms_str)
{
set_pin(jtag_tms,tms_str [i])
jtag_short_delay ()
set_pin(jtag_tck,高)
jtag_clock_delay()
set_pin(jtag_tck,low)
jtag_clock_delay()
}
}
shift_tdi_str(tdi_str)
{
set_pin(JTAG_TMS, LOW) //保持TMS LOW,平移
对于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,low)
jtag_clock_delay()
}
}
shift_tdo_str(长度)
{
//此函数返回从TDO移出的字符串
SET_PIN(JTAG_TMS,LOW)//在移位时保持低电平
Output_str = {}
对于i = 0:长度
{
set_pin(jtag_tck,高)
jtag_short_delay ()
output_str + = read_pin(jtag_tdo)
jtag_clock_delay()
set_pin(jtag_tck,low)
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) //转移指令数据
传输_tms_str({1,0,1,1,0})//返回运行测试/空闲
}
read_jtag_register(reg_length)
{
//这个函数读取当前数据寄存器(由大多数设置)
/ /最近的指令)
//假设我们在运行测试/空闲
//注意:没有错误检查,早期退出或暂停是
/ /在这里实现
传输_tms_str({1,0,0})//将我们放在Shift-Dr状态
reg_str = shift_tdo_str(reg_length) //移出寄存器数据
传输_tms_str({1,0,1,1,0})//返回运行测试/空闲
返回reg_str.
}
如果浏览Black Magic Probe源代码,您可以看到JTAG接口编程的一个实际示例,在这里的github上可用。(特别是src/platforms/目录和src/include/目录)。
结论
我们现在已经看到了JTAG TAP最重要的部分,即它的状态机。在IEEE 1149.1-2013标准中可以找到本系列前两部分所涉及的材料,以及许多有用的实现提示和细节。
从这里开始,我们将变得更加实际,看看各种可用的JTAG接口,讨论常用的pinouts和连接器,最后仔细看看Arm调试接口(ADI),作为实践中的JTAG示例。