# 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.
