Dragonfruit: A 68k/Dragonball Palm device emulator for ESP32 devices
Summary
Dragonfruit is an open-source emulator of the Motorola DragonBall processor that runs Palm OS 3.x on ESP32 devices like the M5Paper, supporting stylus input, ROM loading, and add-on installation.
View Cached Full Text
Cached at: 07/06/26, 08:02 AM
megabytefisher/Dragonfruit
Source: https://github.com/megabytefisher/Dragonfruit
Dragonfruit
An emulator of the Motorola MC68EZ328 (“DragonBall EZ”), the 68000-based system-on-chip at the heart of the late-90s Palm handhelds, with enough of the surrounding machine modeled to boot stock Palm OS 3.x and run it. Everything is written from scratch in portable C: a 68000 interpreter plus models of the DragonBall’s on-chip peripherals (interrupt controller, timer, RTC, GPIO, SPI, UART, LCD controller).
The core has no platform dependencies. It runs headless on a PC for development and on ESP32 hardware for the real thing. The reference target is the M5Paper, an ESP32 board with an e-ink panel and a capacitive touchscreen, which the emulator turns into a working Palm IIIx: it boots to the launcher, runs the first-boot setup wizard, and takes stylus input including Graffiti handwriting.
You supply the ROM. Palm OS is copyrighted and is not included here; see Running it.

What works
- Boots Palm OS 3.1 from a stock Palm IIIx ROM, all the way to the launcher, on both the PC host and the device.
- First-boot setup wizard: welcome, digitizer calibration, country / time / date.
- Stylus input: taps, the silkscreen buttons (Apps / Menu / Calc / Find), and Graffiti handwriting, all over one continuous digitizer surface that the ROM handles natively.
- Real-time clock and 100 Hz system tick driven by wall-clock time, so both stay correct regardless of emulation speed.
- Sleep and auto-off (the DragonBall’s PLL-off
STOPmode) with power-key wake through the modeled keyboard matrix. On the M5Paper this also drives the ESP32 into light sleep. - Installs
.prc/.pdb/.pqafiles from the SD card into emulated RAM, and backs up or restores the device’s databases to the card. - Optional configurable on-screen layout: relocate or resize the silkscreen, rotate to landscape, or magnify, all from a file on the SD card.
Portability
The project is the emulator, not any single board. The split is deliberate:
- Core, portable C. The 68000 interpreter, the DragonBall peripheral models, the bus, and the Palm OS integration (pen injection, the installer, backup/restore) carry no ESP-IDF or board dependencies. The PC host build compiles exactly this code with a thin shim standing in for ESP-IDF, which is what makes day-to-day work possible without flashing hardware.
- Performance backend, per-ISA. On device the hot path is a burst JIT that translates 68000 blocks to native code. Its code generator sits behind a backend interface selected at build time, so a new instruction set is a new backend rather than a rewrite. The classic ESP32 (Xtensa) backend is complete; an ESP32-P4 (RISC-V) build links and runs interpreter-only while its backend is still to be written.
- Board, peripherals. The e-ink driver, touch controller, SD mount, and battery sensing live in their own components. Bringing up a different ESP32 board is a matter of writing those drivers, not touching the core.
On the ESP32 side the requirements are external PSRAM (the 2 MB of emulated RAM and the ROM image live there) and two cores (the JIT’s compiler runs on the second one). That rules out single-core, no-PSRAM parts such as the ESP32-C3.
Hardware (M5Paper reference target)
- SoC — ESP32-D0WDQ6-V3, dual-core 240 MHz, 16 MB flash, 8 MB PSRAM.
- Display — IT8951 e-ink controller over SPI, 960×540 panel. The Palm’s 160×160 1bpp framebuffer is scaled and rotated 90° counter-clockwise into a top-aligned portrait layout, with the Graffiti silkscreen rendered below it.
- Touch — GT911 capacitive controller over I²C.
Repository layout
src/
main/ ESP-IDF entry point and the FreeRTOS tasks (CPU, display, input, battery)
components/
m68k/ 68000 interpreter (decode, addressing, ALU, move, branch, shift, bit,
BCD, system) plus the device-only burst JIT and its per-ISA backend
bus/ 24-bit address space: 2 MB RAM, the ROM window, peripheral decode
dragonball/ MC68EZ328 peripherals: interrupt controller, timer, RTC, GPIO,
SPI (digitizer + battery ADC), UART, LCD controller
display/ IT8951 e-ink driver; composites the framebuffer and silkscreen overlay
input/ GT911 touch polling into a pen-event queue; button latches
layout/ Panel-to-Palm coordinate mapping, shared by display and input
config/ Reads the optional layout config off the SD card at boot
rom_loader/ Loads the ROM from the SD card into PSRAM at boot
installer/ Installs PRC/PDB/PQA into RAM; backs up and restores databases
m5_sd/ Owns the shared microSD mount on the e-ink SPI bus
host/ PC build harness: runs the core headless, with esp_shim.h in place of
ESP-IDF and a PNG snapshotter (plus an optional SDL window) for the screen
tools/ Host-side scripts that drive the on-device serial debug console
reference/ Read-only reference emulators and datasheets, consulted for hardware
behavior and never copied (not committed; see below)
reference/ holds third-party emulators (CloudpilotEmu, Mu, POSE) and vendor driver examples
used only to understand how the hardware behaves. It is not part of this repository’s source
and is not committed.
Running it
You need a Palm OS 3.x ROM for the Palm IIIx. It is not distributed here. The usual source is to transfer it off a device you own (the classic Palm OS Emulator shipped a ROM-transfer tool for exactly that).
On a PC, no hardware
The fastest way to iterate. The host build compiles the same emulator core and writes a PNG whenever the screen changes.
cmake -S src/host -B build-host
cmake --build build-host
./build-host/dragonfruit -r Palm-IIIx-3.1.rom -c 150000000
-r selects the ROM, -c caps the cycle count, -i <file> queues a PRC/PDB to auto-install,
and -b <dir> exports the RAM databases on exit. For an interactive window (the emulated
screen and silkscreen, with mouse clicks passed through as pen taps), build with the SDL UI
and run with --ui:
cmake -S src/host -B build-host -DHOST_UI=ON
cmake --build build-host
./build-host/dragonfruit -r Palm-IIIx-3.1.rom --ui
On the M5Paper
The firmware builds in a reproducible ESP-IDF Docker container; flashing runs on the host, because Docker Desktop on Windows cannot pass through COM ports.
./build.ps1 # idf.py build inside the container (subcommands pass through)
./flash.ps1 -Port COM5 -Monitor # esptool from the host; -Monitor opens the serial log at 115200
The ROM is not embedded in the firmware. Copy a Palm IIIx ROM to a FAT32 SD card as
palm.rom and insert it before powering on. At boot the firmware mounts the card (it shares
the e-ink SPI bus), reads the ROM into PSRAM, then unmounts. If the card or file is missing or
invalid, the device prints the reason on the e-ink panel and halts.
What goes on the SD card
The firmware reads everything from the card’s root. Only palm.rom is required; the rest are
optional and can be added later.
palm.rom (required) The Palm IIIx ROM image, read into PSRAM at boot.
palm.cfg (optional) On-screen layout (relocate/rotate/magnify the silkscreen) plus
serial-bridge settings.
digitizer.cfg (optional) Touch-sensitivity tuning. If absent, the firmware writes one
from the panel's current values on first boot, ready to edit.
install/ (optional) A directory of .prc / .pdb / .pqa files installed into RAM at
every boot. Files are left in place; emulated RAM is volatile,
so they reinstall on each cold start.
backup/ (optional) Destination for database backups. Hold the UP side button for a
second to back up here; hold DOWN to restore.
To customize the layout, copy palm.cfg.example to the card as palm.cfg
and edit it.
Requirements: Docker Desktop, and on the host Python with esptool and pyserial
(pip install esptool pyserial).
How it works
- CPU. A switch-dispatched 68000 interpreter executes the ROM, handling vectored
interrupts and the
STOPinstruction used for sleep. - Bus. A 24-bit address space: 2 MB RAM at
0x0, the ROM window at0x10C08000, and the DragonBall register block at0xFFFFF000, with the hot read/write paths inlined. - Peripherals. The DragonBall model drives the interrupt controller, the 100 Hz timer, the RTC (from wall-clock time), GPIO, the SPI master (both the digitizer and the battery ADC), the UART, and the LCD controller that publishes the framebuffer address.
- Display and input. The 1bpp framebuffer is composited with the silkscreen and blitted
to the panel. Touch points are not injected through the digitizer hardware — that path
fatal-errors on the IIIx — but enqueued through the ROM’s
EvtEnqueuePenPointsyscall, the same device-independent route other Palm emulators take. - JIT (device). Hot ROM blocks are compiled to native code on the second core and cached in executable memory; cold code runs an inlined-interpreter burst. Only ROM is compiled, so there is no self-modifying-code invalidation to handle.
Performance
The pure interpreter runs the 68000 at roughly 8 MHz, about 58% of the real IIIx’s 16.58 MHz, and is compute-bound on per-instruction work. The burst JIT brings a settled screen to around 87% of real time. The remaining gap is cold operating-system code that runs too few times to be worth compiling and stays at the interpreter floor; closing it is a cold-path problem, not a matter of more JIT tuning. The JIT is on by default and can be disabled to fall back to the interpreter.
License
MIT. See LICENSE.

