Flow B: CPU instruction and memory access cycle
The heart of SameBoy's accuracy: every memory access is a bus cycle that advances all hardware in lockstep.
Trigger
Frontend calls GB_run(gb) → GB_cpu_run(gb).
Architecture diagram
GB_cpu_run — entry and branches
GB_cpu_run handles several paths before normal opcode fetch:
- STOP mode (
gb->stopped): advance 4 cycles, check JOYP to wake - Interrupt service when
IME && (IE & IF): push PC, jump to vector, clear IF bit — with OAM bug side effects on stack operations - HALT wake without IME: exit halt, optionally start HDMA
- Normal: read opcode byte, optional HDMA trigger,
execution_callbackhook, dispatchopcodes[opcode]
IME toggle from EI instruction is deferred: ime_toggle applies at start of next instruction.
cycle_read / cycle_write — bus-cycle timing
Each memory access:
- Flushes
pending_cyclesviaGB_advance_cycles(advances PPU/APU/timer by prior instruction cycles) - Sets
address_bus - Calls
GB_read_memoryorGB_write_memory - Sets
pending_cycles = 4(one M-cycle = 4 T-cycles in 8MHz units after speed adjustment)
Bus conflicts: For I/O writes in FF00–FF7F, cycle_write selects a per-model conflict_map (DMG, CGB, CGB double-speed, SGB) determining whether CPU and PPU "see" old or new values when accessing the same register in the same cycle.
GB_read_memory — address decoding
Top-level decode in GB_read_memory (memory.c:776):
| Range | Handler | Notes |
|---|---|---|
| 0000–7FFF | read_mbc_rom | Cartridge ROM, bank switched |
| 8000–9FFF | read_vram | VRAM; PPU may block during mode 3 |
| A000–BFFF | read_mbc_ram | External RAM or RTC registers |
| C000–DFFF | read_ram | WRAM (banked on CGB) |
| E000–FDFF | Echo of C000–DDFF | |
| FE00–FE9F | OAM | Blocked during DMA and certain PPU modes |
| FF00–FF7F | read_high_memory | I/O registers |
| FF80–FFFE | HRAM | |
| FFFF | IE register |
I/O reads fan out: GB_IO_LY syncs PPU first; APU registers via GB_apu_read; joypad via GB_joypad_read.
Cheats: read_memory_callback can intercept; cheat hash may override values.
GB_write_memory — side effects
Notable write side effects:
0xFF46(DMA) — starts OAM DMA, setsdma_cycles0xFF40(LCDC) — may callGB_lcd_off, schedule frame repeat0xFF41(STAT) —GB_STAT_update0xFF04–07— timer/divider;GB_emulate_timer_glitchon TAC change0xFF4D(KEY1) — CGB speed switch countdown- MBC range 0000–7FFF, A000–BFFF —
write_mbcupdates bank pointers
GB_trigger_oam_bug called on specific inc/dec patterns affecting OAM region (DMG only).
Important data structures per cycle
gb->pending_cycles— T-cycles to advance before next bus accessgb->address_bus,gb->data_bus— open bus emulationgb->cycles_since_run— returned byGB_run(8 MHz units)gb->accessed_oam_row— for OAM corruption tracking
What breaks if changed incorrectly
- Skipping
GB_advance_cyclesincycle_read→ PPU/APU desync, Acid2 failures - Wrong conflict map → raster effects (SCX/STAT glitches) break
- Calling
GB_read_memorywithout PPU sync on LY/STAT → wrong mode interrupts - Removing OAM bug →
oam_bug-2.gbtest fails