4.0 KiB
4.0 KiB
GameBoy Emulator (Tactility Prototype, No Audio)
DMG Game Boy emulator for Tactility side-loaded apps, using Peanut-GB (MIT) as CPU/LCD core.
Status
- Prototype v0.1.0-dev – compiling draft focused on architecture, not yet production-hardened.
- No audio (ENABLE_SOUND 0). Audio path stubbed for future MiniGB APU or i2s-driven implementation.
- Supports MBC1/MBC2/MBC3/MBC5 via Peanut-GB.
- ROM loader from SD card.
- Save RAM persistence via
.savfile next to ROM. - LVGL framebuffer: native 160x144 RGB565, integer-scaled if display large enough, centered on black background.
- Input: on-screen D-pad + A/B + Start/Select + hardware keyboard arrows + LVGL key events (z= A, x= B).
- Timer-driven at ~16ms (~60Hz) calling
gb_run_frame().
ROM Location
- Scanned directory:
/sdcard/roms/gb/for*.gb,*.gbc,*.bin(up to 64 entries). - Default quick-load:
/sdcard/roms/gb/default.gb– if present on app show, autoloads and jumps directly to emulation. - Place your legally dumped ROMs there; no ROMs are bundled.
Save RAM Path Design (stubbed + implemented minimal)
- Save file = ROM path with extension replaced by
.sav(e.g./sdcard/roms/gb/tetris.gb->/sdcard/roms/gb/tetris.sav). - Loaded on ROM load, saved on:
- switching back to menu
- app hide
- error recovery path
- Size queried via
gb_get_save_size_s()/gb_get_save_size(). - Future improvement: also mirror to app user-data dir (
tt_app_get_user_data_child_path) if SD is read-only.
Memory Considerations (ESP32-S3 / PSRAM)
- Large buffers allocated via
heap_caps_malloc(..., MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT)with fallback to internal. - ROM buffer: up to 2MB (MBC5 max-ish) – PSRAM preferred.
- Cart RAM: variable, often 8KB-32KB, PSRAM.
- Framebuffer: 1601442 = 46,080 bytes (~45KB) native RGB565. PSRAM preferred. No double buffering needed (line callback writes directly).
- No huge heap allocations.
- Emulator context
struct gb_sis static inside AppCtx (~few KB).
Controls / Input Mapping
| GB | On-screen | Keyboard | Remarks |
|---|---|---|---|
| D-pad | 4 arrow buttons | LV_KEY_ arrows | press/release tracked |
| A | A button (right cluster) | z | |
| B | B button (right cluster) | x | |
| Start | Sta | Enter / Space | |
| Select | Sel | Esc / Backspace | |
| Touch | Quadrants not yet separated – buttons cover |
Future: touch quadrants mapping via pointToQuadrant like GameKitInput.
LCD Rendering
- Peanut-GB calls
lcd_draw_line(gb, pixels[160], line)per scanline. pixelslow 2 bits = shade 0-3.- Mapped to olive/gray palette RGB565 (editable).
- Canvas buffer is the framebuffer itself.
- Scale: if display resolution >= 320x432 => 2x, >=480x576 => 3x via LVGL transform scale (keeps native buffer).
No-Audio Limitation
ENABLE_SOUND 0– audio callbacks not compiled.- To add audio:
- Vendor MiniGB APU (
minigb_apu) or similar. - Implement
audio_read/audio_writeforwarding to APU. - Define ENABLE_SOUND 1, include APU, create audio task similar to BookPlayer (i2s_controller).
- Feed APU samples in timer / separate task.
- Vendor MiniGB APU (
Build
Same as other Tactility apps:
. $IDF_PATH/export.sh
export TACTILITY_SDK_PATH=...
python3 tactility.py Apps/GameBoy build esp32s3 --local-sdk
Licensing
- App code: GPLv3 (same as Tactility Apps).
- Peanut-GB vendored lib: MIT (Copyright (c) 2018-2023 Mahyar Koshkouei). License preserved in
Libraries/PeanutGB/peanut_gb.h.
Next Steps
- Improve input: add touch quadrant → D-pad, repeat timers for held buttons.
- Add pause/resume UI, FPS display.
- Add palette selector (auto_assign_palette logic from peanut_sdl).
- Add file picker dialog (
tt_app_selectiondialog_start) improvement + recursive folder browsing. - Audio: vendoring
minigb_apuand creating I2S task. - Save state beyond cart RAM (full emu snapshot).
- RTC persistence for MBC3 RTC games.
- Error dialog via
tt_app_alertdialog_start. - Validate with Cppcheck / clang-format and ESP-IDF build.