- C 36.2%
- Assembly 35%
- RobotFramework 12.6%
- Makefile 9.5%
- CMake 3.8%
- Other 2.9%
| platform | ||
| src | ||
| launch_in_renode.resc | ||
| Makefile | ||
| README.md | ||
asm-c-interop — C ⇄ assembly on Cortex-M0+ (ARMv6-M)
| File | Content |
|---|---|
src/asm_basic.S |
Part 1 – C calls asm: args in r0-r3, 5th+ args on the stack, 64-bit return in r0:r1, saving r4-r7 and r8 |
src/asm_calls_c.S |
Part 2 – asm calls C (callback through a pointer, named function), globals and a struct shared both ways |
src/inline.c |
Part 3 – GCC extended inline asm, constraints, clobbers, naked function |
src/pitfalls.S |
Part 4 – deliberately wrong code: missing Thumb bit, clobbered r4, misaligned SP |
src/shared.h |
The C prototypes = the contract with the asm (+ _Static_assert on struct offsets) |
src/main.c |
Runs every example and prints PASS/FAIL |
platform/common/startup.S |
Vector table, .data/.bss init, bl main, HardFault → C (QEMU and Renode) |
platform/qemu/ |
Linker script, semihosting console |
platform/renode/ |
Minimal RP2040 machine (.repl), linker script at 0x10000000, PL011 UART0 driver, run.resc, Robot test |
platform/pico/ |
pico-sdk CMake project for a real Pico (also used for Renode_RP2040) |
platform/renode-rp2040/ |
run.resc + Robot test for the full RP2040 model of matgla/Renode_RP2040 |
QEMU (no hardware)
Needs gcc-arm-none-eabi and qemu-system-arm.
make run # all examples (2 FAILs in Part 4 are expected)
make run PITFALL=1 # + HardFault caused by a missing .thumb_func
make disasm # listing.txt: C and asm side by side
make debug # then: gdb-multiarch build/demo.elf -ex "target remote :1234"
QEMU microbit is a Cortex-M0 (ARMv6-M, like the M0+): same instruction set.
Renode (minimal RP2040: Cortex-M0+, RP2040 memory map, UART0 = PL011 @ 0x40034000)
Needs Renode ≥ 1.15 (renode and renode-test in the PATH, or RENODE=/path/to/renode).
For renode-test: pip install -r <renode>/tests/requirements.txt.
make renode # headless; UART0 lines appear in the log as "uart0: ..."; 'quit' to leave
make renode-gui # same, with a UART window
make renode-test # Robot Framework: 5 tests pass, the HardFault one is skipped
make renode-test PITFALL=1 # HardFault test runs, "Only The Expected Failures" is skipped
# gdb: the .resc starts a GDB server -> gdb-multiarch build-renode/demo.elf -ex "target remote :3333"
Emulator fidelity: Renode reports the bad-Thumb-state fault as exception 6 (UsageFault,
which does not exist on ARMv6-M), so the reserved vector slots are routed to the HardFault
handler (startup.S, and isr_invalid in platform/pico/hardfault.S). Renode 1.16 also
stacks the PC of the blx (T bit still 1) instead of the even target address with T = 0.
Renode + matgla/Renode_RP2040 (full RP2040 model, real pico-sdk firmware)
Runs the unmodified pico-sdk build: boot ROM -> boot2 -> crt0 -> main, console on UART0.
Needs Renode 1.16.1 (the linux-portable mono build, as advised by Renode_RP2040),
the pico-sdk and a clone of https://github.com/matgla/Renode_RP2040.
git clone https://github.com/matgla/Renode_RP2040 ~/Renode_RP2040
make renode-rp2040 PICO_SDK_PATH=~/pico-sdk RP2040_PATH=~/Renode_RP2040
make renode-rp2040-test PICO_SDK_PATH=~/pico-sdk RP2040_PATH=~/Renode_RP2040 [PITFALL=1]
The firmware is built in build-pico-uart/ with -DSTDIO_USB=0 (Renode_RP2040 has no USB
model). The C# peripherals are compiled from source when the machine is created (~15 s).
Offline machines: cores/rp2040.repl downloads RP2040.svd.gz from dl.antmicro.com;
without network access, comment out its ApplySVD line.
Raspberry Pi Pico
cd platform/pico && mkdir build && cd build
cmake .. -DPICO_SDK_PATH=/path/to/pico-sdk # -DPITFALL=1 HardFault demo, -DSTDIO_USB=0 UART only
make # copy asm_c_interop.uf2 to the RPI-RP2 drive
Console on USB CDC and UART0 (GP0/GP1, 115200 baud).
Tested with arm-none-eabi-gcc 13.2, QEMU 8.2, Renode 1.15.3 and 1.16.1, pico-sdk 2.1.1, Renode_RP2040 commit 5aca847 (2026-09-18). Not yet run on a physical Pico.