SNES Development
Backgrounds

BG Modes

The SNES has 7 background modes, two of which have major variations. The modes are selected by bits 0-2 of register $2105. The variation of Mode 1 is selected by bit 3 of $2105, and the variation of Mode 7 is selected by bit 6 of $2133.

Mode    # Colors for BG
         1   2   3   4
======---=---=---=---=
0        4   4   4   4
1       16  16   4   -
2       16  16   -   -
3      256  16   -   -
4      256   4   -   -
5       16   4   -   -
6       16   -   -   -
7      256   -   -   -
7EXTBG 256 128   -   -

In all modes and for all BGs, color 0 in any palette is considered transparent.

Tile Maps & Character Maps

Each BG has two regions of VRAM associated with it: one for the tilemap, and one for the character data.

The tilemap address is selected by bits 2-7 of registers $2107-a, and the tilemap size is selected by bits 0-1 of that same register. All tilemaps are 32x32, bits 0-1 simply select the number of 32x32 tilemaps and how they’re laid out in memory:

00  32x32   AA
            AA
01  64x32   AB
            AB
10  32x64   AA
            BB
11  64x64   AB
            CD

Starting at the tilemap address, the first $800 bytes are for tilemap A. Then come the $800 bytes for B, then C then D. Of course, if only A is required something else could be stuck in the empty space. Each entry in the tilemap is 2 bytes, formatted as (high low):

vhopppcc cccccccc
v/h        = Vertical/Horizontal flip this tile.
o          = Tile priority.
ppp        = Tile palette. The number of entries in the palette depends on the Mode and the BG.
cccccccccc = Tile number.

To find the tilemap word address for a particular tile (X and Y), you’d use a formula something like this:

(Addr<<9) + ((Y&0x1f)<<5) + (X&0x1f) + (SY ? ((Y&0x20)<<(SX ? 6 : 5)) : 0) + (SX ? ((X&0x20)<<5) : 0)

The tile character data is stored at the address pointed to by registers $210b-c, starting at byte address:

(Base<<13) + (TileNumber * 8*NumBitplanes)

Each tile is (normally) 8x8 pixels. The data is stored in bitplanes. Each row of the tile fills 1 byte, with the leftmost pixel being in bit 7. For 4-color tiles, bitplanes 0 and 1 are stored in the low and high bytes of a word, with 8 words making up the tile. For a 16-color tile, bitplanes 0 and 1 are stored as for a 4-color tile, followed by bitplanes 2 and 3 in the same format. A 256-color tile is stored in the same way as 2 4-color tiles.

If the appropriate bit of $2105 is set, each "tile" of the tilemap actually corresponds to a 16x16 pixel block consisting of Tile, Tile+1, Tile+16, and Tile+17. In this case, the 32x32 tile tilemap codes for a 512x512 pixel screen rather than a 256x256 pixel screen as normal. Thus, using both 16x16 tiles and the 64x64 tilemap each BG can be up to 1024x1024 pixels. There is no wrapping like there is for 16x16 sprites: if you specify Tile=$2ff, you’ll get $2ff, $300, $30f, and $310 (as opposed to $2ff, $2f0, $20f, and $200 you might otherwise expect). $3ff goes to $000, of course. Flipping in this mode flips th whole 16x16 tile, not just the individual 8x8 tiles.

BG Scrolling

Of course, depending on the BG mode and the interlace setting, Modes 0-6 have an actual display of 256x224 or 256x239 pixels. The BG scroll registers $210d-$2114 control the offset of the displayed area within that possible 256x256 to 1024x1024 pixel BG.

The display can never fall outside the BG: if that would seem to be the case, simply wrap around back to 0 (or ‘tile’ the BG to fill the full 1024x1024, however you like to think of it).

The registers $210d-$2114 are all write-twice to set the 16-bit value. The way this works, the last write to any of these registers is stored in a buffer. When a new byte is written to any register, the current register value, the previous byte written to any of the 6 registers, and the new byte written are combined as follows:

