⚠️ 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.

MBC Activity Monitor

Date:2025-12-23 StepID:0261 State: draft

Summary

This Step implements the MBC1 code implemented in Step 0260 to monitor ROM bank changes and detect out-of-range read attempts. The goal is to confirm if the game is selecting ROM banks correctly and if our MMU is responding appropriately. If the game tries to change banks but we don't see logs, it means there is a problem in the detection logic. If we see bank changes but the VRAM is still empty, the problem is reading data from the correct banks.

Hardware Concept

MBC1 (Memory Bank Controller 1)is a chip present in large cartridges (>32KB) that allows the game to dynamically change which ROM bank appears in the `0x4000-0x7FFF` memory space. The game selects the bank by writing a value in the range `0x2000-0x3FFF` (which is normally read-only ROM, but the MBC intercepts these writes).

When a game needs to access graphics data, code, or resources stored in ROM banks other than bank 0, it must first select the correct bank by writing to `0x2000-0x3FFF`, and then read from `0x4000-0x7FFF`. If the game attempts to change banks but the MBC does not respond, the game will read incorrect data (possibly zeros or garbage) and copy that data to VRAM, resulting in a blank screen.

Integrity Diagnosis:If we implement MBC1 but the VRAM logs still show zeros, we need to know: 1. Is the game trying to change banks? (If we don't see change logs, the game may be crashing before we get there.) 2. Is reading from the selected bank working? (If we see bank changes but readings out of range, there is an error in the offset calculation).

Fountain:Pan Docs - "MBC1", "Memory Bank Controllers", "Cartridge Types"

Implementation

Modified the `write()` method of `MMU.cpp` to log ROM bank changes only when the bank actually changes (avoiding cluttering the logs with repeated writes to the same bank). Also added a security log in the `read()` method to detect read attempts outside the valid range of the ROM.

Modified components

  • MMU::write(): Changed to compare the new bank with the current bank before logging in. It is only recorded when there is an actual change.
  • MMU::read(): Added critical log when trying to read from an offset that exceeds the size of the loaded ROM.

Design decisions

Conditional log of bank changes:Instead of logging every write to `0x2000-0x3FFF`, we only log when the bank actually changes. This avoids cluttering the logs with repeated writes to the same bank (some games write the same value multiple times for security).

Critical log of readings out of range:If the offset calculation is incorrect or the selected bank exceeds the ROM size, the game will read invalid data. This log allows us to detect these cases and correct the offset calculation or bank validation logic.

Log format:The logs include the current Program Counter (PC) to correlate bank changes with the game instructions that cause them. This makes debugging easier if there are synchronization problems.

Affected Files

  • src/core/cpp/MMU.cpp- Modified methodwrite()to log ROM bank changes only when they change (Step 0261). Modified methodread()to log out-of-range read attempts (Step 0261).

Tests and Verification

To validate this instrumentation:

  1. Recompile: .\rebuild_cpp.ps1
  2. Execute: python main.py roms/pkmn.gb(Pokémon Red is ideal because it has 1024KB of ROM and requires multiple banks).
  3. Observe the logs:
    • Look for[MBC1] PC:XXXX -> ROM Bank Switch: N -> M- Confirm that the game is changing banks.
    • If you see bank changes (ex:1 -> 2, 2 -> 6), the game is trying to access data from different banks.
    • YeahNOyou see changes, the game may be crashing before reaching bank selection, or it may be using a cartridge without MBC.
    • Look for[MBC1 CRITICAL]- Indicates that there is an error in the offset calculation or that the selected bank exceeds the ROM size.

Expected validation:If MBC1 is working correctly, you should see multiple bank changes during game initialization, especially when the game loads graphics from different ROM banks.

Sources consulted

Educational Integrity

What I Understand Now

  • MBC1 Banking:The game selects banks by writing to `0x2000-0x3FFF`, but these writes are intercepted by the MBC and do not modify the ROM (which is read-only). The selected bank appears at `0x4000-0x7FFF`.
  • Activity diagnosis:If the game does not change banks, it may be crashing before reaching bank selection, or it may be using a cartridge without MBC. If you change banks but the VRAM is still empty, the problem is reading data from the correct banks.
  • Offset validation:The offset calculation `(bank * 0x4000) + (addr - 0x4000)` must be validated to avoid out-of-range reads resulting in invalid data.

What remains to be confirmed

  • Game activity:Is the game really trying to switch banks? The logs will tell us if we see bank changes or if the game never gets to that part of the code.
  • Reading Integrity:Are the readings from the selected banks working correctly? The critical log will tell us if there are errors in the offset calculation.
  • Correlation with VRAM:If we see bank changes but the VRAM is still empty, we need to check if the game is reading the correct data from the selected banks.

Hypotheses and Assumptions

Main hypothesis:If we implement MBC1 in Step 0260 but the VRAM logs continue to show zeros, it is possible that: 1. The game is not changing banks (fails before getting there). 2. The game is changing banks but reading incorrect data (offset calculation error). 3. The game is reading correct data but not copying it to VRAM (problem in data copy logic).

This instrumentation will allow us to distinguish between these cases and determine where the real problem is.

Next Steps

  • [ ] Executepython main.py roms/pkmn.gband observe the bank change logs.
  • [ ] If we see bank changes, verify that the data read from those banks is correct (not zeros).
  • [ ] If we don't see bank changes, investigate why the game doesn't reach bank selection.
  • [ ] If we see critical logs of readings out of range, correct the offset calculation or bank validation.
  • [ ] Correlate bank changes with VRAM writes to determine if the correct data is reaching VRAM.