PPU: The NES Picture Processor
Dedicated silicon for smooth scrolling and sprites
The Ricoh 2C02 Picture Processing Unit gave the NES hardware sprites, tile-based backgrounds, and smooth scrolling—defining the look of 8-bit console gaming.
Overview
The Picture Processing Unit (PPU) was Nintendo’s secret weapon. While home computers relied on the CPU for graphics, the NES offloaded rendering to dedicated hardware. This freed the 6502 for game logic and gave the console its characteristic smooth scrolling and fluid sprite animation.
Fast facts
- Resolution: 256×240 pixels (NTSC crops to ~256×224 visible).
- Colours: 52 available colours, 25 on screen simultaneously.
- Backgrounds: two nametables (screens) of 32×30 tiles.
- Sprites: 64 sprites, 8 per scanline maximum.
- Tile size: 8×8 pixels for both backgrounds and sprites.
Memory architecture
| Address Range | Contents |
|---|---|
| $0000-$0FFF | Pattern table 0 (left, 256 tiles) |
| $1000-$1FFF | Pattern table 1 (right, 256 tiles) |
| $2000-$23FF | Nametable 0 |
| $2400-$27FF | Nametable 1 |
| $2800-$2BFF | Nametable 2 (mirror or RAM) |
| $2C00-$2FFF | Nametable 3 (mirror or RAM) |
| $3F00-$3F1F | Palette RAM |
CPU interface registers
| Address | Register | Purpose |
|---|---|---|
| $2000 | PPUCTRL | NMI enable, sprite size, pattern tables |
| $2001 | PPUMASK | Colour emphasis, sprite/BG enable |
| $2002 | PPUSTATUS | VBlank flag, sprite 0 hit |
| $2003 | OAMADDR | Sprite memory address |
| $2004 | OAMDATA | Sprite memory data |
| $2005 | PPUSCROLL | Scroll position (write twice: X, Y) |
| $2006 | PPUADDR | VRAM address (write twice: high, low) |
| $2007 | PPUDATA | VRAM data read/write |
Sprite attributes
Each of the 64 sprites uses 4 bytes in OAM (Object Attribute Memory):
| Byte | Purpose |
|---|---|
| 0 | Y position (sprite appears on next scanline) |
| 1 | Tile index |
| 2 | Attributes (palette, priority, flip H/V) |
| 3 | X position |
Key techniques
- VBlank timing: all VRAM updates must happen during the ~2270 cycles of vertical blank.
- Sprite 0 hit: detect when sprite 0’s opaque pixel overlaps background for mid-screen effects.
- Scroll splitting: change scroll mid-frame using sprite 0 hit or mapper IRQs.
- Attribute table tricks: work around the 16×16 pixel colour grid constraint.
Limitations and workarounds
- 8 sprites per scanline: exceeded sprites flicker; games cycle priority to spread flicker.
- Colour granularity: 16×16 pixel attribute blocks; design around this constraint.
- No line-by-line scroll: requires sprite 0 hit or mapper assistance.
- Pattern table size: 512 tiles total; mappers add bank switching.