Debug Module
- Version: V2R2
- Status: OK
- Date: 2025/01/20
- Commit: xxx
Terminology Description
Abbreviation | Full Name | Description |
---|---|---|
DM | Debug Module | Debug Module |
DTM | Debug Transport Module | Debug Transport Module |
DMI | Debug Module Interface | Debug Module Interface |
Parameter Design
Parameter | Default Value | Description |
---|---|---|
baseAddress | 0x38020800 | Debug Module MMIO Base Address |
nDMIAddrSize | 7 | DMI Address Width |
nProgramBufferWords | 16 | Number of Program Buffers |
nAbstractDataWords | 4 | Number of Abstract Commands |
hasBusMaster | true | System Bus Master |
maxSupportedSBAccess | 64 | Max System Bus Access Width |
supportQuickAccess | false | QuickAccess Support |
supportHartArray | true | Hart Array Support |
nHaltGroups | 1 | Number of Halt Groups |
nExtTriggers | 0 | Number of External Triggers |
hasHartResets | true | Resets selected harts |
hasImplicitEbreak | false | Implicit Ebreak Support |
Overall Design
Overall Block Diagram
As shown in 此图:
Multi-clock Domain
As shown in 此图:
Debug MMIO
As shown in 此表:
Address (Base Address 0x3802_0000) | Name | Description | Content stored at this address |
---|---|---|---|
0x800 | debugEntry | Debug entry address / Base address of debug rom | |
0x808 | debugException | Exception entry address when executing in dmode | |
0x100 | HALTED | hartid of the hart that entered dmode, Debug Module will get it | |
0x104 | GOING | whereto, eventually jumps to ABSTRACT for execution | |
0x108 | RESUMING | Executes dret | |
0x10c | EXCEPTION | ||
0x300 | WHERETO | Instruction stored at this address | Jump instruction generated by DM to jump to ABSTRACT |
0x380 | DATA | Base address of DATA (for ld/st) | Data exchange |
DATA-4*nProgBuf | PROGBUF | Address of progbuf0 | Instructions generated by DM (prepared before go) |
DATA-4 | IMPEBREAK | Implicit ebreak instruction | |
PROGBUF - 4* nAbstractInst | ABSTRACT | AbstractInstructions | Instructions generated by DM (prepared before go) |
0x400 | FLAGS | Base address for hartid corresponding flags. Each flag is 8bits. 0x400 represents the flag address for hartid=0 | Only the lowest two bits of this 8bits are valid. The second lowest bit indicates resume, the lowest bit indicates go. The address space is 1k, i.e., 0x400 -> (0x500-0x1) |
Module Design
Debug Module
The current implementation of Debug in Kunming Lake is as follows:
- Supports debugging from the first instruction, entering debug mode after CPU reset.
- Supports run control for single core and multi-core (selected cores) debugging, including halt, resume, and reset.
- Supports single-step debugging.
- Supports stopcount and stoptime.
- Supports software breakpoints (ebreak instruction), hardware breakpoints (trigger), and memory breakpoints (trigger).
- Supports GPR, CSR, and memory access, using both progbuf and sysbus access methods.
- Supports entering debug mode via debug interrupt (haltreq, haltgroup, halt-on-reset), trigger fire, ebreak, singlestep, critical error, etc.
Trigger Module
The current implementation of the Trigger Module in Kunming Lake is as follows:
- The debug-related CSRs currently implemented by the Kunming Lake Trigger Module are shown in the table below.
- The default number of triggers configured is 4 (user-configurable).
- Supports triggers for mcontrol6 type instructions and memory accesses.
- Supports match types equal to, greater than or equal to, and less than (vector access currently only supports equal type matching).
- Only supports address matching, not data matching.
- Only supports timing = before.
- Only supports chaining of one pair of triggers.
- To prevent secondary breakpoint exceptions from triggers, control via xSTATUS.xIE is supported.
- Supports software and hardware breakpoints and watchpoint debugging methods for the H extension.
- Supports memory access triggers for atomic instructions.
The following table describes the access granularity in the microarchitecture and the trigger matching granularity for memory access instructions currently supported by Kunming Lake: For scalar instructions and vector instructions that access elements by element granularity, the match types >=, =, < are supported; for other vector instructions, only match type = is supported. In addition, for vector memory access instructions, triggers fired by instructions with smaller element indices are handled (regardless of whether their trigger action is breakpoint or debug).
Instruction Type | Access Granularity | Trigger Matching Granularity |
---|---|---|
Scalar Memory Access Instructions | Instruction (element) | Checks element little-endian address, supports >=, =, < |
Atomic Memory Access (lr/sc) | Instruction (element) | Checks element little-endian address, supports >=, =, <; lr is treated as load, sc as store (regardless of success) |
Atomic Memory Access (amo) | Instruction (element) | Checks element little-endian address, supports >=, =, <; Checks both load and store when vaddr is available |
Vector Memory Access (unit-stride) | Vector Register Width (128bit) | Supports checking any address within the access range of the instruction (at 8-bit granularity), but only supports = match |
Vector Memory Access (whole) | Vector Register Width (128bit) | Supports checking any address within the access range of the instruction (at 8-bit granularity), but only supports = match |
Vector Memory Access (fof unit-stride) | Vector Register Width (128bit) | Supports checking any address within the access range of the instruction (at 8-bit granularity), but only supports element 0 = match |
Vector Memory Access (segment) | Element | Checks each element's little-endian address, but only supports = match |
Other Vector Memory Access | Element | Checks each element's little-endian address, supports >=, =, < |
Name | Address | Read/Write | Description | Reset Value |
---|---|---|---|---|
Tselect | 0x7A0 | RW | Trigger Select Register | 0X0 |
Tdata1(Mcontrol6) | 0x7A1 | RW | Trigger Data1 | 0xF0000000000000000 |
Tdata2 | 0x7A2 | RW | Trigger Data2 | 0x0 |
Tinfo | 0x7A4 | RO | Trigger Info | 0x40 |
Dcsr | 0x7B0 | RW | Debug Control and Status | 0x40000003 |
Dpc | 0x7B1 | RW | Debug PC | 0x0 |
Dscratch0 | 0x7B2 | RW | Debug Scratch Register 0 | - |
Dscratch1 | 0x7B3 | RW | Debug Scratch Register 1 | |
mcontext | 0x7A8 | RW | Machine Context | - |
hcontext | 0x6A8 | RW | Hypervisor Context | - |
scontext | 0x5A8 | RW | Supervisor Context | - |
Debug Flow Examples
CSR Access:
Debug Module CSR access is accomplished through the cooperation of abstract commands and progbuff. According to the abstract command, corresponding instructions will be generated at the ABSTRACT and PROGBUFF addresses respectively (these two address spaces are contiguous) for the CPU to execute, achieving the purpose of accessing CSRs. The instructions generated at ABSTRACT are lw/st instructions, which perform data exchange between the MMIO address and GPR s0/s1. The instructions generated at PROGBUFF are CSR read/write instructions. Below is an example illustrating how the Debug Module accesses the mstatus register:
- Assume the software issues a command to write the mstatus CSR. This command will sequentially pass through JtagProbe, JtagDTM, DMI, and be converted into DMI operations.
- The DMI operations, via dmi2tl, modify the internal control signals of the Debug Module, changing DMI_COMMAND to the command for writing the mstatus register.
- OpenOCD first reads the value of s0/fp and saves it, then writes the CSR write instruction to the progbuffer.
- Execute ABSTRACT (ld instruction), writing DATA to s0.
-
Execute progbuffer (CSR write instruction). Progbuff ends with an ebreak instruction, re-entering the parking loop.
If it's a read CSR operation: 6. Execute progbuffer (CSR read instruction), reading the CSR value into s0. 7. Execute ABSTRACT (st instruction), writing s0 to DATA.
Hardware Breakpoint:
The following content takes setting a breakpoint as an example to illustrate the collaborative workflow between software and hardware during debugging:
- First, the software issues a halt command. This command sequentially passes through JtagProbe, JtagDTM, DMI, and is converted into DMI operations.
- The DMI operations, via dmi2tl, modify the internal control signals of the Debug Module, sending an external debug interrupt to the hart. This interrupt is eventually transmitted to the CSR module inside the hart.
- The CSR handles the external debug interrupt: the hart will Trap to the Debug Module's entry address (see Debug Module MMIO) and enter DMode.
- After the Hart enters DMode, it executes instructions in the debug ROM. It will write its hartid to HALTED (see Section 8 Debug ROM), notifying the Debug Module that it (the hart) has entered dmode and can now be debugged by the Debugger in Dmode.
- When the software issues a command to set a hardware breakpoint, the hart will jump to whereto. Abstract and progbuff cooperate to control the hart to execute CSR instructions (progbuffer) to configure the trigger CSR register, writing the breakpoint information into the trigger CSR. Progbuff ends with an ebreak instruction. Executing this ebreak will cause it to jump back to the Debug Module's entry address.
- The software issues a resume command. The hart will jump to _resume to execute the dret instruction, exiting dMode and returning to resume execution where it was before halting at step 1. (There is preparatory work before resuming: it needs to execute a step first, committing only one instruction, and then trap to debugMode via a single-step exception. You can look at the OpenOCD source code for this.)
- When the hart executes the program and reaches the breakpoint location, the instruction's pc matches the breakpoint address configured in the trigger CSR. The trigger fires, and the hart will enter dmode again (Trap to the Debug Module's entry address) to execute instructions in the debug ROM, waiting for the debugger to debug.