Dragonfruit: A 68k/Dragonball Palm device emulator for ESP32 devices

Lobsters Hottest Tools

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.

<p><a href="https://lobste.rs/s/6fhbtz/dragonfruit_68k_dragonball_palm_device">Comments</a></p>
Original Article
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.

A Palm IIIx running on the M5Paper, recognizing Graffiti handwriting input

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 STOP mode) with power-key wake through the modeled keyboard matrix. On the M5Paper this also drives the ESP32 into light sleep.
  • Installs .prc / .pdb / .pqa files 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

  1. CPU. A switch-dispatched 68000 interpreter executes the ROM, handling vectored interrupts and the STOP instruction used for sleep.
  2. Bus. A 24-bit address space: 2 MB RAM at 0x0, the ROM window at 0x10C08000, and the DragonBall register block at 0xFFFFF000, with the hot read/write paths inlined.
  3. 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.
  4. 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 EvtEnqueuePenPoint syscall, the same device-independent route other Palm emulators take.
  5. 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.

The Palm OS launcher running on the M5Paper’s e-ink display

Similar Articles

GameBoy Emulator on ESP32 + Eink

Lobsters Hottest

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?

Hacker News Top

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

Product Hunt

M5Stack PaperColor is a 4-inch color E-ink development board powered by ESP32 with audio I/O capabilities.

Plexus P/20 Emulator

Hacker News Top

A new open-source WebAssembly-based emulator for the 1980s Plexus P/20 Unix server, letting users run SystemV Unix in the browser.