Debug Module

Overview

The debug module implements a subset of the RISC-V Debug Specification, providing external debug support for the Kelvin core. It allows a debugger to halt, resume, and single-step the core, as well as read and write core registers and memory.

Architecture

The debug module is a standalone module that connects to the core via a dedicated debug interface. It communicates with an external debugger through a simple request/response protocol.

The following diagram illustrates the high-level architecture of the debug module:

Debug Module Architecture

Interfaces

The following table describes the internal hardware interfaces of the debug module:

NameDirectionTypeWidthDescription
ext.reqInputDecoupledExternal debugger request.
validBool1The request is valid.
readyBool1The module is ready for a request.
bitsDebugModuleReqIOThe request payload.
addressUInt32The address of the register to access.
dataUInt32The data to write.
opDmReqOp2The operation to perform (NOP, READ, WRITE).
ext.rspOutputDecoupledExternal debugger response.
validBool1The response is valid.
readyBool1The debugger is ready for a response.
bitsDebugModuleRspIOThe response payload.
dataUInt32The data read from the register.
opDmRspOp2The result of the operation (SUCCESS, FAILED, BUSY).
csrOutputValidCSR command.
validBool1The command is valid.
bitsCsrCmdThe command payload.
csr_rdInputValidCSR read data.
validBool1The read data is valid.
bitsUInt32The read data.
scalar_rdOutputDecoupledScalar register file write command.
validBool1The write command is valid.
readyBool1The register file is ready.
bitsRegfileWriteDataIOThe write command payload.
scalar_rsBundleScalar register file read interface.
idxOutputUInt5Scalar register file read address.
dataInputUInt32Scalar register file read data.
float_rdOutputValidFloating-point register file write command.
validBool1The write command is valid.
bitsFRegfileWriteThe write command payload.
float_rsBundleFloating-point register file read interface.
validInputBool1Floating-point register file read valid.
addrInputUInt5Floating-point register file read address.
dataInputUInt32Floating-point register file read data.
haltreqOutputBool1Request to halt the core.
resumereqOutputBool1Request to resume the core.
resumeackInputBool1Core has resumed.
ndmresetOutputBool1Reset the debug module.
haltedInputBool1Core is halted.
runningInputBool1Core is running.
haveresetInputBool1Core has been reset.

Command Protocol

An external debugger communicates with the debug module by reading and writing a set of memory-mapped Control and Status Registers (CSRs) over the AXI interface. These CSRs provide a communication channel to the debug module's internal registers.

Write Operation

To write to an internal debug module register (e.g., writing 0x1 to dmcontrol at address 0x10):

  1. Poll for readiness: Read the status CSR at 0x31014 and wait for bit 0 to be 1.
  2. Set address: Write the target internal register address (0x10) to the req_addr CSR at 0x31000.
  3. Set data: Write the data (0x1) to the req_data CSR at 0x31004.
  4. Initiate write: Write the WRITE operation code (2) to the req_op CSR at 0x31008.
  5. Poll for response: Read the status CSR at 0x31014 and wait for bit 1 to be 1.
  6. Check status: Read the rsp_op CSR at 0x31010 to confirm the operation was successful.
  7. Acknowledge response: Write to the status CSR at 0x31014 to clear the response.

Read Operation

To read from an internal debug module register (e.g., reading from dmstatus at address 0x11):

  1. Poll for readiness: Read the status CSR at 0x31014 and wait for bit 0 to be 1.
  2. Set address: Write the target internal register address (0x11) to the req_addr CSR at 0x31000.
  3. Initiate read: Write the READ operation code (1) to the req_op CSR at 0x31008.
  4. Poll for response: Read the status CSR at 0x31014 and wait for bit 1 to be 1.
  5. Check status: Read the rsp_op CSR at 0x31010 to confirm the operation was successful.
  6. Read data: Read the result from the rsp_data CSR at 0x3100c.
  7. Acknowledge response: Write to the status CSR at 0x31014 to clear the response.

