JTAG(Joint Test Action Group)联合测试⾏动⼩组)是⼀种国际标准测试协议(IEEE 1149.1兼容),主要⽤于芯⽚内部测试。现在多数的⾼级器件都⽀持JTAG协议,如DSP、FPGA器件等。标准的JTAG接⼝是4线:TMS、 TCK、TDI、TDO,分别为模式选择、时钟、数据输⼊和数据输出线。
JTAG最初是⽤来对芯⽚进⾏测试的,基本原理是在器件内部定义⼀个TAP(Test Access Port?测试访问⼝)通过专⽤的JTAG测试⼯具对进⾏内部节点进⾏测试。JTAG测试允许多个器件通过JTAG接⼝串联在⼀起,形成⼀个JTAG链,能实现对各个器件分别测试。现在,JTAG接⼝还常⽤于实现ISP(In-System Programmable?在线编程),对FLASH等器件进⾏编程。
JTAG编程⽅式是在线编程,传统⽣产流程中先对芯⽚进⾏预编程实现再装到板上因此⽽改变,简化的流程为先固定器件到电路板上,再⽤JTAG编程,从⽽⼤⼤加快⼯程进度。JTAG接⼝可对PSD芯⽚内部的所有部件进⾏编程
上⾯的信息是从度娘百科引⽤过来的,对于jtag没有了解过的⼈来说,上⾯的⼤部分内容都不知道说什么,当然,我是⼀开始看的时候也看不懂。
不过从上⾯得出来的信息知道,jtag是⼀个协议,标准有4个引脚,⽤于芯⽚的测试与编程调试。
jtag是有硬件实现的。
在cpu(注意:这⾥的cpu是指运算处理单元,只包含了内部寄存器以及运算单元等基本部件)外围,处理器(即cpu扩展芯⽚,不是soc)内部包含了jtag的硬件实现,并且向外界提供接⼝,也就是上⾯所说的TMS,TCK,TDI,TDO,四个引脚。
如图:
边界扫描链
jtag如何⽤于芯⽚测试呢? 其中⽤到的最主要部件就是边界扫描链。命名为边界扫描链,是由于它位置处于处理器的边界上。
我们知道cpu是通过引脚与外围交流的,所有的数据都会通过引脚输⼊或者输出,⽽jtag就是通过监控引脚的信号达到芯⽚测试的⽬的。
⽽边界扫描链就是在引脚上的⼀个部件。如下图:
通过边界扫描链,当有信号输⼊的时候,边界扫描链就能获取信号,当cpu要输出信号的时候,边界扫描链也能获取要输出的信号。
另外也可以通过边界扫描链来直接向外部输出信号。
⽆论是信号的抓取还是输出,都需要有接⼝来保存这些信号,TDI跟TDO就是做这样⼀些⼯作的。如图:
本来边界扫描链保存着引脚上的信号,当通过TDI引脚输⼊我们⾃⼰的信号的时候,会发⽣沿上⾯红线⽅向的移位操作, TDI ——〉 边界扫描链 —— 〉 TDO
就能从TDO获取边界扫描链上的信号,我们从TDI输⼊的信号也会到边界扫描链上去。
在cpu跟外界通信的引脚上的数据⽆⾮就是 指令 跟 数据信号(包括地址跟数据) 两种。但是这两者的结合形成了⼀个完整的程序,能对它们进⾏监控就表明我们能进⾏程序的调试。
上⾯的只是jtag最基本的原理,要对程序更好的调试还需要控制部件,还有更多寄存器的结合等等。
下⾯是⼀个完整的jtag调试部件:
下⾯来讲讲arm上的jtag调试,openocd就是⼀个jtag的调试⼯具以下基于s3c2440,openocd
我们在调试程序的时候,通常需要设置断点,断点也就是指令所在的位置,断点分为两种:硬件断点跟软件断点
硬件断点:指令的地址。当cpu要去某个地址取指令的时候,就暂停cpu的运⾏。在s3c2440上只⽀持两个硬件断点 软件断点:软件断点不限制断点的个数,因此硬件断点的⽅法是不可⽤的。当我们需要在某个指令上打断点的时候,openocd会先去取得断点的地址,然后把每个断点处的值替换成某个特定的值(如deeedeee),当cpu取数据的时候得到该特定的值,就知道到达了断点地址,暂停cpu的运⾏,去除断点的时候再把原本的值换回去。如果没指定硬件断点的话,⼀般都默认是软件断点。
另外openocd对于软件断点有特定的要求:
1.程序必须位于它的链接地址上,即如果指定了. = 0x30000000,那么程序必须实际上是位于0x30000000这个地⽅,也就是说程序必须已经重定位好,位于它的链接地址。
2.程序必须按照某种特定的顺序排放:
SECTIONS{
. = 0x30000000;.text :{head.o(.text)init.o(.text)nand.o*(.text)}
.rodata ALIGN(4) : {*(.rodata)}.data ALIGN(4) : {*(.data)}
.bss ALIGN(4) : {*(.bss) *(COMMON)}}
gdb调试就是基于软件断点的调试,我们可以⽤gdb对程序代码的某⼀⾏进⾏断点设置,那么它是如何定位到某个指令的地址的?
这就需要有调试信息,也就是在编译的时候加上 -g 给程序添加调试信息。
eclipse对gdb进⾏了进⼀步的封装(GUI),我们可以通过对eclipse进⾏某些设置达到调试arm程序的⽬的。1.⾸先把⽂件加⼊⼯程2.设置调试配置: 点⼯具栏上的⼩⾍⼦ Debug Configurations... 新建⼀个调试配置
选择选项卡Main,在C/C++ Application: 选项上选择要调试的elf⽂件
选择选项卡Debugger,GDB debugger: 选择为arm-elf-gdb 选择选项卡Commands, 'Initialize'conmmands 下输⼊命令:
target remote 127.0.0.1:3333 //连接openocd load //加载程序到内存 break _start //设置断点到_start c //continue继续执⾏
然后Apply ,最后Debug开始调试
3.当然,上述程序是在内存执⾏的,但是开发板⼀开始的时候内存还没初始化,是不可⽤的,因此我们需要先设置内存 在openocd的命令控制台上(telnet 127.0.0.1 4444进⼊openocd控制台)
halt //暂停cpu
load_image init.bin 0 //加载内存初始化程序 init.bin 到 0 地址 resume 0 //在0地址开始运⾏ halt //暂停cpu
然后就可以Debug了
Debug时,当运⾏到断点处的时候,我们可以看到某些寄存器或者变量的值,这些值在eclipse上显⽰:
因篇幅问题不能全部显示,请点此查看更多更全内容