Tilemap Memory
5.1 Overview
The main rendering area on the Zeal Video Board is the tilemap. It's made up of two contiguous RAM blocks of 3,200 bytes each: layer0 and layer1.
- layer0 starts at offset
0x0000in video memory - layer1 starts at offset
0x1000
Given these offsets, toggling a single bit is enough to switch between the same tile position in either layer.
These layers divide the screen into an 80x40 grid of tiles. Each tile is represented by one byte, so each layer takes up exactly 80 x 40 = 3200 bytes.
Each byte points to a tile in either the Font Memory or the Tileset Memory.
The tile offset for a tile at position (x, y) is calculated as:
offset = y * 80 + x
This formula stays the same regardless of the current screen mode. So for example, in 320x240 resolution, the first character of the second line is still at offset 80.
The size of the tiles depends on the mode:
- Text mode: tiles are
8x12pixels - Graphics mode: tiles are
16x16pixels
layer0 is always the main drawing area (background).
layer1 can either act as a foreground layer (sits above layer0) or as an attribute layer (adds extra info to layer0 tiles), depending on the current mode.
⚠️ In firmware v0.1.0, both memories were read-only. It's recommended to upgrade to firmware v1.0.0 or later to get full read-write access.
5.2 Tile Rendering Basics
Let's assume we're in graphics mode (tiles are 16x16). The 640x480 screen is divided into a grid of 40x30 tiles. Each entry in the tilemap holds an 8-bit value.
To get the tile at row i, column j:
layer0[i * 80 + j]→ background tilelayer1[i * 80 + j]→ foreground tile
5.3 In Text Mode
In both 640x480 and 320x240 text modes, the layers act the same way: the layer0 is used to store the characters (tiles) to show on screen, taken from the Font Memory, while the layer1 describes the background and foreground colors to use for each character.
Each entry in the layer1 is a one byte value:
Each entry in layer1 is 1 byte:
- High nibble (bits 7-4): background color
- Low nibble (bits 3-0): foreground color
These are indexes from the first 16 entries of the Palette Memory.
Example
layer0[0] = 'H'; layer0[1] = 'e'; layer0[2] = 'l'; layer0[3] = 'l'; layer0[4] = 'o'; layer1[0] = 0xf1; // 0xf for background color, 0x1 for foreground color layer1[1] = 0xf2; // 0xf for background color, 0x2 for foreground color layer1[2] = 0xf3; // 0xf for background color, 0x3 for foreground color layer1[3] = 0xf4; // 0xf for background color, 0x4 for foreground color layer1[4] = 0xf5; // 0xf for background color, 0x5 for foreground color
The top left of the screen will look like the following. The red grid is only presented as a guide to show the 8x12 tiles.
The tilemap can scroll both horizontally and vertically (character granularity) using the SCROLL_X and SCROLL_Y registers:
- In 640x480: scroll wraps around the screen
- In 320x240: scroll can reveal hidden characters
5.4 In 8-bit Tiled Mode
In this mode, both layer0 and layer1 are used to render tiles on screen:
- layer0 is the background
- layer1 is the foreground
Similarly to sprites, layer1 supports transparency, any entry of value 0 in a tile will be considered transparent and will instead show the pixel underneath, from layer0. For more information about transparency, check Tileset Memory in 8-bit tiled mode
The tilemap represents an area of 80*16 x 40*16 = 1280 x 640px, which exceeds the visible resolution of the screen. In 640x480 mode, the viewport displays 40x30 tiles at a time. In 320x240 mode, only 20x15 tiles are visible, effectively providing a zoomed-in view of the same tilemap.
| Mode | Visible tiles |
|---|---|
| 640x480 | 40x30 |
| 320x240 | 20x15 (zoomed view) |
Scrolling can be used to adjust the visible portion of the tilemap, effectively shifting the viewport over a larger virtual area. Each layer supports independent scrolling along both X and Y axes, with pixel-level granularity. This allows fine control over which part of the tilemap is displayed on screen.
For details and register usage, refer to the Screen Scrolling section in Video Configuration chapter.
5.5 In 4-bit Tile Mode
In this mode, layer0 retains its role as the background tile layer. The tileset now supports up to 512 unique tiles, but since the tilemap entries are still 8-bit values, only 256 tiles can be directly addressed.
To overcome this limitation, layer1 is repurposed as an attribute layer rather than a second tile layer. It stores additional metadata associated with each tile in layer0.
Tile Data Encoding
For each tile at index n, the tile information is composed of:
layer0[n]: lower 8 bits of the tile index (0–255)layer1[n]: 8-bit attribute field- Bit 0 – Tile index MSB: adds the bit 8 (value
0x100)0: tile index =layer0[n]1: tile index =0x100 | layer0[n]
- Bit 1 – Reserved (unused)
- Bit 2 – Flip Y: vertically flips the tile if set
- Bit 3 – Flip X: horizontally flips the tile if set
- Bits 7–4 – Palette group (4-bit index): selects one of 16 palette base offsets
- Bit 0 – Tile index MSB: adds the bit 8 (value
Flip X and Y functionality is only available in this mode when rendering tilemaps.
Palette Behavior
In this mode, tiles use 4 bits per pixel (4bpp). Each pixel's color is calculated as:
color = (layer1[n] & 0xF0) | pixel_value
Where:
- The upper nibble of
layer1[n]selects the base palette (e.g.0x50) - The pixel value comes from the tile graphics data (tileset) in 4-bit format
Example
Suppose tile n contains the following 4 bytes (8 pixels):
0x12, 0x23, 0x34, 0x45
If layer1[n] has the upper 4 bits set to 0x5 (palette index), the final rendered colors for each pixel will be:
0x51 0x52 0x52 0x53 0x53 0x54 0x54 0x55
⚠️ Scrolling is not supported for layer1 in this mode, since attribute values are tightly coupled to the corresponding tiles in layer0. Any scroll-related registers applied to layer1 are ignored.
5.6 In Bitmap Modes
In both bitmap modes, the layer0 and layer1 are not used, they can be freely accessed by the host CPU.