PPU palettes
The NES has a limited selection of color outputs. A 6-bit value in the palette memory area corresponds to one of 64 outputs. The emphasis bits of the PPUMASK register ($2001) provide an additional color modifier.
For more information on how the colors are generated on an NTSC NES, see: NTSC video
Memory Map
The palette for the background runs from VRAM $3F00 to $3F0F; the palette for the sprites runs from $3F10 to $3F1F. Each color takes up one byte.
Address | Purpose |
---|---|
$3F00 | Universal background color |
$3F01-$3F03 | Background palette 0 |
$3F05-$3F07 | Background palette 1 |
$3F09-$3F0B | Background palette 2 |
$3F0D-$3F0F | Background palette 3 |
$3F11-$3F13 | Sprite palette 0 |
$3F15-$3F17 | Sprite palette 1 |
$3F19-$3F1B | Sprite palette 2 |
$3F1D-$3F1F | Sprite palette 3 |
Each palette has three colors. Each 16x16 pixel area of the background can use the backdrop color and the three colors from one of the four background palettes. The choice of palette for each 16x16 pixel area is controlled by bits in the attribute table at the end of each nametable. Each sprite can use the three colors from one of the sprite palettes. The choice of palette is in attribute 2 of each sprite (see PPU OAM).
Addresses $3F04/$3F08/$3F0C can contain unique data, though these values are not used by the PPU when normally rendering (since the pattern values that would otherwise select those cells select the backdrop color instead). They can still be shown using the background palette hack, explained below.
Addresses $3F10/$3F14/$3F18/$3F1C are mirrors of $3F00/$3F04/$3F08/$3F0C. Note that this goes for writing as well as reading. A symptom of not having implemented this correctly in an emulator is the sky being black in Super Mario Bros., which writes the backdrop color through $3F10.
Thus, indices into the palette are formed as follows:
43210 ||||| |||++- Pixel value from tile data |++--- Palette number from attribute table or OAM +----- Background/Sprite select
As in some second-generation game consoles, values in the NES palette are based on hue and brightness:
76543210 |||||||| ||||++++- Hue (phase, determines NTSC/PAL chroma) ||++----- Value (voltage, determines NTSC/PAL luma) ++------- Unimplemented, reads back as 0
Hue $0 is light gray, $1-$C are blue to red to green to cyan, $D is dark gray, and $E-$F are mirrors of $1D (black). The canonical code for "black" is $0F or $1D. $0D should not be used; it results in a "blacker than black" signal that may cause problems for some TVs. It works this way because of the way colors are represented in an NTSC or PAL signal, with the phase of a color subcarrier controlling the hue. For details, see NTSC video, or for a list see Color $0D games.
The 2C03 RGB PPU used in the PlayChoice-10 and Famicom Titler renders hue $D as black, not dark gray. The 2C04 PPUs used in many Vs. System arcade games have completely different palettes as a copy protection measure.
Palettes
2C02
The RF Famicom, AV Famicom, NES (both front- and top-loading), and the North American version of the Sharp Nintendo TV use the 2C02 PPU. Unlike some other consoles' video circuits, the 2C02 does not generate RGB video and then encode that to composite. Instead it generates NTSC video directly in the composite domain. The TV decodes this into RGB to drive its picture tube, and most TVs' decoders intentionally deviate somewhat from the NTSC standard.
Some emulators decode the NTSC signal in real time. Others use a predefined palette, such as one commonly stored in Classic VGA Palette format (.pal), in which each triplet represents the sRGB color that results from decoding a large flat area with a given palette value. Using such a table directly will result in overly "clean" video that looks somewhat more like a PlayChoice (see 2C03 below), and some games will look graphically sterile if quirks of the NES's video output are not emulated. However, sometimes people want something functional before they bother with actually generating a composite signal and decoding it, or they're making an emulator for a low-end device that cannot decode NTSC video in real time.
The following table was generated using blargg's Full Palette demo on Nestopia:
84 84 84 0 30 116 8 16 144 48 0 136 68 0 100 92 0 48 84 4 0 60 24 0 32 42 0 8 58 0 0 64 0 0 60 0 0 50 60 0 0 0 152 150 152 8 76 196 48 50 236 92 30 228 136 20 176 160 20 100 152 34 32 120 60 0 84 90 0 40 114 0 8 124 0 0 118 40 0 102 120 0 0 0 236 238 236 76 154 236 120 124 236 176 98 236 228 84 236 236 88 180 236 106 100 212 136 32 160 170 0 116 196 0 76 208 32 56 204 108 56 180 204 60 60 60 236 238 236 168 204 236 188 188 236 212 178 236 236 174 236 236 174 212 236 180 176 228 196 144 204 210 120 180 222 120 168 226 144 152 226 180 160 214 228 160 162 160
Other tools for generating a palette include one by Bisqwit and one by Drag. These simulate generating a large area of one flat color and then decoding that with the adjustment knobs set to various settings.
The 2C03, 2C04, and 2C05, on the other hand, all output analog red, green, blue, and sync (RGBS) signals. The sync signal contains horizontal and vertical sync pulses in the same format as an all-black composite signal. Each of the three video channels uses a 3-bit DAC driven by a look-up table in a 64x9-bit ROM inside the PPU. The look-up tables (one digit for each of red, green, and blue, in order) are given below:
2C03 and 2C05
This palette is intentionally similar to the NES's standard palette, but notably is missing the greys in entries $2D and $3D.
The 2C03 is used in Vs. Duck Hunt, Vs. Tennis, all PlayChoice games, the Famicom Titler, and the Famicom TV.
The 2C05 is used in some later Vs. games as a copy protection measure.
Both have been used in RGB mods for the NES, as a circuit implementing A0' = A0 xor (A1 nor A2)
can swap PPUCTRL and PPUMASK to make a 2C05 behave as a 2C03.
333,014,006,326,403,503,510,420,320,120,031,040,022,000,000,000 555,036,027,407,507,704,700,630,430,140,040,053,044,000,000,000 777,357,447,637,707,737,740,750,660,360,070,276,077,000,000,000 777,567,657,757,747,755,764,772,773,572,473,276,467,000,000,000
0x00 | 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09 | 0x0A | 0x0B | 0x0C | 0x0D | 0x0E | 0x0F |
0x10 | 0x11 | 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1A | 0x1B | 0x1C | 0x1D | 0x1E | 0x1F |
0x20 | 0x21 | 0x22 | 0x23 | 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2A | 0x2B | 0x2C | 0x2D | 0x2E | 0x2F |
0x30 | 0x31 | 0x32 | 0x33 | 0x34 | 0x35 | 0x36 | 0x37 | 0x38 | 0x39 | 0x3A | 0x3B | 0x3C | 0x3D | 0x3E | 0x3F |
Kevtris's dumped palettes imply that the monochrome bit has unique function on the 2C03 and 2C05: instead of just using the leftmost column of the palette (and forcing the lower four bits to zero), instead the top two bits index into a palette with colors: 000, 333, 777, 777. Given that the 2C04 does not do this, this exception feels weird, and corroboration would be appreciated.
RC2C03B
For no particularly discernible reason, the palette for this specific PPU varies in six colors:
333,014,006,326,403,503,510,420,320,100,031,040,022,000,000,000 555,016,027,407,507,704,700,630,430,140,040,053,044,000,000,000 777,357,447,637,707,717,740,750,660,340,070,276,077,000,000,000 777,547,657,757,747,755,764,772,773,552,473,276,467,000,000,000
0x00 | 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09 | 0x0a | 0x0b | 0x0c | 0x0d | 0x0e | 0x0f |
0x10 | 0x11 | 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1a | 0x1b | 0x1c | 0x1d | 0x1e | 0x1f |
0x20 | 0x21 | 0x22 | 0x23 | 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2a | 0x2b | 0x2c | 0x2d | 0x2e | 0x2f |
0x30 | 0x31 | 0x32 | 0x33 | 0x34 | 0x35 | 0x36 | 0x37 | 0x38 | 0x39 | 0x3a | 0x3b | 0x3c | 0x3d | 0x3e | 0x3f |
The pattern compared to the normal 2C03 is that where color bits 0-1 are 01, green is ANDed with 5 (bit 1 is 0). No games are known to be designed for this palette. Given the pattern, it was probably a mistake in the mask.
2C04
All four 2C04 PPUs contain the same master palette, but in different permutations. It's almost a superset of the 2C03/5 palette, adding four greys, six other colors, and making the bright yellow more pure.
No version of the 2C04 was ever made with the below ordering, but it shows the similarity to the 2C03:
333 | 014 | 006 | 326 | 403 | 503 | 510 | 420 | 320 | 120 | 031 | dup of ↙ | 022 | 111 | 003 | 020 |
555 | 036 | 027 | 407 | 507 | 704 | 700 | 630 | 430 | 140 | 040 | 053 | 044 | 222 | 200 | 310 |
777 | 357 | 447 | 637 | 707 | 737 | 740 | 750 | 660 | 360 | 070 | dup of ↓ | 077 | 444 | 000 | 000 |
777 | 567 | 657 | 757 | 747 | 755 | 764 | 770 | 773 | 572 | 473 | 276 | 467 | 666 | 653 | 760 |
The PPUMASK monochrome bit has the same implementation as on the 2C02, and so it has an unintuitive effect on the 2C04 CPUs. Rather than forcing colors to grayscale, it instead forces them to the first column.
RP2C04-0001
MAME's source claims that Baseball, Freedom Force, Gradius, Hogan's Alley, Mach Rider, Pinball, and Platoon require this palette.
755,637,700,447,044,120,222,704,777,333,750,503,403,660,320,777 357,653,310,360,467,657,764,027,760,276,000,200,666,444,707,014 003,567,757,070,077,022,053,507,000,420,747,510,407,006,740,000 000,140,555,031,572,326,770,630,020,036,040,111,773,737,430,473
RP2C04-0002
MAME's source claims that Castlevania, Mach Rider (Endurance Course), Raid on Bungeling Bay, Slalom, Soccer, Stroke & Match Golf (both versions), and Wrecking Crew require this palette.
000,750,430,572,473,737,044,567,700,407,773,747,777,637,467,040 020,357,510,666,053,360,200,447,222,707,003,276,657,320,000,326 403,764,740,757,036,310,555,006,507,760,333,120,027,000,660,777 653,111,070,630,022,014,704,140,000,077,420,770,755,503,031,444
RP2C04-0003
MAME's source claims that Balloon Fight, Dr. Mario, Excitebike (US), Goonies, and Soccer require this palette.
507,737,473,555,040,777,567,120,014,000,764,320,704,666,653,467 447,044,503,027,140,430,630,053,333,326,000,006,700,510,747,755 637,020,003,770,111,750,740,777,360,403,357,707,036,444,000,310 077,200,572,757,420,070,660,222,031,000,657,773,407,276,760,022
RP2C04-0004
MAME's source claims that Clu Clu Land, Excitebike (Japan), Ice Climber (both versions), and Super Mario Bros. require this palette.
430,326,044,660,000,755,014,630,555,310,070,003,764,770,040,572 737,200,027,747,000,222,510,740,653,053,447,140,403,000,473,357 503,031,420,006,407,507,333,704,022,666,036,020,111,773,444,707 757,777,320,700,760,276,777,467,000,750,637,567,360,657,077,120
Backdrop color (palette index 0) uses
During forced blanking, when neither background nor sprites are enabled in PPUMASK ($2001), the picture will show the backdrop color. If only the background or sprites are disabled, or if the left 8 pixels are clipped off, the PPU continues its normal video memory access pattern but uses the backdrop color for anything disabled.
The background palette hack
If the current VRAM address points in the range $3F00-$3FFF during forced blanking, the color indicated by this palette location will be shown on screen instead of the backdrop color. (Looking at the relevant circuitry in Visual 2C02, this is an intentional feature of the PPU and not merely a side effect of how rendering works.) This can be used to display colors from the normally unused $3F04/$3F08/$3F0C palette locations. A loop that fills the palette will cause each color in turn to be shown on the screen, so to avoid horizontal rainbow bar glitches while loading the palette, wait for a real vertical blank first using an NMI technique.
Color names
When programmers and artists are communicating, it's often useful to have human-readable names for colors. Many graphic designers who have done web or game work will be familiar with HTML color names.
Luma
- $0F: Black
- $00: Dark gray
- $10: Light gray or silver
- $20: White
- $01-$0C: Dark colors, medium mixed with black
- $11-$1C: Medium colors, similar brightness to dark gray
- $21-$2C: Light colors, similar brightness to light gray
- $31-$3C: Pale colors, light mixed with white
Chroma
Names for hues:
- $x0: Gray
- $x2: Blue
- $x4: Magenta
- $x6: Red
- $x7: Orange
- $x8: Yellow or olive
- $xA: Green
- $xC: Cyan
RGBI
These NES colors approximate colors in 16-color RGBI palettes, such as the CGA, EGA, or classic Windows palette, though the NES doesn't really have a good yellow:
- $02: Navy
- $06: Maroon
- $12: Blue
- $14: Purple
- $16: Red
- $17: Brown
- $18: Olive
- $1A: Green
- $1C: Aqua
- $24: Fuchsia/Magenta
- $2A: Lime
- $2C: Teal
See also
- NTSC video - details of the NTSC signal generation and how it produces the palette
- PAL video
- PPU_palettes/zh - this page in Chinese