RISCV memory access

 This is a small summary of why accessing memory when debugging a riscv cpu is complicated.

It is work in progress, the current code is available on swindle's github.

Introduction

As usual, as it is RISCV, a lot is optional with important details left to implementation

So let's see what is possible (definition from Gemini):

  • Recommended : Program Buffer Execution (ProgBuf): Memory is accessed by halting the CPU and executing standard load or store instructions placed into a dedicated buffer. This uses the core's native pipeline, meaning all MMU translations, Physical Memory Protection (PMP), and cache hierarchy rules apply automatically.
  • Optional: System Bus Access (SysBus): The Debug Module acts as an independent master directly on the system interconnect, bypassing the CPU entirely. This allows reading or writing physical memory while the core is actively running, though it does not go through the CPU's MMU or local L1/L2 caches. (NB this is more or less what ARM does).

  • Optional : Access Memory Abstract Commands (Abstrac): The Debug Module uses dedicated hardware interfaces to read or write memory locations directly. This provides rapid memory access without pushing assembly instruction sequences, though support for executing this while the core is running depends on the specific hardware implementation.

  • Optional : Access Memory Abstract Commands with autoexecute (AbstAuto) : Variant of abstract where it can auto execute upon writing to register.

NB: The ability to read/write while the MCU is running helps to have a better RTT system.


CH32V307  


So let's add some autoprobing extra code for swindle with the help of deepseek and gemini, a small derivation of the native blackmagic code. The goal is to get some numbers.

The numbers are the numbers of DMI accesses, so it's immune to interrupts, interface speed etc....

The benchmark writes and reads back either one 32 bits word or a block of 64 bits word

CH32V3xx results:
Running RISC-V memory benchmark at 0x20000000
Abstract  : OK (1-word: 10 DMI, 64-word: 514 DMI)
AbstAuto  : OK (1-word: 16 DMI, 64-word: 142 DMI)
Progbuf   : OK (1-word: 61 DMI, 64-word: 188 DMI)
Sysbus    : UNSUPPORTED

Ok so no sysbus. Abstract with auto exec *IS* supported and is the faster. Let's use that.

Wait a second, actually it IS the faster IF the block size is big enough (like 4 words). So we should use abstract for "small" blocks, and "abstract + autoexec" for larger blocks for a 20% speed up.

RP2350 Hazard3

Ok, to see how much fun is the RISCV ecosystem, let's do the same thing on a RP2350 running in RISCV mode :

Abstract  : FAILED
AbstAuto  : FAILED
Progbuf   : OK (1-word: 52 DMI, 64-word: 1060 DMI)
Sysbus    : OK (1-word: 10 DMI, 64-word: 137 DMI)

 Ok, so completely different picture. Please note how bad the progbuf performs.


Conclusion

In order to get the best results significant code needs to be there to handle all configurations and even using 2 (or 3) memory access methods : For small blocks, for larger block, to do it without stopping the MCU.

The difference in performances between faster and slower is HUGE.

Again, this is work in progress and might be incorrect.




Comments

Popular posts from this blog

G600 Microscope Battery charging mod

INA3221, weird wiring

Component tester with STM32 : Part 1 ADC, Resistor