2. 调试接口标准:JTAG、cJTAG 与 RISC-V DTM
调试接口,说白了就是芯片和调试器之间的“握手通道”。我做了这么多年芯片,调试接口这块踩过的坑真不少。今天咱们就聊聊 JTAG、cJTAG 和 RISC-V 的 DTM 规范。
2.1 JTAG 接口协议详解
JTAG 全称是 Joint Test Action Group,最初是为了电路板测试搞出来的。后来发现它调试芯片也挺好用,就成了事实标准。
JTAG 有 5 根信号线,我习惯叫它们“五虎上将”:
- TCK(测试时钟):所有操作都跟着它走
- TMS(测试模式选择):控制状态机跳转
- TDI(测试数据输入):数据从这儿进去
- TDO(测试数据输出):数据从这儿出来
- TRST(测试复位,可选):复位 TAP 控制器
JTAG 的核心是 TAP(Test Access Port)状态机。你想想看,它就像个自动售货机——你投币(TMS 信号),它给你出饮料(状态跳转)。
重要概念:JTAG 的 TAP 状态机有 16 个状态,但常用的就几个:Test-Logic-Reset、Run-Test/Idle、Shift-DR、Shift-IR。
我个人习惯把 TAP 状态机分成两路:一路是指令寄存器(IR),一路是数据寄存器(DR)。指令寄存器告诉芯片“你要干啥”,数据寄存器存的是“具体数据”。
JTAG 操作流程
一次完整的 JTAG 操作,我总结为三步走:
- 复位:TMS 保持 5 个 TCK 周期的 1,进入 Test-Logic-Reset
- 送指令:通过 Shift-IR 状态,把指令从 TDI 送进去
- 传数据:通过 Shift-DR 状态,读写数据寄存器
我的经验:刚开始做 JTAG 时,我总搞混 IR 和 DR 的切换。后来我记住一句话:“先指路,再走路”——先送指令,再传数据。
2.2 cJTAG(紧凑 JTAG)介绍
cJTAG 是 JTAG 的“瘦身版”。为什么需要它?因为有些芯片引脚太金贵了,5 根线实在舍不得。
cJTAG 把 5 根线压缩成了 2 根:
- TMSC:数据和模式选择复用
- TCKC:时钟
说白了,cJTAG 就是把 TMS 和 TDI/TDO 合并到一根线上。代价是什么?速度慢了一半左右。但省下的 3 个引脚,在 IoT 芯片里可是真金白银。
注意:cJTAG 不是所有调试器都支持。我曾在项目里吃过这个亏——芯片选了 cJTAG,结果调试器不支持,最后只能飞线转接。选型时一定要确认调试器兼容性。
cJTAG 的协议层和标准 JTAG 是兼容的。也就是说,TAP 状态机、指令寄存器这些概念完全一样。只是物理层做了压缩。
2.3 RISC-V 调试传输模块(DTM)规范
RISC-V 的调试架构,我把它比作“三层汉堡”:
- 顶层:调试主机(你的 PC 或调试器)
- 中间层:DTM(调试传输模块)
- 底层:DM(调试模块,挂在 CPU 上)
DTM 的作用,就是“翻译官”——把 JTAG 的串行数据,翻译成 DM 能理解的并行数据。
DTM 的寄存器
DTM 有 4 个关键寄存器,我列个表方便你对照:
| 寄存器 | 地址 | 作用 |
|---|---|---|
| dmi | 0x11 | 数据寄存器,读写 DM 的寄存器 |
| dtmcs | 0x10 | 状态和控制寄存器 |
| idcode | 0x01 | 芯片 ID,用于识别 |
| dtmcontrol | 0x10 | DTM 控制寄存器(和 dtmcs 共用) |
DTM 的指令集很简单,就 3 条:
- 0x00:操作 dmi 寄存器
- 0x01:操作 dtmcs 寄存器
- 0x02:操作 idcode 寄存器
核心要点:DTM 的 dmi 寄存器是 41 位的。其中 1 位是读写标志,7 位是地址,剩下的 33 位是数据。这个设计很巧妙——一次操作就能完成地址和数据传输。
DTM 操作示例
假设我们要读 DM 的抽象命令寄存器(地址 0x11),DTM 的操作序列是这样的:
// 1. 通过 JTAG 送指令 0x00(操作 dmi)
// 2. 构造 dmi 数据:读标志(1) + 地址(0x11) + 数据(0)
// 3. 通过 JTAG 的 Shift-DR 写入
// 4. 再次通过 JTAG 读回 dmi 数据
// 5. 解析返回的 33 位数据
我曾经在调试一个 RISC-V 核时,发现 DTM 读回来的数据总是错的。查了半天,原来是 JTAG 时钟太快了,DTM 跟不上。后来把 TCK 降到 10MHz,问题就解决了。
避坑指南:DTM 的 dmi 操作是“写后读”模式。也就是说,你写一个 dmi 请求,必须再读一次才能拿到结果。中间至少要等 2 个 TCK 周期。这个时序很多人会忽略。
知识体系结构图
下面这张图,我画了调试接口的整体结构。你可以看到 JTAG、cJTAG 和 DTM 的关系:
从这张图你可以看到,调试数据从主机出发,经过 JTAG 协议层,再到 DTM 翻译,最后通过 DM 操作 CPU。每一层都有明确的职责。
嗯,调试接口这块内容不少,但核心就三点:JTAG 是物理通道,cJTAG 是省引脚方案,DTM 是协议转换层。搞懂了这三者的关系,RISC-V 调试的大门就算打开了。