# 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 `.sav` file 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: 160*144*2 = 46,080 bytes (~45KB) native RGB565. PSRAM preferred. No double buffering needed (line callback writes directly). - No huge heap allocations. - Emulator context `struct gb_s` is 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. - `pixels` low 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: 1. Vendor MiniGB APU (`minigb_apu`) or similar. 2. Implement `audio_read` / `audio_write` forwarding to APU. 3. Define ENABLE_SOUND 1, include APU, create audio task similar to BookPlayer (i2s_controller). 4. Feed APU samples in timer / separate task. ## 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_apu` and 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.