Skip to content
Hardware

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.

nintendo-entertainment-systemgraphicsprocessorsricohnintendo1983–present

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: 64-entry master palette (with several near-duplicates depending on PPU revision); 25 colours on screen simultaneously (1 backdrop + 4 background palettes × 3 + 4 sprite palettes × 3).
  • Backgrounds: four logical nametables (32×30 tiles each), backed by 2 KB of CIRAM (two physical pages); cartridge mirroring (horizontal, vertical, single-screen, or four-screen) decides which logical maps where.
  • Sprites: 64 sprites in OAM, 8 per scanline maximum (hardware-enforced).
  • Tile size: 8×8 backgrounds; sprites are 8×8 or 8×16 (mode set globally via PPUCTRL bit 5).

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, sprite overflow
$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

OAM DMA lives separately on the CPU bus:

Address Register Purpose
$4014 OAMDMA 256-byte CPU→OAM DMA transfer; CPU stalls 513–514 cycles

OAMDMA is the canonical mechanism for refreshing sprite RAM each frame (writing the 256 OAM bytes one at a time via OAMDATA would not fit in vblank).

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.

See also