Five EmbedDev logo Five EmbedDev

An Embedded RISC-V Blog
RISC-V External Debug Support

5 RISC-V Debug

Modifications to the RISC-V core to support debug are kept to a minimum. There is a special execution mode (Debug Mode) and a few extra CSRs. The DM takes care of the rest.

In order to be compliant with this specification an implementation must implement everything described in this section that is not explicitly listed as optional.

5.1 Debug Mode

Debug Mode is a special processor mode used only when a hart is halted for external debugging. Because the hart is halted, there is no forward progress in the normal instruction stream. How Debug Mode is implemented is not specified here.

When executing code due to an abstract command, the hart stays in Debug Mode and the following apply:

All operations are executed at machine mode privilege level, except that in may be ignored according to .

All interrupts (including NMI) are masked.

Exceptions don’t update any registers. That includes cause, epc, tval, dpc, and . They do end execution of the Program Buffer.

No action is taken if a trigger matches.

If is 0 then counters continue. If it is 1 then counters are stopped.

If is 0 then timers continue. If it is 1 then timers are stopped.

The wfi instruction acts as a nop.

Almost all instructions that change the privilege level have undefined behavior. This includes ecall, mret, sret, and uret. (To change the privilege level, the debugger can write in ). The only exception is ebreak, which ends execution of the Program Buffer when executed.

[fence] Completing Program Buffer execution is considered output for the purpose of fence instructions.

All control transfer instructions may act as illegal instructions if their destination is in the Program Buffer. If one such instruction acts as an illegal instruction, all such instructions must act as illegal instructions.

All control transfer instructions may act as illegal instructions if their destination is outside the Program Buffer. If one such instruction acts as an illegal instruction, all such instructions must act as illegal instructions.

Instructions that depend on the value of the PC (e.g. auipc) may act as illegal instructions.

Effective XLEN is DXLEN.

Forward progress is guaranteed.

In general, the debugger is expected to be able to simulate all the effects of . The exception is the case of Sv32 systems, which need functionality in order to access 34-bit physical addresses. Other systems are likely to tie to 0.

5.2 Load-Reserved/Store-Conditional Instructions

The reservation registered by an lr instruction on a memory address may be lost when entering Debug Mode or while in Debug Mode. This means that there may be no forward progress if Debug Mode is entered between lr and sc pairs.

This is a behavior that debug users must be aware of. If they have a breakpoint set between a lr and sc pair, or are stepping through such code, the sc may never succeed. Fortunately in general use there will be very few instructions in such a sequence, and anybody debugging it will quickly notice that the reservation is not occurring. The solution in that case is to set a breakpoint on the first instruction after the sc and run to it. A higher level debugger may choose to automate this.

5.3 Wait for Interrupt Instruction

If halt is requested while wfi is executing, then the hart must leave the stalled state, completing this instruction’s execution, and then enter Debug Mode.

5.4 Single Step

5.4.1 Step Bit In Dcsr

This method is only available to external debuggers, and is the preferred way to single step.

An external debugger can cause a halted hart to execute a single instruction or trap and then re-enter Debug Mode by setting before setting .

If control is transferred to a trap handler while executing the instruction, then Debug Mode is re-entered immediately after the PC is changed to the trap handler, and the appropriate tval and cause registers are updated. In this case none of the trap handler is executed, and if the cause was a pending interrupt no instructions might be executed at all.

If executing or fetching the instruction causes a trigger to fire, Debug Mode is re-entered immediately after that trigger has fired. In that case is set to 2 (trigger) instead of 4 (single step). Whether the instruction is executed or not depends on the specific configuration of the trigger.

If the instruction that is executed causes the PC to change to an address where an instruction fetch causes an exception, that exception does not occur until the next time the hart is resumed. Similarly, a trigger at the new address does not fire until the hart actually attempts to execute that instruction.

If the instruction being stepped over is wfi and would normally stall the hart, then instead the instruction is treated as nop.

5.4.2 Icount Trigger

Native debuggers won’t have access to , but can use the trigger by setting to 1.

This approach does have some limitations:

Interrupts will fire as usual. Debuggers that want to disable interrupts while stepping must disable them by changing , and specially handle instructions that read .

wfi instructions are not treated specially and might take a very long time to complete.

5.5 Reset

If the halt signal (driven by the hart’s halt request bit in the Debug Module) or are asserted when a hart comes out of reset, the hart must enter Debug Mode before executing any instructions, but after performing any initialization that would usually happen before the first instruction is executed.

5.6 Resume

When a hart resumes:

changes to the value stored in .

The current privilege mode is changed to that specified by .

If the new privilege mode is less privileged than M mode, in is cleared.

The hart is no longer in debug mode.

5.7 dret Instruction

To return from Debug Mode, a new instruction is defined: dret. It has an encoding of 0x7b200073. On harts which support this instruction, executing dret in Debug Mode cause the hart to resume as described above.

Executing dret outside of Debug Mode causes an illegal instruction exception.

It is not necessary for the debugger to know whether an implementation supports dret, as the Debug Module will ensure that it is executed if necessary. It is defined in this specification only to reserve the opcode and allow for reusable Debug Module implementations.

5.8 XLEN

While in Debug Mode, XLEN is DXLEN. It is up to the debugger to determine the XLEN during normal program execution (by looking at ) and to clearly communicate this to the user.

5.9 Core Debug Registers

The supported Core Debug Registers must be implemented for each hart that can be debugged. They are CSRs, accessible using the RISC-V csr opcodes and optionally also using abstract debug commands.


5.10 Virtual Debug Registers