Skip to content
RetrogamingDeep Dive Published Updated 7 min readViews unavailable

Game Boy MBC7: Accelerometer Latches, EEPROM Commands, and Save States

Emulate MBC7 register gating, latched tilt samples, serial EEPROM timing, and uncertain cartridge capacities without mistaking observations for guarantees.

The Game Boy MBC7 is more than a ROM bank switcher. Its cartridge combines an MBC with a two-axis accelerometer and a small serial EEPROM. The documented register window is $A000–$AFFF, not the full $A000–$BFFF region commonly used by other cartridge hardware. Pan Docs marks $B000–$BFFF as unknown and says observed reads appear to return $FF. The documented registers are not a byte-addressable RAM array, so the emulated device has two different state machines: a latched sensor path and a bit-clocked nonvolatile-memory path.

That distinction is valuable for emulator work and hardware preservation. A game can perform the right high-level “read save” or “tilt” operation and still observe wrong behavior if the emulator ignores register gating, treats sensor values as live values instead of a snapshot, or collapses the EEPROM pins into direct address reads. The published behavior is reverse-engineered documentation, not a complete Nintendo programming specification; keep uncertain registers and timings labeled as such.

Enable the register window before using it

Pan Docs describes two enable writes for the MBC7 registers. Write $0A in the $0000–$1FFF region and $40 in $4000–$5FFF; the second condition is required as well as the first. When disabled, reads from the register window return $FF and writes have no effect. The upper address bits select the register, while the low address bits in the mirrored window are ignored.

An emulator should model that as explicit controller state rather than checking only whether the address falls in the $A000–$BFFF range. For a test ROM or trace harness, start with the enable sequence and then assert both sides of the gate: a write while disabled must not change a latch or EEPROM command, and a read while disabled must not leak the prior register value.

Treat sensor reads as a latched pair

Accelerometer values are not sampled by reading the X and Y registers independently. The software first writes $55 to an Ax0x address to clear the previous sample, then writes $AA to an Ax1x address to latch a new sample. Reads return $FF from the latch command registers. Pan Docs notes that another latch attempt without first clearing does not update the value.

The X value is 16-bit: Ax2x contains its low byte and Ax3x its high byte. Y is at Ax4x and Ax5x in the same order. Before a first latch, the documented reads return $8000. Pan Docs describes a center near $81D0 and a rough change of $70 per 1 g, while noting that the maximum register range is unknown. Analog Devices specifies a ±2 g full-scale range for the ADXL202E, but that alone does not establish the MBC7 register endpoints or saturation behavior. Treat the observed mapping as a calibration starting point, not a universal formula for every replacement sensor or input device.

write 0x0A to 0x0000       ; enable register access, stage 1
write 0x40 to 0x4000       ; enable register access, stage 2
write 0x55 to 0xA000       ; clear the old accelerometer latch
write 0xAA to 0xA010       ; capture a new sample
wait at least 1.2 ms before HALT
x = read(0xA020) | (read(0xA030) << 8)
y = read(0xA040) | (read(0xA050) << 8)

The wait is part of the observable hardware contract. Pan Docs warns that the Game Boy’s PHI cartridge clock stops when the CPU enters HALT; halting too soon after the latch can add substantial noise to the sampled values. The reference says to wait at least 1.2 milliseconds regardless of CGB double-speed mode. An emulator should advance the device using emulated time and preserve that timing relationship, rather than using a host sleep or assuming a latch is an instantaneous, noise-free ADC read.

For deterministic input, the frontend can map a normalized tilt value into the observed register domain, but the core should still expose a stable 16-bit sample after the latch event. In save states, store the current latched X/Y values and the latch phase. Do not regenerate the latched pair from the current host controller position during load: that would make a restored game observe a different sample before it performs another latch.

Model EEPROM access as serial pin transitions

The EEPROM is controlled through the Ax8x register family. Pan Docs maps bit 0 to data out (DO), bit 1 to data in (DI), bit 6 to clock (CLK/SK), and bit 7 to chip select (CS). A write to the register changes pin levels; it is not a request to read or write one EEPROM byte directly. The emulated chip must notice the CS and clock transitions, shift command bits in MSB-first, and shift response data back out through DO.

Pan Docs documents a 93LC56, 256-byte configuration and describes EEPROM addresses as 16-bit words: address 1 represents bytes 2–3. A GBDev hardware-investigation thread reports that one opened Command Master cartridge used an LC66 (“4K”) EEPROM and describes Kirby cartridges as using LC56, while cautioning that boards and populations may differ and that the manufacturer was not confirmed. Treat these as sample observations, not a universal MBC7 bill of materials. Microchip specifies the 93LC66 as 4 Kbit (512 bytes: 512 × 8 or 256 × 16), not 4 KiB, and the 93LC56 as 2 Kbit (256 bytes: 256 × 8 or 128 × 16); organization depends on the ORG input. Select capacity and organization from documented per-cartridge evidence or an explicit configuration rather than mapper type alone, and preserve the full cartridge-sized image.

Commands include READ, WRITE, ERASE, EWEN, EWDS, ERAL, and WRAL. Programming operations require an erase/write-enable command first. The 93LC56/66 datasheet makes ready/busy polling through DO conditional: after an erase or write has started, firmware must hold CS low for at least 250 ns, then raise CS to expose status during the programming cycle; DO is low while busy and high when ready. If CS never falls, the programming cycle does not start, and if status is not being presented DO is high-impedance rather than a valid completion signal. When checking status after the cycle has finished, follow the datasheet’s pull-up requirement. Model the chip’s self-timed programming interval and CS-dependent status behavior instead of assuming that every DO read reports completion. Keep the cartridge-sized nonvolatile image separate from this transient protocol state.

That separation also improves save-state correctness. A robust serialized core state includes the selected cartridge EEPROM profile and contents plus the currently selected controller register, serial command phase, number of shifted bits, pending data, write-enable state, and any active busy interval. If a save state is captured halfway through an EEPROM command, restoring only the EEPROM bytes can leave the next clock edge in a different state than the original run.

Preserve unknown behavior instead of filling gaps with guesses

Pan Docs marks several address ranges as unknown or only partially confirmed. Ax6x reads as $00 and Ax7x as $FF in the documented observations; the suggestion that these might be for a nonexistent Z axis is explicitly speculative. The $B000–$BFFF region appears to read $FF, and some bank-enable behavior is not fully tested. A compatibility layer should record these as observed behavior with provenance, not convert a guess into a precise hardware guarantee.

A useful regression suite separates confirmed behavior from uncertain cases:

  • Verify disabled-register reads and writes, then both enable stages.
  • Confirm the initial sensor result, clear-then-latch ordering, repeated-latch behavior, byte order, and minimum pre-HALT timing.
  • Exercise EEPROM EWDS versus EWEN, one 16-bit READ/WRITE, address boundaries, and DO polling while a programming operation is busy.
  • Save and restore mid-latch and mid-command, checking that the next register read or clock transition is identical.
  • Keep unknown registers under a labeled compatibility test so a future hardware observation can update one assumption without changing unrelated controller logic.

Use real cartridge traces or board measurements when refining the uncertain cases. Do not claim the sensor’s undocumented maximum range, treat the peripheral as a third-axis accelerometer, or rely on a single emulator’s undocumented approximation as proof of original hardware behavior.

Related:

Sources:

Comments