VexRiscv-Debug

MkDocs icon
SWD Debug support in VexRiscv

RISC-V Debug Support

RISC-V ISA

RISC-V is an open standard instruction set architecture based on established RISC (Reduced Instruction Set Computer) principles.

Comparing to ARM and x86, a RISC-V CPU has the following advantages:


RISC-V Minimal Viable Debugger

To create a minimum viable debugger on a RISC-V Processor, you need the following capabilities:

Here’s a simplified diagram representing these core components:

     +---------------------+      +-----------------------+
     |    Debugger Host    |      |    Target Device      |
     +---------------------+      +-----------------------+
             |                           |
             |      (Debug Interface)    |
             v                           v
    +-----------------------+      +-----------------------+
    |   Memory Access       |----->| Memory                |
    |  (Read/Write)         |      |                       |
    +-----------------------+      +-----------------------+
             |                           |
             |                           |
    +-----------------------+      +-----------------------+
    | CPU Register Access   |----->| CPU Registers         |
    |  (Read/Write)         |      |                       |
    +-----------------------+      +-----------------------+
             |                           |
             |                           |
    +-----------------------+      +-----------------------+
    |   CPU Control         |----->| CPU (Halt, Step, etc.)|
    | (Halt, Step, Reset)   |      |                       |
    +-----------------------+      +-----------------------+

Vexriscv Processor

VexRiscv is an FPGA-friendly CPU core that implements the RISC-V instruction set architecture (ISA). Designed with flexibility and scalability in mind, it caters to a wide range of applications, from compact microcontroller-based systems to more complex multi-core configurations. The project is open-source under the MIT license, promoting community collaboration and adaptation.

VexRiscv is developed using SpinalHDL, a high-level hardware description language that enhances design modularity and reusability. This approach allows for a plugin-based architecture, enabling users to customize and extend the CPU’s capabilities to meet specific project requirements.

JTAG support in Vexriscv

JTAG stands for Joint Test Action Group. JTAG support in VexRiscv is implemented through a combination of hardware and software components that adhere to the JTAG standard (IEEE 1149.1).

The diagram below describe how a host computer (with GDB) uses a JTAG interface to debug a VexRiscv CPU.


+-----------------+
|  GDB (Host PC)  |
+-------+---------+
        |
        v
+-----------------+     +--------------------+
|   OpenOCD       | --> |  JTAG Dongle       |
|(VexRiscv Driver)|     | (Jtag Uart Cable)  |
|   (Host PC)     |     |(TCK, TMS, TDI, TDO)|
+-----------------+     |                    |
                        +--------------------+
                                  |
                                  v
                    +--------------------------------------------------------------+
                    |                     Target                                   |
                    |    +-----------------+    +-------------------+              |
                    |    |  JTAG Bridge    |--->|  VexRiscv Debug   |              |
                    |    |(TAP, IR, DR,    |    |     Plugin        |              |
                    |    |State Machine)   |    |(SystemDebugBus)   |              |
                    |    +-----------------+    +--------+----------+              |
                    |                                | (CPU Control, Registers)    |
                    |                                v                             |
                    |                     +--------------------------+             |
                    |                     |      VexRiscv CPU        |             |
                    |                     +--------------------------+             |
                    +--------------------------------------------------------------+

Debugging VexRiscv using JTAG involves connecting a JTAG dongle to the FPGA, and then using OpenOCD with a VexRiscv specific driver, to communicate with the JTAG bridge, which accesses the CPU debug module, all while GDB executes on the host machine.

Host Setup

Terminal 1 on Host :

  openocd -f interface/ftdi/olimex-jtag-tiny.cfg -f target/riscv.cfg

Terminal 2 on Host :

  riscv32-unknown-elf-gdb hello.elf
  (gdb) target remote :3333
  (gdb) load
  (gdb) break main
  (gdb) continue
  (gdb) info registers
  (gdb) next
  (gdb) print message
  (gdb) x/16x 0x80000000

Target Setup

MkDocs icon


VexRiscv Current Debugging Status

The VexRiscv soft core supports minimal custom debugging by utilizing a debug plugin, which has two registers that allow for complete control of the CPU.

With these two registers, the core has all the necessary functions for a complete debugger, thus meeting the minimum requirements of a viable debugger.


Deviation from Standardized Debugging

The VexRiscv CPU has its own specific debugging implementation that is not compatible with the standard RISC-V Debug Specification (v1.0.0-rc4). Current deviation from the ratified RISC-V debug specification is listed below :

