Video summary

Gameboy Emulator Development - Part 05

Main summary

Key takeaways

Technology

Tech Focus of the Video (Game Boy Emulator, Part 05)

Goal

  • Finish CPU memory access for:
    • Working RAM (WRAM)
    • High RAM (HRAM)
  • Implement enough instruction behavior to test the emulator.

Context / What was broken before

  • In the previous video, the emulator hit unsupported bus access (e.g., around addresses like 0xD600).
  • This video fixes the emulator’s bus read/write memory map and adds RAM backing storage.

Memory Map Implementation (Bus Read/Write)

The speaker updates the emulator’s bus read and bus write routing using an else if chain to map address ranges to correct backing memory and behavior.

Mapped regions described

  • Cartridge / character-related placeholder

    • Addresses starting around 0xA000
    • Treated as CHR/character map data / BG map areas
    • Not fully implemented yet (marked as “todo/ignore”)
  • Cartridge RAM

    • Range 0xC0000xDFFF
    • Mapped to cartridge RAM via:
      • cart_read
      • cart_write
  • Working RAM (WRAM)

    • Range 0xE000–…
    • Includes WRAM bank 0 / bank 1
    • Uses dedicated functions:
      • wram_read
      • wram_write
  • Echo RAM

    • Described as “reserved aka echo ram” around the 0xE000 area
    • The speaker doesn’t understand it deeply yet and returns 0 / ignores it for now
  • OAM / PPU-related placeholder

    • 0xFE000xFE9F: Object Attribute Memory (OAM)
    • Marked TODO
    • Deferred until the PPU is implemented (with a note to avoid derailing CPU emulation progress)
  • Unusable / reserved ranges

    • Several regions like 0xFEA00xFF00 and portions under 0xFF00
    • Treated as “unusable/reserved” and return 0
  • I/O registers (deferred)

    • Up to 0xFF80 includes controller and other I/O registers
    • Current behavior:
      • If accessed, log an error
      • Do not exit, so tests can proceed
  • High RAM (HRAM)

    • Range 0xFF800xFFFF
    • Mapped as HRAM using:
      • hram_read
      • hram_write
    • Note: the speaker mentions HRAM is sometimes called “zero page” (naming varies)

New RAM Module Added

A new module is introduced:

  • ram.c
  • Header: ram.h

RAM sizes

  • WRAM size: 0x2000 bytes
  • HRAM size: 0x80 bytes

Provided functions

  • wram_read(addr)
  • wram_write(addr, value)
  • hram_read(addr)
  • hram_write(addr, value)

Implementation details

  • Reads/writes offset the address by subtracting the region base:
    • WRAM subtracts 0xC000
    • HRAM subtracts 0xFF80
  • Includes a basic example for invalid addresses (though the speaker expects the bus won’t send invalid ranges)

Result

  • After compiling/rerunning, the earlier “invalid bus read/write” issue disappears.
  • More debug output becomes visible.

Register Debugging Improvements

The debug output improves from showing only:

  • A B C

to showing:

  • B, C, D, E, H, L

It also uses combined register printing from fields like ctx->regs.* to better verify instruction effects involving memory/register interactions.


Instruction Implementation / Update: LDH and Bus Testing

Identifying the issue

  • Failures around 0xE0 are traced to the LDH instruction.
  • The target addressing was unsupported/mismapped.
  • The fix is to implement LDH with correct HRAM addressing.

Implementation summary

  • Adds a proc ldh function.
  • Uses conditional logic based on instruction addressing mode fields.
  • For the “read from C register OR A to HRAM” style:

    • If reg1 == A:
      • Read from A
      • Write to HRAM using the immediate offset/address bits
      • Mentions masking with & 0xFF00
    • Else:
      • Opposite direction (write/fetch depending on mode)
  • Adds an extra CPU cycle for LDH.

Opcode table integration

  • Adds LDH mapping for:
    • 0xE0 (LDH A,(a8) style)
    • 0xF0 (LDH A,(a8) style opposite direction)
  • The instruction table entry includes:
    • addressing mode noted as “am”
    • register types like A8 and A

Verifying Memory Map Correctness via Emulator Tests

After RAM + LDH:

  • The emulator progresses further through more LD / LDH instructions.
  • New failures are traced to:
    • I/O access at 0xFF00 (handled by logging an error and continuing)
    • Interrupt enable register IE at 0xFFFF
      • Reads/writes fail because it wasn’t implemented yet

Implementing Interrupt Enable Register (IE) Support

To fix failures at 0xFFFF:

Changes made

  • Add ie as a field in CPU context:
    • u8 ie
  • Add CPU accessors:
    • cpu_get_ie_register()
    • cpu_set_ie_register(value)
  • Update bus/CPU logic to read/write the IE register using those accessors.

Result

  • Execution proceeds past the earlier failing instruction locations.

Deferred to the Next Video (Part 06)

  • Call / jump / return instructions (explicitly stated as the main focus of Part 06)
  • PPU / OAM implementation is deferred
  • I/O controller/register handling is deferred (currently only error logging exists)
  • Echo RAM behavior is simplified/ignored

Main Speakers / Sources

  • Primary speaker: the author of “low-level devil” (YouTube)
  • Source narration: “Gameboy Emulator Development - Part 05”

Original video