For BGnHOFS: (NewByte<<8) | (PrevByte&~7) | ((CurrentValue>>8)&7)
For BGnVOFS: (NewByte<<8) | PrevByte

For the most part, the details don’t really matter as most games always write two bytes to one of these registers. However, some games write only one byte, or they do other odd things.

Thus, the tilemap entry for a particular X and Y position on the screen may be calculated as follows:

Size = 8 or 16 depending on the appropriate bit of $2105
TileX = (X + BGnHOFS)/Size
TileY = (Y + BGnVOFS)/Size
Look up the tile at TileX and TileY as described above.

Note that many games will set their vertical scroll values to -1 rather than 0. This is bacause the SNES loads OBJ data for each scanline during the previous scanline. The very first line, though, wouldn’t have any OBJ data loaded! So the SNES doesn’t actually output scanline 0, although it does everything to render it. These games want the first line of their tilemap to be the first line output, so they set their VOFS registers in this manner. Note that an interlace screen needs -2 rather than -1 to properly correct for the missing line 0 (and an emulator would need to add 2 instead of 1 to account for this).

Direct Color Mode

For the 256-color BGs of Modes 3, 4, and 7, $2130 bit 0 when set enables direct color mode. In this mode, instead of ignoring ppp and using the character data as the palette index, you treat the character data as expressing a color BBGGGRRR, and use the 3 bits of ppp as bgr to make the color

Red=RRRr0, Green=GGGg0, Blue=BBb00

In direct color mode you cannot have a black pixel, since any pixel with character data = 0 is still considered transparent. Use one of the almost-black colors instead (01, 08 or 09 are good choices).

Mode 0

In Mode 0, you have 4 BGs of 4 colors each. To calculate the starting palette entry for a particular tile, you calculate:

