[ 准备知识 ]
A、基本的状态机知识
B、基本的C语言能力,包括位操作、常用宏定义、数组、指针等常见内容 C、会使用一种单片机
D、熟悉SPI协议的物理原理 E、对JTAG的好奇和兴趣
JTAG协议是目前应用最广泛的下载和仿真协议,对协议的最初缔造者来说,这也许有点无心插柳柳成荫的感觉——最初的JTAG协议只是用来辅助专门的硬件质检部门对印刷电路进行检测的。这些老账现不再提了
我们现在看到的各种JTAG下载和仿真协议都是各生产厂商在原有JTAG协议的思想上进行扩充的,并不具有通用性,甚至连最基本的电路检测部分功能也被加以改造——比如,一个JTAG指令可能在大部分的版本中是4 位长度的,而对于AVR32来说,一个JTAG指令却是5位。总之,现在大行其道的JTAG协议,不变的部分就只有其核心TAP状态机了。ARM有ARM的JTAG,AVR有AVR的JTAG,51有51的JTAG……
在这样一个缺乏统一标准的“街头”JTAG时代,如果你想学好JTAG下载仿真协议的破解,就必须从TAP 状态机开始。
[原理解析]
在你被复杂的时序图弄得眼花缭乱之前,你应该首先记住以下的断言:
A、JTAG协议的本质与SPI协议并没有什么不同,它等于一个复杂的SS状态机+变长的MOSI和MISO数据移位操作。不过所谓的变长,都是事先约定好的。
B、JTAG协议是一个同步通讯协议,它是全双工的。它的通讯原则是“以物易物”——即你如果想得到某些东西,你必须先给与相同长度的内容;你如果只是想发送一些数据,也会自动获取相同长度的内容,
至于交换的内容是否有意义,这是另外一回事了。 C、JTAG协议无论多么复杂,实际上只有4根线起作用(有时候还有两根鸡肋的nSRST和TRST),他们分别是TMS、TCK、TDI和TDO,他们分别对应SPI协议里面的SS、SCK、MOSI和MISO。在本质上,他们并没有什么不同。即便是ARM的JTAG那么多的引脚,实际上起作用JTAG的也就这4根线而已。
D、JTAG的数据操作都是基于移位寄存器的。
E、如果JTAG协议在某个下载仿真协议中只是用来发送控制信息和少量的数据,而大量的数据传输是通过额外的其它引脚进行的,即便这个协议被称为JTAG仿真其本质也早已超过JTAG了,严格来说,不应该称之为JTAG。因为JTAG协议中就只有4根线(有时候也算上nSRST和TRST)而已。典型的如NEXUS协议。
说了这么多,我们终于可以开始正式的讲解了。
一、从SPI到JTAG
如果熟悉SPI,你会发现SPI是如此的简单、和谐——一根用于二进制位同步的时钟线SCK,一根用于主机发送到从机的数据线MOSI(Master Out Slave In),一根用于从机发送到主机的数据线MISO(MasterIn Slave Out),外加一根用于复位SPI从机控制器以达到通讯同步的控制信号SS(不妨理解为Slave Synchronization)。如果乐意,你很容易就
通过消减MOSI和MISO的方法获得精简的单向通讯。
前面我们提到,JTAG的数据操作都是基于移位寄存器的,这一点和SPI是相同的。JTAG协议的核心在于能够有效地传输指令和数据,并且传输指令和数据的过程是能够明确的加以区别对待而不会造成歧义的。
如何实现这一功能呢?JTAG协议只是将原本用来复位从机的SS信号扩展为一个状态机。而该状态机每一个状态都有两个状态触发——在TCK(也就是SCK)的上升沿,TMS(也就是SS)的电平决定了跳转的分支。
下图就是一个典型的TAP状态机,值得庆幸的是,该状态机所有JTAG协议中都会遵守的部分。
如果这是你第一次研究TAP状态机,首先你不必去追究TAP究竟是哪些英文单词的缩写,因为Test Access Port已经是过去很久的事情了,现在的JTAG状态机虽然功能没
变,但早就从事其它“高科技”行业了。
第二眼看着附图,你会发现,其实整个状态机不过分为三个部分:信道选择部分、数据信道和指令信道。
所谓的信道选择,就是图中最顶上由四个状态组成的矩形,分别对应着四个状态: 1、JTAG TAP状态机复位状态
顾名思义,就是进入该状态,将导致整个硬件TAP控制器复位,所有的寄存器都将被初始化。在TCK的上升沿,TMS为低电平时,进入下一个状态;否则保持不变。 2、JTAG TAP的Run-Test/Idle状态
其实就是“开工”和“休息”的选择分支点。在TCK的上升沿,TMS的高电平将导致状态切换,进入数据信道的通讯状态;否则保持不变。 3、JTAG TAP的Select-DR Scan状态
Select DR Scan翻译成中文就是“选择数据移位寄存器进行移位操作”,简单说来,就是当我们 在该状态下,TCK的上升沿读取到了TMS的低电平将直接进入数据信道的操作子状态机;在TCK的上升 沿读取到了TMS的高电平,将切换到指令信道的通讯状态。 4、JTAG TAP的Select-IR Scan状态
Select-IR Scan翻译成中文就是“选择指令寄存器进行移位操作”,简单来说,就是当我们在该状 态下,TCK的上升沿读取到了TMS的低电平将直接进入指令信道的操作状态机;在TCK的上升沿读取到了TMS的高电平,将重新回到JTAG的复位状态
数据信道和指令信道对应着两个子状态机,从本质上数据和指令并没有任何不同,只是习惯上,指令 的长度固定为4个二进制位(AVR32的JTAG是5个),而数据则随着不同的指令选择了不同长度的指令寄存器,这个就需要具体查阅相关的协议说明了,比如JTAG IDCODE的长度固定为32位,而AVR32的复 位指令却有5位(很多情况下别指望是8的倍数)。根据阅读前面“选择部分4个状态机”的经验,大家 应该对照着图片自己尝试去理解剩下的两个信道。下面,我只就常见的几个状态进行解释(以数据信 道为例,指令信道可以参考其内容)。 1、Capture DR状态
前文说过,JTAG协议是基于移位寄存器的,其通讯具有“以物易物”的特性,在我们进入真正的数据传输之前,需要告知JTAG“准备通讯了哦?你有没有东西要给我哈?”,于是Capture DR就是一个 给JTAG机会将需要传达给我们的数据放入指定的移位寄存器中的状态。
2、Shift DR状态
这个状态就是通过TDI和TDO进行数据传输的状态。需要说明的是,即便进入了该状态,TMS上的电平 在TCK的上升沿也是会被读取的,从图中看到,一旦在TMS上读取到高电平,系统就会跳出Shift DR状态
如果此时数据没有传输完成,造成的后果是不确定的。请大家注意,我所说的是不确定,而不是“很严重”:同样是因为移位寄存的传输特性,有时候并不要求一定要将所有的数据都完整的进行传输,比如在AVR32中,针对SAB的数据操作,往往只需要进行最关键的部分,详细地内容可以参照相关的数据手册;
但有的时候,数据的不完整传输则会导致很严重的后果,这取决于具体的JTAG通讯协议。所以,为了保 险起见,一旦进入Shift DR状态,在发送最后一个数据之前,请保持TMS为低电平,当要发送最后一个数据时,应该将TMS设置为高电平,这样,当TCK跳变为上升沿时,系统既完成了最后一个数据的传输,也成功的退出了Shift DR状态。 3、Exit1 DR状态
该状态提供了我们一个在刚才输入的数据生效前,重新修改的机会。一般情况下,
我们直接保持TMS的高电平,并在TCK的上升沿驱动TAP状态机,直接进入Update-DR状态。
4、Update-DR状态 顾名思义,就是使我们输入的数据生效——一般JTAG内部的动作就是触发一个锁存信号,将移位寄存器中的内容并行的读取到对应的寄存器中。Update-DR有两个出口,一个是,TMS的低电平对应Run-test/Idle,还有一个是TMS的高电平对应的Select-DR Scan。这两个操作看似区别不大,但是意义非凡。前者往往会导致JTAG内部产生额外的时序(比如发生一个信号,表示完成了一个特定的周期操作,在AVR的JTAG下载中有此实例);后者则表示完成了一次数据操作,将进行下一个数据的操作,但是这些操作属于同一个操作周期。当然有些情况下,这两种方法是没有区别的。
关于理论部分的讲解,到此为止,留下一个小小的思考,当TAP状态机处于一个未知的状态时,如何才能 通过一个统一的操作使其回到Run-Test/Idel状态呢?给一个小小的提示,针对TAP状态机的TMS信号,给定固定的电平,在有限的TCK上升沿中,完成状态机的复位。那么这个有限的范围最少是多少个时钟周期? 这个固定的电平究竟是高还是低呢? [实际应用]
下面的代码是我应用在Snail mkII DEMO中用来操作TAP状态机的实际代码,它根据用户输入的TAP控制流,产生TAP控制时序,比如我们需要从Run-Test/Idle状态进入Shift-IR状态,根据TAP状态图,我们很容易得出需要产生的TMS信号依次为1(进入Select DR Scan)1(进入Select IR Scan)0(进入Capture IR)0(进入Shift-IR Scan),一共四个二进制位,根据从LSB到MSB依次发送的顺序,需要传送给函数的值就是0x03,长度为4。需要注意的是,进入Shift-IR状态以后,有可能要设置此时的需要TMS保持的电平状态,因此,实际传送的0x03其内容应该是1 1 0 0 0,最后一个0表示完成前面4个TMS时序的输入以后,TMS保持低电平。最后一个0不计入长度。
1.
2. /*********************************************************** 3. * 函数说明:JTAG TAP 状态机控制函数 * 4. * 输入: 控制序列,序列长度 * 5. * 输出: 无 * 6. * 调用函数:无 * 7. * -------------------------------------------------------- *
8. * 使用说明 *
9. * 1、 TMS在TCK上升边沿输出状态控制量。 *
10. * 2、 连续5个TCK周期在TMS上输出高电平将进入Test- * 11. * Logic-Reset模式。 *
12. * 3、 使用该函数时,请将状态机跳转以后TMS需要保 * 13. * 持的电平也作为一个有效输入加入到序列的末尾 * 14. * 但描述序列长度的数值不需要相应的增加。 *
15. ***********************************************************/ 16. void JTAG_TAP_Control(UINT8 chCTRStream,UINT8 chLength) 17. {
18. UINT8 n = 0;
19.
20. //状态机控制序列
21. for (n = 0;n < chLength;n++) 22. {
23. CLR_TCK
24. if (chCTRStream & BIT(n)) 25. {
26. SET_TMS 27. } 28. else 29. {
30. CLR_TMS 31. }
32. JTAG_CLOCK_DELAY 33. SET_TCK 34.
35. /* 延时部分 */ 36. JTAG_CLOCK_DELAY 37. } 38.
39. //保持电平
40. if (chCTRStream & BIT(chLength)) 41. {
42. SET_TMS 43. } 44. else 45. {
46. CLR_TMS 47. } 48. } 49. 复制代码
为了方便使用,我们可以将一些常用的TAP操作用宏进行封装,从而获得较高的代码可读性:
1.
2. # define JTAG_TAP_TEST_LOGIC_RESET JTAG_TAP_Control(0x1F,6); 3. # define JTAG_TAP_SHIFT_IR JTAG_TAP_Control(0x03,4);
4. # define JTAG_TAP_RETURN_RUN_TEST_IDEL JTAG_TAP_Control(0x01,2); 5. # define JTAG_TAP_ENTER_SHIFT_DR_FROM_SHIFT_IR JTAG_TAP_Control(0x03,4); 6. # define JTAG_TAP_SHIFT_DR JTAG_TAP_Control(0x01,3); 7. 复制代码
[工程实例]
Step 1:
首先我们要下载一个JTAG时序分析软件JTAG Hacker
点击此处下载 ourdev_496456.rar(文件大小:235K) (原文件名:上位机.rar)
Step 2:
我们要下载一个示例时序文件 Enter PDI.JTG
点击此处下载 ourdev_496458.rar(文件大小:304字节) (原文件名:Enter PDI.rar)
Step 3:
打开软件JTAG Hacker,从文件菜单中选择打开-〉Enter PDI.JTAG。如图所示。
Step 4:
单击“清除”按钮来复位整个分析期,依次单击“单步分析”按钮,观察左边的TAP状态机,
对照JTAG Log中的说明,观察时序波形,理解TAP状态机的操作流程。
Step 5:
如果你脱离波形文件直接研究TAP状态机,可以通过最右下角的三个按钮来直接驱动TAP状态 机模拟器。
因篇幅问题不能全部显示,请点此查看更多更全内容