Video summary

Gameboy Emulator Development - Part 09

Main summary

Key takeaways

Technology

Overview

This video is the 9th part of a low-level device / dev series where the creator builds a Game Boy emulator CPU. The focus is:

  • Completing remaining CPU instruction implementations
  • Adding interrupt handling
  • Running the CPU in a separate thread
  • Providing a minimal SDL UI so the emulator can be closed cleanly

1) Remaining CPU instructions implemented (mainly bit/flag ops + misc ops)

The speaker begins by collecting leftover opcodes that are not implemented yet, then removes entries that are undefined. They then implement several key remaining instructions:

Rotate/shift accumulator variants

  • RLCA / RRCA / RLA / RRA
  • Implemented by shifting the A register and updating the carry flag (C) appropriately.
  • They compute the bit shifted out:
    • Bit 7 for left rotates
    • Bit 0 for right rotates
  • Flag behavior:
    • For RLCA/RRCA: flags are updated with C set from the outgoing bit.
    • For RLA/RRA: rotation incorporates carry behavior depending on the specific instruction variant.

DAA (Decimal Adjust Accumulator)

  • A special BCD-like correction instruction.
  • Uses temporary arithmetic based on:
    • Flags N/H/C
    • The lower nibble of A
  • Updates flags after adjustment, including carry behavior and which flags are set/cleared.

CPL (Complement Accumulator)

  • Sets A = ~A
  • Updates flags in a fixed pattern according to the instruction rules (including N and H behavior).

SCF (Set Carry Flag)

  • Forces carry to 1
  • Clears N and H

CCF (Complement Carry Flag)

  • Toggles the carry flag using XOR logic.

HALT behavior

  • Implemented as:
    • Set a halted state
    • Remain halted until an interrupt condition occurs

STOP

  • Added, but explicitly treated as not fully supported
    • Includes a placeholder behavior that terminates/prints “stopping”
    • The creator notes uncertainty about correctness and that more research is needed to see whether games use it.

2) Additional instruction coverage (math/stack-ish + interrupt enable/disable)

The creator also adds missing opcode mappings in previously incomplete ranges, including:

  • Sub/SBC immediate variants

    • Example: D6 (SUB A, d8)
    • Related: SBC A, d8 (decrement with carry)
  • Memory/register load specials

    • LD (HL), SP+imm8-style instruction mentioned for opcode F8
      • Uses addressing where HL = SP + signed immediate
    • Also maps LD SP, HL and other special register transfers (e.g., opcode F9)
  • Interrupt control

    • Adds EI (Enable Interrupts) and DI (Disable Interrupts)
    • Important Game Boy nuance:
      • EI does not immediately enable IME behavior in the same instant (there’s a latency/extra cycle, and IME isn’t set right away like DI).

3) Bus/IO missing pieces (needed to run test programs)

When testing begins, the emulator encounters unimplemented bus reads, such as:

  • A stubbed “not implemented” read at an address like 0xFF44 (likely an LCD-related register, e.g., LCD interrupt flag register)

To keep CPU testing moving:

  • They temporarily return 0 / stub behavior
  • They later mention additional bus read/write gaps, but CPU progress continues.

4) Interrupt system added (VBlank/LCD/Timer/Serial/Joypad)

A dedicated interrupt module is introduced:

New files

  • interrupt.h
  • interrupt.c

Interrupt types

Interrupts are defined via an enum, including:

  • VBlank
  • LCD STAT
  • Timer
  • Serial
  • Joypad

Core logic and CPU integration

  • HALT checks interrupt pending flags:
    • If any interrupt is pending, it un-halts
  • The CPU context gains accessors for:

    • IF (interrupt flags register)
    • IE (interrupt enable register)
  • CPU interrupt handling:

    • Checks IF bits & IE bits
    • If an enabled interrupt is pending:
      1. Pushes current PC onto the stack
      2. Jumps PC to the interrupt vector address
      3. Clears the serviced interrupt bit in IF
      4. Clears IME/master enable after servicing
  • Interrupt vectors used (as stated):

    • VBlank → 0x40
    • LCD STAT → 0x48
    • Timer → 0x50
    • Serial → 0x58
    • Joypad → 0x60

The handler processes one interrupt at a time and stops once one is handled.


5) Running the CPU in a separate thread + SDL window for controlled exit

To avoid SDL blocking development/testing (they previously had an infinite loop that couldn’t be stopped with Ctrl+C), they implement:

Minimal UI

  • New files:
    • ui.h
    • ui.c
  • The SDL window is primarily for controlled termination:
    • Closing the window sets a die flag in the emulator context

Separate CPU execution

  • They implement a CPU run function intended for a separate thread:
    • Loops until ctx.die is set
    • Sleeps briefly (e.g., ~1000 microseconds)
    • Calls UI event handling indirectly (cycle timing is mentioned as a planned follow-up)

Threading

  • Adds pthread usage via p_thread.h
  • Notes:
    • POSIX-only
    • TODO exists for Windows compatibility

6) Testing plan and next step

  • They confirm the emulator now runs far enough to:
    • Open/close the UI
    • Exercise HALT/interrupt behavior

Next video goals

  • Find bugs by running test ROMs covering CPU instructions
  • After CPU stabilizes, begin PPU work to render graphics

Main speakers/sources

  • Primary speaker: the video creator/developer presenting the “Gameboy Emulator Development” series (no named individual provided in subtitles)
  • Codebase being modified (modules/files referenced):
    • cpu
    • bus
    • interrupt
    • ui
    • threading via pthread (through p_thread.h)

Original video