Debug & Trigger

CV32E40P offers support for execution-based debug according to the RISC-V Debug Specification, version 0.13.2. The main requirements for the core are described in Chapter 4: RISC-V Debug, Chapter 5: Trigger Module, and Appendix A.2: Execution Based.

The following list shows the simplified overview of events that occur in the core when debug is requested:

  1. Enters Debug Mode

  2. Saves the PC to DPC

  3. Updates the cause in the DCSR

  4. Points the PC to the location determined by the input port dm_haltaddr_i

  5. Begins executing debug control code.

Debug Mode can be entered by one of the following conditions:

  • External debug event using the debug_req_i signal

  • Trigger Module match event

  • ebreak instruction when not in Debug Mode and when DCSR.EBREAKM == 1 (see EBREAK Behavior below)

A user wishing to perform an abstract access, whereby the user can observe or control a core’s GPR (either integer of floating-point one) or CSR register from the hart, is done by invoking debug control code to move values to and from internal registers to an externally addressable Debug Module (DM). Using this execution-based debug allows for the reduction of the overall number of debug interface signals.

Note

Debug support in CV32E40P is only one of the components needed to build a System on Chip design with run-control debug support (think “the ability to attach GDB to a core over JTAG”). Additionally, a Debug Module and a Debug Transport Module, compliant with the RISC-V Debug Specification, are needed.

A supported open source implementation of these building blocks can be found in the RISC-V Debug Support for PULP Cores IP block.

The CV3240P also supports a Trigger Module to enable entry into Debug Mode on a trigger event with the following features:

  • Number of trigger register(s) : 1

  • Supported trigger types: instruction address match (Match Control)

The CV32E40P will not support the optional debug features 10, 11, & 12 listed in Section 4.1 of the RISC-V Debug Specification. Specifically, a control transfer instruction’s destination location being in or out of the Program Buffer and instructions depending on PC value shall not cause an illegal instruction.

Debug Interface

Table 62 Debug interface signals

Signal

Direction

Description

debug_req_i

input

Request to enter Debug Mode

debug_havereset_o

output

Debug status: Core has been reset

debug_running_o

output

Debug status: Core is running

debug_halted_o

output

Debug status: Core is halted

dm_halt_addr_i[31:0]

input

Address for debugger entry

dm_exception_addr_i[31:0]

input

Address for debugger exception entry

debug_req_i is the “debug interrupt”, issued by the debug module when the core should enter Debug Mode. The debug_req_i is synchronous to clk_i and requires a minimum assertion of one clock period to enter Debug Mode. The instruction being decoded during the same cycle that debug_req_i is first asserted shall not be executed before entering Debug Mode.

debug_havereset_o, debug_running_o and debug_mode_o signals provide the operational status of the core to the debug module. The assertion of these signals is mutually exclusive.

debug_havereset_o is used to signal that the CV32E40P has been reset. debug_havereset_o is set high during the assertion of rst_ni. It will be cleared low a few (unspecified) cycles after rst_ni has been deasserted and fetch_enable_i has been sampled high.

debug_running_o is used to signal that the CV32E40P is running normally.

debug_halted_o is used to signal that the CV32E40P is in debug mode.

dm_halt_addr_i is the address where the PC jumps to for a debug entry event. When in Debug Mode, an ebreak instruction will also cause the PC to jump back to this address without affecting status registers (see EBREAK Behavior below).

dm_exception_addr_i is the address where the PC jumps to when an exception occurs during Debug Mode. When in Debug Mode, the mret or uret instruction will also cause the PC to jump back to this address without affecting status registers.

Both dm_halt_addr_i and dm_exception_addr_i must be word aligned.

Core Debug Registers

CV32E40P implements four core debug registers, namely Debug Control and Status (dcsr), Debug PC (dpc) and two debug scratch registers. Access to these registers in non Debug Mode results in an illegal instruction.

Several trigger registers are required to adhere to specification. The following are the most relevant: Trigger Select register (tselect), Trigger Data register 1 (tdata1), Trigger Data register 2 (tdata2) and Trigger Info (tinfo).

The TDATA1.DMODE is hardwired to a value of 1. In non Debug Mode, writes to Trigger registers are ignored and reads reflect CSR values.

Debug state

