7
31
Fork
You've already forked blackmagic
23

Feature: RISC-V semihosting support #2115

Merged
ALTracer merged 6 commits from ALTracer/feature/riscv-semihosting into main 2026年03月29日 23:19:39 +02:00
ALTracer commented 2025年04月27日 14:25:30 +02:00 (Migrated from github.com)
Copy link

Detailed description

  • This is enough code for a new feature.
  • The existing problem is RISC-V semihosting calls not supported by BMD -- target gets stuck on any ebreak, does not step over (unless you manually set $pc=$pc+4).
  • Ths PR solves it by cloning cortexm_hostio_request() into riscv_debug.c and hooking it to riscv_halt_poll() in much the same fashion. Entire semihosting.c can be reused because https://github.com/riscv-non-isa/riscv-semihosting follows https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst w.r.t. syscall numbers and calling convention. Thanks to maintainers for refactoring and splitting out the common code of BMD implementation.

Additional code for stepping over XLEN-wide EBREAK helps me avoid doing $pc manipulation from gdb console, although I'm not sure how correct is it to do so.

Tested on Pico 2 board running basically https://github.com/raspberrypi/pico-examples/blob/master/hello_world/serial/hello_serial.c on the first Hazard3/RISC-V core, but using PICO_STDIO_SEMIHOSTING not PICO_STDIO_UART. Debugger is blackpill-f411ce, running BMF v2.0 with full newlib (not nano because of rvhuimac bug) and/or BMDA. Not tested on RV64. There were 2-byte compressed instructions in disassembly AFAICS, like 0x9002 short ebreak elsewhere, but BMD memory access layer works regardless.

Disassembly snippet of semihosting trampoline
static void stdio_semihosting_out_chars(const char *buf, int length) {
100011a4: 1141 addi sp,sp,-16
 size_t fd;
 const char *buf;
 size_t len;
 } args;

 args.fd = 2; // 2 = stdout
100011a6: 4789 li a5,2
100011a8: c23e sw a5,4(sp)
 args.buf = buf;
100011aa: c42a sw a0,8(sp)
 args.len = length;
100011ac: c62e sw a1,12(sp)
 pico_default_asm (
100011ae: 005c addi a5,sp,4
100011b0: 4515 li a0,5
100011b2: 85be mv a1,a5
100011b4: 01f01013 slli zero,zero,0x1f
100011b8: 00100073 ebreak
100011bc: 40705013 srai zero,zero,0x7
 :
 : [args] "r" (&args)
 : "r0", "r1", "cc", "memory"
#endif
 );
}
100011c0: 0141 addi sp,sp,16
100011c2: 8082 ret