ppp*4 + (BG#-1)*32

The background priority is (from ‘front’ to ‘back’):

Sprites with priority 3
BG1 tiles with priority 1
BG2 tiles with priority 1
Sprites with priority 2
BG1 tiles with priority 0
BG2 tiles with priority 0
Sprites with priority 1
BG3 tiles with priority 1
BG4 tiles with priority 1
Sprites with priority 0
BG3 tiles with priority 0
BG4 tiles with priority 0

Mode 1

In Mode 1, you have 2 BGs of 16 colors and 1 BG of 4 colors. To calculate the starting palette entry, calculate:

ppp*ncolors

The background priority varies depending on the setting of bit 3 of $2105. The priority is (from ‘front’ to ‘back’):

BG3 tiles with priority 1 if bit 3 of $2105 is set
Sprites with priority 3
BG1 tiles with priority 1
BG2 tiles with priority 1
Sprites with priority 2
BG1 tiles with priority 0
BG2 tiles with priority 0
Sprites with priority 1
BG3 tiles with priority 1 if bit 3 of $2105 is clear
Sprites with priority 0
BG3 tiles with priority 0

Mode 2

In Mode 2, you have 2 BGs of 16 colors each. To calculate the starting palette index, calculate:

ppp*16

The priority is (from ‘front’ to ‘back’):

Sprites with priority 3
BG1 tiles with priority 1
Sprites with priority 2
BG2 tiles with priority 1
Sprites with priority 1
BG1 tiles with priority 0
Sprites with priority 0
BG2 tiles with priority 0

Note the change from Modes 0 and 1.

Mode 2 is the first of the Offset-Per-Tile Modes. In this mode, the ‘tile data’ for BG3 actually encodes a (possible) replacement HOffset and/or VOffset value for each tile of BG1 and/or BG2. Consider a visible scanline. Normally, you’d get the pixels something like this:

HOFS = X + BGnHOFS
VOFS = Y + BGnVOFS
Pixel[X,Y] = GetPixel(GetTile(BGn, HOFS, VOFS), HOFS, VOFS)

With offset-per-tile, the formula is a little more complicated:

HOFS = X + BGnHOFS
VOFS = Y + BGnVOFS
ValidBit = 0x2000 for BG1, or 0x4000 for BG2
if (!IsFirst8x8Tile(BGn, HOFS)) {
  /* Hopefully these calculations are right... */
  Hval = GetTile(BG3, (HOFS&7)|(((X-8)&~7)+(BG3HOFS&~7)), BG3VOFS)
  Vval = GetTile(BG3, (HOFS&7)|(((X-8)&~7)+(BG3HOFS&~7)), BG3VOFS + 8)
  if (Hval&ValidBit) HOFS = (HOFS&7) | ((X&~7) + (Hval&~7))
  if (Vval&ValidBit) VOFS = Y + Vval
}
Pixel[X,Y] = GetPixel(Get8x8Tile(BGn, HOFS, VOFS), HOFS, VOFS)

In other words, number the visible tiles in BGn from 0-32, and the ‘visible’ tiles in BG3 the same way. BGn tile 0 is offset as normal, then for 1<=T<33 BGn tile T gets the offset data from BG3 tile T-1. It doesn’t matter whether or not the tiles actually align in any way.

Note that the leftmost visible tile is done as normal in all cases (although as little as 1 pixel may be visible, and if that still bothers you then use a clip window to hide it), and the next tile uses the tilemap entry for what would be BG3’s leftmost tile. Note also that the ‘new’ offset completely overrides the BGnVOFS register, but the lower 3 bits of the BGnHOFS offset are still used. And note that the current Y position on the screen does not affect which row of the BG3 tilemap to reference, it’s as if Y were always 0.

On the other hand, note that even if BGn is 16x16 tiles, BG3 can specify the offset for each 8x8 subtile. And if BG3 is 16x16, the offsets will apply to all the corresponding 8x8 subtiles on BGn. Also note that if BG3 is 16x16, we may end up using the same tile for Hval and Vval.

Mode 3

In Mode 3, you have one 256-color BG and one 16-color BG. To calculate the starting palette index, calculate:

BG1: 0
BG2: ppp*16

The priority is (from ‘front’ to ‘back’):

Sprites with priority 3
BG1 tiles with priority 1
Sprites with priority 2
BG2 tiles with priority 1
Sprites with priority 1
BG1 tiles with priority 0
Sprites with priority 0
BG2 tiles with priority 0

Note that register $2130 may enable Direct Color Mode on BG1.

Mode 4

In Mode 4, you have one 256-color BG and one 4-color BG. To calculate the starting palette index, calculate:

BG1: 0
BG2: ppp*4

The priority is (from ‘front’ to ‘back’):

Sprites with priority 3
BG1 tiles with priority 1
Sprites with priority 2
BG2 tiles with priority 1
Sprites with priority 1
BG1 tiles with priority 0
Sprites with priority 0
BG2 tiles with priority 0

Note that register $2130 may enable Direct Color Mode on BG1.

Mode 4 is the second of the Offset-Per-Tile Modes. It operates much like Mode 2, however the SNES doesn’t have time to load two offset values. Instead, it does this:

Val = GetTile(BG3, ...)
if (Val&0x8000) {
  Hval = 0
  Vval = Val
} else {
  Hval = Val
  Vval = 0
}

Mode 5

In Mode 5, you have one 16-color BG and one 4-color BG. To calculate the starting palette index, calculate:

ppp*ncolors

The priority is (from ‘front’ to ‘back’):

Sprites with priority 3
BG1 tiles with priority 1
Sprites with priority 2
BG2 tiles with priority 1
Sprites with priority 1
BG1 tiles with priority 0
Sprites with priority 0
BG2 tiles with priority 0

Mode 5 is rather different from the previous modes. Instead of using an 8/16 pixel wide tile as normal, it always takes a 16 pixel wide tile (the height may still be 8 or 16) and only uses half the pixels (zero-based, the even pixels for subscreen tiles and the odd pixels for mainscreen tiles). Then it forces pseudo-hires on to render a 512-pixel wide scanline. Also, if Interlace mode is on (see bit 0 of $2133), the screen is 448 or 478 half-lines high instead of 224 or 239. Either the odd half-lines or the even half-lines are drawn each frame, as indicated by bit 7 of $213f. Note that this means you must set $212c and $212d to the same value to get the ‘expected’ display.

Mode 6

In Mode 6, you have only one 16-color BG. To calculate the starting palette index, calculate:

ppp*ncolors

The priority is (from ‘front’ to ‘back’):

Sprites with priority 3
BG1 tiles with priority 1
Sprites with priority 2
Sprites with priority 1
BG1 tiles with priority 0
Sprites with priority 0

Mode 6 has the same oddities as Mode 5. In addition, it is an offset per tile mode! That part works just like as Mode 2. However, remember that Mode 6 always uses 8 pixel (16 half-pixel) wide tiles, this applies to BG3 as well as BG1. You can’t apply the offset to an 8-half-pixel tile nor to a 16-pixel wide area (except by using two offset values for the two 8-pixel areas).

Mode 7

Mode 7 is extremely different from all the modes before. You have one BG of 256 colors. However, the tilemap and character map are laid out completely differently.

The tilemap and charactermap are interleaved, with the character data being in the high byte of each word and the tilemap data being in the low byte (note that in hardware, VRAM is set up such that odd bytes are in one RAM chip and even in another, and each RAM chip has a separate address bus. The Mode 7 renderer probably accesses the two chips independantly). The tilemap is 128x128 entries of one byte each, with that one byte being simply a character map index. The character data is stored packed pixel rather than bitplaned, with one pixel per byte. Thus, to calculate the tilemap entry byte address for an X and Y position in the playing field, you’d calculate:

(((Y&~7)<<4) + (X>>3))<<1

To find the byte address of the pixel, you’d calculate:

(((TileData<<6) + ((Y&7)<<3) + (X&7))<<1) + 1

Note that bits 4-7 of $2105 are ignored, as are $2107-$210c. They can be considered to be always 0.

The next odd thing about Mode 7 is that you have full matrix transformation abilities. With creative use of HDMA, you can even change the matrix per scanline. See registers $211b-$2120 for details on the matrix transformation formula. The entire screen can be flipped with bits 0-1 of $211a.

And finally, the playing field can actually be made larger than the tilemap. If bit 7 of $211a is set, bit 6 of $211a controls what is seen filling the space surrounding the map.

The background priorities are:

Sprites with priority 3
Sprites with priority 2
Sprites with priority 1
BG1
Sprites with priority 0

When bit 6 of $2133 is set, you get a related mode known as Mode 7 EXTBG. In this mode, you get a BG2 with 128 colors, which uses the same tilemap and character data as BG1 but interprets the high bit of the pixel as a priority bit. The priority map is:

Sprites with priority 3
Sprites with priority 2
BG2 pixels with priority 1
Sprites with priority 1
BG1
Sprites with priority 0
BG2 pixels with priority 0

Note that the BG1 pixels (if BG1 is enabled) will usually completely obscure the low-priority BG2 pixels.

BG2 uses the Mode 7 scrolling registers ($210d-e) rather than the ‘normal’ BG2 ones ($210f-10). Subscreen, pseudo-hires, math, and clip windows work as normal; keep in mind OBJ and that you can do things like enable BG1 on main and BG2 on sub if you so desire. Mosaic is somewhat weird, see the section on Mosaic below.

Note that BG1, being a 256-color BG, can do Direct Color mode (in this case, of course, there is no palette value so you’re limited to 256 colors instead of 2048). BG2 does not do direct color mode, since it is only 7-bit.

Rendering the Backgrounds

Rendering a BG is simple.

  1. Get your H and V offsets (either by reading the appropriate registers or by doing the offset-per-tile calculation).
  2. Use those to translate the screen X and Y into playing field X and Y (Note this is rather complicated for Mode 7)
  3. Look up the tilemap for those coordinates
  4. Use that to find the character data
  5. If necessary, de-bitplane it and stick it in a buffer.

See the section "Rendering the Screen" for more details.

Unresolved Issues

  1. What happens to the very first pixel on the scanline in Hires Math?
  2. Various registers still need to know when writing to them is effective.