Skip to content

Datel Orbit mapper support#755

Open
ericlewis wants to merge 1 commit intoLIJI32:masterfrom
ericlewis:gamesharkonline
Open

Datel Orbit mapper support#755
ericlewis wants to merge 1 commit intoLIJI32:masterfrom
ericlewis:gamesharkonline

Conversation

@ericlewis
Copy link
Copy Markdown

Implements a new mapper, GB_DATEL_ORBIT, covering Datel’s Game Boy Color cheat cartridges sold as GameShark Pro (US) and Action Replay Online / V4 (EU), addressing #461.

These carts diverge from standard Nintendo behavior:

  • No valid Nintendo logo in the header (detection falls back to "Action Replay V4" title string)
  • Custom mapper register window at $7FE0–$7FE7
  • 4 KB internal SRAM overlaid into $7000–$7FFF
  • Physical passthrough slot for a second cartridge

Validated against:

  • US firmware (gsonline.gb, ~80 KB)
  • EU firmware (Action Replay Online, ~128 KB)
    with pokered.gb as the inserted cart

Mapper Model

Register Map

Address Function
$7FE0 16 KB ROM bank select for $4000–$7FFF
$7FE1 8 KB sub-bank override for $4000–$5FFF
$7FE5 bit 4 Narrow passthrough: routes $0000–$014F reads to inserted cart (logo/title/cart-type probe)
$7FE6 = 7 Full handoff: swaps ROM pointer to passthrough cart and jumps to its entry
$7FEE bit 4 Menu switch state (firmware-controlled path selection)

Memory Overlay

  • $7000–$7FFF → 4 KB internal SRAM
  • $7FE0–$7FE7 → mapper registers (overrides SRAM region)
  • $7FEE → computed status (not backed by SRAM)

Execution Model

This mapper behaves like a staged bootstrap:

  1. Firmware boots from internal ROM
  2. Uses narrow passthrough ($7FE5) to probe inserted cart
  3. Decides path (menu vs direct handoff) via $7FEE
  4. Executes full handoff ($7FE6 = 7) → swaps ROM + jumps

This is not a traditional MBC. It’s a runtime ROM switch with partial bus forwarding.


Public API

Minimal surface, aligned to hardware behavior:

  • GB_load_passthrough_rom(gb, path)
    Loads the inserted cart. No-op on non-passthrough mappers.

  • GB_set_cart_menu_button(gb, pressed)
    Drives the physical switch:

    • asserted at boot → menu path
    • released after detection → triggers handoff
  • GB_cart_start_game(gb)
    Deterministic handoff. Same endpoint as menu flow, but aligned to a frame boundary.


Test Harness

Flags:

  • --passthrough <rom> → load inserted cart
  • --cart-menu → hold menu switch at boot
  • --start-game → scripted menu → handoff (frame-aligned)

Results

  • --passthrough pokered.gb <cart>
    → boots to title (US + EU)

  • --cart-menu --passthrough pokered.gb <cart>
    → menu renders correctly

    • EU: detects "Pokemon R&B 1FR"
    • US: "No Game Active" (firmware limitation)
  • --start-game --passthrough pokered.gb <cart>
    → stable menu → handoff → game boots

  • EU firmware prints:
    "POKEMON game found / Please ensure that the switch is in the off position"
    → confirms correct modeling of $7FEE semantics


Known Residual Issues

Mid-frame Handoff Hazard

Organic flow (menu navigation → release switch) triggers handoff mid-frame.

Result:

  • PPU phase mismatch
  • Game init code sees invalid timing state
  • Example: Pokemon Red stalls on LY wait at $20B4

Workaround:

  • --start-game forces handoff on frame boundary → stable

Root cause is architectural: mapper does not synchronize with PPU state before ROM swap.


Unimplemented Features

Out of scope for mapper layer:

  • IR communication
  • Snapshot save/load
  • Flash reprogramming ("Upgrade Cartridge")

These require:

  • modem/IR emulation
  • persistent flash modeling
  • higher-level device simulation

@ericlewis
Copy link
Copy Markdown
Author

happy to leave as a draft, since this may not really fit the normal shape of changes. excessive commenting is for the sake of those using / reviewing this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant