⭅ Previous (CHR Graphics) Next (Sprites) ⭆

NES Graphics Palette

Also available on Youtube.

Last time we saw how the NES stores image data. Since image data only has 2 bits per pixel, the image doesn’t directly encode the color used. Instead these point into something called a palette.

Though we can sort of visualize the image data directly, color makes a big difference. It allows the NES to turn something like this:

Alwa’s Awakening Greyscale

Into something like this:

Alwa’s Awakening Color

(Alwa’s Awakening, a recent Indie title for NES. No affiliation)

The NES palette.

First we’ll describe the palette, and then we’ll talk about how games can control it.

The NES has two sets of palettes. Each set of palettes contains 4 palettes, and each palette has 4 or technically 3 colors. Here’s one way to visualize this:

Palette Debug, EmulationOnline Debugger

(Palette from Megaman Cutman stage)

The background art typically uses a different set of colors than characters and other things that move around. Characters often use higher contrast in order to stick out relative to the background. The NES system design acknowledges this and has two different sets of palettes.

You may have noticed that the first color in each of the BG palettes is the same, as is the first color for all the FG palettes. This is no accident. Color 0 actually indicates “unused” or “background”, depending on how the image is drawn. The NES has two different ways of drawing, depending on BG or FG. We’ll see more about the actual rendering in these modes later.

In both FG and BG, value 0 essentially means “empty”, or “fall back to underneath. For something in the Foreground, this will result in the background showing through. This is how you can have characters that aren’t squares. For the background, value 0 of the palette actually specifies a default background color. Some games use this to implement a sky color, for example.

Each of the drawing modes have some way of specifying which of the palettes to use within its respective mode.

Controlling the palette

So lets assume the game is set up to draw a tile, and has specified which palette to use. How does the game get colors into the palette in the first place?

The palette is a special region of memory managed by the PPU. The CPU is not connected directly to the palette memory, and so needs to ask the PPU whenever it wishes to make changes.

It does this via a technique called “Memory Mapped IO”, or MMIO.

MMIO

We actually saw a little bit of MMIO when we discussed cartridge mapping. There The CPU is able to “read” from a ROM cartridge because the cartridge has mapped the rom into memory, so “memory” reads starting at a certain address actually go to the rom chip.

Interaction with the palette is similar, in that certain memory addresses signify communication with a chip. Rather than going directly to another storage chip, however, the PPU exposes MMIO addresses to act as commands that control various graphics features.

Nearly all interactions with peripherals are accomplished via MMIO on the NES. Lets look at the PPU Palette MMIO specifically.

PPU Palette MMIO

The PPU provides a MMIO addresses to interact with the palette. First, it is worth mentioning that the PPU has its own memory, disconnected from the CPU and accessable only via the PPU. The PPU controls access to this memory, or VRAM(video ram) via MMIO addresses.

0x2006 : PPUADDR or PPU Address. (write only) Writing here sets the VRAM address to which
the PPU will write. Upper byte written first.
0x2007 : PPUDATA or PPU Data. Each byte written here will be copied to the current PPU
Address. The address will then be incremented.

And to make sense of this, lets look at a piece of the VRAM memory map. Just as certain regions of CPU memory have specific purposes, the PPU assigns responsibility to certain regions of VRAM.

PPU VRAM Memory Map:

Start/End (Inclusive) Size Usage
0 - 0x0FFF 0x1000 (4096 bytes) CHR Table 0
01000 - 0x1FFF 0x1000 (4096 bytes) CHR Table 1
0x3F00 - 0x3F1F 0x0020 (32 bytes) Palette

Source: Nesdev

These 32 bytes cover the 32 different palette colors we saw above. 2 groups(BG/FG) each with 4 Palettes, each with 4 colors = 244 = 32. So one byte per color.

There is a fair bit of indirection going on here, so lets illustrate with an example. This little program will write 0x1C (dark cyan) into BG palette 0 position 0. This will set the background color used when neither background nor fg image cover a given pixel.

First we need to set PPUADDR to 0x3f00, which corresponds with bg palette 0 value 0. Since the PPU wants the upper byte first, we write 0x3f, then 0x00.

lda #$3f
sta $2006  ; write to 0x2006=PPUADDR
lda #$00
sta $2006
; ppuaddr is now 0x3f00

Now that PPUADDR is set up, the next write to PPUDATA will write into PPUADDR at the last specified address. We want to write 0x1C, so:

lda #$1c
sta $2007  ; write to 0x2007=PPUDATA
; vram at 0x3f00 is now set to 0x1c
; PPUADDR is now 0x3f01

This auto-increment behavior makes it convenient for setting long spans of VRAM, without needing to write PPUADDR between each value. But it also makes it possible to write single values if necessary.

Color interpretation

You might be wondering how 0x1C turns into cyan. Remember that the NES system connects to a television. Video electronics of the day relied on a CRT display, which scans a beam over some special material (phosphors) that glow based on the voltage applied to them.

If you want to dive deep, the NESdev explains how these color values, like 0x1C, turn into real colors.

But this level of detail is unnecessary for emulator developers, or for understanding the NES. Since each color is only one byte, that leaves only 256 possible colors. Most emulators, mine included, simply include a table which specifies how each of these color values maps into a full RGB color.

This trick is sometimes called the system palette, and can be visualized like so. Across the first row is values 0x00 up to 0x0F. The next row starts at 0x10. So you can think of the hex values as 0xYX, x and y positions into this table.

emulationonline nes system palette

Palette Test ROM

I’ve written a small test program which writes a different value into each palette slot. This helps understand palette operation, and also makes it possible to visualize palette behavior in an emulator.

The nice thing is that, even without drawing anything, setting the first BG color sets the color on screen. This gives the rom a visible effect even without debugging features.

Source and assembled .nes file are provided on the NES index, Note there are two versions. First (palette_fill_novblank), simpler but less correct, writes the palette as soon as the system starts up. The other(palette_fill), waits for a video interrupt before updating the palette.

This second one is more correct, as updating the palette while the PPU is drawing /can/ lead to corruption on a real system. But we havent discussed video interrupts yet, so I’ve also provided a version that doesn’t rely on them.

Source code available at the index page linked above. Here are the two roms:

Running in my debugger gives something that looks like this:

emulationonline nes palette debug view

Summary / Palette Usage Graphic

Since palette usage relies on a fair bit of indirection, a summary might help clarify what we’ve discussed.

Setting Palette from CPU:

  1. Write(2 times) VRAM Palette Address (0x3f, 0x00) to PPUADDR
  2. Write palette value to PPUDATA

Drawing from a tile with a Palette

  1. Tile pixel value looked up. Say, 0b10
  2. Appropriate palette found (specifics to follow in BG/FG articles)
  3. PPU looks up palette in slot based on tile value.
         /----------------------------------|
value 0b10, palette FG 3                    |
                       \---------|          |
                                 |          |
   0         1         2         3          |
FG [? ? ? ?] [? ? ? ?] [? ? ? ?] [0x11 0x05 0x31 0x2d]
                                  0    1    2    3

In this example would be color 0x31, a very light blue.

Next up: Foreground rendering

Now that we know how to apply colors, lets try try actually drawing something on screen. We’ll start with foreground images, aka sprites.

Next article: sprite rendering

⭅ Previous (CHR Graphics) Next (Sprites) ⭆

We publish about 1 post a week discussing emulation and retro systems. Join our email list to get notified when a new post is available. You can unsubscribe at any time.