The same helloworld runs on Cortex-M33 (ARM Secure) when recompiled to, and both arches exhibit a bug where the emit Fwrite packets to file descriptor 0 (subtracted 1 from callsite https://github.com/raspberrypi/pico-sdk/blob/2.1.1/src/rp2_common/pico_stdio_semihosting/stdio_semihosting.c#L24), and I'm not sure whose bug this is. Previously Cortex-M semihosting worked from --rdimon.specs as well as fw-test (on random cortexm targets I mean), so I think Pico C SDK should be fixed, which is what I did locally. Porting blackmagic-test-fw-archive to RISC-V could help test the other calls, I only checked 0x5 SYS_WRITE to fd 2 (stdout) which works, without fd=Fopen(":tt"), both in GDB and in BMF redirect_stdout, as well as DEBUG_INFO("syscall ") diagnostic logs.

This branch is based on #2113 but I could rebase it away because Hazard3/ice40 is not strictly required, it's just another target applicable to testing.
Some refactoring may be needed, like extracting macros for preamble/postamble slli/srai instructions, and that's for review process to deal with.
Scope of support (and possible testing) is obviously RP2350, ESP32-C3/C6 (with manual assembly, no ESP-IDF), GD32VF103 (with -lrdimon etc.), maybe CH32V205/V307 once RVSWD transport is merged, maybe Milk-V Duo and other chips with no flash driver support merged.

Your checklist for this pull request

Closing issues

## Detailed description * This is enough code for a new feature. * The existing problem is RISC-V semihosting calls not supported by BMD -- target gets stuck on any ebreak, does not step over (unless you manually set $pc=$pc+4). * Ths PR solves it by cloning `cortexm_hostio_request()` into riscv_debug.c and hooking it to `riscv_halt_poll()` in much the same fashion. Entire semihosting.c can be reused because https://github.com/riscv-non-isa/riscv-semihosting follows https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst w.r.t. syscall numbers and calling convention. Thanks to maintainers for refactoring and splitting out the common code of BMD implementation. Additional code for stepping over XLEN-wide EBREAK helps me avoid doing $pc manipulation from gdb console, although I'm not sure how correct is it to do so. Tested on Pico 2 board running basically https://github.com/raspberrypi/pico-examples/blob/master/hello_world/serial/hello_serial.c on the first Hazard3/RISC-V core, but using `PICO_STDIO_SEMIHOSTING` not `PICO_STDIO_UART`. Debugger is `blackpill-f411ce`, running BMF v2.0 with full newlib (not nano because of rv`hu`imac bug) and/or BMDA. Not tested on RV64. There were 2-byte compressed instructions in disassembly AFAICS, like 0x9002 short ebreak elsewhere, but BMD memory access layer works regardless. <details> <summary> Disassembly snippet of semihosting trampoline </summary> ```asm static void stdio_semihosting_out_chars(const char *buf, int length) { 100011a4: 1141 addi sp,sp,-16 size_t fd; const char *buf; size_t len; } args; args.fd = 2; // 2 = stdout 100011a6: 4789 li a5,2 100011a8: c23e sw a5,4(sp) args.buf = buf; 100011aa: c42a sw a0,8(sp) args.len = length; 100011ac: c62e sw a1,12(sp) pico_default_asm ( 100011ae: 005c addi a5,sp,4 100011b0: 4515 li a0,5 100011b2: 85be mv a1,a5 100011b4: 01f01013 slli zero,zero,0x1f 100011b8: 00100073 ebreak 100011bc: 40705013 srai zero,zero,0x7 : : [args] "r" (&args) : "r0", "r1", "cc", "memory" #endif ); } 100011c0: 0141 addi sp,sp,16 100011c2: 8082 ret ``` </details> The same helloworld runs on Cortex-M33 (ARM Secure) when recompiled to, and both arches exhibit a bug where the emit Fwrite packets to file descriptor 0 (subtracted 1 from callsite https://github.com/raspberrypi/pico-sdk/blob/2.1.1/src/rp2_common/pico_stdio_semihosting/stdio_semihosting.c#L24), and I'm not sure whose bug this is. Previously Cortex-M semihosting worked from --rdimon.specs as well as fw-test (on random cortexm targets I mean), so I think Pico C SDK should be fixed, which is what I did locally. Porting blackmagic-test-fw-archive to RISC-V could help test the other calls, I only checked 0x5 SYS_WRITE to fd 2 (stdout) which works, without fd=Fopen(":tt"), both in GDB and in BMF redirect_stdout, as well as `DEBUG_INFO("syscall ")` diagnostic logs. This branch is based on #2113 but I could rebase it away because Hazard3/ice40 is not strictly required, it's just another target applicable to testing. Some refactoring may be needed, like extracting macros for preamble/postamble slli/srai instructions, and that's for review process to deal with. Scope of support (and possible testing) is obviously RP2350, ESP32-C3/C6 (with manual assembly, no ESP-IDF), GD32VF103 (with -lrdimon etc.), maybe CH32V205/V307 once RVSWD transport is merged, maybe Milk-V Duo and other chips with no flash driver support merged. ## Your checklist for this pull request * [x] I've read the [Code of Conduct](https://github.com/blackmagic-debug/blackmagic/blob/main/CODE_OF_CONDUCT.md) * [x] I've read the [guidelines for contributing](https://github.com/blackmagic-debug/blackmagic/blob/main/CONTRIBUTING.md) to this repository * [x] It builds for hardware native (see [Building the firmware](https://github.com/blackmagic-debug/blackmagic?tab=readme-ov-file#building-black-magic-debug-firmware)) * [x] It builds as BMDA (see [Building the BMDA](https://github.com/blackmagic-debug/blackmagic?tab=readme-ov-file#building-black-magic-debug-app)) * [x] I've tested it to the best of my ability * [x] My commit messages provide a useful short description of what the commits do ## Closing issues
dragonmux force-pushed ALTracer/feature/riscv-semihosting from 2b7899dc80 to e08f0edf06
Some checks failed
ci/woodpecker/pr/build-firmware/8 Pipeline was successful
ci/woodpecker/pr/build-firmware/4 Pipeline was successful
ci/woodpecker/pr/build-firmware/1 Pipeline was successful
ci/woodpecker/pr/build-firmware/5 Pipeline was successful
ci/woodpecker/pr/build-firmware/3 Pipeline was successful
ci/woodpecker/pr/build-firmware/2 Pipeline was successful
ci/woodpecker/pr/build-firmware/7 Pipeline was successful
ci/woodpecker/pr/build-firmware/6 Pipeline was successful
ci/woodpecker/pr/build-firmware/9 Pipeline was successful
ci/woodpecker/pr/build-firmware/10 Pipeline was successful
ci/woodpecker/pr/build-firmware/11 Pipeline was successful
ci/woodpecker/pr/build-firmware/16 Pipeline was successful
ci/woodpecker/pr/build-firmware/13 Pipeline failed
ci/woodpecker/pr/build-firmware/12 Pipeline was successful
ci/woodpecker/pr/build-firmware/14 Pipeline was successful
ci/woodpecker/pr/build-firmware/15 Pipeline was successful
ci/woodpecker/pr/build-linux/1 Pipeline was successful
ci/woodpecker/pr/build-firmware/18 Pipeline was successful
ci/woodpecker/pr/build-firmware/17 Pipeline was successful
ci/woodpecker/pr/build-linux/2 Pipeline was successful
ci/woodpecker/pr/build-firmware/19 Pipeline was successful
ci/woodpecker/pr/build-firmware/20 Pipeline was successful
ci/woodpecker/pr/build-windows Pipeline was successful
2026年03月22日 21:32:56 +01:00
Compare
dragonmux requested changes 2026年03月23日 10:54:14 +01:00
Dismissed
dragonmux left a comment
Copy link

There are a few things that could do with some tweaking, but overall this looks pretty good. With them taken care of we'll be happy to get this provisional RV semihosting support merged.

There are a few things that could do with some tweaking, but overall this looks pretty good. With them taken care of we'll be happy to get this provisional RV semihosting support merged.
@ -896,1 +897,4 @@
static target_addr_t riscv_pc_read(riscv_hart_s *const hart)
{
target_addr_t data = 0;

Missing U suffix. Use target_addr64_t as insurance when this code is run on a 64-bit RV part?

Missing `U` suffix. Use `target_addr64_t` as insurance when this code is run on a 64-bit RV part?
dragonmux marked this conversation as resolved
@ -897,0 +899,4 @@
{
target_addr_t data = 0;
riscv_csr_read(hart, RV_DPC, &data);
//riscv32_reg_read(target, 32, &data, sizeof(data));

This line doesn't look like it has any purpose?..

This line doesn't look like it has any purpose?..
Contributor
Copy link

Yes, I'll remove it. Initially, of course, I looked at cortexm.c driver and wanted to read $PC, which would be g-p reg 15 in DCRSR. riscv32.c contains special treatment for reg 32 and returns RV_DPC value. But then I've noticed I can skip a layer.

Yes, I'll remove it. Initially, of course, I looked at `cortexm.c` driver and wanted to read $PC, which would be g-p reg 15 in DCRSR. `riscv32.c` contains special treatment for reg 32 and returns RV_DPC value. But then I've noticed I can skip a layer.
dragonmux marked this conversation as resolved
@ -897,0 +907,4 @@
{
/* Read out syscall number from a0/x10 and first argument from a1/x11 */
uint32_t syscall = 0U;
target_reg_read(target, 10, &syscall, sizeof(syscall));

Is there a reason you're not using a 64-bit variable for each of these and naming the registers with #define's? eg, RV_REG_A0, RV_REG_A1

Is there a reason you're not using a 64-bit variable for each of these and naming the registers with `#define`'s? eg, `RV_REG_A0`, `RV_REG_A1`
Contributor
Copy link

Yes, the reason is I don't have any RV64 processors debuggable by BMD to test on (or care about). If it's as easy as allocating 64-bit variables and paying that price on RV32 debug in firmware, then I'll extend them.
I can use RV_GPR_A0, which is in TU scope, for the otherwise direct port of cortexm_hostio_request() which uses 0 and 1 for register numbers, not r0/r1. However, first argument is in RV_GPR_A1 and I would like to add that macro for unrelated Progbuf-based memory access PR (so that it's not (RV_GPR_A0 + 1)).

Yes, the reason is I don't have any RV64 processors debuggable by BMD to test on (or care about). If it's as easy as allocating 64-bit variables and paying that price on RV32 debug in firmware, then I'll extend them. I can use RV_GPR_A0, which is in TU scope, for the otherwise direct port of `cortexm_hostio_request()` which uses 0 and 1 for register numbers, not r0/r1. However, first argument is in RV_GPR_A1 and I would like to add that macro for unrelated Progbuf-based memory access PR (so that it's not `(RV_GPR_A0 + 1)`).

We would prefer with A1 for there to be an actual macro and for it to be defined to just the register's index, not defined in terms of A0, so that works.

We would prefer with A1 for there to be an actual macro and for it to be defined to just the register's index, not defined in terms of A0, so that works.
dragonmux marked this conversation as resolved
@ -1108,1 +1134,4 @@
return;
/* Step over coded breakpoints */
uint32_t dcsr_cause = 0U;
riscv_csr_read(hart, RV_DCSR, &dcsr_cause);

You may wish to provide RV_CSR_FORCE_32_BIT here so the cause value doesn't fail to read due to there not being enough space to hold it when used on a 64-bit part.

You may wish to provide `RV_CSR_FORCE_32_BIT` here so the cause value doesn't fail to read due to there not being enough space to hold it when used on a 64-bit part.
Contributor
Copy link

Accepted. Is that stepping_config also RV_DCSR? Can I eliminate a bunch of DM accesses?

Accepted. Is that `stepping_config` also RV_DCSR? Can I eliminate a bunch of DM accesses?

Yes, it is - forced-to-32-bit accesses for reading out the register and then setting up continuation state

Yes, it is - forced-to-32-bit accesses for reading out the register and then setting up continuation state
Contributor
Copy link

I don't want to drag this any further, it can be revisited if double RV_DCSR reads end up a bottleneck.

I don't want to drag this any further, it can be revisited if double RV_DCSR reads end up a bottleneck.
dragonmux marked this conversation as resolved
@ -1136,0 +1178,4 @@
uint32_t instructions[3] = {0};
target_mem32_read(target, &instructions, program_counter - 4U, 12);
/* A semihosting call is three consecutive uncompressed instructions: slli zero, zero 0x1f; ebreak, srai zero, zero, 7. */
if (instructions[0] == 0x01f01013 && instructions[1] == RV_EBREAK && instructions[2] == 0x40705013) {

Please suffix these constants with U and, preferably, name them with some #defines at top of file to say what they are and mean.

Please suffix these constants with `U` and, preferably, name them with some `#defines` at top of file to say what they are and mean.
Contributor
Copy link

RV_SLLI_X0_X0_1F and RV_SRAI_X0_X0_7 would be precise and useless, so what should they be called? G-p reg X0 is called "zero", which is even longer. Maybe RV_ENTRY_NOP and RV_EXIT_NOP?

RV_SLLI_X0_X0_1F and RV_SRAI_X0_X0_7 would be precise and useless, so what should they be called? G-p reg X0 is called "zero", which is even longer. Maybe RV_ENTRY_NOP and RV_EXIT_NOP?

RV_ENTRY_NOP and RV_EXIT_NOP work 👍 - we can always add that they're semihosting at a later point, but having them as named and documented constants is already a massive improvement and what we were hoping for here.

RV_ENTRY_NOP and RV_EXIT_NOP work 👍 - we can always add that they're semihosting at a later point, but having them as named and documented constants is already a massive improvement and what we were hoping for here.
dragonmux marked this conversation as resolved
riscv_debug: Prepare for 64-bit DPC and address space in semihosting
Some checks failed
ci/woodpecker/pr/build-firmware/6 Pipeline was successful
ci/woodpecker/pr/build-firmware/2 Pipeline was successful
ci/woodpecker/pr/build-firmware/5 Pipeline was successful
ci/woodpecker/pr/build-firmware/1 Pipeline was successful
ci/woodpecker/pr/build-firmware/4 Pipeline was successful
ci/woodpecker/pr/build-firmware/7 Pipeline was successful
ci/woodpecker/pr/build-firmware/3 Pipeline was successful
ci/woodpecker/pr/build-firmware/8 Pipeline failed
ci/woodpecker/pr/build-firmware/13 Pipeline failed
ci/woodpecker/pr/build-firmware/10 Pipeline was successful
ci/woodpecker/pr/build-firmware/12 Pipeline was successful
ci/woodpecker/pr/build-firmware/9 Pipeline was successful
ci/woodpecker/pr/build-firmware/14 Pipeline was successful
ci/woodpecker/pr/build-firmware/15 Pipeline was successful
ci/woodpecker/pr/build-firmware/11 Pipeline was successful
ci/woodpecker/pr/build-linux/1 Pipeline was successful
ci/woodpecker/pr/build-linux/2 Pipeline was successful
ci/woodpecker/pr/build-firmware/20 Pipeline was successful
ci/woodpecker/pr/build-firmware/19 Pipeline was successful
ci/woodpecker/pr/build-firmware/18 Pipeline was successful
ci/woodpecker/pr/build-firmware/16 Pipeline was successful
ci/woodpecker/pr/build-firmware/17 Pipeline was successful
ci/woodpecker/pr/build-windows Pipeline was successful
c3dd76607e
dragonmux force-pushed ALTracer/feature/riscv-semihosting from c3dd76607e
Some checks failed
ci/woodpecker/pr/build-firmware/6 Pipeline was successful
ci/woodpecker/pr/build-firmware/2 Pipeline was successful
ci/woodpecker/pr/build-firmware/5 Pipeline was successful
ci/woodpecker/pr/build-firmware/1 Pipeline was successful
ci/woodpecker/pr/build-firmware/4 Pipeline was successful
ci/woodpecker/pr/build-firmware/7 Pipeline was successful
ci/woodpecker/pr/build-firmware/3 Pipeline was successful
ci/woodpecker/pr/build-firmware/8 Pipeline failed
ci/woodpecker/pr/build-firmware/13 Pipeline failed
ci/woodpecker/pr/build-firmware/10 Pipeline was successful
ci/woodpecker/pr/build-firmware/12 Pipeline was successful
ci/woodpecker/pr/build-firmware/9 Pipeline was successful
ci/woodpecker/pr/build-firmware/14 Pipeline was successful
ci/woodpecker/pr/build-firmware/15 Pipeline was successful
ci/woodpecker/pr/build-firmware/11 Pipeline was successful
ci/woodpecker/pr/build-linux/1 Pipeline was successful
ci/woodpecker/pr/build-linux/2 Pipeline was successful
ci/woodpecker/pr/build-firmware/20 Pipeline was successful
ci/woodpecker/pr/build-firmware/19 Pipeline was successful
ci/woodpecker/pr/build-firmware/18 Pipeline was successful
ci/woodpecker/pr/build-firmware/16 Pipeline was successful
ci/woodpecker/pr/build-firmware/17 Pipeline was successful
ci/woodpecker/pr/build-windows Pipeline was successful
to d1f6de56bd
Some checks failed
ci/woodpecker/pr/build-firmware/8 Pipeline failed
ci/woodpecker/pr/build-firmware/6 Pipeline was successful
ci/woodpecker/pr/build-firmware/5 Pipeline was successful
ci/woodpecker/pr/build-firmware/1 Pipeline was successful
ci/woodpecker/pr/build-firmware/2 Pipeline was successful
ci/woodpecker/pr/build-firmware/7 Pipeline was successful
ci/woodpecker/pr/build-firmware/3 Pipeline was successful
ci/woodpecker/pr/build-firmware/4 Pipeline was successful
ci/woodpecker/pr/build-firmware/9 Pipeline was successful
ci/woodpecker/pr/build-firmware/13 Pipeline failed
ci/woodpecker/pr/build-firmware/14 Pipeline was successful
ci/woodpecker/pr/build-firmware/12 Pipeline was successful
ci/woodpecker/pr/build-firmware/16 Pipeline was successful
ci/woodpecker/pr/build-firmware/17 Pipeline was successful
ci/woodpecker/pr/build-firmware/15 Pipeline was successful
ci/woodpecker/pr/build-firmware/10 Pipeline was successful
ci/woodpecker/pr/build-firmware/18 Pipeline was successful
ci/woodpecker/pr/build-firmware/11 Pipeline was successful
ci/woodpecker/pr/build-linux/1 Pipeline was successful
ci/woodpecker/pr/build-firmware/19 Pipeline was successful
ci/woodpecker/pr/build-firmware/20 Pipeline was successful
ci/woodpecker/pr/build-linux/2 Pipeline was successful
ci/woodpecker/pr/build-windows Pipeline was successful
2026年03月23日 21:22:39 +01:00
Compare
@ -112,6 +113,8 @@
/* GPR a0, aka x10 is used as a bounce buffer for our progbuf CSR I/O */

Might be worth editing this GPR description to include a bit about it being used as the semihosting syscall number and result register too.

Might be worth editing this GPR description to include a bit about it being used as the semihosting syscall number and result register too.
Contributor
Copy link

It is commented in riscv_hostio_request() but sure.

It is commented in riscv_hostio_request() but sure.
dragonmux marked this conversation as resolved
dragonmux force-pushed ALTracer/feature/riscv-semihosting from 5d6fb753c5 to 5f145abd4b
Some checks failed
ci/woodpecker/pr/build-firmware/5 Pipeline was successful
ci/woodpecker/pr/build-firmware/4 Pipeline was successful
ci/woodpecker/pr/build-firmware/1 Pipeline was successful
ci/woodpecker/pr/build-firmware/6 Pipeline was successful
ci/woodpecker/pr/build-firmware/7 Pipeline was successful
ci/woodpecker/pr/build-firmware/2 Pipeline was successful
ci/woodpecker/pr/build-firmware/3 Pipeline was successful
ci/woodpecker/pr/build-firmware/8 Pipeline failed
ci/woodpecker/pr/build-firmware/12 Pipeline was successful
ci/woodpecker/pr/build-firmware/13 Pipeline failed
ci/woodpecker/pr/build-firmware/14 Pipeline was successful
ci/woodpecker/pr/build-firmware/9 Pipeline was successful
ci/woodpecker/pr/build-firmware/10 Pipeline was successful
ci/woodpecker/pr/build-firmware/11 Pipeline was successful
ci/woodpecker/pr/build-firmware/15 Pipeline was successful
ci/woodpecker/pr/build-linux/1 Pipeline was successful
ci/woodpecker/pr/build-firmware/16 Pipeline was successful
ci/woodpecker/pr/build-linux/2 Pipeline was successful
ci/woodpecker/pr/build-firmware/17 Pipeline was successful
ci/woodpecker/pr/build-firmware/19 Pipeline was successful
ci/woodpecker/pr/build-firmware/18 Pipeline was successful
ci/woodpecker/pr/build-firmware/20 Pipeline was successful
ci/woodpecker/pr/build-windows Pipeline was successful
2026年03月27日 23:15:44 +01:00
Compare
@ -897,0 +920,4 @@
{
/* Read out syscall number from a0/x10 and first argument from a1/x11 */
uint32_t syscall = 0U;
target_reg_read(target, RV_GPR_A0 - RV_GPR_BASE, &syscall, sizeof(syscall));

Just realised that this likely actually wants to be riscv_csr_read() and into a uint64_t so we automatically handle 64-bit targets and don't have to do the silly with subtracting RV_GPR_BASE - from this architecture's perspective you're wanting to do a CSR read, which then bypasses all the GDB alignment machinary involved in interfacing to the target register API layer.

Just realised that this likely actually wants to be `riscv_csr_read()` and into a uint64_t so we automatically handle 64-bit targets and don't have to do the silly with subtracting `RV_GPR_BASE` - from this architecture's perspective you're wanting to do a CSR read, which then bypasses all the GDB alignment machinary involved in interfacing to the target register API layer.
Contributor
Copy link

Replacing reads with riscv_csr_read() is simple enough (grabbing riscv_hart_struct()), however semihosting_request() expects and returns 32-bit numbers, what do I do about that? Especially with result writeback in riscv_csr_write(hart, RV_GPR_A0, &result)
Likewise I think that by the same token cortexm_hostio_request() should be sed -i s/target_reg_read/cortexm_reg_read/gas it's the only use of indirection layer in that source (and reg_write).

Replacing reads with `riscv_csr_read()` is simple enough (grabbing `riscv_hart_struct()`), however `semihosting_request()` expects and returns 32-bit numbers, what do I do about that? Especially with result writeback in `riscv_csr_write(hart, RV_GPR_A0, &result)` Likewise I think that by the same token `cortexm_hostio_request()` should be `sed -i s/target_reg_read/cortexm_reg_read/g`as it's the only use of indirection layer in that source (and reg_write).

For now, just let the numbers get truncated down to 32 bits - we can fix the API in a follow-up.. having this be correct in this layer is worth it.

For now, just let the numbers get truncated down to 32 bits - we can fix the API in a follow-up.. having this be correct in this layer is worth it.
dragonmux marked this conversation as resolved
dragonmux force-pushed ALTracer/feature/riscv-semihosting from 5f145abd4b
Some checks failed
ci/woodpecker/pr/build-firmware/5 Pipeline was successful
ci/woodpecker/pr/build-firmware/4 Pipeline was successful
ci/woodpecker/pr/build-firmware/1 Pipeline was successful
ci/woodpecker/pr/build-firmware/6 Pipeline was successful
ci/woodpecker/pr/build-firmware/7 Pipeline was successful
ci/woodpecker/pr/build-firmware/2 Pipeline was successful
ci/woodpecker/pr/build-firmware/3 Pipeline was successful
ci/woodpecker/pr/build-firmware/8 Pipeline failed
ci/woodpecker/pr/build-firmware/12 Pipeline was successful
ci/woodpecker/pr/build-firmware/13 Pipeline failed
ci/woodpecker/pr/build-firmware/14 Pipeline was successful
ci/woodpecker/pr/build-firmware/9 Pipeline was successful
ci/woodpecker/pr/build-firmware/10 Pipeline was successful
ci/woodpecker/pr/build-firmware/11 Pipeline was successful
ci/woodpecker/pr/build-firmware/15 Pipeline was successful
ci/woodpecker/pr/build-linux/1 Pipeline was successful
ci/woodpecker/pr/build-firmware/16 Pipeline was successful
ci/woodpecker/pr/build-linux/2 Pipeline was successful
ci/woodpecker/pr/build-firmware/17 Pipeline was successful
ci/woodpecker/pr/build-firmware/19 Pipeline was successful
ci/woodpecker/pr/build-firmware/18 Pipeline was successful
ci/woodpecker/pr/build-firmware/20 Pipeline was successful
ci/woodpecker/pr/build-windows Pipeline was successful
to 22b92866b7
Some checks failed
ci/woodpecker/pr/build-firmware/3 Pipeline was successful
ci/woodpecker/pr/build-firmware/2 Pipeline was successful
ci/woodpecker/pr/build-firmware/5 Pipeline was successful
ci/woodpecker/pr/build-firmware/1 Pipeline was successful
ci/woodpecker/pr/build-firmware/6 Pipeline was successful
ci/woodpecker/pr/build-firmware/7 Pipeline was successful
ci/woodpecker/pr/build-firmware/4 Pipeline was successful
ci/woodpecker/pr/build-firmware/8 Pipeline failed
ci/woodpecker/pr/build-firmware/9 Pipeline was successful
ci/woodpecker/pr/build-firmware/11 Pipeline was successful
ci/woodpecker/pr/build-firmware/14 Pipeline was successful
ci/woodpecker/pr/build-firmware/16 Pipeline was successful
ci/woodpecker/pr/build-firmware/10 Pipeline was successful
ci/woodpecker/pr/build-firmware/13 Pipeline failed
ci/woodpecker/pr/build-firmware/12 Pipeline was successful
ci/woodpecker/pr/build-firmware/15 Pipeline was successful
ci/woodpecker/pr/build-linux/1 Pipeline was successful
ci/woodpecker/pr/build-linux/2 Pipeline was successful
ci/woodpecker/pr/build-firmware/20 Pipeline was successful
ci/woodpecker/pr/build-firmware/17 Pipeline was successful
ci/woodpecker/pr/build-firmware/18 Pipeline was successful
ci/woodpecker/pr/build-firmware/19 Pipeline was successful
ci/woodpecker/pr/build-windows Pipeline was successful
2026年03月29日 19:37:03 +02:00
Compare
dragonmux force-pushed ALTracer/feature/riscv-semihosting from 22b92866b7
Some checks failed
ci/woodpecker/pr/build-firmware/3 Pipeline was successful
ci/woodpecker/pr/build-firmware/2 Pipeline was successful
ci/woodpecker/pr/build-firmware/5 Pipeline was successful
ci/woodpecker/pr/build-firmware/1 Pipeline was successful
ci/woodpecker/pr/build-firmware/6 Pipeline was successful
ci/woodpecker/pr/build-firmware/7 Pipeline was successful
ci/woodpecker/pr/build-firmware/4 Pipeline was successful
ci/woodpecker/pr/build-firmware/8 Pipeline failed
ci/woodpecker/pr/build-firmware/9 Pipeline was successful
ci/woodpecker/pr/build-firmware/11 Pipeline was successful
ci/woodpecker/pr/build-firmware/14 Pipeline was successful
ci/woodpecker/pr/build-firmware/16 Pipeline was successful
ci/woodpecker/pr/build-firmware/10 Pipeline was successful
ci/woodpecker/pr/build-firmware/13 Pipeline failed
ci/woodpecker/pr/build-firmware/12 Pipeline was successful
ci/woodpecker/pr/build-firmware/15 Pipeline was successful
ci/woodpecker/pr/build-linux/1 Pipeline was successful
ci/woodpecker/pr/build-linux/2 Pipeline was successful
ci/woodpecker/pr/build-firmware/20 Pipeline was successful
ci/woodpecker/pr/build-firmware/17 Pipeline was successful
ci/woodpecker/pr/build-firmware/18 Pipeline was successful
ci/woodpecker/pr/build-firmware/19 Pipeline was successful
ci/woodpecker/pr/build-windows Pipeline was successful
to eea215dd8e
All checks were successful
ci/woodpecker/pr/build-linux/1 Pipeline was successful
ci/woodpecker/pr/build-firmware/17 Pipeline was successful
ci/woodpecker/pr/build-firmware/19 Pipeline was successful
ci/woodpecker/pr/build-firmware/18 Pipeline was successful
ci/woodpecker/pr/build-firmware/20 Pipeline was successful
ci/woodpecker/pr/build-linux/2 Pipeline was successful
ci/woodpecker/pr/build-windows Pipeline was successful
ci/woodpecker/push/build-firmware/1 Pipeline was successful
ci/woodpecker/push/build-firmware/2 Pipeline was successful
ci/woodpecker/push/build-firmware/5 Pipeline was successful
ci/woodpecker/push/build-firmware/8 Pipeline was successful
ci/woodpecker/push/build-firmware/4 Pipeline was successful
ci/woodpecker/push/build-firmware/7 Pipeline was successful
ci/woodpecker/push/build-firmware/6 Pipeline was successful
ci/woodpecker/push/build-firmware/3 Pipeline was successful
ci/woodpecker/push/build-firmware/13 Pipeline was successful
ci/woodpecker/push/build-firmware/11 Pipeline was successful
ci/woodpecker/push/build-firmware/10 Pipeline was successful
ci/woodpecker/push/build-firmware/15 Pipeline was successful
ci/woodpecker/push/build-firmware/14 Pipeline was successful
ci/woodpecker/push/build-firmware/9 Pipeline was successful
ci/woodpecker/push/build-firmware/16 Pipeline was successful
ci/woodpecker/push/build-firmware/12 Pipeline was successful
ci/woodpecker/push/build-firmware/17 Pipeline was successful
ci/woodpecker/push/build-firmware/18 Pipeline was successful
ci/woodpecker/push/build-linux/1 Pipeline was successful
ci/woodpecker/push/build-firmware/20 Pipeline was successful
ci/woodpecker/push/build-firmware/19 Pipeline was successful
ci/woodpecker/push/build-linux/2 Pipeline was successful
ci/woodpecker/push/build-windows Pipeline was successful
2026年03月29日 23:03:40 +02:00
Compare
dragonmux left a comment
Copy link

This all LGTM - a great initial run at semihosting support even if it doesn't necessarily handle compressed instructions, or breakpoints found at the start of valid memory regions quite correctly right now. We can always iterate though, so merging knowing this at least works enough to show the feature working for non-compressed-instructions RV32. Thank you for the contribution!

This all LGTM - a great initial run at semihosting support even if it doesn't necessarily handle compressed instructions, or breakpoints found at the start of valid memory regions quite correctly right now. We can always iterate though, so merging knowing this at least works enough to show the feature working for non-compressed-instructions RV32. Thank you for the contribution!
dragonmux deleted branch ALTracer/feature/riscv-semihosting 2026年03月29日 23:19:40 +02:00
Sign in to join this conversation.
No reviewers
Labels
Clear labels
BMD App
Black Magic Debug App (aka. PC hosted) (not firmware)
BMP Firmware
Black Magic Probe Firmware (not PC hosted software)
Bug
Confirmed bug
Build system
Build system
Can't reproduce
Maintainers can't reproduce this problem
CI
Continuous Integration System
Contribution wanted
User contributions welcome
Documentation
Project documentation
Draft
Work in progress draft
Duplicate
This issue or pull request already exists
Enhancement
General project improvement
Feedback wanted
Requires additional submitter feedback
Foreign Host Board
Non Native hardware to runing Black Magic firmware on
GDB
Issue/PR related to GDB
Good first issue
Good for newcommers
HwIssue Mitigation
Solving or mitigating a Hardware issue in Software
Information Needed
Maintainers need more information
NativeHardware
Official Black Magic Debug Hardware
New Host Board
New hardware to run Black Magic firmware on
New Target
New debug target
Off Topic
Something that does not involve the project in any way
Potential Bug
A potential, unconfirmed or very special circumstance bug
Regression
Bug caused by a regression
User Interest Needed
More user interest required before consideration
User Testing Needed
Looking for user testing reports
Won't fix
Outside of the project scope or works as intended
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
blackmagic-debug/blackmagic!2115
Reference in a new issue
blackmagic-debug/blackmagic
No description provided.
Delete branch "ALTracer/feature/riscv-semihosting"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?