As specified in RISC-V Debug Specification every hart that can be selected by the Debug Module is in exactly one of four states: nonexistent, unavailable, running or halted.

The remainder of this section assumes that the CV32E40P will not be classified as nonexistent by the integrator.

The CV32E40P signals to the Debug Module whether it is running or halted via its debug_running_o and debug_halted_o pins respectively. Therefore, assuming that this core will not be integrated as a nonexistent core, the CV32E40P is classified as unavailable when neither debug_running_o or debug_halted_o is asserted. Upon rst_ni assertion the debug state will be unavailable until some cycle(s) after rst_ni has been deasserted and fetch_enable_i has been sampled high. After this point (until a next reset assertion) the core will transition between having its debug_halted_o or debug_running_o pin asserted depending whether the core is in debug mode or not. Exactly one of the debug_havereset_o, debug_running_o or debug_halted_o is asserted at all times.

Figure 3 and show Figure 4 show typical examples of transitioning into the running and halted states.

Figure 3 Transition into debug running state

Figure 4 Transition into debug halted state

The key properties of the debug states are:

  • The CV32E40P can remain in its unavailable state for an arbitrarily long time (depending on rst_ni and fetch_enable_i).

  • If debug_req_i is asserted after rst_ni deassertion and before or coincident with the assertion of fetch_enable_i, then the CV32E40P is guaranteed to transition straight from its unavailable state into its halted state. If debug_req_i is asserted at a later point in time, then the CV32E40P might transition through the running state on its ways to the halted state.

  • If debug_req_i is asserted during the running state, the core will eventually transition into the halted state (typically after a couple of cycles).

EBREAK Behavior

The EBREAK instruction description is distributed across several RISC-V specifications: RISC-V Debug Specification, RISC-V Priveleged Specification, RISC-V ISA. The following is a summary of the behavior for three common scenarios.

Scenario 1 : Enter Exception

Executing the EBREAK instruction when the core is not in Debug Mode and the DCSR.EBREAKM == 0 shall result in the following actions:

  • The core enters the exception handler routine located at MTVEC (Debug Mode is not entered)

  • MEPC & MCAUSE are updated

To properly return from the exception, the ebreak handler will need to increment the MEPC to the next instruction. This requires querying the size of the ebreak instruction that was used to enter the exception (16 bit c.ebreak or 32 bit ebreak).

As mentioned in Hardware loops impact on application, exception handlers and debug program, some additional cases exist for MEPC update when ebreak is the last instruction of an Hardware Loop.

Note

The CV32E40P does not support MTVAL CSR register which would have saved the value of the instruction for exceptions. This may be supported on a future core.

Scenario 2 : Enter Debug Mode

Executing the EBREAK instruction when the core is not in Debug Mode and the DCSR.EBREAKM == 1 shall result in the following actions:

  • The core enters Debug Mode and starts executing debug code located at dm_halt_addr_i (exception routine not called)

  • DPC & DCSR are updated

Similar to the exception scenario above, the debugger will need to increment the DPC to the next instruction before returning from Debug Mode.

There is no forseseen situtation where it would be needed to enter in Debug Mode only on the last instruction of an Hardware Loop but just in case this is mentioned in Hardware loops impact on application, exception handlers and debug program as well.

Note

The default value of DCSR.EBREAKM is 0 and the DCSR is only accessible in Debug Mode. To enter Debug Mode from EBREAK, the user will first need to enter Debug Mode through some other means, such as from the external debug_req_i, and set DCSR.EBREAKM.

Scenario 3 : Exit Program Buffer & Restart Debug Code

Executing the EBREAK instruction when the core is in Debug Mode shall result in the following actions:

  • The core remains in Debug Mode and execution jumps back to the beginning of the debug code located at dm_halt_addr_i

  • none of the CSRs are modified

Interrupts during Single-Step Behavior

The CV32E40P is not compliant with the intended interpretation of the RISC-V Debug spec 0.13.2 specification when interrupts occur during Single-Steps. However, the intended behavior has been clarified a posteriori only in version 1.0.0. See https://github.com/riscv/riscv-debug-spec/issues/510. The CV32E40P executes the first instruction of the interrupt handler and retires it before re-entering in Debug Mode, which is prohibited in version 1.0.0 but not specified in 0.13.2. For details about the specific use-case, please refer to https://github.com/openhwgroup/core-v-verif/issues/904.