Map decoding in President

From Pin Eight
Jump to: navigation, search

President's architecture is heavily inspired by that of Super Mario Bros. (SMB1).

President compared to SMB1

Like SMB1:

  • Map is composed of "objects".
  • Map is decoded to 8-bit metatile entries in a 2-screen-wide sliding window.
  • Layer of "clouds", or a repeating sequence of columns where each column has a 1x3-tile object at a given height.
  • Layer of "wall", or a 1x12-tile repeated object drawn on top of "clouds".
  • Division of metatile number space into four subspaces $00-$3F, $40-$7F, $80-$BF, $C0-$FF.
  • Subspace number, bits 7-6 of the metatile number, directly determines attribute value.
  • Four 64-entry metatile tables, one for each subspace.

Unlike SMB1:

  • The camera can move freely in the sliding window.
  • Each map has a 32-entry directory containing the length of each screen's data.
  • The decoder can operate on either side of the sliding window.
  • When a block is destroyed in one of the 512 columns of a map, it sets a bit in a destruction buffer.
  • A lookup table supports translating objects in a destroyed column into destroyed objects.
  • A Markov chain supports efficient decoding of objects taller than one block by treating empty metatiles (those with a value of $00) specially.
  • Clouds can be drawn in front of a wall, not just behind it. That's useful when using clouds to cut "windows" into a wall.
  • It's CHR RAM based; map types can replace tile data.
  • President is free software.

Decoding procedure

To decode column x of screen s

  1. Clear the column buffer
  2. If s > 0:
    • Seek to screen s - 1
    • x += 16
  3. Else:
    • Seek to screen s
  4. While x > 0:
    1. Draw all objects obj where obj.x <= x and obj.x + 16 >= x
    2. Seek to next screen
    3. x -= 16
  5. If this column's destroyed bit is set, apply destruction to column buffer
  6. Apply Markov chain from the top of the column buffer to the bottom
  7. Draw clouds into empty metatiles, if clouds in front are enabled
  8. Draw the wall into empty metatiles, if wall is enabled
  9. Draw clouds into empty metatiles, if clouds in back are enabled
  10. Draw column to nametable transfer buffer
  11. Copy column to sliding window buffer
  12. Wait for vertical blank
  13. Copy nametable transfer buffer to VRAM
  • CPU RAM 12 bytes: Column decoding buffer


Each screen's map data has a 32-entry table giving the length in bytes of each screen's map data. When the decoder seeks to the previous or next screen, it follows the chain of lengths when modifying curMapPageDataStart.


A cloud pattern has

  • Number of screens (1 byte), value = 1 to 4
  • Metatiles making up each of 16 1x3 patterns (48 bytes)
  • Column entries (16 to 64 bytes, 1 byte for each column)

Format of each column entry:

7654 3210
|||| ||||
|||| ++++- Pattern number
++++------ Height at which pattern is drawn


A "wall" is a horizontal strip of identical tiles placed behind empty metatiles. This can represent water, a long castle wall, etc. It is defined as a 1x12, 2x12, 4x12, or 8x12 tile repeating block.

Background objects

Most scenery in a level that the player can interact with is stored in a list of objects. Each level has a list of the lengths in bytes of each screen's data, consisting of the objects whose leftmost tile lies within that page.

7654 3210  Background object: first byte
|||| ||||
|||| ++++- Vertical position of object (0 to 11)
++++------ Horizontal position of object (0 to 15)

7654 3210  Background object: first byte
|||| ||||
|||| ||++- Argument; some uses this as a size argument (1, 2, 4, or 8 tiles)
++++-++--- Index into table of decoder procedures

The decoder for a background object is called with (x - o.x, y, obj), and it is responsible for overwriting metatiles in the column buffer.

A background object can never be wider than 16 tiles, because then it could sit across more than the two screens that the decoder considers.

Sliding window

There are two 192-byte buffers, each holding 16x12 bytes, where each byte controls what metatile is placed there. This is used for redrawing and collision. Columns of even screens go in buffer 0; columns of odd screens go in buffer 1.

  • CPU RAM $0600-$06BF: Even screen buffer
  • CPU RAM $0700-$07BF: Odd screen buffer


Between the two buffers of the sliding window is a destruction buffer organized as a 512-bit array. When a block is destroyed, the corresponding bit turns on.

The map decoder has a set of four 64-entry tables, one for each subspace, defining which tiles become which when destroyed. For example, if table[0][$19] = $8B, then all tiles of attribute 0 and value $19 become attribute 2 and value $0B in a destroyed column. This happens before Markov.

  • CPU RAM $06C0-$06FF: Destruction buffer


Each subspace has a table of up to 64 entries from each tile to the most common tile below it. For example, if table[0][$23] = $64, then the most common tile below a tile of attribute 0 and value $23 is attribute 1 and value $24. Empty metatiles are replaced with the most common tile below the tile above them.

Metatile to nametable

The top 2 bits of a metatile number are the subspace number, and each subspace is hardcoded to one of the four color sets. Each subspace has a set of four lookup tables of up to 64 entries, each entry being 4 bytes, from each tile to the top left, bottom left, top right, and bottom right nametable entries making up a metatile. Which table is used depends on the metatile's attribute number.


To be written.

  • CHR RAM $0000-$0FFF: Background tiles
  • CHR RAM $1000-$1FFF: Sprite tiles