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


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: Extend current implementation with spec compliant implementation.

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


2. SWD Debug Transport Implementation

Goal: Add Serial Wire Debug support alongside JTAG. Reference Specs: ARM Debug Interface Architecture Specification ADIv6.0

The following Architecture diagram explains the components and data flow involved in debugging VexRiscv via SWD, showing both existing (implemented) and new (to be built) components with their implementation phases:

+===========================+
|     Debug Host PC         |
|   GDB + OpenOCD           |
|   (transport select swd)  |
+=============+=============+
              |
              | USB (CMSIS-DAP / J-Link / ST-Link)
              v
+===========================+
|     Debug Adapter         |
|  USB-to-SWD Converter     |
|  (probe hardware)         |
+=============+=============+
              |
              | SWCLK + SWDIO (2 wires)
              v
+=============================================================+
|                    Target System (FPGA)                     |
|                                                             |
|  +-------------------------------------------------------+  |
|  | SWD Interface  [Phase 2A]                             |  |
|  |                                                       |  |
|  |  SWD Pins ──> SWD Protocol State Machine              |  |
|  |  (SWCLK,      - 8-bit packet request parser           |  |
|  |   SWDIO)      - 3-bit ACK generator (OK/WAIT/FAULT)   |  |
|  |               - Turnaround & parity handling          |  |
|  |               - Line reset detection (50+ clocks)     |  |
|  +---------------------------+---------------------------+  |
|                              |                              |
|                              v                              |
|  +-------------------------------------------------------+  |
|  | SW-DP (Debug Port)  [Phase 2B]                        |  |
|  |                                                       |  |
|  |  DP Registers:                                        |  |
|  |  +--------+  +-----------+  +--------+                |  |
|  |  | DPIDR  |  | CTRL/STAT |  | SELECT |                |  |
|  |  | (ID)   |  | (sticky   |  | (AP/   |                |  |
|  |  |        |  |  errors)  |  |  bank) |                |  |
|  |  +--------+  +-----------+  +--------+                |  |
|  |  +--------+  +-----------+                            |  |
|  |  | RDBUFF |  |   ABORT   |                            |  |
|  |  | (read  |  | (error    |                            |  |
|  |  |  buf)  |  |  clear)   |                            |  |
|  |  +--------+  +-----------+                            |  |
|  +---------------------------+---------------------------+  |
|                              |                              |
|                              | AP Access                    |
|                              v                              |
|  +-------------------------------------------------------+  |
|  | DMI Bus Adapter  [Phase 2C]                           |  |
|  |                                                       |  |
|  |  AP addr + data  ──>  DebugBus.cmd (DebugCmd)         |  |
|  |  DebugBus.rsp (DebugRsp)  ──>  RDATA + ACK            |  |
|  |  (cross-clock-domain via ccToggle)                    |  |
|  +---------------------------+---------------------------+  |
|                              |                              |
|                              | DebugBus                     |
|                              | (DebugCmd / DebugRsp)        |
|                              v                              |
|  +---------------------------+---------------------------+  |
|  | Debug Module (DM)  [EXISTING - DebugModule.scala]     |  |
|  |                                                       |  |
|  |  dmcontrol (0x10)  |  dmstatus (0x11)                 |  |
|  |  abstractcs (0x16) |  command (0x17)                  |  |
|  |  data0-N (0x04+)   |  progbuf0-N (0x20+)              |  |
|  |  sbcs (0x38)       |  sbaddress0/sbdata0              |  |
|  |  hartinfo (0x12)   |  haltsum0 (0x40)                 |  |
|  +-------------+----------------+------------------------+  |
|                |                |                           |
|    DebugHartBus|                | SBA (System Bus Access)   |
|    (halt/resume|                |                           |
|     signals,   |                v                           |
|     dmToHart,  |  +-----------------------------------+     |
|     hartToDm)  |  | Memory System Bus                 |     |
|                |  | (Tilelink / AXI / Wishbone)       |     |
|                |  +-----------------------------------+     |
|                v                                            |
|  +-------------------------------------------------------+  |
|  | VexRiscv CPU  [EXISTING - CsrPlugin.scala]            |  |
|  |                                                       |  |
|  |  Debug CSRs:        Trigger Module:                   |  |
|  |  dcsr (0x7B0)       tselect (0x7A0)                   |  |
|  |  dpc  (0x7B1)       tdata1  (0x7A1) - type 2          |  |
|  |                     tdata2  (0x7A2) - PC match        |  |
|  |  Debug Mode:        tinfo   (0x7A4)                   |  |
|  |  entry/exit,                                          |  |
|  |  step FSM,          Instruction injection,            |  |
|  |  ebreakm/s/u        data CSR (0x7B4)                  |  |
|  +-------------------------------------------------------+  |
|                                                             |
+=============================================================+

