OPEN-JTAG
TWENTYONE XUZHOUHE@HOTMAIL.COM & DUYUNHAI DUYUNHAI@HOTMAIL.COM
1
ARM JTAG 调试原理
Twentyone
1 前言
这篇文章主要介绍 ARM JTAG 调试的基本原理。基本的内容包括了 TAP (TEST ACCESS
PORT) 和 BOUNDARY-SCAN ARCHITECTURE 的介绍,在此基础上,结合 ARM7TDMI 详细
介绍了的 JTAG 调试原理。
这篇文章主要是总结了前段时间的一些心得体会,希望对想了解 ARM JTAG 调试的网友们
有所帮助。我个人对 ARM JTAG 的理解还不是很透彻,在文章中,难免会有偏失和不准确的地
方,希望精通 JTAG 调试原理的大侠们不要拍砖,有什么问题提出来,我一定尽力纠正。同时
也欢迎对 ARM JTAG 调试感兴趣的朋友们一起交流学习。
2 IEEE Standard 1149.1 - Test Access Port and Boundary-Scan Architecture
既然是介绍 JTAG 调试,还是让我们从 IEEE 的 JTAG 调试
标准
excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载
开始吧。JTAG 是 JOINT
TEST ACTION GROUP 的简称。IEEE 1149.1 标准就是由 JTAG 这个组织最初提出的,最终由
IEEE 批准并且标准化的。所以,这个 IEEE 1149.1 这个标准一般也俗称 JTAG 调试标准。
接 下 来 的 这 一 部 分 , 主 要 简 单 的 介 绍 了 TAP (TEST ACCESS PORT) 和
BOUNDARY-SCAN ARCHITECTURE 的基本构架。虽然不是很全面,但对了解 JTAG 的基本
原理来说,应该是差不离了。如果希望更全面深入的了解 JTAG 的工作原理,可以参考 IEEE
1149.1 标准。
2-1 边界扫描
在 JTAG 调试当中,边界扫描(Boundary-Scan)是一个很重要的概念。边界扫描技术的
基本思想是在靠近芯片的输入输出管脚上增加一个移位寄存器单元。因为这些移位寄存器单
元都分布在芯片的边界上(周围),所以被称为边界扫描寄存器(Boundary-Scan Register Cell)。
当芯片处于调试状态的时候,这些边界扫描寄存器可以将芯片和外围的输入输出隔离开来。
通过这些边界扫描寄存器单元,可以实现对芯片输入输出信号的观察和控制。对于芯片的输
入管脚,可以通过与之相连的边界扫描寄存器单元把信号(数据)加载倒该管脚中去;对于
芯片的输出管脚,也可以通过与之相连的边界扫描寄存器“捕获”(CAPTURE)该管脚上的
输出信号。在正常的运行状态下,这些边界扫描寄存器对芯片来说是透明的,所以正常的运
行不会受到任何影响。这样,边界扫描寄存器提供了一个便捷的方式用以观测和控制所需要
调试的芯片。另外,芯片输入输出管脚上的边界扫描(移位)寄存器单元可以相互连接起来,
在芯片的周围形成一个边界扫描链(Boundary-Scan Chain)。一般的芯片都会提供几条独立的
边界扫描链,用来实现完整的测试功能。边界扫描链可以串行的输入和输出,通过相应的时
钟信号和控制信号,就可以方便的观察和控制处在调试状态下的芯片。
利用边界扫描链可以实现对芯片的输入输出进行观察和控制。下一个问题是:如何来管
理和使用这些边界扫描链?对边界扫描链的控制主要是通过 TAP (Test Access Port)Controller
来完成的。在下一个小节,我们一起来看看 TAP 是如何工作的。
2-2 TAP (TEST ACCESS PORT)
在上一节,我们已经简单介绍了边界扫描链,而且也了解了一般的芯片都会提供几条边
界扫描链,用来实现完整的测试功能。下面,我将逐步介绍如何实现扫描链的控制和访问。
OPEN-JTAG
TWENTYONE XUZHOUHE@HOTMAIL.COM & DUYUNHAI DUYUNHAI@HOTMAIL.COM
2
在 IEEE 1149.1 标准里面,寄存器被分为两大类:数据寄存器(DR-Data Register)和指令
寄存器(IR-Instruction Register)。边界扫描链属于数据寄存器中很重要的一种。边界扫描链用
来实现对芯片的输入输出的观察和控制。而指令寄存器用来实现对数据寄存器的控制,例如:
在芯片提供的所有边界扫描链中,选择一条指定的边界扫描链作为当前的目标扫描链,并作
为访问对象。下面,让我们从 TAP(Test Access Port)开始。
TAP 是一个通用的端口,通过 TAP 可以访问芯片提供的所有数据寄存器(DR)和指令
寄存器(IR)。对整个 TAP 的控制是通过 TAP Controller 来完成的。TAP 总共包括 5 个信号接
口 TCK、TMS、TDI、TDO 和 TRST :其中 4 个是输入信号接口和另外 1 个是输出信号接口。
一般,我们见到的开发板上都有一个 JTAG 接口,该 JTAG 接口的主要信号接口就是这 5 个。
下面,我先分别介绍这个 5 个接口信号及其作用。
Test Clock Input (TCK)
TCK 为 TAP 的操作提供了一个独立的、基本的时钟信号,TAP 的所有操作都是通过
这个时钟信号来驱动的。TCK 在 IEEE 1149.1 标准里是强制
要求
对教师党员的评价套管和固井爆破片与爆破装置仓库管理基本要求三甲医院都需要复审吗
的。
Test Mode Selection Input (TMS)
TMS 信号用来控制 TAP 状态机的转换。通过 TMS 信号,可以控制 TAP 在不同的状
态间相互转换。TMS 信号在 TCK 的上升沿有效。TMS 在 IEEE 1149.1 标准里是强制
要求的。
Test Data Input (TDI)
TDI 是数据输入的接口。所有要输入到特定寄存器的数据都是通过 TDI 接口一位一位
串行输入的(由 TCK 驱动)。TDI 在 IEEE 1149.1 标准里是强制要求的。
Test Data Output (TDO)
TDO 是数据输出的接口。所有要从特定的寄存器中输出的数据都是通过 TDO 接口一
位一位串行输出的(由 TCK 驱动)。TDO 在 IEEE 1149.1 标准里是强制要求的。
Test Reset Input (TRST)
TRST可以用来对TAP Controller进行复位(初始化)。不过这个信号接口在 IEEE 1149.1
标准里是可选的,并不是强制要求的。因为通过 TMS 也可以对 TAP Controller 进行复
位(初始化)。
事实上,通过 TAP 接口,对数据寄存器(DR)进行访问的一般过程是:
通过指令寄存器(IR),选定一个需要访问的数据寄存器;
把选定的数据寄存器连接到 TDI 和 TDO 之间;
由 TCK 驱动,通过 TDI,把需要的数据输入到选定的数据寄存器当中去;同时把选
定的数据寄存器中的数据通过 TDO 读出来。
接下来,让我们一起来了解一下 TAP 的状态机。TAP 的状态机如图 1 所示,总共有 16 个
状态。在图中,每个六边形
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
示一个状态,六边形中标有该状态的名称和标识代码。图中的
箭头表示了 TAP Controller 内部所有可能的状态转换
流程
快递问题件怎么处理流程河南自建厂房流程下载关于规范招聘需求审批流程制作流程表下载邮件下载流程设计
。状态的转换是由 TMS 控制的,所
以在每个箭头上有标有 tms = 0 或者 tms = 1。在 TCK 的驱动下,从当前状态到下一个状态
的转换是由 TMS 信号决定。假设 TAP Controller 的当前状态为 Select-DR-Scan,在 TCK 的驱
动下,如果 TMS = 0,TAP Controller 进入 Capture-DR 状态;如果 TMS = 1,TAP Controller
进入 Select-IR-Scan 状态。
OPEN-JTAG
TWENTYONE XUZHOUHE@HOTMAIL.COM & DUYUNHAI DUYUNHAI@HOTMAIL.COM
3
图 1. TAP Controller State Transitions
这个状态机看似很复杂,其实理解以后会发现这个状态机其实很直接、很简单。观察图
1,我们可以发现,除了 Test-Logic Reset 和 Test-Run/Idle 状态外,其他的状态有些类似。例
如 Select-DR-Scan 和 Select-IR-Scan 对应,Capture-DR 和 Capture-IR 对应,Shift-DR 和 Shift-IR
对应,等等。在这些对应的状态中,DR 表示 Data Register,IR 表示 Instruction Register。记
得我们前面说过吗,寄存器分为两大类,数据寄存器和指令寄存器。其实标识有 DR 的这些
状态是用来访问数据寄存器的,而标识有 IR 的这些状态是用来访问指令寄存器的。
在详细描述整个状态机中的每一个状态之前,首先让我们来想一想:要通过边界扫描链
来观察和控制芯片的输入和输出,需要做些什么?如果需要捕获芯片某个管脚上的输出,首
先需要把该管脚上的输出装载到边界扫描链的寄存器单元里去,然后通过 TDO 输出,这样我
们就可以从 TDO 上得到相应管脚上的输出信号。如果要在芯片的某个管脚上加载一个特定的
信号,则首先需要通过 TDI 把期望的信号移位到与相应管脚相连的边界扫描链的寄存器单元
里去,然后把该寄存器单元的值加载到相应的芯片管脚。下面,让我们一起来看看每个状态
具体表示什么意思?完成什么功能?
Test-Logic Reset
系统上电后,TAP Controller 自动进入该状态。在该状态下,测试部分的逻辑电路全部被
OPEN-JTAG
TWENTYONE XUZHOUHE@HOTMAIL.COM & DUYUNHAI DUYUNHAI@HOTMAIL.COM
4
禁用,以保证芯片核心逻辑电路的正常工作。通过 TRST 信号也可以对测试逻辑电路进
行复位,使得 TAP Controller 进入 Test-Logic Reset 状态。前面我们说过 TRST 是可选的
一个信号接口,这是因为在 TMS 上连续加 5 个 TCK 脉冲宽度的“1”信号也可以对测试
逻辑电路进行复位,使得 TAP Controller 进入 Test-Logic Reset 状态。所以,在不提供 TRST
信号的情况下,也不会产生影响。在该状态下,如果 TMS 一直保持为“1”,TAP Controller
将保持在 Test-Logic Reset 状态下;如果 TMS 由“1”变为“0”(在 TCK 的上升沿触发),
将使 TAP Controller 进入 Run-Test/Idle 状态。
Run-Test/Idle
这个是 TAP Controller 在不同操作间的一个中间状态。这个状态下的动作取决于当前指令
寄存器中的指令。有些指令会在该状态下执行一定的操作,而有些指令在该状态下不需
要执行任何操作。在该状态下,如果 TMS 一直保持为“0”,TAP Controller 将一直保持
在 Run-Test/Idle 状态下;如果 TMS 由“0”变为“1”(在 TCK 的上升沿触发),将使 TAP
Controller 进入 Select-DR-Scan 状态。
Select-DR-Scan
这是一个临时的中间状态。如果 TMS 为“0” (在 TCK 的上升沿触发),TAP Controller
进入 Capture-DR 状态,后续的系列动作都将以数据寄存器作为操作对象;如果 TMS 为
“1” (在 TCK 的上升沿触发),TAP Controller 进入 Select-IR-Scan 状态。
Capture-DR
当 TAP Controller 在这个状态中,在 TCK 的上升沿,芯片输出管脚上的信号将被“捕获”
到与之对应的数据寄存器的各个单元中去。如果 TMS 为“0” (在 TCK 的上升沿触发),
TAP Controller 进入 Shift-DR 状态;如果 TMS 为“1” (在 TCK 的上升沿触发),TAP
Controller 进入 Exit1-DR 状态。
Shift-DR
在这个状态中,由 TCK 驱动,每一个时钟周期,被连接在 TDI 和 TDO 之间的数据寄存
器将从 TDI 接收一位数据,同时通过 TDO 输出一位数据。如果 TMS 为“0” (在 TCK
的上升沿触发),TAP Controller 保持在 Shift-DR 状态; 如果 TMS 为“1” (在 TCK 的
上升沿触发),TAP Controller 进入到 Exit1-DR 状态。假设当前的数据寄存器的长度为 4。
如果 TMS 保持为 0,那在 4 个 TCK 时钟周期后,该数据寄存器中原来的 4 位数据(一
般是在 Capture-DR 状态中捕获的数据)将从 TDO 输出来;同时该数据寄存器中的每个
寄存器单元中将分别获得从 TDI 输入的 4 位新数据。
Update-DR
在 Update-DR 状态下,由 TCK 上升沿驱动,数据寄存器当中的数据将被加载到相应的芯
片管脚上去,用以驱动芯片。在该状态下,如果 TMS 为“0”,TAP Controller 将回到
Run-Test/Idle 状态;如果 TMS 为“1”,TAP Controller 将进入 Select-DR-Scan 状态。
Select-IR-Scan
这是一个临时的中间状态。如果 TMS 为“0” (在 TCK 的上升沿触发),TAP Controller
进入 Capture-IR 状态,后续的系列动作都将以指令寄存器作为操作对象;如果 TMS 为“1”
(在 TCK 的上升沿触发),TAP Controller 进入 Test-Logic Reset 状态。
Capture-IR
当 TAP Controller 在这个状态中,在 TCK 的上升沿,一个特定的逻辑序列将被装载到指
令寄存器中去。如果 TMS 为“0” (在 TCK 的上升沿触发),TAP Controller 进入 Shift-IR
状态;如果 TMS 为“1” (在 TCK 的上升沿触发),TAP Controller 进入 Exit1-IR 状态。
Shift-IR
在这个状态中,由 TCK 驱动,每一个时钟周期,被连接在 TDI 和 TDO 之间的指令寄存
OPEN-JTAG
TWENTYONE XUZHOUHE@HOTMAIL.COM & DUYUNHAI DUYUNHAI@HOTMAIL.COM
5
器将从 TDI 接收一位数据,同时通过 TDO 输出一位数据。如果 TMS 为“0” (在 TCK
的上升沿触发),TAP Controller 保持在 Shift-IR 状态; 如果 TMS 为“1” (在 TCK 的
上升沿触发),TAP Controller 进入到 Exit1-IR 状态。假设指令寄存器的长度为 4。如果
TMS 保持为 0,那在 4 个 TCK 时钟周期后,指令寄存器中原来的 4bit 长的特定逻辑序列
(在 Capture-IR 状态中捕获的特定逻辑序列)将从 TDO 输出来,该特定的逻辑序列可以
用来判断操作是否正确;同时指令寄存器将获得从 TDI 输入的一个 4bit 长的新指令。
Update-IR
在这个状态中,在 Shift-IR 状态下输入的新指令将被用来更新指令寄存器。
说了那么多,下面,让我们先看看指令寄存器和数据寄存器访问的一般过程,以便建立一个
直观的概念。
1. 系统上电,TAP Controller 进入 Test-Logic Reset 状态,然后依次进入:Run-Test/Idle Æ
Select-DR-Scan Æ Select-IR-Scan Æ Capture-IR Æ Shift-IR Æ Exit1-IR Æ Update-IR,
最后回到 Run-Test/Idle 状态。在 Capture-IR 状态中,一个特定的逻辑序列被加载到
指令寄存器当中;然后进入到 Shift-IR 状态。在 Shift-IR 状态下,通过 TCK 的驱动,
可以将一条特定的指令送到指令寄存器当中去。每条指令都将确定一条相关的数据
寄存器。然后从 Shift-IR Æ Exit1-IR Æ Update-IR。在 Update-IR 状态,刚才输入到指
令寄存器中的指令将用来更新指令寄存器。最后,进入到 Run-Test/Idle 状态,指令
生效,完成对指令寄存器的访问。
2. 当前可以访问的数据寄存器由指令寄存器中的当前指令决定。要访问由刚才的指令
选定的数据寄存器,需要以 Run-Test/Idle 为起点,依次进入 Select-DR-Scan Æ
Capture-DR Æ Shift-DR Æ Exit1-DR Æ Update-DR,最后回到 Run-Test/Idle 状态。在
这个过程当中,被当前指令选定的数据寄存器会被连接在 TDI 和 TDO 之间。通过
TDI 和 TDO,就可以将新的数据加载到数据寄存器当中去,同时,也可以捕获数据
寄存器中的数据。具体过程如下。在 Capture-DR 状态中,由 TCK 的驱动,芯片管脚
上的输出信号会被“捕获”到相应的边界扫描寄存器单元中去。这样,当前的数据
寄存器当中就记录了芯片相应管脚上的输出信号。接下来从 Capture-DR 进入到
Shift-DR 状态中去。在 Shift-DR 状态中,由 TCK 驱动,在每一个时钟周期内,一位
新的数据可以通过 TDI 串行输入到数据寄存器当中去,同时,数据寄存器可以通过
TDO 串行输出一位先前捕获的数据。在经过与数据寄存器长度相同的时钟周期后,
就可以完成新信号的输入和捕获数据的输出。接下来通过 Exit1-DR 状态进入到
Update-DR 状态。在 Update-DR 状态中,数据寄存器中的新数据被加载到与数据寄
存器的每个寄存器单元相连的芯片管脚上去。最后,回到 Run-Test/Idle 状态,完成
对数据寄存器的访问。
上面描述的就是通过 TAP 对数据寄存器进行访问的一般流程。会不会还是觉得很抽象?让我
们来看一个更直观的例子。现在假设,TAP Controller 现在处在 Run-Test/Idle 状态,指令寄存
器当中已经成功的写入了一条新的指令,该指令选定的是一条长度为 6 的边界扫描链。下面
让我们来看看实际如何来访问这条边界扫描链。图 2 所示的是测试芯片及其被当前指令选定
的长度为 6 的边界扫描链。由图 2 可以看出,当前选择的边界扫描链由 6 个边界扫描移位寄
存器单元组成,并且被连接在 TDI 和 TDO 之间。TCK 时钟信号与每个边界扫描移位寄存器
单元相连。每个时钟周期可以驱动边界扫描链的数据由 TDI 到 TDO 的方向移动一位,这样,
新的数据可以通过 TDI 输入一位,边界扫描链的数据可以通过 TDO 输出一位。经过 6 个时钟
周期,就可以完全更新边界扫描链里的数据,而且可以将边界扫描链里捕获的 6 位数据通过
OPEN-JTAG
TWENTYONE XUZHOUHE@HOTMAIL.COM & DUYUNHAI DUYUNHAI@HOTMAIL.COM
6
TDO 全部移出来。
图 2. 测试芯片及其当前选定的边界扫描链
图 3 表示了边界扫描链的访问过程。图 3.1 表示了芯片和边界扫描链的初始化状态,在测试
状态下,芯片的外部输入和输出被隔离开了,芯片的输入和输出可以通过相应的边界扫描链
来观察和控制。在图 3.1 中,扫描链里的每个移位寄存器单元的数据是不确定的,所以在图
中用 X 表示,整个扫描链里的数据序列是 XXXXXX。要从 TDI 输入到测试芯片上的数据序
列是:101010. 同时要从TDO得到芯片相应管脚上的状态。现在TAP Controller从Run-Test/Idle
状态经过 Select-DR-Scan 状态进入到 Capture-DR 状态,在 Capture-DR 状态当中,在一个 TCK
时钟的驱动下,芯片管脚上的信号状态全部被捕获到相应的边界扫描移位寄存器单元当中去,
如图 3.2 所示。从图 3.2 中我们可以看出,在进入 Capture-DR 状态后,经过一个 TCK 时钟周
期,现在扫描链中的数据序列变成了:111000. 在数据捕获完成以后,从 Capture-DR 状态进
入到 Shift-DR 状态。在 Shift-DR 状态中,我们将通过 6 个 TCK 时钟周期来把新的数据序列
(101010)通过 TDI 输入到边界扫描链当中去;同时,将边界扫描链中捕获的数据序列
(111000)通过 TDO 输出来。在进入到 Shift-DR 状态后,每经过一个 TCK 时钟驱动,边界
扫描链从 TDO 输出一位数据;同时,从 TDI 接收一位新的数据。图 3.3 所示的是在 Shift-DR
状态下,1 个 TCK 时钟周期后的扫描链的变化。图 3.4 所示的是在 Shift-DR 状态下,2 个 TCK
时钟周期后的扫描链的变化。此时,扫描链已经从 TDI 串行得到了两位新数据,从 TDO 也串
行输出了两位数据。在 TCK 时钟的驱动下,这个过程一直继续下去。图 3.5 所示的是在经过
6 个 TCK 时钟周期以后扫描链的情况。从图 3.5 中我们可以看到:边界扫描链当中已经包含
了新的数据序列:101010. 在 TDO 端,经过 6 个 TCK 时钟驱动以后,也接收到了在 Capture-DR
状态下捕获到的数据序列:111000. 到目前为止,虽然扫描链当中包含了新的数据序列:
101010,但测试芯片的管脚上的状态还是保持为:111000. 下一步,需要更新测试芯片相应管
脚上的信号状态。要实现更新,TAP Controller 从 Shift-DR 状态,经过 Exit1-DR 状态,进入
到 Update-DR 状态。在 Update-DR 状态中,经过一个周期的 TCK 时钟驱动,边界扫描链中的
新数据序列将被加载到测试芯片的相应管脚上去,如图 3.6 所示。从图 3.6 可以看出,测试芯
片的状态已经被更新,相应管脚上的状态序列已经从 111000 变为 101010. 最后从 Update-DR
状态回到 Run-Test/Idle 状态,完成对选定的边界扫描链的访问。
OPEN-JTAG
TWENTYONE XUZHOUHE@HOTMAIL.COM & DUYUNHAI DUYUNHAI@HOTMAIL.COM
7
(1)初始化状态
(2)CAPTURE-DR
(3)SHIFT-DR + 1 TCK
OPEN-JTAG
TWENTYONE XUZHOUHE@HOTMAIL.COM & DUYUNHAI DUYUNHAI@HOTMAIL.COM
8
(4)SHIFT-DR + 2 TCK
(5)SHIFT-DR + 6 TCK
(6)UPDATE-DR
图 3. 边界扫描链的访问过程
OPEN-JTAG
TWENTYONE XUZHOUHE@HOTMAIL.COM & DUYUNHAI DUYUNHAI@HOTMAIL.COM
9
在看完上面这个例子以后,对 TAP Controller 的状态机应该大概了解了吧?对如何访问边界扫
描链应该也有个直观的概念了吧?虽然上面的这个例子只是说明了如何访问边界扫描链,对
其它的数据寄存器、指令寄存器的访问过程也是类似的。要实现对指令寄存器的访问,不同
的是 TAP Controller 必须经过不同的状态序列:Run-Test/Idle Æ Select-DR-Scan Æ
Select-IR-Scan Æ Capture-IR Æ Shift-IR Æ Exit1-IR Æ Update-IR Æ Run-Test/Idle.
2-3 指令寄存器、公共指令以及数据寄存器
在 IEEE 1149.1 标准当中,规定了一些指令寄存器、公共指令和相关的一些数据寄存器。
对于特定的芯片而言,芯片厂商都一般都会在 IEEE 1149.1 标准的基础上,扩充一些私有的指
令和数据寄存器,以帮助在开发过程中进行进行方便的测试和调试。在这一部分,我将简单
介绍 IEEE 1149.1 规定的一些常用的指令及其相关的寄存器。与 ARM7TDMI 相关的私有指令
和寄存器将在后面的部分专门介绍。
指令寄存器:
指令寄存器允许特定的指令被装载到指令寄存器当中,用来选择需要执行的测试,或者
选择需要访问的测试数据寄存器。每个支持 JTAG 调试的芯片必须包含一个指令寄存器。
BYPASS 指令和 Bypass 寄存器:
Bypass 寄存器是一个一位的移位寄存器,通过 BYPASS 指令,可以将 bypass 寄存器连接
到 TDI 和 TDO 之间。在不需要进行任何测试的时候,将 bypass 寄存器连接在 TDI 和 TDO
之间,在 TDI 和 TDO 之间提供一条长度最短的串行路径。这样允许测试数据可以快速的
通过当前的芯片送到开发板上别的芯片上去。
IDCODE 指令和 Device Identification 寄存器:
Device identification 寄存器中可以包括生产厂商的信息,部件号码,和器件的版本信息等。
使用 IDCODE指令,就可以通过TAP来确定器件的这些相关信息。例如,ARM MULTI-ICE
可以自动识别当前调试的是什么片子,其实就是通过 IDCODE 指令访问 Device
Identification 寄存器来获取的。
INTEST 指令和 Boundary-Scan 寄存器:
Boundary-Scan 寄存器就是我们前面例子中说到的边界扫描链。通过边界扫描链,可以进
行部件间的连通性测试。当然,更重要的是可以对测试器件的输入输出进行观测和控制,
以达到测试器件的内部逻辑的目的。INTEST 指令是在 IEEE 1149.1 标准里面定义的一条
很重要的指令:结合边界扫描链,该指令允许对开发板上器件的系统逻辑进行内部测试。
在 ARM JTAG 调试当中,这是一条频繁使用的测试指令。
我们前面说过,寄存器分为两大类:指令寄存器和数据寄存器。在上面提到的 Bypass 寄存器、
Device Identification 寄存器和 Boundary-scan 寄存器(边界扫描链),都属于数据寄存器。在
调试当中,边界扫描寄存器(边界扫描链)最重要,使用的也最为频繁。
3 ARM7TDMI 调试构架
在这个小节里,我将介绍一下 ARM7TIMI 的调试构架,让大家对 ARM7TDMI JTAG 调
有个大概的认识。细节问题将在下一小节中介绍。
ARM7TDMI 典型的调试系统结构如图 4 所示。一个调试系统一般包括三个部分:调试主
机、协议转换器和调试目标。
OPEN-JTAG
TWENTYONE XUZHOUHE@HOTMAIL.COM & DUYUNHAI DUYUNHAI@HOTMAIL.COM
10
图 4. ARM7TDMI 典型的系统调试结构
调试主机一般是一台运行调试软件(例如 ADS)的计算机。调试主机可以发出一些高层的调
试命令,例如设置断点、访问内存等。协议转换器(例如 MULTI-ICE),用来将调试主机发
出的高层调试命令转换为底层的ARM JTAG调试命令。调试目标一般就是指基于ARM7TDMI
内核 MCU 目标开发板。经过协议转换器进行命令解释,主机上运行的调试软件就可以通过
JTAG 接口直接和 ARM7TDMI 内核对话。通过扫描链,可以把 ARM/THUMB 指令插入到
ARM7TDMI 的指令流水线当中去执行。通过插入特定 ARM/THUMB 指令,我们可以检查、
保存或者改变内核和系统的状态。为了支持底层的调试,ARM7TDMI 处理器提供了硬件上的
扩展,。这些调试扩展包括:
停止程序的运行
检查和修改 ARM7TDMI 的内核状态
观察和修改内存
恢复程序的运行
ARM7TDMI 处理器的结构框图如下图所示:
图 5. ARM7TDMI 处理器结构框图
OPEN-JTAG
TWENTYONE XUZHOUHE@HOTMAIL.COM & DUYUNHAI DUYUNHAI@HOTMAIL.COM
11
从图 5 可以看到,ARM7TDMI 处理器主要包括三大部分:
ARM CPU Main Processor Logic
这部分包括了对调试的硬件支持;
Embedded ICE-RT Logic
这部分包括了一组寄存器和比较器,用来产生调试异常、设置断点和观察点;
TAP Controller
TAP Controller 通过 JTAG 接口来控制和操作扫描链。
从图 5,我们可以发现 ARM7TDMI 提供了 4 条扫描链:Scan Chain 0, 1, 2 & 3.
Scan Chain 0
通过扫描链 0 可以访问 ARM7TDMI 内核的外围电路,包括数据总线。通过该扫描链
可以进行芯片间的测试(EXTEST)和芯片的内部测试(INTEST)。该扫描链长度为
113 位,具体包括:数据总线的 0-31 位,内核控制信号,地址总线的 31-0 位,
EmbeddedICE-RT 的控制信号。
Scan Chain 1
扫描链 1 是扫描链 0 的子集,长度为 33 位,具体包括:数据总线的 0-31 位、BREAKPT
信号。扫描链 1 比扫描链 0 的长度短了很多,通过扫描链 1 可以更快的插入指令或者
是数据到 ARM7TDMI 的内部。
Scan Chain 2
扫描链 2 长度为 38 位,该扫描链是专门用来访问 EmbeddedICE-RT 内部的寄存器。
通过访问 EmbeddedICE-RT 的内部寄存器,可以让 ARM7TDMI 进入调试状态、设置
断点、设置观察点。
Scan Chain 3
通过扫描链 3,ARM7TDMI 可以访问外部的边界扫描链。该扫描链用的很少,在此
就不介绍了,想了解的网友可以参考 ARM7TDMI 手册。
在实际的调试过程中,扫描链 1 和扫描链 2 用的最多。基本上所有的调试动作都是通过这两
条扫描链来完成的。
ARM7TDMI 还提供了 3 个附加的信号:DBGRQ、DBGACK 和 BREAKPT. 这 3 个信号都被
EmbeddedICE-RT 控制,可以用来使得处理器从正常的运行状态进入调试状态或从调试状态返
回到正常的运行状态。
DBGREQ
调试请求,通过把 DBGREQ 置“1”,可以迫使 ARM7TDMI 进入调试状态。
DBGACK
调试确认,通过 DBGACK,可以判断当前 ARM7TDMI 是否在调试状态。
BREAKPT
断点信号,这个信号是输入到 ARM7TDMI 处理器内核的。如果 BREAKPT 被置“1”,
当前的内存访问被设置为断点。如果当前的内存访问是取指令的话,当该指令被执行
的时候,ARM7TDMI 处理器自动进入调试状态;如果当前的内存访问是存取数据的
话,在存储完成以后,ARM7TDMI 处理器自动进入调试状态。
OPEN-JTAG
TWENTYONE XUZHOUHE@HOTMAIL.COM & DUYUNHAI DUYUNHAI@HOTMAIL.COM
12
4 ARM7TDMI 调试原理
在这个小节里,我将详细介绍 ARM7TIMI 的调试原理,并对一些比较感兴趣的问题进行
讨论。例如,如何设置断点?如何让 ARM7TDMI 进入调试状态? 在调试状态下,如何访问
ARM7TDMI 的内部寄存器?如何访问内存单元?
在继续之前,看看 ARM7TDMI 的正常运行状态和调试状态的区别。在正常运行状态下,
ARM7TDMI 由 MCLK(Memory Clock)驱动,正常运行。在调试状态下,ARM7TDMI 的正
常运行被打断,并且和系统的其它部分隔离开来。在调试状态下,我们可以通过插入特定的
ARM/THUMB 的指令来读写 ARM7TDMI 的内部寄存器和修改内存的内容。在调试状态下,
ARM7TDMI 由内部的调试时钟 DCLK(Debug Clock)驱动。DCLK 比 MCLK 慢很多,所以
在调试状态下,插入的 ARM/THUMB 指令的运行速度会比较慢(现对而言)。在完成需要的
操作后,可以用 RESTART JTAG 指令让 ARM7TDMI 返回到正常运行状态,恢复原来的运行。
4-1 ARM7TDMI 的指令寄存器及常用 JTAG 指令
ARM7TDMI 的指令寄存器长度是 4 位,通过 TAP 和 JTAG 接口,可以把指令装载到指令
寄存器当中去。在 CAPTURE-IR 状态下,固定值 B0001 总是被装载到指令寄存器当中去。在
SHIFT-IR 状态中,可以把 ARM7TDMI 支持的新指令从 TDI 串行输入,同时固定值 B0001 会
从 TDO 串行输出。通过这个输出的固定值,可以判断当前的操作是否正确。在 UPDATE-IR
状态,新输入的指令被装载到指令寄存器当中去。最后回到 RUN-TEST/IDLE 状态后,新指
令立即生效。
下面先来看看在 ARM7TDMI 调试当中经常用到的几条 JTAG 指令。
IDCODE
该指令的二进制代码是 1110。IDCODE 指令将 Device Identification Code 寄存器连接
到 TDI 和 TDO 之间。Device Identification Code 寄存器的长度是 32 位,通过 TAP 就
可以将 ARM7TDMI 的 ID 给读出来。ARM7TDMI 的 ID 是 0x1F0F0F0F. 在
CAPTURE-DR 状态下,器件的 ID 被捕获到 ID 寄存器里面。在 SHIFT-DR 状态下,
先前捕获的 ID 通过 TDO 位移出来,总共需要 32 个 TCK 时钟周期。在 UPDATE-DR
状态下,ID 寄存器不受任何影响。
SCAN_N
该指令的二进制代码是 0010。ARM7TDMI 提供了 4 条扫描链,通过 SCAN_N 指令可
以选择需要访问的扫描链。一般来说,需要访问 Embedded ICE-RT 的寄存器时,选择
扫描链 2;需要插入指令到 ARM7TDMI 内核去执行的时候,选择扫描链 1。选择扫
描链的过程如下:先把 SCAN_N 指令装载到指令寄存器当中去,该指令会将长度为 4
位的扫描链选择寄存器连接到 TDI 和 TDO 之间;然后进入到 CAPTURE-DR 状态,
在这个状态下,固定值 B1000 将被捕获到扫描链选择寄存器当中去;在 SHIFT-DR 状
态下,将需要选择的扫描链的号码通过 TDI 输入到扫描链选择寄存器当中去;在
UPDATE-DR 状态下,被选择的扫描链将被连接到 TDI 和 TDO 之间。在 TAP 被复位
以后,默认状态下选择的是扫描链 3。在使用 SCAN_N 选定了一条扫描链后,当前选
定的扫描链会一直保持不变,直到在下一次调用 SCAN_N 选择另外的扫描链。
BYPASS
该指令的二进制代码是 1111。BYPASS 指令将 1-BIT 长的 BYPASS 寄存器连接到 TDI
和 TDO 之间。
INTEST
该指令的二进制代码是 1100。INTEST 指令将通过 SCAN_N 选定的扫描链置于内部测
OPEN-JTAG
TWENTYONE XUZHOUHE@HOTMAIL.COM & DUYUNHAI DUYUNHAI@HOTMAIL.COM
13
试模式。
RESTART
该指令的二进制代码是 0100。RESTART 指令用来使 ARM7TDMI 处理器从调试状态
退回到正常的运行状态。
4-2 EmbeddedICE-RT Logic
在这个小节里,主要介绍通过扫描链 2 来访问 EmbeddedICE-RT 内部的寄存器。
EmbeddedICE-RT 内部包括了丰富的寄存器,通过这些寄存器,可以控制 ARM7TDMI 进入或
者退出调试状态;可以设置断点和观察点。
先来看看 EmbeddedICE-RT 包括那些寄存器,下面这个表里罗列了 EmbeddedICE-RT 中
包含的所有寄存器。不同的寄存器有不同的长度,而且被分配了一个长度为 5 的地址。其中
Debug Control Register 用来控制 EmbeddedICE-RT;通过 Debug Status Register 可以查询当前
系统的状态;Abort Status Register 用来确定异常的产生原因:断点、观察点还是真的异常;
Debug Comms Control Register 和 Debug Comms Data Register 是用来控制和操作 Debug
Communication Channel 的;后面的所有寄存器都是关于 WATCH POINT 的,设置断点和观察
点就是通过设置这些寄存器来实现的。后面我将逐一的进行介绍。
TABLE I. Mapping of EmbeddedICE-RT Registers
要访问 EmbeddedICE-RT 内部的寄存器,必须通过扫描链 2 来实现。扫描链的长度是 38
位,其中 0-4 位用来标识要访问的寄存器的 5 位宽的地址;5-36 位为数据位;第 37 位用
来标识对当前寄存器进行读操作还是写操作。如果是对当前寄存器进行写操作,5-36 的数
OPEN-JTAG
TWENTYONE XUZHOUHE@HOTMAIL.COM & DUYUNHAI DUYUNHAI@HOTMAIL.COM
14
据位用来标识需要写入到寄存器的数据;如果对当前寄存器进行读操作,5-36 的数据位用
来存储从寄存器中读出的数据。假设我们现在想访问 Debug Control Register,对其进行写操
作,首先需要选择扫描链 2,将其连接到 TDI 和 TDO 之间,然后通过扫描链 2 对 Debug Control
Register 进行访问。其过程如下所述。通过 TAP 将 SCAN_N 指令写入到指令寄存器当中去,
TAP 状态转换如下:RUN-TEST/IDLE Æ SELECT-DR-SCAN Æ SELECT-IR-SCAN Æ
CAPTURE-IR Æ SHIFT-IR Æ EXIT1-IR Æ UPDATE-IR Æ RUN-TEST/IDLE,在 SHIFT-IR 状
态下,将 SCAN_N 通过 TDI 写到指令寄存器中去;接下来,访问被 SCAN_N 指令连接到 TDI
和 TDO 直接的扫描链选择寄存器,通过将 2 写入到扫描链选择寄存器当中去,以将扫描链 2
连接到 TDI 和 TDO 之间,TAP 状态转换过程如下:RUN-TEST/IDLE Æ SELECT-DR-SCAN Æ
CAPTURE-DR Æ SHIFT-DR Æ EXIT1-DR Æ UPDATE-DR Æ RUN-TEST/IDLE,在 SHIFT-DR
状态下,将数值 2 通过 TDI 写到扫描链选择寄存器当中去。在通过扫描链 2 访问任何
EmbeddedICE-RT 内部寄存器之前,我们还需要用 INTEST 指令将当前通过 SCAN_N 指令选
择的扫描链置内部测试状态。写入 INTEST 指令的过程和写入 SCAN_N 指令的过程类似。在
此就不多说了。好,至此,我们已经选择了扫描链 2,并且将它置于内部测试状态。接下来,
我们就可以通过扫描链 2 访问 EmbeddedICE-RT 内部寄存器了。下面,以写 Debug Control
Register 为例,看看怎样实现访问。假设要将 Debug Control Register 的 6 位全部置“1”,按照
扫描链 2 的格式,需要写入到扫描链 2 第序列应该为:
1,0000,0000,0000,0000,0000,0000,0011,1111,00000
在上面这个长度为 38 位的序列当中,低 5 位红色标识的数列是 Debug Control Register 的地址;
最高位蓝色标识的 1 表示对 Debug Control Register 进行写操作;中间黑色表示的 32 位是要写
入到 Debug Control Register 的数据,因为 Debug Control Register 长度为 6,所以只有低 6 为
的数据序列 111111 有效。要将上面长度为 38 位的序列写入到扫描链 2 中,TAP 状态转换过
程如下: RUN-TEST/IDLE Æ SELECT-DR-SCAN Æ CAPTURE-DR Æ SHIFT-DR Æ
EXIT1-DR Æ UPDATE-DR Æ RUN-TEST/IDLE。在 SHIFT-DR 状态下,通过 38 个 TCK 时钟
驱动,就可以将上面的序列串行输入到扫描练 2 当中去。在回到 RUN-TEST/IDLE 状态后,
Debug Control Register 的值就会被改写为 111111。
我们已经知道如何访问 EmbeddedICE-RT 的内部寄存器了,下面让我们一起来了解了解
各个寄存器的作用。
Debug Control Register
从该寄存器的名称可以看出,该寄存器是用来控制调试的。下面这个表是 Debug
Control 寄存器的格式。
DBGACK,用来控制 DBGACK 信号的值,通过 Debug Control 寄存器,可以设置
DBGACK 的值。个人的感觉是,不要人为的去设置这个值,让 EmbeddedICE-RT 自
动控制。DBGRQ,是调试请求信号,通过将该信号置“1”,可以强制 ARM7TDMI
暂停当前的指令,进入调试状态。INTDIS 用来控制中断。SBZ/RAZ 任何时候都必须
被置“0”。Monitor Mode Enable 用来控制是否进入 Monitor 模式,我没有用过这个控
制位,按我个人的理解,该模式在调试当中一般不会用到。EmbeddedICE-RT Disable,
很明显,这个控制位用来控制整个 EmbeddedICE-RT,是启用还是禁用。如果禁用的
话,ARM7TDMI 将一直保持在正常的运行状态。总结一下,通过 Debug Control 寄存
器,可以强制让 ARM7TDMI 进入调试状态。这是第一种让 ARM7TDMI 进入调试状
态的方法,另外,也可以通过断点或者是观察点来进入调试状态,每当设置的断点或
OPEN-JTAG
TWENTYONE XUZHOUHE@HOTMAIL.COM & DUYUNHAI DUYUNHAI@HOTMAIL.COM
15
者观察点被触发后,ARM7TDMI 自动进入调试状态。在我们调试的时候,第一步一
般都是先用 DBGRQ 信号使得 ARM7TDMI 进入调试状态,然后将我们需要调试的程
序装载到内存里去,接着在需要的地方设置断点和观察点,开始调试(单步运行、全
速运行、让断点或者观察点触发)。
Debug Status Register
从该寄存器的名称可以看出,该寄存器是用来保存当前低调试状态的。虽然参手册上
说该寄存器可读可写,不过建议对该寄存器只进行读操作。该寄存器的长度位 5,格
式如下:
DBGACK 信号用来标识当前系统是否处于调试状态,当 ARM7TDMI 进入调试状态
后,该信号会被自动置“1”。所以,通过查询该位,就可以判断 ARM7TDMI 当前的
状态。DBGRQ 信号用来标识 DBGRQ 信号的当前状态,要设置 DBGRQ 信号请访问
Debug Control 寄存器。IFEN 用来标识系统的中断控制状态:启用还是禁用?cgenL,
可以用来判断当前对调试器(DEBUGGER)在调试状态下对内存的访问是否完成。
TBIT,该位用来判断 ARM7TDMI 是从 ARM 状态还是 THUMB 状态进入到调试状态
的。
Abort Status Register
该寄存器的长度为 1,该寄存器用来判断一个异常的产生的原因:断点触发?观察点
触发?还是一个真的异常?
Watch Point 0/1 Address Value/Mask Register
Watch Point 0/1 Data Value/Mask Register
Watch Point 0/1 Control Value/Mask Register
关于 WATCH POINT 的 6 个寄存器,因为联系比较紧密,我在这里对这 6 个寄存器
一并介绍。ARM7TDMI 有两组 WATCH POINT 寄存器,所以总共有 12 个寄存器,在
这里我只介绍其中的一组,另外一组的功能完全是一样的。看看上面提到的 6 个寄存
器,其实是 3 对寄存器,其中 3 个是 Value 寄存器,另外 3 个是 Mask 寄存器,通过
Mask 寄存器的设置,可以屏蔽相应的 Value 寄存器的某些或全部数据位,在比较的时
候不予以考虑。WP Address Value/Mask 是用来监控地址总线的,WP Data Value/Mask
是用来监控数据总线的。每组寄存器都与一个比较器相联系,该比较器的比较结果决
定了断点条件是否满足。每次对存储空间进行访问,Watch Point 的比较器都会判断当
前访问的地址和 WP Address Value 寄存器的中的地址是否匹配?该地址中的数据和
WP Data Value 寄存器中的数据是否匹配? 如果地址和数据同时都匹配,BREAKPT
信号会被置 1,当前的内存访问被设置为断点。如果当前的内存访问是取指令的话,
当该指令被执行的时候,ARM7TDMI 处理器自动进入调试状态;如果当前的内存访
问是存取数据的话,在存储完成以后,ARM7TDMI 处理器自动进入调试状态。通过
相应的 MASK 寄存器,可以使得比较器的使用很灵活。例如,我们只考虑地址是否
匹配,可将 WP Data Mask 寄存器的值设置为:0xFFFFFFFF.