Projet_SETI_RISC-V/neorv32/docs/datasheet/on_chip_debugger.adoc
2023-03-06 14:48:14 +01:00

817 lines
38 KiB
Text
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<<<
:sectnums:
== On-Chip Debugger (OCD)
The NEORV32 Processor features an _on-chip debugger_ (OCD) implementing **execution-based debugging** compatible
to the **Minimal RISC-V Debug Specification Version 1.0**. Please refer to this spec for in-deep information.
A copy of the specification is available in `docs/references`.
**Section Structure**
* <<_debug_transport_module_dtm>>
* <<_debug_module_dm>>
* <<_cpu_debug_mode>>
* <<_trigger_module>>
The NEORV32 OCD provides the following key features:
* JTAG access port
* run-control of the CPU: halting, single-stepping and resuming
* executing arbitrary programs during debugging
* indirect access to all core registers (via program buffer)
* indirect access to the whole processor address space (via program buffer)
* trigger module for hardware breakpoints
* compatible with upstream OpenOCD and GDB
.OCD Security Note
[NOTE]
Access via the OCD is _always authenticated_ (`dmstatus.authenticated = 1`). Hence, the
_whole system_ can always be accessed via the on-chip debugger. Currently, there is no option
to disable the OCD via software - the OCD can only be disabled by disabling implementation
(setting <<_on_chip_debugger_en>> generic to _false_).
.Hands-On Tutorial
[TIP]
A simple example on how to use NEORV32 on-chip debugger in combination with OpenOCD and the GNU debugger
is shown in section https://stnolting.github.io/neorv32/ug/#_debugging_using_the_on_chip_debugger[Debugging using the On-Chip Debugger]
of the User Guide.
The NEORV32 on-chip debugger complex is based on four hardware modules:
.NEORV32 on-chip debugger complex
image::neorv32_ocd_complex.png[align=center]
[start=1]
. <<_debug_transport_module_dtm>> (`rtl/core/neorv32_debug_dtm.vhd`): JTAG access tap to allow an external
adapter to interface with the _debug module(DM)_ using the _debug module interface (dmi)_ - this interface is compatible to
the interface description shown in Appendix 3 of the "RISC-V debug stable" specification.
. <<_debug_module_dm>> (`rtl/core/neorv32_debug_tm.vhd`): Debugger control unit that is configured by the DTM via the
the _dmi_. From the CPU's "point of view" this module behaves as another memory-mapped "peripheral" that can be accessed
via the processor-internal bus. The memory-mapped registers provide an internal _data buffer_ for data transfer
from/to the DM, a _code ROM_ containing the "park loop" code, a _program buffer_ to allow the debugger to
execute small programs defined by the DM and a _status register_ that is used to communicate
_exception, _halt_, _resume_ and _execute_ requests/acknowledges from/to the DM.
. CPU <<_cpu_debug_mode>> extension (part of `rtl/core/neorv32_cpu_control.vhd`):
This extension provides the "debug execution mode" which executes the "park loop" code from the DM.
The mode also provides additional CSRs.
. CPU <<_trigger_module>> (also part of `rtl/core/neorv32_cpu_control.vhd`):
This module provides a single _hardware_ breakpoint, which allows to debug code executed from ROM.
**Theory of Operation**
When debugging the system using the OCD, the debugger issues a halt request to the CPU (via the CPU's
`db_halt_req_i` signal) to make the CPU enter _debug mode_. In this state, the application-defined architectural
state of the system/CPU is "frozen" so the debugger can monitor if without interfering the actual application.
However, the OCD can also modify the entire architectural state at any time.
While in debug mode, the CPU executes the "park loop" code from the _code ROM_ of the DM.
This park loop implements an endless loop, in which the CPU polls the memory-mapped _status register_ that is
controlled by the _debug module (DM)_. The flags in this register are used to communicate requests from
the DM and to acknowledge them by the CPU: trigger execution of the program buffer or resume the halted
application. Furthermore, the CPU uses this register to signal that the CPU has halted after a halt request
and to signal that an exception has fired while in debug mode.
<<<
// ####################################################################################################################
:sectnums:
=== Debug Transport Module (DTM)
The debug transport module (VHDL module: `rtl/core/neorv32_debug_dtm.vhd`) provides a JTAG test access port (TAP).
The DTM is the first entity in the debug system, which connects and external debugger via JTAG to the next debugging
entity - the debug module (DM).
External JTAG access is provided by the following top-level ports.
.JTAG top level signals
[cols="^2,^2,^2,<8"]
[options="header",grid="rows"]
|=======================
| Name | Width | Direction | Description
| `jtag_trst_i` | 1 | in | TAP reset (low-active); this signal is optional, make sure to pull it _high_ if it is not used by the JTAG adapter
| `jtag_tck_i` | 1 | in | serial clock
| `jtag_tdi_i` | 1 | in | serial data input
| `jtag_tdo_o` | 1 | out | serial data output
| `jtag_tms_i` | 1 | in | mode select
|=======================
.Maximum JTAG Clock
[IMPORTANT]
All JTAG signals are synchronized to the processor clock domain by oversampling them in the DTM. Hence, no additional
clock domain is required for the DTM. However, this constraints the maximal JTAG clock frequency (`jtag_tck_i`) to be less
than or equal to **1/5** of the processor clock frequency (`clk_i`).
[NOTE]
If the on-chip debugger is disabled (<<_on_chip_debugger_en>> = false) the JTAG serial input `jtag_tdi_i` is directly
connected to the JTAG serial output `jtag_tdo_o` to maintain the JTAG chain.
[NOTE]
The NEORV32 JTAG TAP does not provide a _boundary check_ function (yet?). Hence, physical device pins cannot be accessed.
The DTM uses the "debug module interface (dmi)" to access the actual debug module (DM).
The accesses are controlled by TAP-internal registers, which are selected by the JTAG instruction register (`IR`)
and accessed through the JTAG data register (`DR`).
[NOTE]
The DTM's instruction and data registers can be accessed using OpenOCD's `irscan` and `drscan` commands.
OpenOCD also provides low-level RISC-V-specific commands for direct DMI accesses (`riscv dmi_read` & `riscv dmi_write`).
JTAG accesses are based on a single _instruction register_ `IR`, which is 5 bit wide, and several _data registers_ `DR`
with different sizes. The individual data registers are accessed by writing the according address to the instruction
register. The following table shows the available data registers and their addresses:
.JTAG TAP registers
[cols="^2,^2,^2,<8"]
[options="header",grid="rows"]
|=======================
| Address (via `IR`) | Name | Size [bits] | Description
| `00001` | `IDCODE` | 32 | identifier, default: `0x0CAFE001` (configurable via package's `jtag_tap_idcode_*` constants)
| `10000` | `DTMCS` | 32 | debug transport module control and status register
| `10001` | `DMI` | 40 | debug module interface (_dmi_); 6-bit address, 32-bit read/write data, 2-bit operation (`00` = NOP; `10` = write; `01` = read)
| others | `BYPASS` | 1 | default JTAG bypass register
|=======================
.`DTMCS` - DTM Control and Status Register
[cols="^2,^3,^1,<8"]
[options="header",grid="rows"]
|=======================
| Bit(s) | Name | R/W | Description
| 31:18 | - | r/- | _reserved_, hardwired to zero
| 17 | `dmihardreset` | r/w | setting this bit will reset the debug module interface; this bit auto-clears
| 16 | `dmireset` | r/w | setting this bit will clear the sticky error state; this bit auto-clears
| 15 | - | r/- | _reserved_, hardwired to zero
| 14:12 | `idle` | r/- | recommended idle states (= 0, no idle states required)
| 11:10 | `dmistat` | r/- | DMI status: `00` = no error, `01` = reserved, `10` = operation failed, `11` = failed operation during pending DMI operation
| 9:4 | `abits` | r/- | number of address bits in `DMI` register (= 6)
| 3:0 | `version` | r/- | `0001` = DTM is compatible to spec. version 0.13 & 1.0
|=======================
[INFO]
See the https://github.com/riscv/riscv-debug-spec[RISC-V debug specification] for more information regarding the data
registers and operations. A local copy can be found in `docs/references`.
[NOTE]
Most FPGAs are programmed over a JTAG connection itself and support the use of it in user designs with instantiation of
platform-specific entities. So instead of two JTAG connections, one to program the FPGA and one to debug the core,
only one connection is needed. See the setups in [`neorv32-setups`](https://github.com/stnolting/neorv32-setups)
for example implementations.
<<<
// ####################################################################################################################
:sectnums:
=== Debug Module (DM)
According to the RISC-V debug specification, the DM (VHDL module: `rtl/core/neorv32_debug_dm.vhd`)
acts as a translation interface between abstract operations issued by the debugger (application) and the
platform-specific debugger (circuit) implementation. It supports the following features (excerpt from the debug spec):
* Gives the debugger necessary information about the implementation.
* Allows the hart to be halted and resumed and provides status of the current state.
* Provides abstract read and write access to the halted hart's GPRs.
* Provides access to a reset signal that allows debugging from the very first instruction after reset.
* Provides a mechanism to allow debugging the hart immediately out of reset. (_still experimental_)
* Provides a Program Buffer to force the hart to execute arbitrary instructions.
* Allows memory access from a hart's point of view.
The NEORV32 DM follows the "Minimal RISC-V External Debug Specification" to provide full debugging
capabilities while keeping resource/area requirements at a minimum level.
It implements the **execution based debugging scheme** for a single hart and provides the following
hardware features:
* program buffer with 2 entries and implicit `ebreak` instruction afterwards
* no _direct_ bus access; indirect bus access via the CPU using the program buffer
* abstract commands: "access register" plus auto-execution
* no _dedicated_ halt-on-reset capabilities yet (but can be emulated)
The DM provides two access "point of views": accesses from the DTM via the _debug module interface (dmi)_ and
accesses from the CPU via the processor-internal bus. From the DTM's point of view, the DM implements a set of
<<_dm_registers>> that are used to control and monitor the actual debugging. From the CPU's point of view, the
DM implements several memory-mapped registers (within the _normal_ address space) that are used for communicating
debugging control and status (<<_dm_cpu_access>>).
:sectnums:
==== DM Registers
The DM is controlled via a set of registers that are accessed via the DTM's _dmi_.
The "Minimal RISC-V Debug Specification" requires only a subset of the registers specified in the spec.
The following registers are implemented:
[NOTE]
Write accesses to registers that are not implemented are simply ignored and read accesses will always return zero.
Register names that are encapsulated in "( )" are not actually implemented; however, they are listed to explicitly show
their functionality.
.Available DM registers
[cols="^2,^3,<7"]
[options="header",grid="rows"]
|=======================
| Address | Name | Description
| `0x04` | `data0` | Abstract data 0, used for data transfer between debugger and processor
| `0x10` | `dmcontrol` | Debug module control
| `0x11` | `dmstatus` | Debug module status
| `0x12` | `hartinfo` | Hart information
| `0x16` | `abstracts` | Abstract control and status
| `0x17` | `command` | Abstract command
| `0x18` | `abstractauto` | Abstract command auto-execution
| `0x1d` | (`nextdm`) | Base address of _next_ DM; reads as zero to indicate there is only _one_ DM
| `0x20` | `progbuf0` | Program buffer 0
| `0x21` | `progbuf1` | Program buffer 1
| `0x38` | (`sbcs`) | System bus access control and status; reads as zero to indicate there is no _direct_ system bus access
|=======================
:sectnums!:
===== **`data`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x04 | **Abstract data 0** | `data0`
3+| Reset value: `0x00000000`
3+| Basic read/write registers to be used with abstract commands (for example to read/write data from/to CPU GPRs).
|======
:sectnums!:
===== **`dmcontrol`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x10 | **Debug module control register** | `dmcontrol`
3+| Reset value: `0x00000000`
3+| Control of the overall debug module and the hart. The following table shows all implemented bits. All remaining bits/bit-fields
are configured as "zero" and are read-only. Writing '1' to these bits/fields will be ignored.
|======
.`dmcontrol` - debug module control register bits
[cols="^1,^2,^1,<8"]
[options="header",grid="rows"]
|=======================
| Bit | Name [RISC-V] | R/W | Description
| 31 | `haltreq` | -/w | set/clear hart halt request
| 30 | `resumereq` | -/w | request hart to resume
| 28 | `ackhavereset` | -/w | write `1` to clear `*havereset` flags
| 1 | `ndmreset` | r/w | put whole processor into reset when `1`
| 0 | `dmactive` | r/w | DM enable; writing `0`-`1` will reset the DM
|=======================
:sectnums!:
===== **`dmstatus`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x11 | **Debug module status register** | `dmstatus`
3+| Reset value: `0x00400083`
3+| Current status of the overall debug module and the hart. The entire register is read-only.
|======
.`dmstatus` - debug module status register bits
[cols="^1,^2,<10"]
[options="header",grid="rows"]
|=======================
| Bit | Name [RISC-V] | Description
| 31:23 | _reserved_ | reserved; always zero
| 22 | `impebreak` | always `1`; indicates an implicit `ebreak` instruction after the last program buffer entry
| 21:20 | _reserved_ | reserved; always zero
| 19 | `allhavereset` .2+| `1` when the hart is in reset
| 18 | `anyhavereset`
| 17 | `allresumeack` .2+| `1` when the hart has acknowledged a resume request
| 16 | `anyresumeack`
| 15 | `allnonexistent` .2+| always zero to indicate the hart is always existent
| 14 | `anynonexistent`
| 13 | `allunavail` .2+| `1` when the DM is disabled to indicate the hart is unavailable
| 12 | `anyunavail`
| 11 | `allrunning` .2+| `1` when the hart is running
| 10 | `anyrunning`
| 9 | `allhalted` .2+| `1` when the hart is halted
| 8 | `anyhalted`
| 7 | `authenticated` | always `1`; there is no authentication
| 6 | `authbusy` | always `0`; there is no authentication
| 5 | `hasresethaltreq` | always `0`; halt-on-reset is not supported (directly)
| 4 | `confstrptrvalid` | always `0`; no configuration string available
| 3:0 | `version` | `0011` - DM is compatible to spec. version 1.0
|=======================
:sectnums!:
===== **`hartinfo`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x12 | **Hart information** | `hartinfo`
3+| Reset value: _see below_
3+| This register gives information about the hart. The entire register is read-only.
|======
.`hartinfo` - hart information register bits
[cols="^1,^2,<8"]
[options="header",grid="rows"]
|=======================
| Bit | Name [RISC-V] | Description
| 31:24 | _reserved_ | reserved; always zero
| 23:20 | `nscratch` | `0001`, number of `dscratch*` CPU registers = 1
| 19:17 | _reserved_ | reserved; always zero
| 16 | `dataccess` | `0`, the `data` registers are shadowed in the hart's address space
| 15:12 | `datasize` | `0001`, number of 32-bit words in the address space dedicated to shadowing the `data` registers (1 register)
| 11:0 | `dataaddr` | = `dm_data_base_c(11:0)`, signed base address of `data` words (see address map in <<_dm_cpu_access>>)
|=======================
:sectnums!:
===== **`abstracts`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x16 | **Abstract control and status** | `abstracts`
3+| Reset value: `0x02000801`
3+| Command execution info and status.
|======
.`abstracts` - abstract control and status register bits
[cols="^1,^2,^1,<8"]
[options="header",grid="rows"]
|=======================
| Bit | Name [RISC-V] | R/W | Description
| 31:29 | _reserved_ | r/- | reserved; always zero
| 28:24 | `progbufsize` | r/- | always `0010`: size of the program buffer (`progbuf`) = 2 entries
| 23:11 | _reserved_ | r/- | reserved; always zero
| 12 | `busy` | r/- | `1` when a command is being executed
| 11 | `relaxedpriv` | r/- | always `1`: PMP rules are ignored when in debug mode
| 10:8 | `cmderr` | r/w | error during command execution (see below); has to be cleared by writing `111`
| 7:4 | _reserved_ | r/- | reserved; always zero
| 3:0 | `datacount` | r/- | always `0001`: number of implemented `data` registers for abstract commands = 1
|=======================
Error codes in `cmderr` (highest priority first):
* `000` - no error
* `100` - command cannot be executed since hart is not in expected state
* `011` - exception during command execution
* `010` - unsupported command
* `001` - invalid DM register read/write while command is/was executing
.PMP Rules
[NOTE]
When in debug-mode all PMP rules are ignored making the debugger have maximum access rights.
:sectnums!:
===== **`command`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x17 | **Abstract command** | `command`
3+| Reset value: `0x00000000`
3+| Writing this register will trigger the execution of an abstract command. New command can only be executed if
`cmderr` is zero. The entire register in write-only (reads will return zero).
|======
[NOTE]
The NEORV32 DM only supports **Access Register** abstract commands. These commands can only access the
hart's GPRs (abstract command register index `0x1000` - `0x101f`).
.`command` - abstract command register - "access register" commands only
[cols="^1,^2,^1,<8"]
[options="header",grid="rows"]
|=======================
| Bit | Name [RISC-V] | R/W | Description / required value
| 31:24 | `cmdtype` | -/w | `00000000` to indicate "access register" command
| 23 | _reserved_ | -/w | reserved, has to be `0` when writing
| 22:20 | `aarsize` | -/w | `010` to indicate 32-bit accesses
| 21 | `aarpostincrement` | -/w | `0`, post-increment is not supported
| 18 | `postexec` | -/w | if set the program buffer is executed _after_ the command
| 17 | `transfer` | -/w | if set the operation in `write` is conducted
| 16 | `write` | -/w | `1`: copy `data0` to `[regno]`, `0`: copy `[regno]` to `data0`
| 15:0 | `regno` | -/w | GPR-access only; has to be `0x1000` - `0x101f`
|=======================
:sectnums!:
===== **`abstractauto`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x18 | **Abstract command auto-execution** | `abstractauto`
3+| Reset value: `0x00000000`
3+| Register to configure when a read/write access to a DM repeats execution of the last abstract command.
|======
.`abstractauto` - Abstract command auto-execution register bits
[cols="^1,^2,^1,<8"]
[options="header",grid="rows"]
|=======================
| Bit | Name [RISC-V] | R/W | Description
| 17 | `autoexecprogbuf[1]` | r/w | when set reading/writing from/to `progbuf1` will execute `command` again
| 16 | `autoexecprogbuf[0]` | r/w | when set reading/writing from/to `progbuf0` will execute `command` again
| 0 | `autoexecdata[0]` | r/w | when set reading/writing from/to `data0` will execute `command` again
|=======================
:sectnums!:
===== **`progbuf`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x20 | **Program buffer 0** | `progbuf0`
| 0x21 | **Program buffer 1** | `progbuf1`
3+| Reset value: `0x00000013` ("NOP")
3+| Program buffer (two entries) for the DM. Note that this register is read-only for the DM (allowed since spec. version 1.0)!
|======
:sectnums:
==== DM CPU Access
From the CPU's perspective, the DM behaves as a memory-mapped peripheral that includes the following sub-modules:
* a small ROM that contains the code for the "park loop", which is executed when the CPU is _in_ debug mode
* a program buffer populated by the debugger host to execute small programs
* a data buffer to transfer data between the processor and the debugger host
* a status register to communicate debugging requests and status
(see `sw/ocd-firmware/README.md`).
The DM occupies 256 bytes of the CPU's address space starting at address `dm_base_c` (see table below).
This address space is divided into four sections of 64 bytes each to provide access to the _park loop code ROM_,
the _program buffer_, the _data buffer_ and the _status register_. The program buffer, the data buffer and the
status register do not fully occupy the 64-byte-wide sections. However, the according registers are mirrored
to fill the entire section.
.DM CPU access - address map (divided into four sections)
[cols="^2,^4,^2,<7"]
[options="header",grid="rows"]
|=======================
| Base address | Name [VHDL package] | Actual size | Description
| `0xfffff800` | `dm_code_base_c` (= `dm_base_c`) | 64 bytes | ROM for the "park loop" code
| `0xfffff840` | `dm_pbuf_base_c` | 16 bytes | Program buffer, provided by DM
| `0xfffff880` | `dm_data_base_c` | 4 bytes | Data buffer (`dm.data0`)
| `0xfffff8c0` | `dm_sreg_base_c` | 4 bytes | Control and status register
|=======================
.DM Register Access
[IMPORTANT]
All memory-mapped registers of the DM can only be accessed by the CPU if it is actually _in_ debug mode.
Hence, the DM registers are not "visible" for normal CPU operations.
Any CPU access outside of debug mode will raise a bus access fault exception.
.Park Loop Code Sources ("OCD Firmware")
[NOTE]
The assembly sources of the **park loop code** are available in `sw/ocd-firmware/park_loop.S`. Please note, that
these sources are not intended to be changed by the user. Hence, the makefile does not provide an automatic option
to compile and "install" the debugger ROM code into the HDL sources and require a manual copy
:sectnums:
===== Code ROM Entry Points
The park loop code provides two entry points, where the actual code execution can start. These are used to enter
the park loop either when an explicit request has been issued (for example a halt request) or when an exception
has occurred _while executing_ the park loop itself.
.Park Loop Entry Points
[cols="^6,<4"]
[options="header",grid="rows"]
|=======================
| Address | Description
| `dm_exc_entry_c` (`dm_base_c` + 0) | Exception entry address
| `dm_park_entry_c` (`dm_base_c` + 8) | Normal entry address
|=======================
When the CPU enters or re-enters debug mode (for example via an `ebreak` in the DM's program buffer), it jumps to
address of the _normal entry point_ for the park loop code defined by the <<_cpu_debug_park_addr>> generic.
By default, this generic is set to `dm_park_entry_c`, which is defined in main package file.
If an exception is encountered during debug mode, the CPU jumps to the address of the _exception entry point_
defined by the <<_cpu_debug_exc_addr>> generic. By default, this generic is set to `dm_exc_entry_c`, which is
also defined in main package file.
:sectnums:
===== Status Register
The status register provides a direct communication channel between the CPU's debug mode executing the park loop
and the host-controlled debug module (DM). This register is used to communicate _requests_, which are issued by the
DM. and the according _acknowledges_, which are generated by the CPU.
There are only 4 bits in this register that are used to implement the requests/acknowledges. Each bit is left-aligned
in one sub-byte of the entire 32-bit register. Thus, the CPU can access each bit individually using _store-byte_ and
_load-byte_ instruction. This eliminates the need to perform bit-masking in the park loop code leading to less code size
and faster execution.
.DM Status Register - CPU Access
[cols="^1,^3,^2,<8"]
[options="header",grid="rows"]
|=======================
| Bit | Name | CPU access <| Description
.2+| 0 | `sreg_halt_ack` | read <| _this bit is write-only_
| - | write <| Set by the CPU while it is halted (and executing the park loop)
.2+| 8 | `sreg_resume_req` | read <| Set by the DM to request the CPU to resume normal operation
| `sreg_resume_ack` | write <| Set by the CPU before it starts resuming
.2+| 16 | `sreg_execute_req` | read <| Set by the DM to request execution of the program buffer
| `sreg_execute_ack` | write <| Set by the CPU before it starts executing the program buffer
.2+| 24 | - | read <| _this bit is write-only_
| `sreg_execute_ack` | write <| Set by the CPU if an exception occurs while being in debug mode
|=======================
.Access Details
[NOTE]
The underlaying hardware to implement the CPU access to the status register is highly optimized to provide
fastest access times while requiring minimal code and hardware size: the actual data written by the CPU is irrelevant
as only the sub-byte accesses (so, the actual bus transactions) are tracked by the status register hardware.
<<<
// ####################################################################################################################
:sectnums:
=== CPU Debug Mode
The NEORV32 CPU Debug Mode `DB` or `DEBUG` is compatible to the **Minimal RISC-V Debug Specification 1.0**
`Sdext` (external debug) ISA extension. When enabled via the <<_cpu_extension_riscv_sdext>> generic (CPU) and/or
the <<_on_chip_debugger_en>> (Processor) it adds a new CPU operation mode ("debug mode"), three additional CSRs
(section <<_cpu_debug_mode_csrs>>) and one additional instruction (`dret`) to the core.
[IMPORTANT]
The CPU debug mode requires the `Zicsr` and `Zifencei` CPU extension to be implemented (top generics
<<_cpu_extension_riscv_zicsr>> and <<_cpu_extension_riscv_zifencei>> = true).
The CPU debug-mode is entered when one of the following events appear:
[start=1]
. executed `ebreak` instruction (when in machine-mode and `dcsr.ebreakm` is set OR when in user-mode and `dcsr.ebreaku` is set)
. debug halt request from external DM (via CPU signal `db_halt_req_i`, high-active, triggering on rising-edge)
. finished executing of a single instruction while in single-step debugging mode (enabled via `dcsr.step`)
. hardware trigger by the <<_trigger_module>>
From a hardware point of view, these "entry conditions" are special traps that are handled transparently by the control logic.
**Whenever the CPU enters debug-mode it performs the following operations:**
* wake-up CPU if it was send to sleep mode by the `wfi` instruction
* move `pc` to `dpc`
* copy the hart's current privilege level to `dcsr.prv`
* set `dcrs.cause` according to the cause why debug mode is entered
* **no update** of `mtval`, `mcause`, `mtval` and `mstatus` CSRs
* load the address configured via the CPU's <<_cpu_debug_park_addr>> generic to the `pc` to jump to the
"debugger park loop" code stored in the debug module (DM)
**When the CPU is in debug-mode the following things are important:**
* while in debug mode, the CPU executes the parking loop and - if requested by the DM - the program buffer
* effective CPU privilege level is `machine` mode; any active physical memory protection (PMP) configuration is bypassed
* the `wfi` instruction acts as a `nop` (also during single-stepping)
* if an exception occurs while being in debug mode:
** if the exception was caused by any debug-mode entry action the CPU jumps to the _normal entry point_
(defined by <<_cpu_debug_park_addr>> generic) of the park loop again (for example when executing `ebreak` while in debug-mode)
** for all other exception sources the CPU jumps to the _exception entry point_ (defined by <<_cpu_debug_exc_addr>> generic)
to signal an exception to the DM; the CPU restarts the park loop again afterwards
* interrupts are disabled; however, they will remain pending and will get executed after the CPU has left debug mode
* if the DM makes a resume request, the park loop exits and the CPU leaves debug mode (executing `dret`)
* the standard counters <<_machine_counter_and_timer_csrs>> `[m]cycle[h]` and `[m]instret[h]` are stopped; note that the
<<_machine_system_timer_mtime>> keep running as well as it's shadowed copies in the `[m]time[h]` CSRs
* all <<_hardware_performance_monitors_hpm_csrs>> are stopped
Debug mode is left either by executing the `dret` instruction or by performing
a hardware reset of the CPU. Executing `dret` outside of debug mode will raise an illegal instruction exception.
**Whenever the CPU leaves debug mode it performs the following operations:**
* set the hart's current privilege level according to `dcsr.prv`
* restore `pc` from `dpcs`
* resume normal operation at `pc`
:sectnums:
==== CPU Debug Mode CSRs
Two additional CSRs are required by the _Minimal RISC-V Debug Specification_: the debug mode control and status register
`dcsr` and the debug program counter `dpc`. An additional general purpose scratch register for debug mode only
(`dscratch0`) allows faster execution by having a fast-accessible backup register.
[NOTE]
The debug-mode CSRs are only accessible when the CPU is _in_ debug mode. If these CSRs are accessed outside of debug mode
an illegal instruction exception is raised.
:sectnums!:
===== **`dcsr`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x7b0 | **Debug control and status register** | `dcsr`
3+<| Reset value: `0x40000413`
3+<| The `dcsr` CSR is compatible to the RISC-V debug spec. It is used to configure debug mode and provides additional status information.
The following bits are implemented. The reaming bits are read-only and always read as zero.
|======
.Debug control and status register `dcsr` bits
[cols="^1,^2,^1,<8"]
[options="header",grid="rows"]
|=======================
| Bit | Name [RISC-V] | R/W | Description
| 31:28 | `xdebugver` | r/- | `0100` - CPU debug mode is compatible to spec. version 1.0
| 27:16 | - | r/- | `000000000000` - _reserved_
| 15 | `ebereakm` | r/w | `ebreak` instructions in `machine` mode will _enter_ debug mode when set
| 14 | `ebereakh` | r/- | `0` - hypervisor mode not supported
| 13 | `ebereaks` | r/- | `0` - supervisor mode not supported
| 12 | `ebereaku` | r/w | `ebreak` instructions in `user` mode will _enter_ debug mode when set
| 11 | `stepie` | r/- | `0` - IRQs are disabled during single-stepping
| 10 | `stopcount` | r/- | `1` - standard counters and HPMs are stopped when in debug mode
| 9 | `stoptime` | r/- | `0` - timers increment as usual
| 8:6 | `cause` | r/- | cause identifier - why debug mode was entered (see below)
| 5 | - | r/- | `0` - _reserved_
| 4 | `mprven` | r/- | `1` - <<_mstatus>>`.mprv` is also evaluated when in debug mode
| 3 | `nmip` | r/- | `0` - non-maskable interrupt is pending
| 2 | `step` | r/w | enable single-stepping when set
| 1:0 | `prv` | r/w | CPU privilege level before/after debug mode
|=======================
Cause codes in `dcsr.cause` (highest priority first):
* `010` - trigger by hardware <<_trigger_module>>
* `001` - executed `EBREAK` instruction
* `011` - external halt request (from DM)
* `100` - return from single-stepping
:sectnums!:
===== **`dpc`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x7b1 | **Debug program counter** | `dpc`
3+<| Reset value: `0x00000000`
3+<| The `dcsr` CSR is compatible to the RISC-V debug spec. It is used to store the current program counter when
debug mode is entered. The `dret` instruction will return to `dpc` by moving `dpc` to `pc`.
|======
:sectnums!:
===== **`dscratch0`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x7b2 | **Debug scratch register 0** | `dscratch0`
3+<| Reset value: `0x00000000`
3+<| The `dscratch0` CSR is compatible to the RISC-V debug spec. It provides a general purpose debug mode-only scratch register.
|======
<<<
// ####################################################################################################################
:sectnums:
=== Trigger Module
The RISC-V `Sdtrig` ISA extension add a programmable _trigger module_ to the processor when enabled
(via the <<_cpu_extension_riscv_sdtrig>>). The NEORV32 trigger module implements a subset of the features
described in the "RISC-V Debug Specification / Trigger Module".
The trigger module only provides a _single_ trigger supporting only the "instruction address match" type. This limitation
is granted by the RISC-V specs. and is sufficient to **debug code executed from read-only memory (ROM)**.
"Normal" _software_ breakpoints (using GDB's `b`/`break` command) are implemented by temporarily replacing the according
instruction word by an `ebreak` instruction. This is not possible when debugging code that is executed from read-only memory
(for example when debugging programs that are executed via the <<_execute_in_place_module_xip>>).
Therefore, the NEORV32 trigger module provides a single "instruction address match" trigger to enter debug mode when
executing the instruction at a specific address. These "hardware-assisted breakpoints" are used by GDB's `hb`/`hbreak` command.
The trigger module can also be used independently of the CPU debug-mode (so independent of the on-chip debugger).
Machine-mode software can use the trigger module to raise a Break exception when the instruction at a programmable
address gets executed.
:sectnums:
==== Trigger Module CSRs
The `Sdtrig` ISA extension add 8 additional CSRs, which are accessible in debug-mode and also in machine-mode.
Machine-level accesses can be ignore by setting <<_tdata1>>`.dmode´. This is automatically done by GDB if it uses the trigger module
for implementing a "hardware breakpoint"
:sectnums!:
===== **`tselect`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x7a0 | **Trigger select register** | `tselect`
3+<| Reset value: `0x00000000`
3+<| This CSR is hardwired to zero indicating there is only one trigger available. Any write access is ignored.
|======
:sectnums!:
===== **`tdata1`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x7a1 | **Trigger data register 1 / match control register** | `tdata1` / `mcontrol`
3+<| Reset value: `0x20040040`
3+<| This CSR is used to configure the address match trigger. Only one bit is writable, the remaining bits are hardwired (see table below).
Write attempts to the hardwired bits are ignored.
|======
.Match control CSR (`tdata1`) bits
[cols="^1,^2,^1,<8"]
[options="header",grid="rows"]
|=======================
| Bit | Name [RISC-V] | R/W | Description
| 31:28 | `type` | r/- | `0010` - address match trigger
| 27 | `dmode` | r/w | set to ignore `tdata*` CSR accesses from machine-mode
| 26:21 | `maskmax` | r/- | `000000` - only exact values
| 20 | `hit` | r/- | `0` - feature not supported
| 19 | `select` | r/- | `0` - fire trigger on address match
| 18 | `timing` | r/- | `1` - trigger **after** executing the triggering instruction
| 17:16 | `sizelo` | r/- | `00` - match against an access of any size
| 15:12 | `action` | r/w | `0001` = enter debug-mode on trigger fire; `0000` = normal m-mode break exception on trigger fire
| 11 | `chain` | r/- | `0` - chaining is not supported - there is only one trigger
| 10:6 | `match` | r/- | `0000` - only full-address match
| 6 | `m` | r/- | `1` - trigger enabled when in machine-mode
| 5 | `h` | r/- | `0` - hypervisor-mode not supported
| 4 | `s` | r/- | `0` - supervisor-mode not supported
| 3 | `u` | r/- | trigger enabled when in user-mode, set when `U` ISA extension is enabled
| 2 | `exe` | r/w | set to enable trigger
| 1 | `store` | r/- | `0` - store address/data matching not supported
| 0 | `load` | r/- | `0` - load address/data matching not supported
|=======================
:sectnums!:
===== **`tdata2`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x7a2 | **Trigger data register 2** | `tdata2`
3+<| Reset value: `0x00000000`
3+<| Since only the "address match trigger" type is supported, this r/w CSR is used to configure the address of the triggering instruction.
|======
:sectnums!:
===== **`tdata3`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x7a3 | **Trigger data register 3** | `tdata3`
3+<| Reset value: `0x00000000`
3+<| This CSR is not required for the NEORV32 trigger module. Hence, it is hardwired to zero and any write access is ignored.
|======
:sectnums!:
===== **`tinfo`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x7a4 | **Trigger information register** | `tinfo`
3+<| Reset value: `0x00000004`
3+<| This CSR is hardwired to "4" indicating there is only an "address match trigger" available. Any write access is ignored.
|======
:sectnums!:
===== **`tcontrol`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x7a5 | **Trigger control register** | `tcontrol`
3+<| Reset value: `0x00000000`
3+<| This CSR is not required for the NEORV32 trigger module. Hence, it is hardwired to zero and any write access is ignored.
|======
:sectnums!:
===== **`mcontext`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x7a8 | **Machine context register** | `mcontext`
3+<| Reset value: `0x00000000`
3+<| This CSR is not required for the NEORV32 trigger module. Hence, it is hardwired to zero and any write access is ignored.
|======
:sectnums!:
===== **`scontext`**
[cols="4,27,>7"]
[frame="topbot",grid="none"]
|======
| 0x7aa | **Supervisor context register** | `scontext`
3+<| Reset value: `0x00000000`
3+<| This CSR is not required for the NEORV32 trigger module. Hence, it is hardwired to zero and any write access is ignored.
|======