RISC-V Debug协议解读

此文对RISC-V Debug协议做一个简单的介绍,具体的内容,大家可以查看协议本身内容。
https://github.com/riscv/riscv-debug-spec/blob/master/riscv-debug-stable.pdf

介绍是按目录结构进行的。

1 Introduction

  1. All hart registers (including CSRs) can be read/written.
  2. Memory can be accessed either from the hart’s point of view, through the system bus directly, or both.
  3. RV32, RV64, and future RV128 are all supported.
  4. Any hart in the hardware platform can be independently debugged.
  5. A debugger can discover almost everything it needs to know itself, without user configuration.
  6. Each hart can be debugged from the very first instruction executed.
  7. A RISC-V hart can be halted when a software breakpoint instruction is executed.
  8. Hardware single-step can execute one instruction at a time.
  9. Debug functionality is independent of the debug transport used.
  10. The debugger does not need to know anything about the microarchitecture of the harts it is debugging.
  11. Arbitrary subsets of harts can be halted and resumed simultaneously. (Optional)
  12. Arbitrary instructions can be executed on a halted hart. That means no new debug functionality is needed when a core has additional or custom instructions or state, as long as there exist programs that can move that state into GPRs. (Optional)
  13. Registers can be accessed without halting. (Optional)
  14. A running hart can be directed to execute a short sequence of instructions, with little overhead. (Optional)
  15. A system bus master allows memory access without involving any hart. (Optional)
  16. A RISC-V hart can be halted when a trigger matches the PC, read/write address/data, or an instruction opcode. (Optional)
  17. Harts can be grouped, and harts in the same group will all halt when any of them halts. These groups can also react to or notify external triggers. (Optional)

RISC-V Debug协议主要支持的特性就上面17点,有些是必须实现的,有些事可选的。

2 System Overview

系统总体框架:
在这里插入图片描述

重要的内容有:

  1. The user interacts with the Debug Host (e.g. laptop), which is running a debugger (e.g. gdb). (软件层面)
  2. The debugger communicates with a Debug Translator (e.g. OpenOCD, which may include a hardware driver) to communicate with Debug Transport Hardware (e.g. Olimex USB-JTAG adapter). (OpenOCD为软件,Olimex USB-JTAG adapter为硬件驱动)
  3. The Debug Transport Hardware connects the Debug Host to the Platform’s Debug Transport Module (DTM). (硬件底层接收模块,例如JTAG信号的接收和处理)
  4. The DTM provides access to one or more Debug Modules (DMs) using the Debug Module Interface (DMI). (接口,例如JTAG2TileLink,JTAG2AHB,一边是DTM的硬件接口,接收host的信号,一边是驱动DM模块的总线接口,驱动DM模块的总线接口由系统自行决定,可以是ABH、AXI4、TileLink或者其他简单的接口)

3 Debug Module (DM), non-ISA

  1. Give the debugger necessary information about the implementation. (Required)
  2. Allow any individual hart to be halted and resumed. (Required)
  3. Provide status on which harts are halted. (Required)
  4. Provide abstract read and write access to a halted hart’s GPRs. (Required)
  5. Provide access to a reset signal that allows debugging from the very first instruction after
    reset. (Required)
  6. Provide a mechanism to allow debugging harts immediately out of reset (regardless of the
    reset cause). (Optional)
  7. Provide abstract access to non-GPR hart registers. (Optional)
  8. Provide a Program Buffer to force the hart to execute arbitrary instructions. (Optional)
  9. Allow multiple harts to be halted, resumed, and/or reset at the same time. (Optional)
  10. Allow memory access from a hart’s point of view. (Optional)
  11. Allow direct System Bus Access. (Optional)
  12. Group harts. When any hart in the group halts, they all halt. (Optional)
  13. Respond to external triggers by halting each hart in a configured group. (Optional)
  14. Signal an external trigger when a hart in a group halts. (Optional)

In order to be compliant with this specification an implementation must:

  1. Implement all the required features listed above.
  2. Implement at least one of Program Buffer, System Bus Access, or Abstract Access Memory
    command mechanisms.
  3. Do at least one of:
    a. Implement the Program Buffer.
    b. Implement abstract access to all registers that are visible to software running on the hart including all the registers that are present on the hart and listed in Table 3.3.
    c. Implement abstract access to at least all GPRs, dcsr, and dpc, and advertise the implementation as conforming to the “Minimal RISC-V Debug Specification 1.0.0-STABLE”, instead of the “RISC-V Debug Specification 1.0.0-STABLE”.

