⚠️ Clean-Room / Educational

This project is educational and Open Source. No code is copied from other emulators. Implementation based solely on technical documentation and permitted tests.

Unified MBC & VRAM/WRAM Instrumentation

Date:2025-12-25 StepID:0272 State: draft

Summary

Unified bank controller (MBC) support in the C++ MMU for ROM_ONLY, MBC1, MBC2, MBC3 and MBC5, sizing the external RAM according to the header and normalizing ROM/RAM banks. Added light traces to detect writes/reads at0xD732, VRAM and interrupt requests/service.

The GPS monitor now separatesVRAM_TILE_SUM(0x8000-0x97FF)VRAM_MAP_SUM(0x9800-0x9FFF) and reports0xD732hot. Current result (Pokémon Red): VBlank is requested and served,D732it is only written with00, a sweep of VRAM writes is detected, filling the tile data with zeros from PC=0x36E3, and the tilemap is still full of 0x7F (green screen).

Hardware Concept

MBCs (Memory Bank Controllers) allow >32KB cartridges to expose switchable ROM/RAM banks. MBC1 combines low/high bits and ROM/RAM mode; MBC2 comes with 512x4-bit internal RAM; MBC3 adds RTC and selectable RAM banks; MBC5 extends to 9 bits of ROM bank and up to 16 banks of RAM.

Instrument VRAM and status flags (e.g.0xD732) is key to verify if the CPU is copying graphics (tile data) or just modifying the tilemap. Separating tile data vs tilemap helps locate the cause of green screen when the map changes but the tiles do not.

Implementation

InMMU.cpp/MMU.hppadded status fields for each MBC, bank calculation from the header, RAM allocation by declared size and bank mappingbank0_rom/bankN_rom. Implemented write paths for RAM enable, ROM/RAM bank selection (MBC1/2/3/5) and RTC stub in MBC3. Banks are normalized against the loaded total to avoid out of range readings.

The first writings/readings were implemented0xD732and VRAM (0x8000-0x9FFF) to detect real activity. Inviboy.pyGPS now reports separate sums of tile data and tilemap, plus the reading ofD732every second.

Components created/modified

  • src/core/cpp/MMU.hpp / MMU.cpp– Unified MBC1/2/3/5 support, dynamic RAM allocation, VRAM/WRAM logs.
  • src/viboy.py– Expanded GPS withVRAM_TILE_SUM, VRAM_MAP_SUMand reading of0xD732.

Design decisions

The per-MBC state was maintained so as not to break compatibility with small cartridges (ROM_ONLY) and the logs were limited to the first accesses so as not to flood the output in mode.--verbose. Visibility was prioritized over visual correction while the lack of tile data writes was diagnosed.

Affected Files

  • src/core/cpp/MMU.hpp– New MBC/RAM status fields and helpers.
  • src/core/cpp/MMU.cpp– Unified banking logic, RAM allocation, VRAM/WRAM logs.
  • src/viboy.py– Separate VRAM metrics and readingD732in GPS.

Tests and Verification

  • ROM: python main.py roms/pkmn.gb --verbose(10-15s). Observed:VRAM_TILE_SUM=0, VRAM_MAP_SUM=16256, D732=00, PC at 0x615x; VBlank IRQs requested/served; bulk write 0x00 to VRAM tile data from PC=0x36E3; tilemap remains at 0x7F.
  • Rebuild: rebuild_cpp.ps1after every change in C++.
  • Initial VRAM:PyMMU + cartridge: 0x8000/0x9800 boot at 0x00 (confirmed that filling of 0x7F occurs at runtime, not at load).

Sources consulted

  • Pan Docs – Sections: MBC1, MBC2, MBC3, MBC5, Memory Map.
  • Pan Docs – LCD Control, VRAM layout (tile data 0x8000-0x97FF, tilemaps 0x9800/0x9C00).

Educational Integrity

What I Understand Now

  • Pokémon Red (type 0x13) uses MBC3: needs high ROM banks and RAM with enabled.
  • The tilemap is filling (0x7F); the tile data is overwritten with zeros since PC=0x36E3, which explains the green screen.
  • 0xD732remains at 0, only written with 0x00 in PC=0x1F80.
  • VBlank is requested and serviced (logs in IRQ/VBlank), so basic interrupts are alive.

What remains to be confirmed

  • Who and why clears the tile data to 0x00 at PC=0x36E3 (disassemble that routine and its bank).
  • Who should setD732and in which routine (possible ISR or init loop).

Hypotheses and Assumptions

The game initializes tilemap and then clears tile data (0x36E3) because it has not yet run the routine that copies the actual tiles; could be stuck waitingD732before loading graphics or in another init branch.

Next Steps

  • [ ] Log writes to 0x9800-0x9FFF and 0x8000-0x97FF with a higher limit to capture the first copy.
  • [ ] Disassemble the block at 0x6150 (active bank) and the routine at 0x36E3 that clears VRAM to see tile loading conditions.
  • [ ] Identify when it should be writtenD732(ISR or init loop) and force a log there.