Video summary

Gameboy Emulator Development - Part 15

Main summary

Key takeaways

Technology

Summary of the video (Part 15: Window + Gamepad for a Game Boy Emulator)

1) PPU update: implement the Window rendering

  • Added a window line variable to the PPU context (tracking the currently rendered horizontal line within the window).
  • During PPU rendering, the emulator increments this window line when LY falls within the window’s vertical range, using LCD/window coordinate logic such as:
    • LY >= WY and LY < WY + 144
  • Reset window_y to 0 at VBlank, so the counter restarts every frame.

2) Window visibility logic

  • Implemented a helper (e.g., “window visible”) to quickly determine whether the window should affect the current pixel.
  • This checks LCD/window enable and screen bounds using X/Y comparisons (including checks like x within limits and y < y_res).

3) Pipeline rendering: load window tiles instead of background tiles

  • In the PPU pipeline’s background/window fetch area, added a function such as pipeline load window tile.
  • When pixels fall inside the window region and the window is enabled:
    • Compute the tile row via window_y / 8
    • Compute the tile column via logic like ((x + 7) - WX), including bounds checks
    • Fetch the tile id from the window tile map address:
      • LCDC win map area
    • Select the correct tile data bank/ID offset:
      • If using the second tile set, increment the tile index by 128
  • Added a missing guard condition (return when the window is not visible).
  • Result: the test ROM matched expectations.

4) Game input: implement the Joypad / gamepad register (0xFF00)

  • Implemented Game Boy joypad behavior using the FF00 I/O register:
    • Selection bits choose whether reads refer to:
      • Direction buttons (D-pad)
      • Action buttons (A/B/Start/Select)
  • Added gamepad.h and gamepad.c with:
    • A gamepad_state structure storing button states: start, select, a, b, up, down, left, right
    • Selection/flag fields controlling whether the register is targeting direction or buttons
  • gamepad_get_output() builds the FF00 return value:
    • Starts from a default like 0xCF
    • Uses the Game Boy convention: 0 means pressed, 1 means not pressed
    • Clears specific bits depending on which keys are pressed and the current selection mode.

5) Wire gamepad into the emulator bus / IO

  • Updated emulator IO/MMIO handling:
    • Read at 0xFF00 returns gamepad_get_output()
    • Write to 0xFF00 updates selection bits via gamepad_set_cell(...)

6) UI event handling: map SDL keys to joypad inputs

  • Updated ui.c to process SDL key down/up events and update the gamepad state.
  • Mapped inputs:
    • A buttonZ
    • B buttonX
    • StartRETURN
    • SelectTAB
    • D-pad → arrow keys
  • Added a function like ui_on_key(key, down) to update the gamepad struct accordingly.
  • Verified with games:
    • Dr. Mario: player switching works; arrow keys move and play correctly.
    • Tetris: game plays, confirming PPU + input integration.
    • Super Mario Land: reported stopping due to an unresolved issue (to be fixed later).

7) Next planned work

  • Next video: implement MBC (Memory Bank Controller) to support larger ROMs and cartridge types requiring banking/RAM (e.g., Metroid, Zelda).

Key speakers / sources

  • Main speaker: “Low Level Devil” (host narrating the emulator development series)
  • Sources referenced: Game Boy hardware documentation for the 0xFF00 joypad register, and emulator GitHub/test ROMs used for validation.

Original video