4. JTAG 指令寄存器(IR)与数据寄存器(DR):BYPASS、IDCODE、SAMPLE/PRELOAD、EXTEST 指令
好,咱们进入 JTAG 的核心地带了。指令寄存器(IR)和数据寄存器(DR),这两个东西搞明白了,JTAG 协议你就掌握了一半。
我个人习惯把 JTAG 比作一个「多路开关」。IR 就是那个开关的档位选择器,你拨到哪个档位,TDI 到 TDO 之间就接通哪条数据通路(DR)。说白了,IR 决定了你要干什么,DR 才是真正干活的地方。
4.1 指令寄存器(IR)的工作原理
IR 是一个移位寄存器,它的长度取决于芯片设计。ARM 芯片通常用 4 位或 5 位,但 IEEE 1149.1 标准规定最少要 2 位。
IR 的操作流程很简单,就两步:
- 移位阶段(Shift-IR):TAP 控制器进入 Shift-IR 状态,每个 TCK 上升沿,TDI 上的数据移入 IR,同时 IR 的当前内容从 TDO 移出。
- 更新阶段(Update-IR):TAP 进入 Update-IR 状态,IR 移位寄存器里的内容被锁存到并行输出端,变成真正的指令。
这里有个关键点:IR 的移位长度是固定的。比如 4 位 IR,你必须在 Shift-IR 状态送 4 个 TCK 脉冲,多一个少一个都不行。我曾经见过一个同事,代码里把 IR 长度配错了,结果死活读不到 IDCODE,折腾了两天。
4.2 数据寄存器(DR)的多样性
DR 就灵活多了。每条 JTAG 指令对应一个 DR 通路,长度从 1 位到几百位不等。TAP 控制器进入 Shift-DR 状态时,TDI 和 TDO 之间就接上了当前指令选中的那个 DR。
DR 的移位操作和 IR 类似,也是先移位再更新。但 DR 的更新时机更讲究——有些 DR 在 Update-DR 时更新,有些在 Capture-DR 时就采样了。
4.3 四大核心指令详解
IEEE 1149.1 规定了几个 mandatory 指令,咱们挑四个最常用的来讲。
| 指令 | IR 编码(4位示例) | DR 长度 | 主要用途 |
|---|---|---|---|
| BYPASS | 1111 | 1 位 | 旁路当前芯片 |
| IDCODE | 0010 | 32 位 | 读取芯片 ID |
| SAMPLE/PRELOAD | 0001 | 边界扫描链长度 | 采样/预装载 |
| EXTEST | 0000 | 边界扫描链长度 | 外部互连测试 |
4.3.1 BYPASS 指令
BYPASS 是最简单的指令。它把 DR 切换成一个 1 位的旁路寄存器。TDI 进来的数据,一个 TCK 周期后就从 TDO 出去了。
为什么要用 BYPASS?你想想看,JTAG 链上可能串了十几颗芯片。如果你只想调试其中一颗,其他芯片设成 BYPASS,数据就能快速穿过它们,直达目标芯片。否则,每颗芯片的边界扫描链可能有几百位长,移位一次得等半天。
4.3.2 IDCODE 指令
IDCODE 是 JTAG 的「身份证」。它是一个 32 位的只读寄存器,芯片上电后默认就选中它。所以,你连上 JTAG 后不用发任何指令,直接进 Shift-DR 就能读到 IDCODE。
IDCODE 的 32 位结构如下:
- 位 31:28:版本号(Version)
- 位 27:12:厂商代码(Part Number),16 位
- 位 11:1:制造商代码(Manufacturer ID),11 位,JEDEC 标准
- 位 0:固定为 1
我记得有一次,客户说板子上的 ARM 芯片不工作。我连上 JTAG 读 IDCODE,发现读出来全是 0xFFFFFFFF。这说明 JTAG 链路不通,或者芯片根本没上电。如果读出来是 0x00000000,那可能是 TMS 时序有问题。这些经验,你多调几次就熟了。
4.3.3 SAMPLE/PRELOAD 指令
这个指令有两个功能,名字就写明白了:
- SAMPLE:在 Capture-DR 时刻,把芯片引脚上的当前值采样进边界扫描寄存器。不影响芯片正常工作。
- PRELOAD:在 Update-DR 时刻,把数据预装载到边界扫描寄存器的输出端。为后续的 EXTEST 做准备。
为什么要把这两个功能合在一个指令里?因为 JTAG 标准的设计者希望:你先用 SAMPLE 抓一下当前状态,然后用 PRELOAD 设好下一个测试向量,最后切到 EXTEST 去驱动引脚。一气呵成,不用切换指令。
4.3.4 EXTEST 指令
EXTEST 是边界扫描的「重头戏」。它让边界扫描寄存器驱动芯片引脚,同时采样引脚上的输入值。说白了,就是你可以通过 JTAG 来控制芯片的每个引脚输出高或低,然后读回引脚上的实际电平。
EXTEST 的典型应用场景:
- 板级互连测试:检查 PCB 上的焊点是否虚焊、短路。
- 引脚电平验证:确认芯片之间的信号电平是否匹配。
- 故障定位:隔离出是芯片问题还是外围电路问题。
我曾经用 EXTEST 抓过一个很隐蔽的 bug。一块板子上有两颗 ARM 芯片通过 SPI 通信,但偶尔会丢数据。我用 EXTEST 把 SPI 的 MOSI 和 MISO 引脚强制拉高拉低,发现 MISO 线上有个毛刺,追查下去是 PCB 走线太长,信号反射导致的。加了个终端电阻就解决了。
4.4 指令与数据寄存器的协同流程
下面这张图展示了 IR 和 DR 在 TAP 状态机中的协同工作流程:
这个流程看起来简单,但实际调试时容易出问题。我见过最典型的错误是:有人想在 Shift-DR 状态下直接切换指令,结果 TAP 状态机跑飞了。记住,每次指令切换都必须经过 Run-Test/Idle 状态,这是标准规定的。
4.5 避坑指南
- IR 长度不匹配:不同芯片的 IR 长度可能不同。链路上混用 4 位和 5 位 IR 的芯片时,必须分别处理。我一开始没注意,结果指令总是发错。
- DR 移位位数算错:边界扫描链的长度不是固定的。换一颗芯片就要重新算。我写过一个脚本自动解析 BSDL 文件,省了不少事。
- TCK 频率太高:有些芯片的 JTAG 接口有最大频率限制。我遇到过一块板子,TCK 超过 10MHz 就丢数据,降到 5MHz 就稳了。