分类: 嵌入式
2016-07-26 13:27:41
原文地址:深入理解jtag接口协议 作者:曾德标
JTAG相关的理论基础
理论基础内容来源于中国芯动力网站论坛:,经过了本人的重新组织。
1. JTAG
JTAG是一种国际标准测试协议,主要用于内部测试。现在多数的高级器件都支持JTAG协议,如、FPGA、arm、PowerPC器件等。标准的是4线:TCK、TMS、TDI、TDO。下面简单介绍4线的作用:
-- 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标准里是强制要求的。
JTAG 主要应用于:电路的边界扫描测试和可编程芯片的在线系统编程、调试。
2. Boundary-Scan 边界扫描
边界扫描技术的基本思想是在靠近芯片的输入输出管脚上增加一个移位寄存器单元。因为这些移位寄存器单元都分布在芯片的边界上(周围),所以被称为边界扫描寄存器(Boundary-Scan Register Cell)。当芯片处于调试状态的时候,这些边界扫描寄存器可以将芯片和外围的输入输出隔离开来。通过这些边界扫描寄存器单元,可以实现对芯片输入输出信号的观察和控制。对于芯片的输入管脚,可以通过与之相连的边界扫描寄存器单元把信号(数据)加载倒该管脚中去;对于芯片的输出管脚,也可以通过与之相连的边界扫描寄存器“捕获”(CAPTURE)该管脚上的输出信号。在正常的运行状态下,这些边界扫描寄存器对芯片来说是透明的,所以正常的运行不会受到任何影响。这样,边界扫描寄存器提供了一个便捷的方式用以观测和控制所需要调试的芯片。另外,芯片输入输出管脚上的边界扫描(移位)寄存器单元可以相互连接起来,在芯片的周围形成一个边界扫描链(Boundary-Scan Chain)。一般的芯片都会提供几条独立的边界扫描链,用来实现完整的测试功能。边界扫描链可以串行的输入和输出,通过相应的时钟信号和控制信号,就可以方便的观察和控制处在调试状态下的芯片。
利用边界扫描链可以实现对芯片的输入输出进行观察和控制。下一个问题是:如何来管理和使用这些边界扫描链?对边界扫描链的控制主要是通过TAP (Test Access Port)Controller来完成的。
3. TAP状态机的工作原理
在前面,我们已经简单介绍了边界扫描链,而且也了解了一般的芯片都会提供几条边界扫描链,用来实现完整的测试功能。下面,我将逐步介绍如何实现扫描链的控制和访问。
在IEEE 1149.1标准里面,寄存器被分为两大类:数据寄存器(DR-Data Register)和指令寄存器(IR-Instruction Register)。边界扫描链属于数据寄存器中很重要的一种。边界扫描链用来实现对芯片的输入输出的观察和控制。而指令寄存器用来实现对数据寄存器的控制,例如:在芯片提供的所有边界扫描链中,选择一条指定的边界扫描链作为当前的目标扫描链,并作为访问对象。下面,让我们从TAP(Test Access Port)开始。
TAP是一个通用的端口,通过TAP可以访问芯片提供的所有数据寄存器(DR)和指令寄存器(IR)。对整个TAP的控制是通过TAP Controller来完成的。事实上,通过TAP接口,对数据寄存器(DR)进行访问的一般过程是:
1) 通过指令寄存器(IR),选定一个需要访问的数据寄存器;(所谓指令就是规定选择哪个数据寄存器)
2) 把选定的数据寄存器连接到TDI和TDO之间;
3) 由TCK驱动,通过TDI,把需要的数据输入到选定的数据寄存器当中去;同时把选定的数据寄存器中的数据通过TDO读出来。
接下来,让我们一起来了解一下TAP的状态机。TAP的状态机如图1所示,总共有16个状态。在图中,每个六边形表示一个状态,六边形中标有该状态的名称和标识代码。图中的箭头表示了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状态。
这个状态机看似很复杂,其实理解以后会发现这个状态机其实很直接、很简单。观察图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自动进入该状态。在该状态下,测试部分的逻辑电路全部被禁用,以保证芯片核心逻辑电路的正常工作。在TMS上连续加5个TCK脉冲宽度的“1”信号也可以对测试逻辑电路进行复位,使得TAP Controller进入Test-Logic Reset状态。在该状态下,如果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之间的指令寄存器将从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位数据通过TDO全部移出来。
在IEEE 1149.1标准当中,规定了一些指令寄存器、公共指令和相关的一些数据寄存器。对于特定的芯片而言,芯片厂商都一般都会在IEEE 1149.1标准的基础上,扩充一些私有的指令和数据寄存器,以帮助在开发过程中进行进行方便的测试和调试。在这一部分,我将简单介绍IEEE 1149.1规定的一些常用的指令及其相关的寄存器。
指令寄存器
指令寄存器允许特定的指令被装载到指令寄存器当中,用来选择需要执行的测试,或者选择需要访问的测试数据寄存器。每个支持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寄存器(边界扫描链),都属于数据寄存器。在调试当中,边界扫描寄存器(边界扫描链)最重要,使用的也最为频繁。
JTAG相关的源码分析
1. 我们可以用C语音程序来模拟以上TAP状态机的状态变化:
#define TEST_LOGIC_RESET 0
#define RUN_TEST_IDLE 1
#define SELECT_DR_SCAN 2
#define CAPTURE_DR 3
#define SHIFT_DR 4
#define EXIT1_DR 5
#define PAUSE_DR 6
#define EXIT2_DR 7
#define UPDATE_DR 8
#define SELECT_IR_SCAN 9
#define CAPTURE_IR 10
#define SHIFT_IR 11
#define EXIT1_IR 12
#define PAUSE_IR 13
#define EXIT2_IR 14
#define UPDATE_IR 15
Const unsight char StateTranslateTbl[16][2]=
{
{RUN_TEST_ IDLE, TEST_LOGIC_RESET },
{ RUN_TEST_ IDLE,SELECT_DR_SCAN},
{ CAPTURE_DR, SELECT_IR_SCAN },
{ SHIFT_DR, EXIT1_DR },
{ SHIFT_DR, EXIT1_DR },
{ PAUSE_DR,UPDATE_DR},
{ PAUSE_DR, EXIT2_DR },
{ SHIFT_DR,UPDATE_DR},
{ IDLE, SELECT_DR_SCAN },
{ CAPTURE_IR, TEST_LOGIC_RESET },
{ SHIFT_IR, EXIT1_IR },
{ SHIFT_IR, EXIT1_IR },
{ PAUSE_IR,UPDATE_IR},
{ PAUSE_IR, EXIT2_IR },
{ SHIFT_IR,UPDATE_IR},
{ RUN_TEST_ IDLE, SELECT_DR_SCAN },
}
/*************************************************
参数: TMS_Value 当前TMS的输入值
返回值:在当前TMS输入作用下所产生的新的状态值
**************************************************/
Unsigned char GetCurrentState(unsigned char TMS_Value)
{
Static unsight char State=RESET;
If(TMS_Value<2)
{
State= StateTranslateTbl[State][ TMS_Value];
Return state;
}
Return 0xff;
}
2.TAP状态机控制的C语音实现:
下面我们只讨论几个基本的操作:
(1)TAP复位操作:
void JTAG_Reset(void)
{
JTAG_SET(TDI_H|TMS_H|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_H|TCK_H);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_H|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_H|TCK_H);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_H|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_H|TCK_H);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_H|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_H|TCK_H);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_H|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_H|TCK_H);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_H|TCK_L);JTAG_DELAY(); //理论上5个周期就可以,不过为了
JTAG_SET(TDI_H|TMS_H|TCK_H);JTAG_DELAY();//可靠稳定,多一个周期也无妨
}
(2)TAP开始运行操作:
void JTAG_RunTestldleState( void )
{
JTAG_Reset();
JTAG_SET(TDI_H|TMS_L|TCK_L);JTAG_DELAY(); //一个周期就可以,
JTAG_SET(TDI_H|TMS_L|TCK_H);JTAG_DELAY(); // 为了稳定可靠可以多加
JTAG_SET(TDI_H|TMS_L|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_L|TCK_H);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_L|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_L|TCK_H);JTAG_DELAY();
}
(3)TAP写指令操作:
void JTAG_ShiftIRState(char *wrIR)
{
int size;
int i;
int tdi;
JTAG_SET(TDI_H|TMS_H|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_H|TCK_H);JTAG_DELAY(); // Select-DR-Scan
JTAG_SET(TDI_H|TMS_H|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_H|TCK_H);JTAG_DELAY(); //Select-IR-Scan
JTAG_SET(TDI_H|TMS_L|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_L|TCK_H);JTAG_DELAY(); //Capture-IR
JTAG_SET(TDI_H|TMS_L|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_L|TCK_H);JTAG_DELAY(); //Shift-IR
size=strlen(wrIR);
for( i=0;i<(size-1);i++)
{
tdi= (wrIR[i] ==HIGH) ? TDI_H:TDI_L;
JTAG_SET(tdi|TMS_L|TCK_L);JTAG_DELAY();
JTAG_SET(tdi|TMS_L|TCK_H);JTAG_DELAY(); //Shift-IR
}
tdi=(wrIR[i] ==HIGH) ? TDI_H:TDI_L; //i=3
JTAG_SET(tdi|TMS_H|TCK_L);JTAG_DELAY();
JTAG_SET(tdi|TMS_H|TCK_H);JTAG_DELAY(); //Exit1-IR
JTAG_SET(TDI_H|TMS_H|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_H|TCK_H);JTAG_DELAY(); //Update-IR
JTAG_SET(TDI_H|TMS_L|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_L|TCK_H);JTAG_DELAY(); //Run-Test/Idle
}
(4)TAP写数据寄存器,同时也读数据寄存器操作:
void JTAG_ShiftDRState(char *wrDR, char *rdDR)
{
int size;
int i;
int tdi;
JTAG_SET(TDI_H|TMS_H|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_H|TCK_H);JTAG_DELAY(); //Select-DR-Scan
JTAG_SET(TDI_H|TMS_L|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_L|TCK_H);JTAG_DELAY(); //Capture-DR
JTAG_SET(TDI_H|TMS_L|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_L|TCK_H);JTAG_DELAY(); //Shift-DR
size=strlen(wrDR);
for(i=0;i<(size-1);i++)
{
tdi=(wrDR[i]==HIGH) ? TDI_H:TDI_L;
JTAG_SET(tdi|TMS_L|TCK_L);JTAG_DELAY();
JTAG_SET(tdi|TMS_L|TCK_H);JTAG_DELAY(); //Shift-DR
rdDR[i]=JTAG_GET_TDO();
}
tdi=(wrDR[i]==HIGH) ? TDI_H:TDI_L; //i=S3C2410_MAX_CELL_INDEX
JTAG_SET(tdi|TMS_H|TCK_L);JTAG_DELAY();
JTAG_SET(tdi|TMS_H|TCK_H);JTAG_DELAY(); //Exit1-DR
rdDR[i] = JTAG_GET_TDO();
JTAG_SET(TDI_H|TMS_H|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_H|TCK_H);JTAG_DELAY(); //Update-DR
JTAG_SET(TDI_H|TMS_L|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_L|TCK_H);JTAG_DELAY(); //Run-Test/Idle
}
(4)TAP只写数据寄存器操作:
void JTAG_ShiftDRStateNoTdo(char *wrDR)
{
int size;
int i;
int tdi;
JTAG_SET(TDI_H|TMS_H|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_H|TCK_H);JTAG_DELAY(); //Select-DR-Scan
JTAG_SET(TDI_H|TMS_L|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_L|TCK_H);JTAG_DELAY(); //Capture-DR
JTAG_SET(TDI_H|TMS_L|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_L|TCK_H);JTAG_DELAY(); //Shift-DR
size=strlen(wrDR);
for(i=0;i<(size-1);i++)
{
tdi=(wrDR[i]==HIGH) ? TDI_H:TDI_L;
JTAG_SET(tdi|TMS_L|TCK_L);JTAG_DELAY();
JTAG_SET(tdi|TMS_L|TCK_H);JTAG_DELAY(); //Shift-DR
}
tdi=(wrDR[i]==HIGH) ? TDI_H:TDI_L; //i=S3C2410_MAX_CELL_INDEX
JTAG_SET(tdi|TMS_H|TCK_L);JTAG_DELAY();
JTAG_SET(tdi|TMS_H|TCK_H);JTAG_DELAY(); //Exit1-DR
JTAG_SET(TDI_H|TMS_H|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_H|TCK_H);JTAG_DELAY(); //Update-DR
JTAG_SET(TDI_H|TMS_L|TCK_L);JTAG_DELAY();
JTAG_SET(TDI_H|TMS_L|TCK_H);JTAG_DELAY(); //Run-Test/Idle
}
所有基于JTAG的测试、编程和调试工具,都是遵循以上TAP状态机的规律的。而所有工具所实现的复杂功能,细化到底层,也离不开以上几个基本的操作。