简单总结:
DM模块接收到抽象调试操作后,会将它转为具体的实现行为。
必须实现下面几点内容。

  1. 向调试者提供有关实现的必要信息,例如支持调试协议的版本号等。
  2. 允许停止和恢复任何单个hart,hart可以理解为就是单个CPU。
  3. 提供停止hart的状态。
  4. 提供对hart GPRs(General Purpose Register)的抽象读写访问,既可以访问通用寄存器。
  5. 提供对复位信号的访问,允许从复位后的第一条指令开始调试,既允许调试者复位hart,有时候不单是复位hart,复位整个系统也是有可能,具体内容看协议,这要看具体设计的实现。

没有说明的,就自己去看协议,谢谢。

3.2 Reset Control

这里说明了DM、DTM和系统的复位关系:

  1. DM模块中存在一个全局复位控制信号,可以用于复位除DM模块和DTM模块外的其他所有模块。
  2. DM模块的复位是采用上电,或者置dmcontrol寄存器中的dmactive位为0。
  3. 在使用DM模块期间,需要将dmcontrol寄存器中的dmactive位置1。
  4. 假设DTM模块采用的是JTAG的方式,那么DTM模块的复位右JTAG协议决定,不受第一点的全局复位信号控制。
  5. 全局复位信号使能后,平台代码需要从第一行重新开始运行。
  6. 后面会提到trigger模式,可以采用trigger模式来使系统进入debug模式,DM模式也能使系统进入debug模式。但trigger模式和DM模式是两个不同的功能模式,它们是独立实现的,两者互不关系。在使用DM模式时trigger模式不会生效。trigger模式后面再作说明。当dmcontrol寄存器中的dmactive位为1时,且当前系统处在暂停的情况,那么进行系统复位后,各harts仍需要维持暂停的状态,此时各harts内部的触发CSRs会被清除。

3.3 Selecting Harts

3.4 Hart States

3.5 Running Control

DM模块有4bits用于控制hart:halt request, resume ack, halt-on-reset request, and hart reset。

暂停请求,恢复应答,复位后暂停的请求,复位请求。halt-on-reset request and hart reset作为可选支持。

  1. halt request:当一个正在运行的hart,或一个刚退出复位的hart,halt request为1时,它会进入暂停状态。当hart本来就是暂停的状态,那么忽略halt request的请求.
  2. resumereq:用于恢复已经暂停的hart,清除hart暂停的相关状态。如果hart本来就存于运行的状态,那么忽略resumereq的请求。
  3. halt-on-reset request:在下次reset后,暂停hart,并进入debug mode。置setresethaltreq 为1生效,置clrresethaltreq 为1清除。因为是可选的功能,如果hasresethaltreq 为1,那么证明,DM模块存在setresethaltreq bit和clrresethaltreq bit。

3.6 Halt Groups, Resume Groups, and External Triggers

3.7 Abstract Commands

抽象指令就是上面说到的抽象调试操作,是由JTAG2XXX来完成的,分为3种操作。
在这里插入图片描述

Access Register

This command gives the debugger access to CPU registers and allows it to execute the Program Buffer. It performs the following sequence of operations:

  1. If write is clear and transfer is set, then copy data from the register specified by regno into the arg0 region of data, and perform any side effects that occur when this register is read from M-mode.
  2. If write is set and transfer is set, then copy data from the arg0 region of data into the register specified by regno, and perform any side effects that occur when this register is written from M-mode.
  3. If aarpostincrement is set, increment regno.
  4. Execute the Program Buffer, if postexec is set.
  • write为0,transfer为1,则读regno对应寄存器的值到data。
  • write为1,transfer为1,则将data的值写到regno对应的寄存器中。
  • aarpostincrement为1的话,完成1/2操作后,regno的寄存器编号自动加1。
  • 如果postexec为1的话,执行 Program Buffffer的指令。

DM模块必须实现Access Register的功能,并且必须支持在所选hart停止时对所有GPRs的读写访问。DM模块可以选择支持访问其他寄存器,或在hart运行时访问寄存器。每个单独的寄存器(除GPRs之外)在读、写和停止状态下可能得到不同的支持。

CSRs,control status registers,在基础指令集和特权指令集中有定义。
GPRs,cpu的通用寄存器,一般是31个,寄存器0固定为0,位宽视CPU而定。

