SNES PPU for NES developers
The SNES PPU and NES PPU use every similar concepts for displaying graphics. This article will summarize some important differences and similarities, and lay out some basics before you learn about things more in-depth.
Video RAM is 64KB and contained within the console. Additional video memory cannot be added via cartridge. VRAM contains the tilemaps used for backgrounds as well as the graphics data for background tiles and sprite tiles. You can decide how much VRAM to dedicate to each use, and there are registers that set the base address for different things.
Like the NES, VRAM is accessed by setting an address via registers, and then writing the data you want to store to other registers, with the address automatically increasing after each write. Unlike the NES, the VRAM address is spread across two registers, and VRAM is 16-bit, so the VRAM data is also spread across two registers (for accessing the low and high byte at each VRAM address). This means that you're writing addresses between $0000-$7FFF instead of $0000-$FFFF like you might expect.
The palette consists of 256 RGB colors, with 5 bits used for the red, green and blue values of each color. You can choose to think of it as 8 background palettes and 8 sprite palettes, each with 15 colors plus a "transparency" color, though different Background modes can change the specifics.
VRAM and CGRAM are accessed with different registers. Colors in the palette are RGB values (with 5 bits per color channel).
DMA is much more flexible than it is on the NES. You can configure the SNES's DMA unit to write to any PPU register, as well as to other registers in the same address range as them. As a result, DMA can transfer data directly from the cartridge (or CPU RAM) into VRAM, CGRAM, OAM, or into CPU RAM.
DMA can work in reverse (copy from VRAM into CPU RAM) as well as do fills. It cannot, however, copy from one section of CPU RAM to another. For that, you can use the new MVN or MVP instructions.
HDMA is a special case of DMA, in which a small amount of data is transferred at the end of a scanline, during HBlank. This makes raster effects much easier, as they no longer require precise timing. Instead, you choose a register and provide a table that lists both a series of values to write into that register, as well a series of scanline counts to wait before the next value is written.
There is still an interrupt that allows you to do things the old way, and you can specify a horizontal coordinate to trigger the interrupt at too.
There are a variety of Background modes that change how the background layers work. The most common (mode 1) provides two layers with 16 colors per tile, and a third layer with 4 colors per tile. The third layer may be given priority over everything else, which makes it useful as a HUD or status bar.
While the SNES produces a similar 240 line picture to the NES, by default it blanks the top and bottom 8 rows to increase vblank time. PPU register $2133 SETINI can be used to enable "overscan" to make it more like the NES' picture viewport.
The SNES always blanks the first scanline of BG rendering, so the 240 line mode is actually only 239 visible lines. The 224 line mode similarly starts rendering 1 "blank" scanline higher than might be expected. A Y scroll position of 0 will not show the top pixel row of the BG because of this blank first line, and in 224 line mode one extra (224th) line of BG will be seen at the bottom.
Positions given to the scroll registers are relative to the top left of the active picture (minus the blanked 1st line), so switching between 224 and 239 lines doesn't just crop the picture with letterboxing, but the 224 line version is also shifted 8 lines lower on the screen. On SNES mid-screen scroll changes are also still relative to the top left, unlike the NES.
SNES tilemaps consist of a series of 16-bit values, containing the palette, priority bit, horizontal/vertical flips, and a tile number. There is no separate attribute table, and a tilemap can access 1024 different tiles instead of only 256.
Tilemaps are 32x32 (instead of the NES's 32x30) and a background layer can decide to have a single tilemap, arrange two horizontally, arrange two vertically, or have a square of four different tilemaps. A background layer can also choose to have 16x16 tiles instead of 8x8.
Sprite limits are much higher. There are 128 sprites, and 32 can be on the same scanline before sprites start to disappear. There is additionally a limit of 34 sprite tiles per scanline.
Sprites can be several different sizes, e.g. 8x8, 16x16, 32x32, 64x64. You can pick two sprite sizes for the PPU to use at one time, and each individual sprite can pick one of those two sizes for itself. There is no 8x16 sprite size.
Sprite data is similar in structure to the NES (X, Y, tile, attributes) but in a different order, and with some additional properties:
- X has a 9th bit allowing a sprite to be placed partially off the left side.
- You have 8 15-color palettes to choose from. Sprite tiles are always 4bpp.
- Priority now has 4 values, allowing each sprite to be placed above, below, or between the various BG layers.
The sprite rendering layer is referred to as OBJ, though the sprite priority attribute potentially makes it work like several layers. Color math and windowing can apply to the OBJ layer in the same way as the BG layers.
Sprites are delayed vertically by 1 scanline, just as on NES, so scroll and sprite positions will work unmodified on SNES, though in the default 224 lines rendering mode, you may wish to move both the sprites and BG 8 lines higher. Unlike the NES, because the first active scanline is always hidden, sprites can appear on the first scanline of the visible picture. (See Background modes above.)