Current deviation from the ratified RISC-V debug specification is listed below :

Ratified Debug Spec Feature VexRiscv Support Status
Halt/Resume/Singlestep ✅ Supported
Register (GPR/CSR) Read/Write ✅ Via instruction injection
Memory Access via Abstract Commands ❌ Not standard; done via instruction injection
Hardware Breakpoints / Triggers ⚠️ Supports PC and load/store triggers, other modes not supported
Program Buffer ✅ Supported
Multi-hart / Multi-DM support ⚠️ Unable to halt/resume multiple harts with a single command
Alternate Transport Modules (non-JTAG) ❌ Not implemented
DM/DTM layer per spec ❌ Partial; custom version used, need to extend to supprt SWD

Other than above features , below feature needs to be implemented :


SWD support in Vexriscv

SWD stands for Serial Wire Debug. The key differences between JTAG and SWD are :

The following conceptual diagram explains the general components and data flow involved in debugging via SWD:

MkDocs icon

In the diagram:

To add support for the RISC-V debug standard over SWD in VexRiscv below steps need to be followed:

1. Debug Module (DM) Implementation:

2. Debug Transport Module (DTM) Implementation:

3. Mapping the Debug Module Interface (DMI) Implementation:


Breakdown of Tasks

1. Implement Standard Debug spec in Vexriscv

Goal: Replace proprietary implementation with spec compliant implementation.

Approach: Build a new DebugModulePlugin alongside the existing DebugPlugin.scala (which remains as a fallback). The existing plugin’s register interface has zero overlap with the spec, so extending it is not viable. The useful pieces (~50 lines of halt/step/RVC handling) will be extracted and reused.

Suggested File Structure:

src/main/scala/vexriscv/plugin/
  DebugPlugin.scala            ← KEEP (existing, for backward compat)
  DebugModulePlugin.scala      ← NEW: DM registers, abstract commands
  DebugTransportPlugin.scala   ← NEW: JTAG DTM with standard dtmcs/dmi
  DebugCsrPlugin.scala         ← NEW: dcsr, dpc, dscratch CSRs on hart
  TriggerPlugin.scala          ← NEW: tselect, tdata1/2/3, tinfo, tcontrol

Dependency Chain:

Phase 1A: JTAG DTM + DMI Bus           ← Foundation, no dependencies
    │
    ▼
Phase 1B: Core DM (dmcontrol/dmstatus)  ← Needs DMI bus
    │
    ▼
Phase 1C: Abstract Register Access      ← Needs DM registers
    │
    ├──▼
    │  Phase 1D: Debug CSRs (dcsr/dpc)   ← Needs register access
    │      │
    │      ▼
    │  Phase 1F: Trigger Module           ← Needs dcsr for cause reporting
    │
    └──▼
       Phase 1E: Memory Access            ← Needs abstract command framework

GDB Capability per Phase for Hello World Debugging

Phase Milestone GDB Capabilities What Can be Verified
1A DTM + DMI bus JTAG chain detected, nothing else JTAG connectivity
1B DM control Halt, resume, reset Hello world UART output starts/stops with halt/resume
1C Register access Read/write all GPRs and CSRs See PC, SP, arguments; identify which function is executing
1D Debug CSRs Single-step, halt cause, debug mode Step through instructions one at a time; see why hart halted
1E Memory access Full debug: load, break, step, print, backtrace, memory Complete hello world debug session (software breakpoints)
1F Triggers Hardware breakpoints, data watchpoints Breakpoints on ROM/flash; watch variable changes

Phases 1A-1D are incremental milestones that let you validate each layer before building the next. Phase 1E is the target for a complete hello world debugging experience with mainstream OpenOCD + GDB.

Detailed tasks and milestones planned for implementation of each Phase can be found at Standard Debug Spec Milestone.


2. SWD Debug Transport Implementation

Goal: Add Serial Wire Debug support alongside JTAG.

Tasks:


3. System Integration into SoC

Goal: Integrate the new debug architecture into the top-level FPGA/System design.

Tasks:


4. Verification & Test Infrastructure

Goal: Ensure the entire debug pipeline behaves per spec.

Tasks:


5. Documentation & Developer Interface

Goal: Make integration/usage clear for future development.

Tasks:


6. Multi-Hart & Advanced Features (Optional)

Goal: Add support for multiple cores and advanced features.

Tasks: