GameBoy: The PPU (Draft)
Reading time: 2 minutes
Similarly to how it’s nice and convenient to think of memory as one big list of bytes (but is, in reality, backed by lots of different peripherals whose access is mediated by the MMU), it’d be nice to live in a world in which all it took to display pixels was to write some RGB values to a pixel-list. Alas, things are never quite so straightforward. The GameBoy’s LCD display is driven by a subsystem called the Picture Processing Unit, or PPU.
The PPU has a number of responsibilities: updating the display 60 times per second, rendering frames using data that is set up by the game, and allowing the game to take action in response to certain periodic events, such as a when a frame finishes drawing to the screen.
It’s worth noting that modern systems generally do make it quite easy to draw pixels straight into a buffer, though the exact mechanism varies considerably based on platform, API layer, and programming language. Eventually, we’re going to want to plug this GameBoy emulator into axle’s desktop environment (remember that?), so we will get to use this sort of approach. Internally to the emulator, though, we’ve got to play by the rules set out by the hardware.
Well, not quite. We’ve got to play by the rules expected by the software we want to run in the emulator, which itself expects a certain set of rules and facilities provided by the environment it was originally intended to run in.
Philosophical points aside, let’s get cracking! Pixel-pushing is always a fun endeavour.
There’s a good reason why the GameBoy doesn’t allow us to write pixels directly to the screen, and that reason is resource constraints. The GameBoy is a limited piece of hardware - limited speed, limited address space, limited RAM - and the design of the system is conscientious of those limits. Instead, Nintendo enforces a tile-based graphics approach. The game is responsible for generating small tiles of pixel data, and also instructing the PPU on where each of these tiles should be rendered on-screen.
Each tile is generally an 8x8 pixel rectangle, and the PPU expects the game logic to populate a data structure that says “draw tile #1 here”, “draw tile #2 there”, “draw tile #1 again but over here”, etc. This allows the game to present repeating graphics with very little wasted memory. For example, if the game wants to display a sentence that contained the letter ‘B’ multiple times, it wouldn’t be necessary to store the same ‘B’ graphic twice: instead, the game can simply say “draw my tile containing ‘B’ in these three places’. Similarly, it allows the game to shift around tiles on-screen, without burning cycles on expensive blitting operations. [*]
Just like our emulated CPU needed to closely mimic the operations the original hardware performed (and that the software we’re emulating is expecting and relying upon), so too will our PPU need to mimic the behavior of the original.
The PPU defines a few areas that software running on the GameBoy should use to populate and manipulate this tile data. Like every other peripheral in the system, access to the PPU is exposed through dedicated regions of memory, and access to these memory regions is mediated by the MMU.
- refer back to this when showing vram debug data, show that games actually do use this alphabet set
then show the digression about legend of zelda?
cartridge data format?
show filling in of the opcode table day by day
blargg test says nop failed
include when timer register not implemented, all squares
assumes knowledge of hex?