Video summary
Gameboy Emulator Development - Part 15
Main summary
Key takeaways
Summary of the video (Part 15: Window + Gamepad for a Game Boy Emulator)
1) PPU update: implement the Window rendering
- Added a
window linevariable to the PPU context (tracking the currently rendered horizontal line within the window). - During PPU rendering, the emulator increments this window line when
LYfalls within the window’s vertical range, using LCD/window coordinate logic such as:LY >= WYandLY < WY + 144
- Reset
window_yto0at 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
xwithin limits andy < 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
- If using the second tile set, increment the tile index by
- Compute the tile row via
- Added a missing guard condition (
returnwhen 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)
- Selection bits choose whether reads refer to:
- Added
gamepad.handgamepad.cwith:- A
gamepad_statestructure storing button states:start, select, a, b, up, down, left, right - Selection/flag fields controlling whether the register is targeting direction or buttons
- A
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.
- Starts from a default like
5) Wire gamepad into the emulator bus / IO
- Updated emulator IO/MMIO handling:
- Read at
0xFF00returnsgamepad_get_output() - Write to
0xFF00updates selection bits viagamepad_set_cell(...)
- Read at
6) UI event handling: map SDL keys to joypad inputs
- Updated
ui.cto process SDL key down/up events and update the gamepad state. - Mapped inputs:
- A button →
Z - B button →
X - Start →
RETURN - Select →
TAB - D-pad → arrow keys
- A button →
- 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.