Writing an NES emulator is a long process. If you’re reading this you’ve likely finally been able to finish implementing the 6502, and now you just want to see some output! While there is a lot of information generally available for the NES PPU it can be difficult to identify the best point of entry to start developing this component. The documentation dives into everything from cycle accuracy to scrolling, and it can be a bit daunting trying to dig in. While these items are definitely all important, how do you simply start getting some semblance of a game running? This guide’s focus isn’t on getting anywhere near a perfect PPU implementation, but to explain the minimum components needed to start rendering and provide details on where to start.
The quickest path forward is to start with the implementation of rendered backgrounds. There are three main pieces that are combined to make up a game’s background. Name tables, pattern tables, and attribute tables. The CPU also needs to know when it can write name tables, this is accomplished through NMI interruption. We’ll describe below each of these and share examples of expected output when each of these are rendered.
At a very high level, the PPU generates 341 pixels for each 262 scan lines. As it moves through this process 240 scan lines produce visible pixels. During these scanlines most games do not write to the PPU memory as it can produce various unexpected (or expected, in some games that take advantage of this) effects. The PPU triggers a vblank period where it announces it is not currently rendering to the screen, and that a game can write to its memory.
This diagram does a great job showing a visual representation of the rendering period: https://wiki.nesdev.org/w/index.php?title=File:Ntsc_timing.png
NMI Interrupt
If you’ve successfully gotten a game running against your 6502 you may notice you’re looping against a repetitive set of CPU opcodes. If you have not yet implemented your NMI interrupt your CPU is likely trying to request an NMI interrupt. The NMI interrupts are determined by 2 of the 8 bytes of CPU memory that control a set of PPU registers.
0x2000 – PPU Controller – The CPU can write to this register. When the CPU wants to write to the PPU it can request an NMI interrupt. This is accomplished by writing 1 to bit 7 of this register.
0x2002 – PPU Status – When a vblank period has been entered this register indicates this by setting bit 7 of this register to 1.
When both of the described bits above are 1 an NMI interrupt should occur. Additional detail on the specific implementation details of NMI interrupts can be found at https://wiki.nesdev.org/w/index.php/NMI
Nametables
Once you’ve successfully implemented an NMI interrupt you should see the CPU start trying to write to 0x2006 and 0x2007. These registers allow the CPU to write data to the PPU’s memory and populate a game’s nametables. Nametables describe the state of the current background. For our initial implementation, let’s forget about mirroring and focus just on rendering the current name table.
The PPU memory maps to 4 names tables stored from 0x2000 to 0x2fff (NOTE: this is separate PPU memory and is separate from the 0x2000 in the CPU memory). The currently displayed nametable is described by bits 0 and 1 of the controller register (0x2000 in the CPU memory). These bits allow us to determine from which nametable we should populate our background. Names tables describe a 32X30 set of tiles on the screen. Each byte in the applicable nametable indexes into the upcoming pattern tables.
When I started to test my name tables, I simply assigned a color to each byte and rendered to a 32X30 screen in SDL2. Output of this step is displayed. While it may not be the most attractive output, it’s easy to see how this can start making up our final title screen.
Provides a good overview of where each name tables starts in the PPU memory: https://wiki.nesdev.org/w/index.php/PPU_nametables
https://wiki.nesdev.org/w/index.php/PPU_memory_map
Pattern Tables
Pattern tables provide the detail that make up the games we know and love. Accessing pattern tables is fairly easy. Pattern tables live in the CHR ROM obtained from the underlying cartridge. This detail is then loaded into the PPU memory starting from 0x0000 to 0x1fff.
There are two pattern tables, and each pattern table is 128X128 pixels and made up of a set of 16X16 tiles. When I first started with my implementation, I first starting by making sure I could render the raw pattern tables to a 256X128 SDL2 window. Each tile is 8×8 pixels, and each is made up by 16 bytes. Each section of 16 bytes is divided up into 2 sets of 8 bytes. Each byte is then broken up into its 8 bits to define patterns.
For example, if byte 0 is 01011010 and byte 8 is 11000011 this would form the first 8 pixels. This would then be combined to determine an index into the applicable color in the upcoming attribute table. This example would produce the following indexes 23011032.
Once you’re able to build the raw pattern table, you would simply need to use the index provided in the nametable to apply the correct tile in the pattern table. As mentioned, the nametables provided a grid of 32X20 bytes. Each byte represents and index into the pattern table to a tile. Each pattern table tile is 8×8 pixels. This provides our standard NES output screen of 256X240.
The following was helping is building pattern tables: https://wiki.nesdev.org/w/index.php/PPU_pattern_tables
Attribute Tables
Our last piece to build our background are attribute tables. Attribute tables sit in the last 64 bytes of memory in our applicable nametable. Attribute tables provide color detail for our screen in an 8×8 grid, so each byte details the color information for a 2×2 section of pattern tiles.
Every two bits of an attribute table byte details the index into the color palette used for that tile. Palette colors are started starting at 0x3f00 in the PPU memory.
Bytes 0 and 1 – Top Left Namespace Tile
Byte 2 and 3 – Top Right Namespace Tile
Byte 4 and 5 – Bottom Left Namespace Tile
Byte 6 and 7 – Bottom Left Namespace Tile
Starting at 0x3f00 color palettes are defined with each color palette containing 4 bytes. Our palette index determined from our attribute table indexes into this memory space, and the index provided by the individual bits in our pattern tables indexes into 1 of the four colors of each palette.
If you’re seeing colors that seem to be applied consistently, but aren’t producing the expected colors I’d recommend checking your nametables. The image above shows a similar situation where the high and low bit making up the nametable was switched.
The PPU has a lot of complexity that makes it difficult to determine how best to start tackling. Hopefully this guide will help clear up some of the confusion. Now off to build sprite rendering!