Skip to content

Commit

Permalink
🧪 add multi-hart support to on-chip-debugger's debu module (#1132)
Browse files Browse the repository at this point in the history
  • Loading branch information
stnolting authored Dec 29, 2024
2 parents 908cef4 + 4aac093 commit 03ac28b
Show file tree
Hide file tree
Showing 7 changed files with 475 additions and 338 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12

| Date | Version | Comment | Ticket |
|:----:|:-------:|:--------|:------:|
| 29.12.2024 | 1.10.8.4 | :warning: rename `SYSINFO.MEM -> SYSINFO.MISC`; add new `SYSINFO-MISC` entry for number of CPU cores (hardwired to one) | [#1134](https://github.com/stnolting/neorv32/pull/1134) |
| 29.12.2024 | 1.10.8.5 | :test_tube: add multi-hart support to debug module | [#1132](https://github.com/stnolting/neorv32/pull/1132) |
| 29.12.2024 | 1.10.8.4 | :warning: rename `SYSINFO.MEM -> SYSINFO.MISC`; add new `SYSINFO.MISC` entry for number of CPU cores (hardwired to one) | [#1134](https://github.com/stnolting/neorv32/pull/1134) |
| 29.12.2024 | 1.10.8.3 | :bug: fix incorrect HPM counter sizes if `HPM_CNT_WIDTH = 64` | [#1128](https://github.com/stnolting/neorv32/pull/1128) |
| 27.12.2024 | 1.10.8.2 | add out-of-band signals to internal request bus | [#1131](https://github.com/stnolting/neorv32/pull/1131) |
| 27.12.2024 | 1.10.8.1 | :warning: replace MTIME by CLINT; :warning: remove `HART_ID` generic | [#1130](https://github.com/stnolting/neorv32/pull/1130) |
Expand Down
278 changes: 169 additions & 109 deletions docs/datasheet/on_chip_debugger.adoc

Large diffs are not rendered by default.

396 changes: 225 additions & 171 deletions rtl/core/neorv32_debug_dm.vhd

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions rtl/core/neorv32_package.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ package neorv32_package is

-- Architecture Constants -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100804"; -- hardware version
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100805"; -- hardware version
constant archid_c : natural := 19; -- official RISC-V architecture ID
constant XLEN : natural := 32; -- native data path width

Expand Down Expand Up @@ -94,8 +94,8 @@ package neorv32_package is
constant base_io_ocd_c : std_ulogic_vector(31 downto 0) := x"ffff0000";

-- On-Chip Debugger - Debug Module Entry Points (Code ROM) --
constant dm_exc_entry_c : std_ulogic_vector(31 downto 0) := x"ffffff00"; -- = base_io_ocd_c + code_rom + 0
constant dm_park_entry_c : std_ulogic_vector(31 downto 0) := x"ffffff08"; -- = base_io_ocd_c + code_rom + 8
constant dm_exc_entry_c : std_ulogic_vector(31 downto 0) := x"fffffe00"; -- = base_io_ocd_c + code_rom_base + 0
constant dm_park_entry_c : std_ulogic_vector(31 downto 0) := x"fffffe10"; -- = base_io_ocd_c + code_rom_base + 16

-- **********************************************************************************************************
-- SoC Definitions
Expand Down
24 changes: 13 additions & 11 deletions rtl/core/neorv32_top.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,8 @@ architecture neorv32_top_rtl of neorv32_top is
signal dmi_rsp : dmi_rsp_t;

-- debug core interface (DCI) --
signal dci_ndmrstn, dci_haltreq : std_ulogic;
signal dci_ndmrstn : std_ulogic;
signal dci_haltreq : std_ulogic_vector(0 downto 0);

-- bus: core complex (CPU + caches) and DMA --
signal cpu_i_req, cpu_d_req, icache_req, dcache_req, core_req, main_req, main2_req, dma_req : bus_req_t;
Expand Down Expand Up @@ -538,7 +539,7 @@ begin
mei_i => mext_irq_i,
mti_i => mtime_irq,
firq_i => cpu_firq,
dbi_i => dci_haltreq,
dbi_i => dci_haltreq(0),
-- instruction bus interface --
ibus_req_o => cpu_i_req,
ibus_rsp_i => cpu_i_rsp,
Expand Down Expand Up @@ -1683,17 +1684,18 @@ begin
-- -------------------------------------------------------------------------------------------
neorv32_debug_dm_inst: entity neorv32.neorv32_debug_dm
generic map (
NUM_HARTS => 1,
AUTHENTICATOR => OCD_AUTHENTICATION
)
port map (
clk_i => clk_i,
rstn_i => rstn_ext,
dmi_req_i => dmi_req,
dmi_rsp_o => dmi_rsp,
bus_req_i => iodev_req(IODEV_OCD),
bus_rsp_o => iodev_rsp(IODEV_OCD),
cpu_ndmrstn_o => dci_ndmrstn,
cpu_halt_req_o => dci_haltreq
clk_i => clk_i,
rstn_i => rstn_ext,
dmi_req_i => dmi_req,
dmi_rsp_o => dmi_rsp,
bus_req_i => iodev_req(IODEV_OCD),
bus_rsp_o => iodev_rsp(IODEV_OCD),
ndmrstn_o => dci_ndmrstn,
halt_req_o => dci_haltreq
);

end generate;
Expand All @@ -1703,7 +1705,7 @@ begin
iodev_rsp(IODEV_OCD) <= rsp_terminate_c;
jtag_tdo_o <= jtag_tdi_i; -- JTAG pass-through
dci_ndmrstn <= '1';
dci_haltreq <= '0';
dci_haltreq <= (others => '0');
end generate;


Expand Down
9 changes: 4 additions & 5 deletions sw/ocd-firmware/debug_rom.ld
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
/* ================================================================================ */
/* NEORV32 CPU - RISC-V GCC Linker Script */
/* -------------------------------------------------------------------------------- */
/* For the execution-based on-chip debugger (OCD) code memory ROM: "park loop" code */
/* (build-in firmware) */
/* "Park loop" code for execution-based on-chip debugger'S (OCD) code ROM. */
/* -------------------------------------------------------------------------------- */
/* The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 */
/* Copyright (c) NEORV32 contributors. */
Expand All @@ -13,17 +12,17 @@

OUTPUT_FORMAT("elf32-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(__start)
ENTRY(_ocd_start)

MEMORY
{
debug_mem (rx) : ORIGIN = 0xFFFFFF00, LENGTH = 128
debug_rom (rx) : ORIGIN = 0xFFFFFE00, LENGTH = 128
}

SECTIONS
{
.text :
{
KEEP(*(.text.ocd));
} > debug_mem
} > debug_rom
}
97 changes: 59 additions & 38 deletions sw/ocd-firmware/park_loop.S
Original file line number Diff line number Diff line change
@@ -1,67 +1,88 @@
// ================================================================================ //
// NEORV32 CPU - park_loop.S - Execution-Based On-Chip Debugger (OCD) Firmware //
// -------------------------------------------------------------------------------- //
// WARNING! This code only supports up to 4 harts! //
// -------------------------------------------------------------------------------- //
// The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 //
// Copyright (c) NEORV32 contributors. //
// Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. //
// Licensed under the BSD-3-Clause license, see LICENSE for details. //
// SPDX-License-Identifier: BSD-3-Clause //
// ================================================================================ //

// debug module (DM) address map
.equ DM_CODE_BASE, 0xffffff00 // base address of debug_module's code ROM (park loop)
.equ DM_PBUF_BASE, 0xffffff40 // base address of debug_module's program buffer (PBUF)
.equ DM_DATA_BASE, 0xffffff80 // base address of debug_module's abstract data buffer (DATA)
.equ DM_SREG_BASE, 0xffffffC0 // base address of debug_module's status register

// status register (SREG) byte(!) offsets
.equ SREG_HLT_ACK, ( 0 / 8) // -/w: CPU has halted in debug mode and is waiting in park loop
.equ SREG_RES_REQ, ( 8 / 8) // r/-: DM requests to resume
.equ SREG_RES_ACK, ( 8 / 8) // -/w: CPU starts to resume
.equ SREG_EXE_REQ, (16 / 8) // r/-: DM requests to execute program buffer
.equ SREG_EXE_ACK, (16 / 8) // -/w: CPU starts to execute program buffer
.equ SREG_EXC_ACK, (24 / 8) // -/w: CPU has detected an exception while in debug-mode

.file "park_loop.S"
.section .text.ocd
.balign 4
.option norvc
.global __start
.global _ocd_start
.global entry_exception
.global entry_normal
.global entry_park

__start:
// debug module (DM) address map
.equ DM_CODE_BASE, 0xFFFFFE00 // base address of code ROM (park loop)
.equ DM_PBUF_BASE, 0xFFFFFE80 // base address of program buffer
.equ DM_DATA_BASE, 0xFFFFFF00 // base address of abstract data buffer
.equ DM_SREG_BASE, 0xFFFFFF80 // base address of status register(s)

// BASE + 0: exception entry - signal EXCEPTION condition to DM and restart parking loop
// Request register (DM_SREG_BASE read-access) byte-field bits
.equ REQ_RES, 0 // r/-: DM requests to resume
.equ REQ_EXE, 1 // r/-: DM requests to execute program buffer

// Acknowledge register (DM_SREG_BASE write-access) address offsets
.equ ACK_HLT, 0x0 // -/w: CPU has halted in debug mode and is waiting in park loop
.equ ACK_RES, 0x4 // -/w: CPU starts to resume
.equ ACK_EXE, 0x8 // -/w: CPU starts to execute program buffer
.equ ACK_EXC, 0xC // -/w: CPU has detected an exception while in debug-mode

_ocd_start:

// BASE + 0: exception entry - exeption during program buffer execution
entry_exception:
sb zero, (DM_SREG_BASE+SREG_EXC_ACK)(zero) // trigger exception-acknowledge to inform DM
ebreak // re-enter debug mode (at "entry_normal" entry point)
sw zero, (DM_SREG_BASE+ACK_EXC)(zero) // send exception-acknowledge (no need for a hart ID)
csrr x8, dscratch0 // restore x8 from dscratch0 (might be changed during PBUF execution)
ebreak // re-enter debug mode (at "entry_park" entry point)
nop // dummy to align the address of "entry_park"

// BASE + 8: normal entry - ebreak in debug-mode, halt request or return from single-stepped instruction
entry_normal:
csrw dscratch0, x8 // backup x8 to dscratch0 so we have a GPR available
// BASE + 16: normal entry - halt CPU: ebreak in debug-mode, halt request or return from single-stepped instruction
entry_park:
csrw dscratch0, x8 // backup x8 to dscratch0 so we have a GPR available
csrr x8, mhartid // get hart ID (0..3)
sw x8, (DM_SREG_BASE+ACK_HLT)(zero) // send halt-acknowledge

// polling loop - waiting for requests
park_loop:
sb zero, (DM_SREG_BASE+SREG_HLT_ACK)(zero) // ACK that CPU is halted
lbu x8, (DM_SREG_BASE+SREG_EXE_REQ)(zero) // request to execute program buffer?
bnez x8, execute
lbu x8, (DM_SREG_BASE+SREG_RES_REQ)(zero) // request to resume?
beqz x8, park_loop
csrr x8, mhartid // get hart ID (0..3)
lbu x8, DM_SREG_BASE(x8) // read hart-specific byte from request register
andi x8, x8, 1 << REQ_EXE // execute-request bit set?
bnez x8, execute

csrr x8, mhartid // get hart ID (0..3)
lbu x8, DM_SREG_BASE(x8) // read hart-specific byte from request register
andi x8, x8, 1 << REQ_RES // resume-request bit set?
beqz x8, park_loop

// resume normal operation
resume:
sb zero, (DM_SREG_BASE+SREG_RES_ACK)(zero) // ACK that CPU is about to resume
csrr x8, dscratch0 // restore x8 from dscratch0
dret // exit debug mode
csrr x8, mhartid // get hart ID (0..3)
sw x8, (DM_SREG_BASE+ACK_RES)(zero) // send resume-acknowledge
csrr x8, dscratch0 // restore x8 from dscratch0
dret // exit debug mode

// execute program buffer
// execute program buffer (implicit ebreak at the end of the buffer will bring us back to "entry_park")
execute:
sb zero, (DM_SREG_BASE+SREG_EXE_ACK)(zero) // ACK that execution is about to start
csrr x8, dscratch0 // restore x8 from dscratch0
fence.i // synchronize instruction fetch with memory (PBUF)
jalr zero, zero, %lo(DM_PBUF_BASE) // jump to beginning of program buffer (PBUF)
csrr x8, mhartid // get hart ID (0..3)
sw x8, (DM_SREG_BASE+ACK_EXE)(zero) // send execute-acknowledge
csrr x8, dscratch0 // restore x8 from dscratch0
fence.i // synchronize instruction fetch with memory (PBUF)
jalr zero, zero, %lo(DM_PBUF_BASE) // jump to beginning of program buffer (PBUF)

// fill remaining ROM space with instructions that cause a debug-mode-internal exception
unused:
ecall // should never be reached
unused: // should never be reached
ecall
ecall
ecall
ecall
ecall
ecall
ecall
ecall

0 comments on commit 03ac28b

Please sign in to comment.