TAP/Chain/target/monitor的关系
在 OpenOCD 的语境下,这四个术语描述了从“物理硬件连接”到“软件调试指令”的不同层级。理解它们的区别对于配置
cv32e40p 这种嵌入式系统至关重要。以下是它们的详细定义和关系:
1. TAP (Test Access Port)
定义:硬件层面的逻辑接口。
TAP 是 JTAG 协议中最基本的单元。每一个具有 JTAG 接口的芯片(或芯片内部的逻辑单元)在 JTAG 链上都表现为一个 TAP。
- 物理上:它对应芯片内部的 JTAG 状态机。
- 功能上:它负责处理指令(IR)和数据(DR)的移位。
- 配置命令:在 OpenOCD 脚本中,你使用
jtag newtap <chip_name> <tap_name> -irlen 6来定义它。
- 类比:TAP 就像是进入大楼(芯片)的一个特定的大门。
2. Chain (JTAG Chain)
定义:物理链路。
当你在电路板上通过线缆连接多个芯片(例如 FPGA、ARM 核心、电源管理芯片)时,它们的 TDI 和 TDO 首尾相连,就构成了一个链。
- 特征:在一个 Chain 中,所有设备共享 TCK 和 TMS,但数据信号(TDI/TDO)是串联的。
- 你的情况:在你当前的
bscan2jtag实验中,FPGA 本身是一个 Chain 的起点,而你的cv32e40p内部的dmi_jtag_tap则是这个 Chain 上的一个特定节点。
- 类比:Chain 就像是整条街道,上面排列着很多扇“大门”(TAP)。
3. Target
定义:调试的对象(通常是 CPU 核心)。
Target 是 OpenOCD 抽象出来的软件对象,代表了一个你可以下达“暂停”、“读取寄存器”或“单步执行”命令的实体。
- 关系:一个 Target 必须绑定在一个特定的 TAP 上。TAP 负责数据的进出,而 Target 负责解释这些数据(例如将其识别为 RISC-V 的调试命令)。
- 配置命令:使用
target create riscv.cpu riscv -chain-position <TAP_NAME>。
- 你的情况:
cv32e40p核心就是 Target。
- 类比:Target 就像是大楼里的住户。你想找住户聊天(调试),必须先通过正确的大门(TAP)。
4. Monitor
定义:GDB 与 OpenOCD 之间的桥梁指令。
当你在使用 GDB(GNU Debugger)进行调试时,GDB 本身并不知道什么是“JTAG”或“FPGA 寄存器”。
- 功能:
monitor是 GDB 的一个特殊前缀。当你输入monitor reset时,GDB 会将这个命令原封不动地传给 OpenOCD。
- 用法:
monitor reset halt:告诉 OpenOCD 重置 Target 并挂起。monitor reg:查看 OpenOCD 层面的寄存器状态。
- 类比:Monitor 就像是对讲机。你通过 GDB 发号施令,通过 Monitor 频道传达给现场的工作人员(OpenOCD)去动手操作硬件。
总结对比表
术语 | 范畴 | 描述 | 关键操作 |
TAP | 硬件逻辑 | JTAG 状态机入口 | 定义 IDCODE、IR 长度 |
Chain | 物理物理 | 多个 TAP 的串联链路 | 确保 TDI/TDO 链路导通 |
Target | 逻辑实体 | 被调试的 CPU/内核 | 读写内存、单步、断点 |
Monitor | 交互接口 | GDB 发往 OpenOCD 的命令 | 执行硬件复位、读写 CSR |
为什么你之前的 Log 报错
Target not examined yet?这意味着 OpenOCD 已经识别到了 Chain 上的 TAP(所以你能看到 IDCODE),但是它在尝试将这个 TAP 关联到 Target(CPU)并进行初始化握手时失败了。这通常是因为 IR 长度不匹配或复位信号(TRST/SRST)配置不当导致的。
既然你正在修改
bscan2jtag,确保你的 target 配置指向的是你新定义的那个 -irlen 6 的 TAP。cfg文件各语句含义?
在这份
config_openocd.cfg 配置文件中,代码可以被划分为四个维度,分别对应物理连接、逻辑设备、调试对象以及操作指令。以下是详细的代码归类与解释:
1. Chain (JTAG 链路层)
这些语句定义了 OpenOCD 如何通过物理硬件(调试器)与 FPGA 上的 JTAG 链路建立通信。它们规定了“路”是怎么修的,以及信号的物理特性。
adapter driver ftdi: 指定使用的物理适配器驱动。
ftdi vid_pid / channel / layout_init / layout_signal: 这些语句在定义物理引脚的映射(哪根线是 TCK,哪根是 TMS 等)。它们决定了如何驱动物理 Chain。
adapter speed 1000: 定义 JTAG 时钟TCK的频率(1000KHz=1MHz),影响整个 Chain 的数据传输速率。
2. TAP (JTAG 逻辑节点)
这部分定义了链路上具体存在的“门”。
jtag newtap $_CHIPNAME cpu -irlen 5:- 性质:这是定义 TAP 的核心命令。
- 关键参数:
irlen 5声明了这个 TAP 指令寄存器的长度。这必须与你硬件(dmi_jtag.sv)中的参数完全匹配。 - 作用:它在逻辑链路上“占了一个位”,告诉 OpenOCD:“这里有一个设备,它的名字叫
riscv.cpu”。
3. Target (调试对象层)
这部分定义了你要调试的“人”(CPU 内核),以及它与“门”(TAP)之间的绑定关系。
target create $_TARGETNAME riscv -chain-position $_TARGETNAME:- 交互:这是 Target 与 TAP 之间的关键交互。
chain-position告诉 OpenOCD:“这个 RISC-V 核心就在刚才定义的那个 TAP 后面”。 - 性质:定义了调试目标的类型(
riscv),使 OpenOCD 知道该用哪套协议(如 RISC-V 的 DMI)来跟它交流。
riscv set_mem_access / set_reset_timeout_sec:- 性质:这些是 Target 的特定属性配置,决定了 OpenOCD 读写内存的方式和容忍超时的时间。
4. Monitor / Command (交互操作层)
这些是动作指令,通常是你手动在 Telnet 窗口输入或者 GDB 通过
monitor 前缀发送的指令。init:- 交互:这是一个“分水岭”指令。它触发 OpenOCD 去扫描物理 Chain,验证 TAP 的 IDCODE,并尝试对 Target 进行初始检查(Examine)。
halt:- 性质:一个具体的控制指令。它要求 Target(CPU)进入暂停状态。
总结对照表
代码语句 | 归属类别 | 说明 |
adapter ... / ftdi ... | Chain | 定义物理调试器如何连接到 JTAG 链路 |
jtag newtap ... -irlen 5 | TAP | 定义链路上有一个 IR 长度为 5 的节点 |
target create ... -chain-position ... | Target & TAP 交互 | 将 CPU 对象挂载到指定的 JTAG 节点上 |
riscv set_mem_access ... | Target | 设置 CPU 调试时的具体行为参数 |
init / halt | Monitor / 操作 | 启动连接流程并下达控制指令 |
数据如何在GDB和dmi模块之间一层一层发送?
理解这个过程,可以把它看作是一条跨越多个协议层级的“数据传输链”。你的调试请求从电脑的 GDB 出发,经过了多种转换,最终到达 CPU 核心内部。
数据传递路径与层级结构
第一层:GDB 与 OpenOCD (软件层)
- 交互协议:GDB Remote Serial Protocol (RSP)。
- 通信状况:逻辑上的串行通信。GDB 通过 TCP 端口(通常是 3333)发送文本指令(如
vCont或m内存读取命令)给 OpenOCD。
第二层:OpenOCD 与 USB 调试器 (指令层)
- 交互协议:USB 控制协议 / FTDI 驱动协议。
- 通信状况:高速串行通信(USB 链路)。OpenOCD 将 GDB 的指令翻译为 JTAG 命令序列。例如,它会计算出需要移位多少个 TCK 时钟周期,以及 TMS 需要在何时从 0 变 1 以控制状态机。
第三层:调试器与 FPGA 引脚 (JTAG 物理层)
- 交互协议:IEEE 1149.1 JTAG 标准。
- 通信状况:同步串行通信。
- 时钟 (TCK):作为所有同步的基准。
- TMS:控制状态机(Test Access Port Controller)。
- TDI/TDO:数据输入/输出引脚。
- FPGA 内部处理:你在
dmi_jtag_tap.sv中看到的,正是这个状态机。它根据TMS的变化,在Shift-IR或Shift-DR状态下完成指令或数据的移位。
第四层:FPGA 内的 JTAG 到 DMI (隧道协议层)
- 协议:Debug Transport Module (DTM) 协议。
- 通信状况:这是
bscan2jtag模块在处理的部分。 - 它将 JTAG 的数据移位转换成了
dmi_req_t这种结构化数据(包含addr、data、op等)。 - CDC (时钟域交叉):
dmi_cdc.sv非常重要。JTAG 信号运行在 TCK 时钟域,而 CPU 的调试模块(DM)运行在系统时钟域 (clk_i)。CDC 通过双触发器(Two-phase handshaking)确保数据在两个频率不等的域之间安全传递。
第五层:DMI 到 DM (内部总线层)
- 协议:DMI (Debug Module Interface) 接口。
- 通信状况:并行握手。
- 这是模块间的直接连接,不再是“位移”式的串行发送,而是基于
valid/ready握手的并行信号传递。 dm_top.sv收到 DMI 请求后,根据addr命中dm_csrs.sv(寄存器读写)或者dm_mem.sv(程序缓冲区访问)。
总结:数据形式的转换历程
阶段 | 数据形态 | 通信类型 |
GDB | 文本指令 (RSP) | 逻辑串行 (TCP) |
OpenOCD | JTAG 位流序列 | 物理串行 (USB) |
FPGA (JTAG TAP) | 位移流 (Shift Register) | 同步串行 (TCK/TMS/TDI/TDO) |
FPGA (DTM/CDC) | 结构化请求 ( dmi_req_t) | 同步/异步握手 |
DM 内部 | 并行总线数据 | 并行信号 |
接口状况的关键点
- 串行转并行:整个过程的核心在于JTAG 移位寄存器。它将电脑端发送的、在时间序列上排列的 32 位甚至更多位的数据,在硬件中变成物理上的并行触发器状态。
- 性能瓶颈:通信最慢的环节通常是 JTAG 位移速度。这就是为什么你修改
adapter speed会直接影响调试响应速度。
- 同步关键:如果你修改了
irlen(IR 长度),JTAG 状态机移位的数据位数就会变动,导致 OpenOCD 认为收到的 IDCODE 是错误的,进而触发Target not examined yet。
理解你的硬件修改方向:
你正在修改的
bscan2jtag,本质上是在 第三层(JTAG 物理层) 和 第四层(隧道协议层) 之间添加了一层自定义的逻辑。通过硬编码 tap_cnt_ok = 1,你实际上是在告诉 OpenOCD:“不要再试图通过隧道协议跟我协商了,直接按我给的 irlen = 6 进行移位操作吧”,从而极大地简化了同步过程。



