Debug & Trigger
CV32E40X offers support for execution-based debug according to [RISC-V-DEBUG] (only) if DEBUG
= 1.
Note
As execution based debug is used, the Debug Module region, as defined by the DM_REGION_START
and DM_REGION_END
parameters, needs to support
code execution, loads and stores when CV32E40X is in debug mode.
In order to achieve this CV32E40X overrules the PMA settings for the Debug Module region when it is in debug mode (see Physical Memory Attribution (PMA)).
The following list shows the simplified overview of events that occur in the core when debug is requested:
Enters Debug Mode
Saves the PC to
dpc
Updates the cause in
dcsr
Points the PC to the location determined by the input port
dm_haltaddr_i
Begins executing debug control code
Debug Mode can be entered by one of the following conditions:
External debug event using the
debug_req_i
signalTrigger Module match event with
tdata1.action
set to 1
ebreak
instruction in machine mode whendcsr.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 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 CV32E40X 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 [RISC-V-DEBUG], 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 CV32E40X also supports a Trigger Module to enable entry into Debug Mode on a trigger event with the following features:
Number of trigger register(s): Parametrizable number of triggers using parameter
DBG_NUM_TRIGGERS
.Supported trigger types: Execute/load/store address match (Match Control) and exception trigger.
The compare value used to determine an execute address match is the PC of the instruction, i.e. only the lowest virtual address
of the instruction is used. The compare value(s) used to determine a load/store address match depend(s) on the size of the transferred
data item as well as the lowest virtual address of the access. A byte load/store for address A
only uses A
as compare value; a
halfword load/store for address A
uses A
and A+1
as compare values; a word load/store for address A
uses A
, A+1
,
A+2
and A+3
as compare values.
A trigger match will cause debug entry if tdata1.ACTION
is 1.
Note
Hardware triggers and breakpoints are not supported for the table fetch used in table jump instructions and CLIC hardware vectored interrupts.
The CV32E40X will not support the optional debug features 10, 11, & 12 listed in Section 4.1 of [RISC-V-DEBUG]. 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.
CV32E40X prioritizes debug mode entry below NMIs, but above regular interrupts and synchronous exceptions.
Interface
Signal |
Direction |
Description |
---|---|---|
|
input |
Request to enter Debug Mode |
|
output |
Debug status: Core has been reset |
|
output |
Debug status: Core is running |
|
output |
Debug status: Core is halted |
|
output |
Valid signal for |
|
output |
PC of last retired instruction |
|
input |
Address for debugger entry |
|
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
signal is synchronous to clk_i
and it is level sensitive.
It is not guaranteed that a short pulse on debug_req_i
will cause CV32E40X to enter 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 CV32E40X 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 CV32E40X is running normally.
debug_halted_o
is used to signal that the CV32E40X is in debug mode.
debug_pc_o
is the PC of the last retired instruction. This signal is only valid when debug_pc_valid_o
= 1.
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
and ecall
instructions 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 and they must both be within the Debug Module region as defined by the DM_REGION_START
and DM_REGION_END
parameters.
Core Debug Registers
If DEBUG
= 1, CV32E40X 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.
The trigger related CSRs (tselect
, tdata1
, tdata2
, tinfo
) are only included if DBG_NUM_TRIGGERS
is
set to a value greater than 0. Further descriptions of these CSRs can be found in Trigger Select Register (tselect), Trigger Data 1 (tdata1), Trigger Data Register 2 (tdata2),
Trigger Info (tinfo) and [RISC-V-DEBUG]. The optional mcontext
and mscontext
CSRs are not implemented.
If DBG_NUM_TRIGGERS
is 0, access to the trigger registers will result in an illegal instruction exception.
The tdata1.DMODE
bitfield controls write access permission to the currently selected triggers tdata*
registers. In CV32E40X this bit is tied to 1, and thus only debug mode is able to write to the trigger registers.
Debug state
As specified in RISC-V Debug Specification ([RISC-V-DEBUG]) 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 CV32E40X will not be classified as nonexistent
by the integrator.
The CV32E40X 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 CV32E40X 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
, debug_halted_o
is asserted at all times.
The key properties of the debug states are:
The CV32E40X can remain in its
unavailable
state for an arbitrarily long time (depending onrst_ni
andfetch_enable_i
).If
debug_req_i
is asserted afterrst_ni
deassertion and before or coincident with the assertion offetch_enable_i
, then the CV32E40X is guaranteed to transition straight from itsunavailable
state into itshalted
state. Ifdebug_req_i
is asserted at a later point in time, then the CV32E40X might transition through therunning
state on its ways to thehalted
state.If
debug_req_i
is asserted during therunning
state, the core will eventually transition into thehalted
state (typically after a couple of cycles).Note
Due to
debug_req_i
being level sensitive, it is not guaranteed that a short pulse ondebug_req_i
will cause CV32E40X to enter itshalted
state in any of the bullets above. To achieve (eventual) transition into thehalted
state,debug_req_i
must be kept asserted untildebug_halted_o
has been asserted.
EBREAK Behavior
The ebreak
instruction description is distributed across several RISC-V specifications: [RISC-V-DEBUG],
[RISC-V-PRIV], [RISC-V-UNPRIV]. The following is a summary of the behavior for three common scenarios.
Scenario 1 : Enter Exception
Executing the ebreak
instruction in machine mode when the core is not in Debug Mode and 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
andmcause
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
).
Note
CV32E40X does not support mtval
CSR register which would have saved the value of the instruction for exceptions.
Scenario 2 : Enter Debug Mode
Executing the ebreak
instruction in machine mode when the core is not in Debug Mode and 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
anddcsr
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.
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 re-enters Debug Mode (without actually having ever left Debug Mode) by jumping back to the beginning of the debug code located at
dm_halt_addr_i
None of the CSRs are modified