Similar Articles
GameBoy Emulator on ESP32 + Eink
The author successfully implemented a playable Gameboy emulator on the M5 Paper S3 (ESP32 S3 + e-ink display). By using high refresh rate driving, an optimized emulation core, and an innovative pseudo-polyphonic sound scheme, classic games run smoothly on the e-ink screen.
Radxa Dragon Q8B: A Laptop Cosplaying as an SBC?
Radxa announces the Dragon Q8B single-board computer powered by a Qualcomm Snapdragon 8cx Gen 3 SoC, with up to 32GB RAM. Early benchmarks show it outperforming the Raspberry Pi 5, though software is still maturing.
M5Stack PaperColor
M5Stack PaperColor is a 4-inch color E-ink development board powered by ESP32 with audio I/O capabilities.
Plexus P/20 Emulator
A new open-source WebAssembly-based emulator for the 1980s Plexus P/20 Unix server, letting users run SystemV Unix in the browser.
@VedaAI00: Developer @zephray_wenting pushes E-ink screen to 60Hz through algorithm and driver optimization, successfully runs GameBoy emulator on M5Stack PaperS3. Under extreme ghosting physical limits, achieved high...
Through algorithm and driver optimization, the developer increased the refresh rate of the M5Stack PaperS3's E-ink screen to 60Hz, successfully ran the GameBoy emulator, and achieved smooth dynamic images.