AXI CSR Interface

These registers are mapped into the Kelvin CSR address space and are used to communicate with the debug module.

AddressNameDescription
0x30800req_addrWrite the target debug module register address here.
0x30804req_dataWrite data for the debug module operation here.
0x30808req_opWrite the operation type (e.g., READ, WRITE) to this register to initiate a debug module command.
0x3080crsp_dataAfter a command completes, the data result is available here.
0x30810rsp_opAfter a command completes, the status result (e.g., SUCCESS, FAILED) is available here.
0x30814statusA read-only register to check the status of the debug module. Bit 0 indicates if the module is ready for a new request. Bit 1 indicates if a response is available.

Internal Debug Module Registers

The debug module implements a set of internal registers that are accessible to an external debugger via the AXI CSR interface. These registers are used to control and monitor the core.

AddressNameDescription
0x04data0Data register for abstract commands.
0x10dmcontrolDebug module control register.
0x11dmstatusDebug module status register.
0x12hartinfoHart information register.
0x16abstractcsAbstract command status register.
0x17commandAbstract command register.

dmcontrol (0x10)

The dmcontrol register is used to control the debug module and the core.

BitsNameDescription
31haltreqRequest to halt the core.
30resumereqRequest to resume the core.
29:2reservedReserved for future use.
1ndmresetReset the debug module.
0dmactiveActivate the debug module.

dmstatus (0x11)

The dmstatus register provides the status of the debug module and the core.

BitsNameDescription
11allrunningAll harts are running.
10anyrunningAny hart is running.
9allhaltedAll harts are halted.
8anyhaltedAny hart is halted.
7:4reservedReserved for future use.
3:0versionDebug module version.

abstractcs (0x16)

The abstractcs register provides the status of abstract commands.

BitsNameDescription
12busyThe abstract command is currently executing.
11reservedReserved for future use.
10:8cmderrAbstract command error code.
7:0reservedReserved for future use.

command (0x17)

The command register is used to issue abstract commands to the core.

BitsNameDescription
31:24cmdtypeThe type of abstract command.
23:0controlCommand-specific control information.

Abstract Commands

Abstract commands are used to perform complex operations on the core, such as reading and writing registers.

To issue an abstract command, the debugger writes to the command register. The cmdtype field specifies the type of command, and the control field contains command-specific information.

Access Register Command (cmdtype=0)

The Access Register command is used to read and write core registers.

The control field for the Access Register command is formatted as follows:

BitsNameDescription
16write1 for a write, 0 for a read.
15:0regnoThe number of the register to access.

The register numbers are defined as follows:

  • 0x0000-0x0FFF: CSRs
  • 0x1000-0x101F: Scalar GPRs
  • 0x1020-0x103F: Floating-point GPRs

Command Examples

Reading a GPR (a0)

  1. Issue the read command: Write to the command register (address 0x17) with the following value:
    • cmdtype (bits 31:24): 0x0 (Access Register)
    • write (bit 16): 0 (read)
    • regno (bits 15:0): 0x100A (for a0)
  2. Wait for completion: Poll the abstractcs register (address 0x16) until the busy bit (bit 12) is cleared.
  3. Check for errors: Read the abstractcs register again and check that the cmderr field (bits 10:8) is 0.
  4. Read the result: If there are no errors, read the value of GPR a0 from the data0 register (address 0x04).

Writing a GPR (a0)

  1. Write the value: Write the desired value for GPR a0 to the data0 register (address 0x04).
  2. Issue the write command: Write to the command register (address 0x17) with the following value:
    • cmdtype (bits 31:24): 0x0 (Access Register)
    • write (bit 16): 1 (write)
    • regno (bits 15:0): 0x100A (for a0)
  3. Wait for completion: Poll the abstractcs register (address 0x16) until the busy bit (bit 12) is cleared.
  4. Check for errors: Read the abstractcs register again and check that the cmderr field (bits 10:8) is 0.