Abstract Command (command, at 0x17) 的低24位内容介绍。
在这里插入图片描述

  • cmdtype,抽象命令的类型。 0:Access Register Command ;1:Quick Access ;2:Access Memory Command 。
  • aasize,指示读写访问寄存器的位宽长度。
  • aarpostincrement,在寄存器成功访问后,regno中的寄存器编号自动加1,超过后绕回至0。
  • postexec,如果transfer为1时,且postexec也为1,那么执行一次程序缓冲区中的代码。
  • transfer,结合postexec或write位完成一次传输操作。这个位可以用于仅仅执行程序缓冲区,而不必担心将有效的值放到aarsize或regno中。与write位结合能完成寄存器读写访问,与postexec位结合能完成program buffer的运行。
  • write,寄存器读写访问的指示。0:读操作;1:写操作。
  • regno,想访问的寄存器的具体编号。参照表格3.3的内容。

Quick Access

  1. If the hart is halted, the command sets cmderr to “halt/resume” and does not continue.
  2. Halt the hart. If the hart halts for some other reason (e.g. breakpoint), the command sets cmderr to “halt/resume” and does not continue.
  3. Execute the Program Buffer. If an exception occurs, cmderr is set to “exception” and the program buffer execution ends, but the quick access command continues.
  4. Resume the hart.

运行Quick Access命令时,按以下操作顺序执行:

  1. 如果hart已经被暂停,那么Quick Access命令会置cmderr为“halt/resume”,并不再继续。
  2. 暂停hart。如果是因为其他原因(例如断点),么Quick Access命令会置cmderr为“halt/resume”,并不再继续。
  3. 执行Program Buffer的内容。如果运行期间产生异常,那么Quick Access命令会置cmderr为“exception”,program buffer程序运行结束,但Quick Access命令继续。
  4. 恢复hart。

我理解的Quick Access命令是这样的:

  1. 如果hart已经暂停了,那么运行Quick Access命令,还是一样没有变化,还是处在暂停。
  2. hart在运行期间,调试人员想hart停在某个地方,因此在那个地方设定了一个断点,然后运行Quick Access命令让hart执行断点的操作。
  3. hart在运行期间,调试人员想对某个通用寄存器/某个CSR寄存器/某个地址的值进行读写操作,那么在program buffer中编好程序后运行Quick Access命令,hart会运行program buffer中程序,运行完后hart不会停,继续运行hart本来的程序。

总结:Quick Access命令是动态调试hart的手段,在不暂停hart的情况下进行断点设置或者动态改变某些值

Access Memory
此命令允许调试器执行内存访问,并且与所选hart具有完全相同的内存映射和权限。这包括访问hart本地内存映射的寄存器等。该命令执行以下操作顺序:

  1. 如果write为0,则将数据从arg1中指定的内存位置复制到arg0中。
  2. 如果write为1,则将数据从arg0中复制到arg1中指定的存储器位置。
  3. 如果aampostincrement为1,则arg1的存储器地址增加。

如果这些操作失败,则设置cmderr,并且不执行任何其余步骤。

调试模块可以可选择地支持此命令,并可以支持所选hart在运行或停止时对内存位置的读写访问。如果此命令支持hart运行时的内存访问,则还必须hart在停止时的内存访问。

此命令仅在读取内存时修改arg0。只有在aampostincrement为1时,它才会修改arg1。其他的数据寄存器没有被更改。
在这里插入图片描述

  • aamvirtual:是否使用虚拟内存转换。0:物理地址;1:虚拟地址,需要经过转换。
  • target-specific:保留。

其他的在前面已经说明过了。

3.8 Program Buffer

为了支持在停止的hart上执行任意指令,DM模块可以包含一个Program Buffer,用于编写小程序。Program Buffer与Abstract Command 是不冲突的,两者不一样。

Program Buffer就是为了实现写一段小程序进行debug的作用。

调试者可以将一个小程序写入Program Buffer,然后使用Access Register Abstract Command,置postexec bit为1,则能精确地执行Program Buffer的程序一次。调试者可以编写任何它喜欢的程序(包括跳出程序缓冲区),但程序必须以ebreak或c.ebreak结束。可以实现当hart执行完Program Buffer的程序,并离开Program Buffer时产生隐性的ebreak。可以使用impebreak来指示这个操作。如果实现了此特性,那么只需要2个32-bit的Program Buffer就能提供有效的调试。

如果progbufsize大小1, 那么impebreak必须也为1。此时Program Buffer可能只能容纳一个32位或16位的指令,因此在这种情况下,调试者必须只能编写一条指令,无论其大小如何。该指令可以是32位的指令,或者是低16位的压缩指令和高16位nop的组合。

在执行这些程序时,hart不会离开调试模式(请参见第4.1节)。如果在执行Program Buffer的过程中遇到异常,则不再执行其他指令,硬件将继续处于调试模式,但会将cmderr设置为3(异常错误)。如果调试者执行的程序不以ebreak指令终止,hart将保持在调试模式,不然调试者会失去对hart的控制。

执行Program Buffer可能会导致dpc阻塞。如果是这样的情况,必须使用postexec 为0的Abstract Command对dpc进行读/写访问。调试者必须尝试在hart停止和hart执行Program Buffer之间保存dpc,然后在离开调试模式之前恢复dpc。

Program Buffer可以采用RAM来实现。调试者可以通过执行Program Buffer时,看PC地址是否试图被读取或者改写来判定。如果是这样,调试者在处理Program Buffer方面具有更大的灵活性。

3.9 Overview of States

3.10 System Bus Access

调试模块还可以包括系统总线访问块,以在不涉及hart的情况下提供内存访问,无论是否实现了程序缓冲区。系统总线访问块使用物理地址。

System Bus Access的目的是为了绕过CPU,进行总线的访问。因为无论Program Buffer还是Abstract Command,都是CPU来帮我们执行的,然后得到相应的结果,而System Bus Access则不需要CPU的参与,直接使用总线的权限。

系统总线访问块可以支持8位、16位、32位、64位和128位的访问。下表显示了每次访问大小中使用sbdata的位宽。

根据微架构的不同,通过系统总线访问访问的数据可能并不总是与每一个hart观察到的数据相一致。如果实现不具有一致性,则由调试者来强制执行一致性。本规范没有定义实现这样做的标准方法。可能包括写入特殊的内存映射位置,或通过程序缓冲区执行特殊的指令。

即使调试模块也实现了程序缓冲区,但实现系统总线访问块也有几个好处。首先,可以在影响最小的运行系统中访问内存。第二,它可以提高访问内存时的性能。第三,它可以提供对hart无法访问的设备的访问。

3.11 Minimally Intrusive Debugging

3.12 Security

3.13 Version Detection

3.14 Debug Module Registers

4 RISC-V Debug, ISA

主要说明进入Debug Mode后,hart(CPU)的一些内部情况。

相对于特权指令集中的user/supervisor/machine mode,是一个特殊的模式。

进入debug mode的方式很多种,可以通过:

  1. 外部debug模块(JTAG,DMI,DTM和DM)。
  2. 硬件断点(breakpoint)。
  3. 触发模块(Trigger Module)。
  4. 特殊指令(ebreak)。
  5. Debug Control and Status (dcsr) CSR (0x7b0)寄存器的step bit。

进入Debug Mode后,有一些特殊的CSR寄存器(具体内容看协议):
在这里插入图片描述

5 Trigger Module, ISA

Triggers can cause a breakpoint exception, entry into Debug Mode, or a trace action without having to execute a special instruction. This makes them invaluable when debugging code from ROM. They can trigger on execution of instructions at a given memory address, or on the address/data in loads/stores. These are all features that can be useful without having the Debug Module present, so the Trigger Module is broken out as a piece that can be implemented separately.

Trigger Module指的是在hart运行期间,设置了某些触发条件,如果符合条件则会使hart进入Debug Mode,例如breakpoint就是其中一种方式。

6 Debug Transport Module (DTM), non-ISA

JTAG内容的介绍,最主要的是JTAG DTM Registers 介绍。

A Hardware Implementations

A.3 Debug Module Interface Signals是DMI接口的建议。

B Debugger Implementation

调试实现用例,包括了:
B.3 Halting
B.4 Running
B.5 Single Step
B.6 Accessing Registers
B.7 Reading Memory
B.8 Writing Memory
B.9 Triggers
B.10 Handling Exceptions
B.11 Quick Access
这里包括了所有我们可能用的一些实例,在理解协议的基础上,帮助我们去实现调试。

C Change Log

最后简单说一下rocket-chip项目是怎么用起Debug协议内容的。
在vsim目录是可以跑VCS仿真的,抛开编译过程,在跑仿真过程中,实际上很大部分时间是通过SimDTM模块将我们编译出来的elf慢慢搬移到SRAM中,最后搬完汇编指令后,再将PC指向我们真正的程序开端,然后开始运行我们的程序。
在SimDTM模块(VCS DPI接口,利用C语言进行编写,将汇编指令转为DMI接口,并驱动DM模块)搬汇编指令的过程中,就用到了Debug协议的内容。
下面我们来看一下跑出来的仿真波形。

启动开始时刻:
在这里插入图片描述
代码搬移过程:
在这里插入图片描述
debug协议运行的过程:
在这里插入图片描述

Trigger Module和BreakPoint的实例这里面是没有的,下次再展示。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值