GBA Emulation with a JIT on the ESP32-P4

Nov 04, 2026 Last reply: 1 day ago 2 Replies
Jump to replies (2)

The starting point here is a chip with RISC-V cores and a maker who wanted a just-in-time translator that could be useful beyond one device. MKDV ported the gpSP GBA emulator to the ESP32-P4 and wrote a fresh RISC-V JIT backend for it, and the result is a handheld running GBA titles from an SD card on an OSPTEK P4C5 board with a 4.3-inch 800x480 touchscreen. The chip itself retails for around five dollars, which makes the whole thing feel almost unreasonable.



The JIT translates ARM and Thumb blocks into RV32 code, and compressed RVC/Zcb instructions keep the generated code small. That matters because the JIT executes from PSRAM, and doubling the L2 cache from 128 to 256 KiB helped more than manually moving hot arrays into internal SRAM. The workload is split across cores: all emulation, including rendering at original resolution, sits on CPU0, while CPU1 handles scaling and display effects. The maker figures this split hints GBA might be doable on lower-clocked RISC-V chips too.



What stands out is the attention to real bottlenecks. Self-modifying code in games like Doom II was the big headache, so instead of flushing the whole code cache on RAM code changes, the JIT now invalidates just the affected blocks and reuses old translations when the original bytes return. Register allocation was the harder fight, since both guests have 32 general-purpose registers and the mapping needs dynamic spilling. Display options are solid as well: 3x nearest, bilinear and LCD grid, plus color modes from unadjusted output to one approximating the original GBA LCD.



The open end: PS1 work is ongoing, with lighter games running well and heavier 3D titles playable at full speed with slight automatic frameskip, but that code has not landed on GitHub yet.



Project by MKDV. Watch it on their YouTube channel:

formatting link


The targeted cache invalidation is the part I find cleverest. Rather than dumping every cached translation when RAM code changes, the JIT drops only the affected blocks and reuses old ones once the original bytes come back, patching some changes in place. Given how expensive constant retranslation had been, that seems like the right trade for something like Doom II.

One concrete idea: since the PPA hardware handles scaling, rotation and blending, and the maker calls it particularly nice on larger displays, it would be interesting to see the same port tried on a bigger P4 touchscreen board. The maker notes not every such board has been tested, and the on-screen controls and menus should make trying other boards simpler, so a larger panel seems like a natural next test.

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required