Legend:

Key Insight:

Phase 2A (SWD Interface) + Phase 2B (SW-DP) together are the SWD equivalent of the existing JTAG DTM. They handle the wire protocol and produce DebugBus commands — the same DebugCmd/DebugRsp interface that the JTAG DTM already produces.

The Debug Module and VexRiscv CPU need NO changes — they only see DebugBus commands and have no knowledge of whether they came from JTAG or SWD.

SoC-level change: Only DebugModuleFiber.scala needs a new withSwdTransport() method alongside existing withJtagTap(), so the SoC builder can choose which transport to instantiate (or both, with a mux at the DebugBus level).

JTAG Path (EXISTING):                        SWD Path (NEW):
==============================               ==============================

JTAG TAP + dtmcs/dmi                         SWD Interface (Phase 2A)
(DebugTransportModuleJtag.scala)             + SW-DP registers (Phase 2B)
  - JTAG state machine                        - SWD protocol state machine
  - IR: IDCODE(0x01), dtmcs(0x10),            - 8-bit packet parser
    dmi(0x11)                                  - 3-bit ACK generator
  - DMI op/address/data in dmi DR              - DP regs: DPIDR, CTRL/STAT,
  - dmiStat busy/error handling                  SELECT, RDBUFF, ABORT
              |                                          |
              |  both produce the                        |
              |  same interface                          | DMI Bus Adapter
              v                                          | (Phase 2C)
        DebugBus (DebugCmd/DebugRsp)                     v
              |                                    DebugBus (DebugCmd/DebugRsp)
              |                                          |
              +──────────────► same bus ◄────────────────+
                                  |
                                  v
                     Debug Module (DM)  ◄── NO CHANGES NEEDED
                     (DebugModule.scala)    (transport-agnostic)
                                  |
                          DebugHartBus
                                  |
                                  v
                     VexRiscv CPU        ◄── NO CHANGES NEEDED
                     (CsrPlugin.scala)      (transport-agnostic)

Why Phase 2C (DMI Bus Adapter) is needed: In the JTAG path, the dmi shift register directly carries DMI address+data+op, so the translation to DebugBus is straightforward. In SWD, access goes through DP registers — the debugger writes SELECT to pick an AP address, then issues AP read/write operations. The adapter translates this DP/AP register access model into DebugBus read/write commands.

Suggested File: DebugTransportModuleSwd.scala (alongside existing DebugTransportModuleJtag.scala)

Phase 2A: SWD Protocol State Machine

Spec Reference: ADIv6.0 Sec B4.1-B4.2

Tasks:

Phase 2B: DP Register File

Spec Reference: ADIv6.0 Sec B2.2 (DP Reference Information)

Tasks:

Phase 2C: DMI Bus Adapter (SWD→DebugBus Bridge)

Spec Reference: Custom bridge layer

Tasks:


3. System Integration into SoC and Toolchain

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

JTAG Specific Tasks:

SWD Specific 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: