1 简介
规范文档定义了面向基于RISC-V ISA硬件平台调试工具和组件的通用接口,概述了 RISC-V 平台上外部调试支持的标准体系结构。
1.1 术语
AMO:原子内存操作。
旁路 :选择单比特数据寄存器的JTAG指令。
组件:RISC-V 内核或硬件平台的其他部分,通常所有组件都将连接到单一的系统总线。
CSR:控制和状态寄存器。
DM:调试模块
DMI:调试模块接口。
DR:JTAG数据寄存器。
DTM:调试传输模块。
DXLEN:hart支持的最宽的XLEN,忽略misa中MXL的当前值。
GPR:通用寄存器。
hart:一个 RISC-V 核心包含一个或多个硬件线程,称为 harts。
IDCODE:32位识别码,以及返回 IDCODE值的JTAG指令。
IR :JTAG指令寄存器
JTAG:Joint Test Action Group 的缩写,原意指的是开发 IEEE 1149.1 标准的开发小组,后用 JTAG 泛指该标准。
MR :消息寄存器。
NAPOT:自然对齐的2次幂。
NMI:不可屏蔽的中断。
物理地址:可在系统总线上直接使用的地址。
SBA:系统总线访问。
TAP:测试访问端口,在 IEEE 1149.1 中定义。
TM :触发模块。
虚拟地址:在hart中看到的地址,如果 hart 使用地址转换,可能会与物理地址产生区别。如果没有地址转换,和物理地址相同。
xpec:适用于捕获模式的异常程序计数器 CSR(例如 mepc)。
1.2关于本文档
表1.1 寄存器访问权限缩写
R | 只读 |
R/W | 可读/写 |
R/W1C | 可读/写1清除。将 0 写入字段无效。将1写入每个位即可清除该字段。 |
WARZ | 写任意值,读零。调试器可以写任何值。读取此字段时,返回0。 |
W1 | 只写。只有写1才有效。读取时返回值为 0 |
WARL | 写任意值,读有效值。调试器可以写任意值,如果值不支持,会转换为受支持的值。 |
寄存器中当前未使用的部分标有数字 0。软件只能将0写入这些字段,在读取时忽略这些值。当这些字段被读取时硬件必须返回0,并忽略它们的写入值。
寄存器及其字段的名称是指向其定义的超链接。
1.3 背景
专用调试硬件有多种用例,包括 CPU内核内部和外部连接的硬件。规范列举出以下用例,可以选择不实现所有功能,即可能不支持某些用例。
- 在没有操作系统或其他软件的情况下调试低级软件。
- 调试操作系统本身的问题。
- 在硬件平台任何可执行代码路径之前,引导系统进行测试、配置和变成组。
- 在CPU不工作的情况下访问系统硬件。
此外,即使没有硬件调试接口,RISC-V CPU架构也可以通过硬件触发器和断点来帮助软件调试和性能分析。
1.4 支持功能
规范中描述的调试接口支持以下特性:
1. 所有hart寄存器(包括CSRs)都可以读取/写入。
2. 内存既可以通过hart访问,也可以直接通过系统总线访问,或者两者都可以。
3. 支持RV32、RV64和RV128。
4. 硬件平台中的任何hart都可以独立调试。
5. 调试器可以发现几乎所有它需要了解自己的东西,不需要用户配置。
6. 每个hart可以从执行的第一个指令开始调试。
7. RISC-V hart可以在软件断点指令执行时停止。
8. 单步硬件一次只能执行一条指令。
9. 调试功能独立于所使用的调试传输。
10. 调试器不需要知道任何正在调试的hart的微架构。
11. hart的任意子集可以同时停止和恢复。(可选)
12. 任意指令可以在停止的hart上执行。意味着当一个核心有额外的或自定义的指令或状态时,不需要新的调试功能,只要存在可以将该状态转移到GPRs中的程序即可。(可选)
13. 可以不停机地访问寄存器。(可选)
14. 运行状态的hart可以被指示执行一条简短的指令序列,开销很小。(可选)
15. 系统总线主控允许在不涉及任何hart的情况下访问内存。(可选)
16. 当触发器与PC、读/写地址/数据或指令操作码匹配时,RISC-V hart会停止。(可选)
17. hart可以分组,当其中任何一个停止时,同一组的hart都会停止。这些组还可以对外部触发器做出反应或通知外部触发器。(可选)
本文档不支持硬件测试、调试或错误检测技术的策略或实现。扫描、内置自检(BIST)等不在本规范范围内,但规范无意限制其在RISC-V系统中的使用。可以调试使用软件线程的代码,但对它没有特殊的调试支持。
可以调试使用软件线程的代码,但对它没有特殊的调试支持。
2 系统总览
图2.1显示了外部调试支持的主要组件,虚线显示的块是可选的。
![](https://img-blog.csdnimg.cn/direct/59bdc298dbb140abb4e80443ec38a288.png)
用户与运行调试器(例如gdb)的调试主机(例如笔记本电脑)进行交互。
调试器与调试转换器(例如OpenOCD,它可能包含一个硬件驱动程序)通信,以与调试传输硬件(例如Olimex USB-JTAG适配器)通信。
调试传输硬件将调试主机连接到平台的调试传输模块(DTM)。DTM通过调试模块接口(DMI)提供对一个或多个调试模块(DMs)的访问。
平台中的每个hart由一个DM精确控制。hart可能是异构。对hart-DM映射没有进一步的限制,但通常单个核心中的所有hart都由相同DM控制。在大多数硬件平台中,只有一个DM控制硬件平台中的所有harts。
DM 与 hart 可以是 1:1 , 也可以是 1:n。
DM在硬件平台中提供对其 hart 的运行控制。通过抽象命令访问GPR。也 可以通过抽象命令或将程序写入可选的程序缓冲区来访问其他寄存器。
程序缓冲区允许调试器在hart上执行任意指令。此机制还可用于访问内存。可选的系统总线访问模块允许在不使用 RISC-V hart 执行访问的情况下进行内存访问。
每个RISC-V hart都可以实现一个触发模块。当满足触发条件时,harts将停止并通知调试模块hart已停止。
3 调试模块(非ISA)
调试模块实现了抽象调试操作与具体实施间的接口转换,支持以下操作:
1. 向调试器提供有关实现的必要信息。(要求)
2. 允许单个hart停止和恢复。(要求)
3. 提供hart停止的状态。(要求)
4. 提供对停止hart GPRs的抽象读写访问。(要求)
5. 提供对复位信号的访问,允许从复位后的第一条指令进行调试。(要求)
6. 提供允许调试 hart 立即退出复位(无论复位原因如何)机制。(可选)
7. 提供对非GPR hart寄存器的抽象访问。(可选)
8. 提供程序缓冲区以强制 hart 执行任意指令。(可选)
9. 允许同时停止、恢复和/或重置多个 hart。(可选)
10. 允许从hart的角度访问内存。(可选)
11. 允许直接访问系统总线。(可选)
12. Group harts:group中的任何一个hart停止,组内其他hart都会停止。(可选)
13. 通过停止已配置组中的每个hart来响应外部触发器。(可选)
14. 当group中的一个hart停止时发出外部触发信号。(可选)
为了与此规范兼容,实现必须:
1. 实现上面列出的所有要求功能。
2. 实现程序缓冲器、系统总线访问或抽象访问存储器命令机制中的至少一个。
3. 至少执行以下一项操作:
(a) 实施程序缓冲区。
(b) 对 hart上运行的软件可见的所有寄存器进行抽象访问,包括 hart上存在的所有寄存器。
(c) 实现对所有 GPRs、dcsr 和 dpc 的抽象访问。
单个DM可以调试多达2^20个hart。
调试模块接口(DMI)
调试模块是DMI的从属设备(slave)。总线的主设备(master)是调试传输模块。DMI可以是具有一个master和一个slave的简单总线,也可以使用功能更全面的总线,如 TileLink 或 AMBA 高级外设总线。
DMI 使用 7 到 32 个地址位,支持读取和写入操作。地址空间的底部用于第一个(通常也是唯一一个)DM,额外的空间可用于自定义调试设备、其他内核、其他 DM 等。如果 DMI 上有其他 DM,则 DMI 地址空间中下一个 DM 的基址将在 nextdm 中给出。
调试模块通过寄存器访问其DMI地址空间进行控制。
复位控制
有两种方法允许调试器重置 harts。ndmreset重置硬件平台中的所有harts以及硬件平台除DM、DTM和DMI的其他部分。受此重置影响的内容取决于实现,但必须能够从执行的第一条指令开始调试程序。hartreset重置所有当前选定的harts。在这种情况下,可能会重置更多的 hart,而不仅仅是选择的hart。调试器可以通过anyhavereset和allhavereset来查看哪些hart被重置。
若执行其中任一重置,调试器首先置位,然后清除。实际复位可能在置位后立即开始,也可能在解除置位后任意长时间开始。重置本身也可能需要任意长的时间。在重置过程中,harts 可能处于运行状态,表示在此期间可以执行一些抽象命令,也可能处于不可用状态,表示在此期间无法执行任何抽象命令。一旦hart复位完成,havereset就会变为置位。当hart退出复位并且haltreq或 resethaltreq 置位时,hart 将立即进入调试模式(停止状态)。否则,如果hart最初正在运行,它将正常执行(运行状态),如果hart最初停止,它现在应该正在运行,但可能会停止。
调试模块自身状态和寄存器仅在上电时复位,dmcontrol中的dmactive 为0。如果有其他机制可以重置DM,此机制还必须重置DM可访问的所有hart。
由于时钟和电源域交叉问题,可能无法跨硬件平台重置执行任意 DMI 访问。当 ndmreset 或任何外部重置被置位时,唯一支持的DM 操作是读取和写入 dmcontrol。其他访问的行为是未定义的。
当 hart 复位时,必须设置一个粘滞的havereset状态位,可以读取在dmstatus寄存器中由 anyhavereset和allhavereset选定的hart的havereset 状态位。通过在 dmcontrol中写入1来清除所选hart的havereset位。当dmactive为低电平时,havereset位可能会被清除,也可能不会被清除。
3.3 选择harts
单个DM最多可以连接2^20个hart,向DM发出的命令仅适用于当前选定的 hart。
要枚举所有hart,调试器必须首先确定hartsellen,方法是将所有 hartsel写入 并读回该值以查看实际设置了哪些位。然后选择从0开始的每个hart,直到 dmstatus中的anynonexistent为 1,或者达到最高索引(取决于hartsellen)。
调试器可以通过使用接口读取 mhartid 或读取硬件平台的配置结构来发现 hart索引和mhartid之间的映射。
3.3.1 选择单个hart
所有调试模块都必须支持选择单个 hart。调试器可以通过将 hart 的索引写入 hartsel 来选择它。hart 索引从 0 开始,在最终索引之前是连续的。
3.3.2 选择多个harts
调试模块可以实现 hart 阵列掩码寄存器,允许一次选择多个 hart。hart阵列掩码寄存器中的第n位适用于索引为n的hart,如果为1,则选择 hart。DM会有一个hart阵列掩码寄存器,其宽度恰好足以选择它支持的所有 hart,但允许将任意位绑定为0。
调试器可以使用 hawindowsel 和 hawindow 在 hart阵列掩码寄存器中设置位,然后通过设置 hasel 将操作应用于所有选定的 hart。如果支持此功能,则可以同时停止、恢复和重置多个 hart。hart阵列掩码寄存器的状态不受设置或清除hasel的影响。
抽象命令的执行忽略了这种机制,只适用于 hartsel 选择的 hart。
3.4 hart调试模块状态
每个可选择的hart都处于以下四种状态之一:不存在、不可用、正在运行或已停止。所选hart所处的状态由allnonexistent、anynonexistent、allunavail、anyunavail、allrunning、anyrunning、allhalted 和 anyhalted反映。
如果hart不能成为这个硬件平台的一部分,那么无论用户等待多长时间,hart都是不存在的。例如,在一个简单的单hart硬件平台中,只有一个hart存在,而其他所有hart都不存在。调试器可能会假设硬件平台没有索引高于第一个不存在的hart。
如果hart可能在以后存在/变得可用,或者如果有其他hart的索引高于此 hart,则hart不可用。hart可能由于各种原因而不可用,包括重置、暂时断电以及未插入硬件平台。这意味着 hart可能随时可用或不可用,尽管这些事件在易于调试的硬件平台中应该很少见。当 hart 可用时,无法保证其状态。
具有大量hart的硬件平台可能会永久禁用某些 hart,从而在原本连续的hart 索引空间中留下孔洞。为了让调试器发现所有hart,不可用的hart必须显示为不可用。
hart在正常执行时,包括处于低功耗模式或等待中断过程,只有停止请求会导致 hart 停止。
hart在处于调试模式时会停止,仅代表调试器执行任务。
重置的hart状态取决于实现。在置位时,以及置位后一段时间,hart可能不可用。在解除重置后,可能会运行一段时间。最后,hart要么运行,要么停止,具体取决于 haltreq 和 resethaltreq。
3.5 运行控制
对于每个hart,DM跟踪4个状态位:halt请求、resume ack、halt-on-reset请求和hart reset(hart复位和复位时停止请求位可选)。这4个状态位重置为 0,但恢复确认除外,它可能会重置为 0 或 1。DM 接收来自每个hart 的停止、运行和复位信号。调试器可以通过allresumeack和anyresumeack观察恢复确认的状态,通过allhalted、anyhalted、allrunning、anyrunning、allhavereset和anyhavereset观察停止、运行和复位信号的状态。
当调试器将1写入haltreq时,将设置每个选定hart的 halt 请求位。当一个正在运行的硬件线程,或是刚从重置状态恢复的硬件线程检测到其暂停请求位为高时,它将响应并暂停,取消运行信号,并声明其已暂停的信号。
当调试器将1写入resumereq时,将清除每个选定 hart 的恢复确认位,并向每个选定的已停止 hart 发送恢复请求。收到请求的hart将响应并恢复运行,它们清除自己的“已暂停”信号,并声明“正在运行”的信号。此过程结束后,该硬件线程的“恢复确认”位会被设置。。所有选定hart的状态信号都反映在 allresumeack、anyresumeack、allrunning 和 anyrunning 中。运行 harts 会忽略恢复请求。
当请求停止或恢复时,hart 必须在不到一秒的时间内做出响应,除非hart不可用。(如何实现没有进一步说明。几个时钟周期将是更典型的延迟)。
DM可以为每个hart实现可选的 halt-on-reset 位,通过将 hasresethaltreq 设置为 1 来指示。这意味着DM实现 setresethaltreq 和 clrresethaltreq 位。将1写入setresethaltreq会为每个选定的hart设置重置后暂停请求位。当设置了 hart 的 halt-on-reset 请求位时,hart将在下次重置解除时立即进入调试模式。请求位会一直保持,直到调试器在硬件线程被选中时向clrresethaltreq 写入1来清除,或由调试模块复位时清除。
如果 DM 在 hart 停止时复位,则未指定该 hart 是否恢复。调试器应使用 resumereq 在清除 dmactive 和断开连接之前显式恢复 hart。
3.6 停止组、恢复组和外部触发器
可选特性允许调试器将 hart 分配到两类组别中:停止组和恢复组。同时,也可以向暂停组和恢复组中添加外部触发器。在任意时刻,每个硬件线程和每个触发器都确切地属于一个暂停组和一个恢复组。
在停止组和恢复组中,组0是特殊的。组0中的harts会像没有实施组别管理一样进行暂停/恢复操作。
当暂停组中的任何一个hart暂停,或者属于该暂停组的外部触发器被激活时:
- 1. hart正常停止,cause反映了停止的原始原因。
- 2. 停止组中所有其他正在运行的hart将迅速停止。这些hart的cause位应设置为 6,但也可能设置为 3。停止组中其他已停止但已开始恢复过程的hart也必须迅速停止。
- 3. 通知该组中的所有外部触发器。
- 2. 停止组中所有其他正在运行的hart将迅速停止。这些hart的cause位应设置为 6,但也可能设置为 3。停止组中其他已停止但已开始恢复过程的hart也必须迅速停止。
将hart添加到停止组不会自动停止该hart,即使组中的其他 hart 已经停止。
当恢复组中的任何一个hart恢复时,或者恢复组中的外部触发器触发时:
- 1. 该组中所有其他停止的hart将在当前执行的任何抽象命令完成后立即恢复。组内每个hart在恢复后立即设置其恢复确认位。正在停止的hart应该完成该过程并保持停止状态。
- 2. 通知组内外部触发器。
将 hart 添加到恢复组不会自动恢复该hart,即使组中的其他hart当前正在运行。
外部触发器是抽象的概念,可以向DM发出信号和/或从DM接收信号。此配置是通过dmcs2完成的,外部触发器通过编号来引用。通常,外部触发器能够将信号从硬件平台发送到DM,以及接收来自DM的信号来执行它们自己的动作。外部触发器允许单向输入或单向输出。按照惯例,外部触发器0-7是双向的,触发器 8-11 是仅输入的,触发器 12-15 是仅输出的,但这不是必需的。
重置DM时,必须将所有 hart 放在的编号最低的停止和恢复组中(通常是组 0)。
某些设计可能会选择将 hart 组硬编码为组 0 以外的组,这意味着永远不可能只停止或恢复单个 hart。这是明确允许的。在这种情况下,即使无法更改配置,也必须能够使用 dmcs2 发现组。
3.7 消息寄存器
消息寄存器(Message Registers,简称MRs)是一种使用方式受限的寄存器,这允许不同的实现方式。它们的存在是为了让双方在已知彼此身份(即谁是发送方、谁是接收方)时进行通信。
MR在两端实现读写操作。当一方读取MR,而上一次写入该寄存器的操作是由另一方执行时,读取的结果就是另一方最后写入的值。反之,如果一方读取MR,而上一次写入操作是同一方执行的,那么读取的结果是不确定的。因此,MR可用于与对方交换数据,但不适合用作后续访问的存储媒介。简言之,信息寄存器主要用于即时的数据交换,而不是作为数据暂存区供后续访问使用。
3.8 抽象命令
DM支持一组可选的抽象命令。根据实现的不同,即使选定的hart没有停止,调试器也可以执行一些抽象命令。调试器只能通过尝试执行这些命令,然后在 abstractcs 寄存器的cmderr位中查看是否执行成功来确定 hart 在给定状态(正在运行、停止或在重置中保持)支持哪些抽象命令。如果命令设置了不支持的选项,或者定义为 0 的位不是 0,则 DM 必须将 cmderr 设置为 2(不支持)。
调试器通过将抽象命令写入command寄存器来执行抽象命令。可以通过读取abstractcs寄存器的busy位来确定抽象命令是否完成。如果调试器在设置繁忙时启动新命令,则cmderr变为 1(繁忙),当前正在执行的命令仍会运行完成,但生成的任何错误都将丢失。完成后,cmderr 指示命令执行是否成功。如果hart 未停止、未运行、不可用或在执行过程中遇到错误,命令可能会失败。
如果命令采用参数,则调试器必须先将参数写入数据 MRs,然后再写入command。如果命令返回结果,则DM必须确保在清除busy之前将结果放置在数据MRs中。表 3.1 中描述了哪些data MRs 用于参数。在所有情况下,最低有效字都放在编号最低的数据MR中。参数宽度取决于正在执行的命令,在未显式指定的情况下为 DXLEN。
表3.1 数据寄存器使用
Argument Width | arg0/return value | arg1 | arg2 |
32 | data0 | data1 | data2 |
64 | data0, data1 | data2, data3 | data4, data5 |
128 | data0–data3 | data4–data7 | data8–data11 |
在启动抽象命令之前,调试器必须确保 haltreq、resumereq 和 ackhavereset 均为 0。当执行抽象命令时( abstractcs 中busy信号拉高),调试器不得更改 hartsel,不得将 1 写入 haltreq、resumereq、ackhavereset、setresethaltreq 或 clrresethaltreq。
如果抽象命令未在预期时间内完成,调试器可以尝试重置 hart(使用 hartreset 或 ndmreset)。如果不能清除busy,可以尝试重置调试模块(使用 dmactive)。
如果在选定不可用的hart启动了抽象命令,或者在执行抽象命令时hart变得不可用,则DM可能会终止抽象命令,将busy设置为低电平,并将cmderr设置为 4(停止/恢复)。
3.8.1 抽象命令列表
本节介绍不同的抽象命令,以及写入command时应如何解释抽象命令字段。每个抽象命令都是一个 32 位值。前 8 位包含 cmdtype,决定了命令的种类。表 3.2 列出了所有命令。
表3.2 cmftype含义
cmdtype | 命令 |
0 | 访问寄存器命令 |
1 | 快速访问 |
2 | 访问存储器命令 |
3.8.2 访问寄存器
此命令允许调试器访问 CPU 寄存器,允许调试器执行程序缓冲区,执行以下操作序列:
- 1. 如果write为0并且transfer为1,则将数据从 regno 指定的寄存器复制到arg0指定的data寄存器,并执行从M模式读取此寄存器时发生的任何副作用。
- 2. 如果write与transfer为1,则将数据从arg0指定的data寄存器复制到 regno 指定的寄存器中,并执行当此寄存器从M模式写入时发生的任何副作用。
- 3. 如果aarpostincrement为1,则递增 regno。如果aarpostincrement置位且transfer未置位,regno同样可能递增。
- 4. 如果postexec为1,则执行程序缓冲区。
如果其中任何操作失败,则cmderr置1,且剩余步骤均不会执行。使用抽象命令访问CPU寄存器可以及早检测到即将发生的故障,并在整个命令到达可能导致故障的步骤之前使其失败。如果请求的寄存器在 hart 中不存在,则将 cmderr 设置为 3(异常)。
DM必须实现访问寄存器命令,支持在所选hart停止时对所有GPR进行读写访问。DM可以选择性地支持访问其他寄存器,或在hart运行时访问寄存器。如果组内的一个寄存器可访问,则该组内的所有寄存器都可以访问,但每个单独的寄存器(GPR 除外)在读取、写入和停止状态方面的支持可能不同。
表3.3 抽象寄存器编号
编号 | 描述 |
0x0000 – 0x0fff | CSRs,“PC”可以通过 dpc 在此处访问。 |
0x1000 – 0x101f | GPRs |
0x1020 – 0x103f | 浮点寄存器 |
0xc000 – 0xffff | 保留给非标准扩展和内部使用。 |
选择 aarsize 的编码来匹配sbcs中的 sbaccess。
命令仅在读取寄存器时修改 arg0,其他数据寄存器不改变。
Field | Description |
cmptype | 0 表示访问寄存器命令 |
aarsize | 2 访问寄存器的最低 32 位。 3 访问寄存器的最低 64 位。 4 访问寄存器的最低 128 位。 如果 aarsize 指定的大小大于寄存器的实际大小,则访问失败。 |
aarpostincrement | 0(禁用):无效果,必须支持此变体。 1(启用):成功访问寄存器后,regno 递增。如果递增超过支持的最高值,则会导致 regno 变为未指定。支持此变体是可选的。当transfer为 0 时是否发生递增不确定。 |
postexec | 0(禁用):无效果,必须支持此变体。 1(启用):在执行完数据传输(如有)后,恰好执行程序缓冲区中的程序一次。支持此功能为可选。 |
transfer | 0(禁用):不执行write指定的操作。 1(启用):执行write指定的操作。此位可用于仅执行程序缓冲区,而不必担心将有效值放入 aarsize 或 regno 中。 |
write | 当transfer为1时: 0 将指定寄存器中的数据复制到arg0指定的data寄存器。 1将数据从arg0指定的data寄存器复制到指定的寄存器中 |
regno | 要访问的寄存器编号,如表 3.3 所述。如果 dpc 在未停止的 hart 上支持此命令,则可以用作 PC 的别名。 |
3.8.3 快速访问
执行以下操作顺序:
- 1. hart 停止,命令将 cmderr 设置为“halt/resume”并停止执行后续操作。
- 2. 执行程序缓冲区。如果发生异常,cmderr设置为“exception”,程序缓冲区执行终止,hart 停止,cause设置为 3。
- 3. 程序缓冲区执行时没有异常,则恢复 hart的运行。
实现此命令是可选的,此命令不影响数据寄存器。
3.8.4 访问存储器
此命令允许调试器执行内存访问,其视图和权限与所选 hart 完全相同,包括对hart本地内存映射寄存器的访问等。该命令执行以下操作序列:
- 1. 如果write为0,则将数据从 arg1 中指定的内存位置复制到arg0指定的data寄存器。
- 2. 如果write为1,则将数据从arg0指定的data寄存器复制到 arg1 中指定的内存位置。
- 3. 如果设置了 aampostincrement,则递增 arg1。
如果其中任何操作失败,则设置 cmderr,且不执行剩余步骤。实现可以及早检测到即将发生的故障,并在整个命令到达可能导致故障的步骤之前使其失败。
DM可以选择性地实现此命令,并且可以支持在所选 hart 运行或停止时对内存位置的读写访问。如果命令支持在 hart 运行时进行内存访问,则它还必须支持 hart 停止时的内存访问。
命令仅在读取内存时修改 arg0。仅当设置了 aampostincrement 时,它才会修改 arg1,其他数据寄存器未更改。
Field | Description |
cmdtype | 2 访问存储器命令 |
aamvirtual | 指令并不强制要求实现对虚拟地址和物理地址的同时访问,但如果遇到不支持的访问类型,必须使其失败。 0 访问的是物理地址 1访问的是虚拟地址,并按照M模式下MPRV设置时的方式进行翻译。 没有地址翻译机制(即虚拟地址等于物理地址)的系统上,调试模块可以选择性地允许将 aamvirtual 设置为 1,这将产生与与该抽象命令在aamvirtual未设置时相同的结果。 |
aamsize | 0 访问内存的低8位。 1 访问内存的低 16 位。 2 访问内存的低 32 位。 3 访问内存的低 64 位。 4 访问内存的低 128 位。 |
aampostincrement | 内存访问完成后,如果此位为 1,则将 arg1(包含使用的地址)递增 aamsize 中编码的字节数。支持此变体是可选的, |
write | 0 将数据从 arg1中指定的内存位置复制到 arg0指定的data寄存器 1 将数据从 arg0 指定的data寄存器复制到 arg1指定的内存位置。 |
target-specific | 这些位保留用于特定于目标的用途。 |
3.9 程序缓冲器
为了支持在停止的 hart 上执行任意指令,DM包含一个程序缓冲区,调试器可以将程序写入其中。仅使用抽象命令就能支持所有必要功能的 DM 可以选择省略程序缓冲区。
调试器可以将一个小程序写入程序缓冲区,在command寄存器中设置 postexec 位,然后使用访问寄存器抽象命令准确地执行一次。调试器可以编写任何程序(包括跳出程序缓冲区的跳转指令),但程序必须以 ebreak 或 c.ebreak 结尾。实现可能支持一种隐式 ebreak,当 hart 执行到程序缓冲区末端时自动执行,这由impebreak表示。借助此功能,仅 2 个 32 位字长的程序缓冲区即可提供高效的调试能力。
如果 progbufsize 为 1,则impebreak必须为 1。程序缓冲区可能只能容纳一条 32 位或 16 位指令,因此在这种情况下,调试器必须只编写一条指令,无论其大小如何。该指令可以是 32 位指令,也可以是下 16 位的压缩指令,并伴有上16位的压缩 nop。
当程序执行时,hart不会离开调试模式。如果在执行程序缓冲区期间遇到异常,则不再执行指令,hart 保持调试模式,并且 cmderr 设置为 3(异常错误)。如果调试器执行的程序未以ebreak指令终止,则hart将保持调试模式,调试器将失去对 hart 的控制。
程序缓冲区可以作为RAM实现,可供 hart 访问。
3.10 Hart调试状态概述
图 3.1 显示了 hart 在运行/停止调试期间传递的状态的概念视图,这些状态受 dmcontrol、abstractcs、abstractauto 和 command 等不同字段的影响。
3.11 系统总线访问
调试器可以使用程序缓冲区或抽象访问内存命令从 hart 的角度访问内存(这两个功能都是可选的)。DM还可以包括一个系统总线访问模块,以便在不涉及hart的情况下提供存储器访问,无论是否实现了程序缓冲区。系统总线访问块使用物理地址进行访问。
系统总线访问块可支持 8 位、16 位、32 位、64 位和 128 位访问。表 3.7 显示了sbdata寄存器中的哪些位用于每种访问大小。
根据微架构的不同,通过系统总线访问的数据可能并不总是与hart观察到的数据一致,由调试器来强制执行一致性。本规范未定义执行此操作的标准方法。
表 3.7 系统总线数据位
访问大小 | 数据位 |
8 | sbdata0 bits 7:0 |
16 | sbdata0 bits 15:0 |
32 | sbdata0 |
64 | sbdata1, sbdata0 |
128 | sbdata3, sbdata2, sbdata1, sbdata0 |
3.12 最小侵入性调试
根据正在执行的任务,一些 harts 只能短暂停止。存在几种机制可以在运行系统中以最小的影响访问资源。
首先,允许一些抽象命令在不停止 hart 的情况下执行。
其次,快速访问抽象命令可用于停止 hart,快速执行 Program Buffer 的内容,然后让 hart 再次运行。结合程序缓冲器访问数据寄存器的指令(如hartinfo中所述),可快速执行存储器或寄存器访问。对于某些硬件平台来说,这可能仍然太过侵入,但对于许多不能被暂停的硬件平台来说,偶尔的一百个周期或更少的中断是可以接受的。
如果实现了系统总线访问模块,则可以在hart运行时来访问系统内存。
3.13 安全
为了保护知识产权,可能需要锁定对调试模块的访问。为了在制造过程中允许访问,而在之后不允许,一个合理的解决方案是在调试模块中增加一个熔丝位,可以永久禁用它。由于这依赖于具体技术,本规范不再进一步讨论。
另一种选择是仅允许拥有访问密钥的用户解锁DM。在authenticated、authbusy 和 authdata之间可以支持复杂的身份验证机制。当authenticated为0时,DM 不得与硬件平台的其余部分交互,也不得公开连接到DM的hart的详细信息。所有 DM 寄存器都应读取 0,写入应忽略,但以下强制例外:
- 1. dmstatus寄存器中authenticated位可读。
- 2. dmstatus寄存器中authbusy 可读。
- 3. dmstatus 寄存器中version可读。
- 4. dmcontrol寄存器中dmactive可读可写。
- 5. authdata可读可写。
3.14 版本检测
为了以最小的副作用检测调试模块的版本,请使用以下流程:
- 1. 读取 dmcontrol。
- 2. 如果 dmactive 为 0 或 ndmreset 为 1:
- (a) 写入 dmcontrol,从读取的值中保留hartreset、hasel、hartsello和 hartselhi,设置 dmactive,并清除所有其他位。
- (b) 读取 dmcontrol,直到 dmactive 为高电平。
- 3. 读取 dmstatus,其中包含version。
如果需要清除ndmreset,可能会产生以下不可避免的副作用:
1. 清除 haltreq,可能会阻止先前调试器发出的暂停请求生效。
2. resumereq 被清除,可能会阻止先前调试器发出的恢复请求生效。
3. ndmreset解除置位,如果之前的调试器设置了它,则释放硬件平台的复位状态。
4. dmactive 置1, 释放调试模块的复位状态。
3.15 调试模块寄存器
本节中描述的寄存器可通过 DMI 总线访问。每个 DM 都有一个基址(第一个 DM 为 0),寄存器地址是与此基址的偏移量。读取时,未实现或不存在的调试模块 DMI 寄存器返回 0,写没有效果。
地址 | 名称 |
0x04 | Abstract Data 0 (data0) |
0x05 | Abstract Data 1 (data1) |
0x06 | Abstract Data 2 (data2) |
0x07 | Abstract Data 3 (data3) |
0x08 | Abstract Data 4 (data4) |
0x09 | Abstract Data 5 (data5) |
0x0a | Abstract Data 6 (data6) |
0x0b | Abstract Data 7 (data7) |
0x0c | Abstract Data 8 (data8) |
0x0d | Abstract Data 9 (data9) |
0x0e | Abstract Data 10 (data10) |
0x0f | Abstract Data 11 (data11) |
0x10 | Debug Module Control (dmcontrol) |
0x11 | Debug Module Status (dmstatus) |
0x12 | Hart Info (hartinfo) |
0x13 | Halt Summary 1 (haltsum1) |
0x14 | Hart Array Window Select (hawindowsel) |
0x15 | Hart Array Window (hawindow) |
0x16 | Abstract Control and Status (abstractcs) |
0x17 | Abstract Command (command) |
0x18 | Abstract Command Autoexec (abstractauto) |
0x19 | Configuration Structure Pointer 0 (confstrptr0) |
0x1a | Configuration Structure Pointer 1 (confstrptr1) |
0x1b | Configuration Structure Pointer 2 (confstrptr2) |
0x1c | Configuration Structure Pointer 3 (confstrptr3) |
0x1d | Next Debug Module (nextdm) |
0x1f | Custom Features (custom) |
0x20 | Program Buffer 0 (progbuf0) |
0x21 | Program Buffer 1 (progbuf1) |
0x22 | Program Buffer 2 (progbuf2) |
0x23 | Program Buffer 3 (progbuf3) |
0x24 | Program Buffer 4 (progbuf4) |
0x25 | Program Buffer 5 (progbuf5) |
0x26 | Program Buffer 6 (progbuf6) |
0x27 | Program Buffer 7 (progbuf7) |
0x28 | Program Buffer 8 (progbuf8) |
0x29 | Program Buffer 9 (progbuf9) |
0x2a | Program Buffer 10 (progbuf10) |
0x2b | Program Buffer 11 (progbuf11) |
0x2c | Program Buffer 12 (progbuf12) |
0x2d | Program Buffer 13 (progbuf13) |
0x2e | Program Buffer 14 (progbuf14) |
0x2f | Program Buffer 15 (progbuf15) |
0x30 | Authentication Data (authdata) |
0x32 | Debug Module Control and Status 2 (dmcs2) |
0x34 | Halt Summary 2 (haltsum2) |
0x35 | Halt Summary 3 (haltsum3) |
0x37 | System Bus Address 127:96 (sbaddress3) |
0x38 | System Bus Access Control and Status (sbcs) |
0x39 | System Bus Address 31:0 (sbaddress0) |
0x3a | System Bus Address 63:32 (sbaddress1) |
0x3b | System Bus Address 95:64 (sbaddress2) |
0x3c | System Bus Data 31:0 (sbdata0) |
0x3d | System Bus Data 63:32 (sbdata1) |
0x3e | System Bus Data 95:64 (sbdata2) |
0x3f | System Bus Data 127:96 (sbdata3) |
0x40 | Halt Summary 0 (haltsum0) |
0x70 | Custom Features 0 (custom0) |
0x71 | Custom Features 1 (custom1) |
0x72 | Custom Features 2 (custom2) |
0x73 | Custom Features 3 (custom3) |
0x74 | Custom Features 4 (custom4) |
0x75 | Custom Features 5 (custom5) |
0x76 | Custom Features 6 (custom6) |
0x77 | Custom Features 7 (custom7) |
0x78 | Custom Features 8 (custom8) |
0x79 | Custom Features 9 (custom9) |
0x7a | Custom Features 10 (custom10) |
0x7b | Custom Features 11 (custom11) |
0x7c | Custom Features 12 (custom12) |
0x7d | Custom Features 13 (custom13) |
0x7e | Custom Features 14 (custom14) |
0x7f | Custom Features 15 (custom15) |
3.15.1 Abstrate Data (data0- data11, at 0x04- 0x0f)
用于abstract command的数据寄存器,长度为32位,可读可写。
3.15.2 Debug Module Control (dmcontrol, at 0x10)
该寄存器控制整个调试模块以及当前选择的harts。在本文档中提到了 hartsel,它是 hartselhi 与 hartsello 的组合。虽然该规范允许 20 个 hartsel 位,但实现可能会选择实现更少的位。hartsel 的实际宽度称为 hartsellen,至少为 0,最大为 20。调试器通过将所有位写入 hartsel(假设最大位宽)并读回值以查看实际设置了哪些位查看 hartsellen。调试器不得在执行抽象命令时更改 hartsel。
有单独的 setresethaltreq 和 clrresethaltreq 位,因此,当并非所有选定的 hart 都具有相同的配置时,可以在不更改每个选定 hart 的 halt-on-reset 请求位的情况下写入 dmcontrol。
在任何给定的写入中,调试器最多只能将 1 写入以下位之一:resumereq、hartreset、ackhavereset、setresethaltreq 和 clrresethaltreq。其他位必须写成 0。
resethaltreq 是 每个hart 状态的可选内部位,无法直接读取,但可以使用 setresethaltreq 和 clrresethaltreq 进行写入操作。
keepalive 是 每个hart 状态的可选内部位,当它被设置时,硬件应该保持hart对调试器可用。即使实现了该位,硬件也可能无法保持 hart 可用。该位是通过 setkeepalive 和 clrkeepalive 写入的。
为了向前兼容,当ndmreset为0且dmactive为 1 时,version将始终可读。
Name | Description | Access | Reset |
haltrep | 当前hart暂停请求位,置1会为所有当前选定的hart设置暂停请求位,正在运行的 hart 会在暂停请求位设置时停止。 | WARZ | - |
resumereq | 当前hart恢复请求位,写1表示恢复停止的hart。同时,它也会清除harts的恢复确认位,如果haltreq被设置,则忽略resumereq。 | W1 | - |
hartreset | 写1表示复位当前所选harts,写0表示撤销复位。(可选) | WARL | 0 |
ackhavereset | 写1表示清除当前hart的havereset状态 | W1 | - |
ackunavail | 写1表示清除当前hart的unavail状态 | W1 | - |
hasel | 0表示当前只选择1个hart,1表示当前选择多个harts | WARL | 0 |
hartsello | 当前选择harts的低10位,1位表示1个hart | WARL | 0 |
hartselhi | 当前选择hart的高10位,1位表示一个hart。如果只有一个hart,hartsello的值为1,hartselhi的值为0 | WARL | 0 |
setkeepalive | 为当前选择的 hart 设置 keepalive(可选) | W1 | - |
clrkeepalive | 清除当前选定的 hart 的 keepalive(可选) | W1 | - |
setresethaltreq | 写1表示当前选择的hart在复位后处于halted状态 | W1 | - |
clrresethaltreq | 写1表示清除setresethaltreq | W1 | - |
ndmreset | 写1表示复位除debug部分所有的硬件平台,0表示撤销复位 | R/W | 0 |
dmactive | 1表示debug模块有效,正常调试时必须置位,0表示复位debug模块 | R/W | 0 |
3.15.3 Debug Module Status (dmstatus, at 0x11)
寄存器报告整个调试模块以及当前选择的 hart 的状态,寄存器地址不会改变,因为它包含version。寄存器是只读的。
Name | Description | Access | Reset |
ndmresetpending | 0(false): 未实现,或者ndmreset为0且当前没有ndmreset操作正在进行。 1(true): ndmreset当前非零,或正在进行ndmreset操作。 | R | - |
stickyunavail | 0表示每个 hart 的 unavail 位反映 hart 的当前状态 1表示每个 hart的unavail位是粘性的,一旦设置,将不会清除,直到调试器使用 ackunavail 确认 | R | Preset |
impebreak | 1表示执行完progbuf指令后自动插入一条ebreak指令,可以节省一个progbuf,当progbufsize为1时,此值必须为1 | R | Preset |
allhavereset | 1表示当前所选harts已复位且尚未对任一hart重置进行确认 | R | - |
anyhavereset | 1表示当前所选harts至少有1个复位且尚未对该hart重置进行确认 | R | - |
allresumeack | 1表示当前所选harts已响应上一次resumereq | R | - |
anyresumeack | 1表示至少有1个所选hart已响应上一次resumereq | R | - |
allnonexistent | 1表示当前所选harts不存在于当前平台 | R | - |
anynonexistent | 1表示当前所选hart至少有1个不存在当前平台 | R | - |
allunavail | 1表示当前选择的hart都不可用 | R | - |
anyunavail | 1表示至少有一个选择了的hart不可用 | R | - |
allrunning | 1表示当前选择的hart都处于running状态 | R | Preset |
anyrunning | 1表示至少有一个选择了的hart处于running状态 | R | - |
allhalted | 1表示当前选择的hart都处于halted状态 | R | - |
anyhalted | 1表示至少有一个选择了的hart处于halted状态 | R | - |
authenticated | 0表示使用DM模块之前需要进行认证,1表示已经通过认证 | R | Preset |
authbusy | 0表示可以进行正常的认证,1表示认证处于忙状态 | R | 0 |
hasresethaltreq | 1表示DM模块支持复位后处于halted状态,0表示不支持 | R | Preset |
confstrptrvalid | 0表示confstrptr0~3寄存器保存了与配置结构无关的信息 1表示confstrptr0~3寄存器保存了配置结构的地址 | R | Preset |
version | 0表示DM模块不存在 1表示DM模块的版本为0.11 2表示DM模块的版本为0.13 3表示DM模块的版本为1.0 | R | 3 |
3.15.4 Hart Info (hartinfo, at 0x12)
提供当前由hartsel选择的 hart 的信息,此寄存器是可选的,如果不存在,应该全部读0。该寄存器只读。
Name | Description | Access | Reset |
nscratch | 表示在program buffer执行期间,debugger可以使用dscratch寄存器的数量,从dscratch0开始。 | R | Preset |
dataaccess | 该字段为0表示abstract data寄存器既是core debug CSRs寄存器,也是dm寄存器; 该字段为1表示abstract data寄存器需要进行memory-map映射; | R | Preset |
datasize | 表示硬件实现的abstract data寄存器的个数; 有 12 个data寄存器,此寄存器中的值必须小于等于12。 | R | Preset |
dataaddr | 表示abstract data0在CSRs空间的编号 | R | Preset |
3.15.5 Hart Array Window Select (hawindowsel, at 0x14)
该寄存器选择在hawindow中可访问Hart Array Mask寄存器的32 bit的哪一部分。
Name | Description | Access | Reset |
hawindowsel | 根据Hart Array Mask寄存器的大小可将hawindowsel的高位赋0,例-当硬件平台有48个harts时只有bit0可写 | WARL | 0 |
3.15.6 Hart Array Window (hawindow, at 0x15)
该寄存器用于从Hart Array Mask寄存器32 bits中选择。bit 0 指 hart hawindowsel ∗ 32,bit 31 指 hart hawindowsel ∗ 32 + 31。寄存器可读/写。
3.15.7 Abstract Control and Status (abstractcs, at 0x16)
Name | Description | Access | Reset |
progbufsize | program buffer的个数,有效范围为0~16,以 32 位字为单位。 | R | Preset |
busy | 0(ready):当前没有正在执行的abstract命令。 1(busy):当前正在执行abstract命令。 写入command后此位立即置1,在命令完成之前不会清除。 | R | 0 |
relaxedpriv | 控制program buffer和abstract memory accesses是使用精确和完整的权限检查集还是使用一组宽松的权限检查(可选)。 0(完全检查):应用完全权限检查。 1(宽松检查):应用宽松权限检查 | WARL | Preset |
cmderr | 仅当 busy 为 0 时,此字段才包含有效值。 0(none):无错误。 1(busy):正在操作 command、abstractcs、abstractauto或 progbuf寄存器。 2(not supported):不支持command中的命令。 3((exception):执行命令时发生异常。 4((halt/resume):hart未处于所需状态(正在运行/已停止)或不可用导致abstract命令无法执行 5(bus):总线错误导致抽象命令失败。 6(reserved):保留以备将来使用。 7(other):命令由于其他原因而失败。 | R/W1C | 0 |
datacount | 所实现的data寄存器数,有效范围为1~12 | R | Preset |
3.15.8 Abstract Command (command, at 0x17)
写入此寄存器会执行相应的abstract命令。
Name | Description | Access | Reset |
cmdtype | 决定抽象命令的整体功能 | WARZ | Preset |
control | 此字段针对每个抽象命令进行描述。 | WARZ | 0 |
3.15.9 Abstract Command Autoexec (abstractauto, at 0x18)
Name | Description | Access | Reset |
autoexecprogbuf | program buffer的size最大是16,因此该字段每个bit对应一个program buffer寄存器,当某个progbuf寄存器对应的autoexecprogbuf比特有效时,对该progbuf寄存器进行读或写访问会在该访问结束后让硬件自动再执行一次command中的命令。 | WARL | 0 |
autoexecdata | program buffer的size最大是12,因此该字段每个bit对应一个data寄存器,当某个data寄存器对应的autoexecdata比特有效时,对该data寄存器进行读或写访问会在该访问结束后让硬件自动再执行一次command中的命令。 | WARL | 0 |
3.15.10 Configuration Structure Pointer (confstrptr0-3, at 0x19-0x1c)
confstrptrvalid为1时,读取confstrptr0寄存器将返回配置结构指针的 31:0 位,读取confstrptr1寄存器将返回配置结构指针的 63:32 位,读取confstrptr2寄存器将返回配置结构指针的 95:64 位,读取confstrptr3寄存器将返回配置结构指针的 127:96 位。
3.15.11 Next Debug Module (nextdm, at 0x1d)
如果DMI 上有多个可访问的 DM,则此寄存器包含链中下一个 DM 的基址。此寄存器只读。
3.15.12 Program Buffer (progbuf0-15, at 0x20-0x2f)
progbuf0-15寄存器必须提供program buffer的写访问权限,debugger可通过这些寄存器对program buffer读访问,读不支持时返回0。
3.15.13 Authentication Data (authdata, at 0x30)
该寄存器用作与认证模块连接的 32 位串行端口。
当 authbusy 清除时,调试器可以通过读取或写入此寄存器与身份验证模块进行通信。没有单独的机制来发出溢出/下溢信号。
3.15.14 Debug Module Control and Status 2 (dmcs2, at 0x32)
Name | Description | Access | Reset |
grouptype | 0 此寄存器中的其余字段配置停止组。 1 此寄存器中的其余字段配置恢复组 | WARL | 0 |
dmexttrigger | 此字段包含当前选定的 DM 外部触发器。 如果写入不存在的触发值,则硬件会将其更改为有效值,如果不存在 DM 外部触发器,则更改为 0 | WARL | 0 |
group | 当 hgselect 为 0 时,包含 hartsel 指定的 hart 组。 当 hgselect 为 1 时,包含由 dmexttrigger 选择的 DM 外部触发器的组。 如果未实现组,整个字段为 0 | WARL | preset |
hgwrite | write为1且hgselect 为 0 时,如果硬件支持该 hart 组,则对于每个选定的 hart,DM 会将其更改为写入组的值。 write为1且hgselect 为 1 时,如果硬件支持该触发器组, DM 会将 dmexttrigger 选择的 DM 外部触发器组更改为写入 group 的值。 写入 0 没有效果。 | W1 | - |
hgselect | 0 对 harts 进行操作。 1 对 DM 外部触发器进行操作。 如果没有 DM 外部触发器,则此字段必须绑定到 0 | WARL | 0 |
3.15.15 Halt Summary (haltsum0-3, at 0x40, 0x13, 0x34, 0x35)
寄存器只读,每一位都指示一组hart中的任何一个是否停止。
haltsum0:如果连接到DM的hart少于2个,则此寄存器可能不存在。
LSB 反映 hart {hartsel[19:5],5'h0} 的停止状态,MSB 反映 hart {hartsel[19:5],5'h1f} 的停止状态。
haltsum1:如果连接到DM的hart少于33个,则此寄存器可能不存在。
LSB 反映了 harts {hartsel[19:10],10'h0} 到 {hartsel[19:10],10'h1f} 的停止状态。MSB 反映了 harts {hartsel[19:10],10'h3e0} 到 {hartsel[19:10],10'h3ff} 的停止状态。
haltsum2:如果连接到DM的hart少于1025个,则此寄存器可能不存在。
LSB 反映了 harts {hartsel[19:15],15'h0} 到 {hartsel[19:15],15'h3ff} 的停止状态。MSB 反映了 harts {hartsel[19:15],15'h7c00} 到 {hartsel[19:15],15'h7fff} 的停止状态。
haltsum3:如果连接到DM的hart少于32769个,则此寄存器可能不存在。
LSB 反映了 harts 20'h0 到 20'h7fff 的停止状态。MSB 反映了 harts 20'hf8000 到 20'hfffff 的停止状态。
3.15.16 System Bus Access Control and Status (sbcs, at 0x38)
Name | Description | Access | Reset |
sbversion | 0 system bus接口符合 2018 年 1 月 1 日之前的规范。 1 表示当前debug spec的版本,即1.0版本 | R | 0 |
sbbusyerror | 当debugger要进行system bus访问操作时,如果上一次的system bus访问还在进行中,此时会置位该位 | R/W1C | 0 |
sbbusy | 1表示system bus正在忙。在进行system bus访问前必须确保该位为0 | R | 0 |
sbreadonaddr | 1表示每次写入 sbaddress0 都会自动触发system bus在新地址读取数据 | R/W | 0 |
sbaccess | system bus访问的数据宽度。 0: 8 位 1: 16 位 2: 32 位 3: 64 位 4: 128 位 | R/W | 2 |
sbautoincrement | 1表示每次system bus访问后,sbaddress 将按在 sbaccess 中选择的访问大小(以字节为单位)递增 | R/W | 0 |
sbreadondata | 1表示每次从 sbdata0 读取都会自动触发system bus从新的地址读取数据。 | R/W | 0 |
sberror | 0:没有总线错误。 1:超时。 2:访问了错误的地址。 3:存在对齐错误。 4:请求了不受支持的大小的访问。 7:其他。 | R/W1C | 0 |
sbasize | system bus地址的宽度,0 表示不支持总线访问。 | R | Preset |
sbaccess128 | 当支持128位system bus访问时置1 | R | Preset |
sbaccess64 | 当支持64位system bus访问时置1 | R | Preset |
sbaccess32 | 当支持32位system bus访问时置1 | R | Preset |
sbaccess16 | 当支持16位system bus访问时置1 | R | Preset |
sbaccess8 | 当支持8位system bus访问时置1 | R | Preset |
3.15.17 System Bus Address (sbaddress0-3, at 0x39-0x3b, 0x37)
sbaddress0:sbaddress物理地址的31-0bit,如果sbcs寄存器中的sbasize的值为0,那么此寄存器可以不用实现(硬件代码中只支持32bit);
sbaddress1:sbaddress物理地址的63-32bit,如果sbcs寄存器中的sbasize小于33,那么此寄存器可以不用实现(硬件代码中只支持32bit);
sbaddress2:sbaddress物理地址的95-64bit,如果sbcs寄存器中的sbasize小于65,那么此寄存器可以不用实现(硬件代码中只支持32bit);
sbaddress3:sbaddress物理地址的127-96bit,如果sbcs寄存器中的sbasize小于97,那么此寄存器可以不用实现(硬件代码中只支持32bit)。
寄存器可读/写。
3.15.18 System Bus Data (sbdata0-3, at 0x3c-0x3f)
sbdata0: sbdata物理地址的31:0 bit;
sbdata1: sbdata物理地址的63:32 bit;
sbdata2: sbdata物理地址的95:64 bit;
sbdata3: sbdata物理地址的127:96 bit.
3.15.19 Custom Features (custom, at 0x1f)
此可选寄存器可用于非标准功能。调试规范的未来版本将不会使用此地址。
3.5.20 Custom Features 0 (custom0, at 0x70)
可选的 custom0 到 custom15 寄存器可用于非标准功能。调试规范的未来版本将不会使用这些地址。
4 Sdext ISA 扩展
扩展添加了调试模式和几个额外的状态控制寄存器
4.1 调试模式
调试模式是一种特殊处理器模式,仅在hart因外部调试而暂停时使用。由于hart已暂停,正常指令流中不会前进。调试模式的具体实现方式在此不做规定。
当因执行抽象命令而执行代码时,hart保持在调试模式,并且适用以下规则:
- 所有操作均在机器模式下执行,额外的调试模式CSR可访问,并且根据mprven,mstatus中的MPRV可能被忽略。根据relaxedpriv,将应用完整的权限检查或宽松的权限检查。
- 所有中断(包括NMI)都被屏蔽。
- 异常不会更新任何寄存器。这包括cause、epc、tval、dpc和mstatus。但会结束程序缓冲区的执行。
- 如果触发器匹配,不采取任何行为。
- 如果stopcount为0,则计数器继续计数。如果为1,则计数器停止。
- 如果stoptime为0,则时间继续更新。如果为1,则时间将不更新。离开调试模式后,它将与mtime重新同步。
- wfi指令作为nop操作。
- 几乎所有改变特权模式的指令的行为都是未指定的。这包括ecall、mret、sret和uret。(要改变特权模式,调试器可以写入dcsr中的prv和v)。唯一的例外是ebreak指令,当执行时它会结束程序缓冲区的执行。
- 如果控制转移指令的目标位于程序缓冲区中,所有控制转移指令都可能作为非法指令处理。如果其中一个指令作为非法指令处理,所有这类指令都必须作为非法指令处理。
- 如果控制转移指令的目标位于程序缓冲区之外,所有控制转移指令都可能作为非法指令处理。如果其中一个指令作为非法指令处理,所有这类指令都必须作为非法指令处理。
- 依赖于PC值的指令(如auipc)可能作为非法指令处理。
- 有效XLEN为DXLEN。
- 可以执行向前的程序。
4.2 加载保留/条件存储指令
在内存地址上由lr(Load-Reserved)指令注册的预留,在进入调试模式或在调试模式期间可能会丢失。这意味着如果在lr与sc(Store-Conditional)指令对之间进入调试模式,可能导致无法向前执行。
如果在lr与sc指令对之间设置了断点,或正在逐步执行此类代码,sc指令可能永远不会成功。解决办法是在sc指令之后的第一条指令上设置断点并执行到那里。更高级别的调试器可能会选择自动执行这一操作。
4.3 等待中断指令
如果在wfi(Wait for Interrupt)指令执行期间请求暂停(halt),则hart必须离开stall状态,完成该指令的执行,然后进入调试模式。
4.4 单步执行
4.4.1 Dcsr中的单步位
此方法仅对外部调试器可用,并且是首选的单步执行方式。
外部调试器可以在 resumereq 置位前对 step 进行置位,使得暂停的hart执行一条指令或陷入异常后重新进入调试模式。
如果在执行指令期间控制权转移到陷阱处理程序,则在PC改变到陷阱处理程序后立即重新进入调试模式,并更新相应的tval和cause寄存器。在这种情况下,陷阱处理程序的任何部分都不会被执行,如果原因是待处理的中断,则可能根本不会执行任何指令。
如果执行或获取指令导致触发器触发且action=1,则在触发器触发后立即重新进入调试模式。在这种情况下,cause被设置为2(触发器)而不是4(单步)。是否执行指令取决于触发器的具体配置。
如果被执行的指令导致PC改变到一个地址,而从该地址获取指令引发了异常,那么该异常直到下一次硬件线程恢复执行时才会发生。同样,新地址处的触发器也要等到硬件线程实际尝试执行那条指令时才会触发。
如果被单步执行的指令是wfi,且通常会使硬件线程挂起,那么该指令会被当作nop处理。
4.4.2 icount触发器
本地调试器无法访问dcsr,但可以通过将count设置为1来使用icount触发器。这种方法有一些限制:
- 1. 中断会像平常一样触发。想要在单步执行时禁用中断的调试器必须通过改变mstatus来禁用它们,并特别处理读取mstatus的指令。
- 2. wfi指令不会被特别处理,可能会花费很长时间才能完成。
此机制可以清晰地支持具有多个特权级别的系统,其中操作系统或调试stub在M-Mode下运行,而被调试的程序在较低权限模式下运行。仅支持M-Mode的系统也可以使用icount,但count必须能计数多条指令(取决于软件实现)。
4.5 复位
如果hart在退出复位时,其在调试模块中的halt请求位驱动的暂停信号或resethaltreq被置位,则硬件线程必须在执行任何指令之前,但在执行第一条指令前所进行的任何初始化之后,进入调试模式。
4.6 暂停
当hart暂停时:
1. 更新cause。
2. prv和v设置为反映当前特权模式的值。
3. dpc设置为应执行的下一条指令的地址。
4. 如果当前指令可以部分执行并且需要重新启动以完成,则更新与此相关的状态。例如,如果在部分执行向量指令时发生暂停,则更新vstart,并将dpc更新为部分执行指令的地址。这类似于向量指令在异常处理中的行为。
5. hart进入调试模式。
4.7 恢复
当硬件线程恢复时:
1. pc变更为dpc中存储的值。
2. 当前特权模式和虚拟化模式更改为由prv和v指定的模式。
3. 如果新的特权模式低于M模式,则mstatus中的MPRV被清零。
4. hart不再处于调试模式。
4.8 XLEN
在调试模式下,XLEN为DXLEN。调试器需在正常程序执行期间(通过查看misa)确定XLEN,并明确向用户传达这一点。
4.9 核心调试寄存器
必须为每个可调试的hart实现所支持的核心调试寄存器。它们是CSRs(控制状态寄存器),可以通过RISC-V的csr操作码访问,并且可选地也可以通过抽象调试命令访问。
尝试访问不存在的核心调试寄存器会引发非法指令异常。
这些寄存器仅能在调试模式下访问。
表 4.1 核心调试寄存器
地址 | 名称 |
0x7b0 | Debug Control and Status (dcsr) |
0x7b1 | Debug PC (dpc) |
0x7b2 | Debug Scratch Register 0 (dscratch0) |
0x7b3 | Debug Scratch Register 1 (dscratch1) |
4.9.1 Debug Control and Status (dcsr, at 0x7b0)
进入调试模式时,v和prv会根据hart先前所在的特权级别进行更新,cause会根据进入调试模式的原因进行更新。除了这些字段和nmip之外,dcsr的其他字段只能由外部调试器写入。
表4.2显示了进入调试模式原因的优先级。实现应按照表格所示设置优先级。为了与本规范的旧版本保持兼容,只要满足以下条件,resethaltreq和haltreq的顺序可以与表中显示的不同:
- resethaltreq的优先级高于haltreq
- 其他四个原因的相对顺序保持不变
表4.2:从高到低进入调试模式的原因优先级
cause encoding | Cause |
5 | resethaltreq |
6 | halt group |
3 | haltreq |
2 | trigger |
1 | ebreak |
4 | step |
此CSR可读/写
Name | Description | Access | Reset |
debugver | 0(无):没有调试支持。 4(1.0版):按照本文档所述存在调试支持。 15(自定义):存在调试支持,但它不符合本规范的任何可用版本。 | R | Preset |
ebreakvs | 0(异常):VS模式下的ebreak指令按照Privileged Spec中的描述行为。 1(调试模式):VS模式下的ebreak指令进入调试模式。 如果硬件线程不支持虚拟化模式,此位硬连接为0。 | WARL | 0 |
ebreakvu | 0(异常):VU模式下的ebreak指令按照Privileged Spec中的描述行为。 1(调试模式):VU模式下的ebreak指令进入调试模式。 如果硬件线程不支持虚拟化模式,此位固定为0。 | WARL | 0 |
ebreakm | 0(异常):M模式下的ebreak指令按照Privileged规范中的描述行为。 1(调试模式):M模式下的ebreak指令进入调试模式。 | R/W | 0 |
ebreaks | 0(异常):S模式下的ebreak指令按照Privileged规范中的说明执行。 1(调试模式):S模式下的ebreak指令会进入调试模式。 如果硬件线程不支持S模式,此位将固定为0。 | WARL | 0 |
ebreaku | 0(异常):U模式下的ebreak指令行为遵循Privileged规范中的描述。 1(调试模式):U模式下的ebreak指令将进入调试模式。 如果硬件线程不支持U模式,此位将固定为0。 | WARL | 0 |
stepie | 0(中断禁止):当step位设置时,在单步执行过程中,中断(包括NMI)被禁止。此值应当被支持。 | WARL | 0 |
stopcount | 0(正常):像往常一样递增计数器。 1(冻结):在调试模式下或因ebreak指令进入调试模式时,不递增任何硬件线程局部的计数器。这些计数器包括instret CSR。在单硬件线程的核心上,cycle应停止递增,但在多硬件线程的核心上,cycle必须继续递增。 实现可以将此位固定为0或1。 | WARL | Preset |
stoptime | 0(正常):time继续反映mtime的值。 1(冻结):time在进入调试模式时被冻结。当退出调试模式时,time将再次反映mtime的最新值。 当所有硬件线程的stoptime均为1且处于调试模式时,允许mtime停止递增。 实现可以将此位硬编码为0或1。 | WARL | Preset |
cause | 解释进入调试模式的原因。 当在一个周期内有多个进入调试模式的原因时,硬件应将cause设置为优先级最高的原因。原因的优先级请参见表4.2。 1 (ebreak): 执行了一个ebreak指令。 | R | 0 |
v | 扩展了prv字段,表示硬件线程进入调试模式时所处的虚拟化模式。编码方式在表4.6中描述。调试器可以更改此值以便在退出调试模式时更改硬件线程的虚拟化模式。在不支持虚拟化模式的硬件线上,此位硬连线为0。 | WARL | 0 |
mprven | 0(禁用):在调试模式下,mstatus中的MPRV被忽略。 1(启用):在调试模式下,mstatus中的MPRV生效。 实现此位是可选的。它可以绑定到0或1。 | WARL | Preset |
nmip | 当设置时,表示有针对该硬件线程的不可屏蔽中断(NMI)挂起。 由于NMI可能指示硬件错误状况,一旦此位被设置,可靠的调试可能不再可能,这依赖于具体实现。 | R | 0 |
step | 当设置且不在调试模式时,硬件线程将仅执行一条指令,然后进入调试模式。详情请参阅4.4.1节。 调试器在硬件线程运行时不得更改此位的值。 | R/W | 0 |
prv | 包含硬件线程进入调试模式时所操作的特权模式。编码方式在表4.6中描述。调试器可以更改此值以在退出调试模式时改变硬件线程的特权模式。 并非所有特权模式在所有硬件线程上都受支持。如果所写入的编码不被支持,或者调试器不允许切换到该模式,硬件线程可能会切换到任何受支持的特权模式。 | WARL | 3 |
4.9.2 Debug PC (dpc, at 0x7b1)
在进入到调试模式的时候,那么下一条会被执行的虚拟地址就会被更新到 dpc中。
执行程序缓冲区可能会导致dpc的值变得不确定。如果出现这种情况,必须能够使用postexec未设置的抽象命令读取/写入dpc。调试器必须尝试在暂停和执行程序缓冲区之间保存dpc,然后在离开调试模式之前恢复dpc。
如果访问寄存器抽象命令支持在硬件线程运行时读取dpc,那么读取的值应该是最近执行过的指令的地址。
如果访问寄存器抽象命令支持在硬件线程运行时写入dpc,那么执行中的程序应在写入后不久跳转到所写入的地址。
dpc的可写性遵循Privileged Spec中定义的与mepc相同的规则。特别是,dpc必须能容纳所有有效的虚拟地址,而低位的可写性取决于IALIGN(Instruction Address Alignment)。
恢复执行时,硬件线程的PC会被更新为dpc中存储的虚拟地址。调试器可以通过写入dpc来改变硬件线程恢复执行的位置。
寄存器可读/写。
4.9.3-4 Debug Scratch Register (dscratch0-1, at 0x7b2-3)
可选的 scratch 寄存器可以被需要它的实现使用。除非在 hartinfo 中有明确提到他,否则调试器禁止写入这个寄存器。
4.10.1 Privilege Mode (priv, at virtual)
一个虚拟调试寄存器是那种硬件上不实际存在,但是调试器显示它是存在的。虚拟寄存器的存在是为了让用户能够访问标准调试器之外的功能,而无需在调试器访问相同的寄存器时仔细修改调试寄存器。调试软件需要实现它们,但是硬件可以跳过这个部分