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 操作,我总结为三步走:

  1. 复位:TMS 保持 5 个 TCK 周期的 1,进入 Test-Logic-Reset
  2. 送指令:通过 Shift-IR 状态,把指令从 TDI 送进去
  3. 传数据:通过 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 的关系:

RISC-V 调试接口体系结构 调试主机(PC/调试器) JTAG 协议(5线) / cJTAG(2线) DTM(调试传输模块) DM(调试模块) RISC-V CPU 核 DTM 关键寄存器 • dmi (0x11): 数据通道 • dtmcs (0x10): 状态控制 • idcode (0x01): 芯片ID • dtmcontrol (0x10): 控制 JTAG 信号线 • TCK: 测试时钟 • TMS: 模式选择 • TDI: 数据输入 • TDO: 数据输出

从这张图你可以看到,调试数据从主机出发,经过 JTAG 协议层,再到 DTM 翻译,最后通过 DM 操作 CPU。每一层都有明确的职责。

嗯,调试接口这块内容不少,但核心就三点:JTAG 是物理通道,cJTAG 是省引脚方案,DTM 是协议转换层。搞懂了这三者的关系,RISC-V 调试的大门就算打开了。