Sprites Memory
7.1 Overview
The Zeal Video Board supports rendering up to 128 sprites simultaneously in tiled graphics mode.
Unlike tiles, which are fixed to the screen's tile grid, sprites can be positioned freely: they can be placed at pixel-level granularity and moved independently across the screen. Sprites are typically used to represent dynamic game elements such as characters, projectiles, or interactive UI elements.
All sprites use the same global tileset as the tilemap. There is no separate or dedicated sprite tileset; sprite graphics are sourced from the same tile memory region used by tilemap layers.
7.2 Sprite Layering
- In 8-bit tiled mode (8bpp): sprites are always rendered above the background layer (layer0). However, their position relative to the foreground layer (layer1) can be configured using the
BEHIND_FG flag. If this bit is set, the sprite will appear behind the foreground layer, otherwise, it will appear in front of it.
- In 4-bit tile mode (4bpp): since only a single tilemap layer (layer0) is used for background rendering, sprites are always rendered above it. The
BEHIND_FG bit is ignored in this mode. Additionally, like tilemap entries, sprites can access all 512 tile indices in the tileset by setting the extended TILE_BIT9 flag.
Regardless of the mode, the hardware renders sprites sequentially from sprite 0 to sprite 127. This means sprite 1 is drawn above sprite 0, but below sprite 2. To achieve proper visual stacking — such as creating a 3D perspective effect or the illusion of depth — it is recommended to assign sprite 0 to the background object, then use sprites 1, 2, 3, and so on for objects progressively closer to the viewer.
7.3 Organization
The sprites RAM is 1024 bytes in total, supporting up to 128 sprites, each defined by 8 bytes. Each sprite entry is organized as follows:
- Bytes 0-1 (16-bit, little-endian) — Y position of the sprite. The Y coordinate is offset by
-16 pixels. This means that a value of 16 places the sprite at the top of the screen. A value of 8 renders the sprite partially off-screen (half hidden), and a value of 0 makes it fully invisible.
- Bytes 2-3 (16-bit, little-endian) — X position of the sprite
Like the Y coordinate, this is also offset by
-16 pixels. Writing 0 results in the sprite being fully off-screen horizontally.
- Byte 4 — FLAGS register, encodes various sprite attributes such as, see the FLAGS section for all details.
- Byte 5 — TILE index
Specifies the lower 8 bits of the tile index. In 4-bit mode, the 9th bit must be set via the
TILE_BIT9 flag in the FLAGS byte.
- Byte 6 — OPTIONS
Used to configure the sprite’s height. If the
HEIGHT_32PX bit is set, the sprite becomes 32 pixels tall. In this case, the tile referenced by the TILE register and the next tile (TILE + 1) will be used together to render the full sprite.
- Byte 7 — Unused / Write Latch Flush
Although this byte is unused, it must be written to apply changes made to the
OPTIONS register. See the explanation below on latching behavior.
Sprite RAM Access and Latching
Internally, the sprite RAM is organized as 512 16-bit entries. As a result, all memory accesses are latched at the word level. The host CPU must always write the low byte (LSB) first, then the high byte (MSB).
Writing the high byte (MSB) without first writing the low byte (LSB) results in undefined behavior. The write may be ignored or result in incorrect data being latched.
However, when reading, bytes may be accessed in any order. This allows updating a single byte (e.g., the TILE index) without needing to cache or rewrite the other byte in the same word.
Example: Updating the TILE Index (Z80 Host)
For example, on a Z80-based host, updating the TILE index of a sprite can be done with:
; Assuming first 16KB of VRAM are mapped at 0x8000
; Sprite 3 begins at: 0x8000 + 0x2800 + 3 * 8 = 0xA818
; TILE offset = 0x4
ld hl, 0xA818 + 0x4 ; HL points to sprite 3's TILE register
ld (hl), 12 ; Set TILE to use tile index 12
; Flush the update by writing to the upper byte of the 16-bit word
inc hl
ld a, (hl)
ld (hl), a ; Write same value back to trigger latch
⚠️ Sprites are only active in tiled graphics modes. They are not rendered in text or bitmap modes, and they are not affected by screen scrolling.
Example: create and animate a sprite
Try the animated sprite example on Zeal 8-bit Playground!
7.4 Registers Summary
| Name |
Description |
Base-relative address |
Access |
| POS_Y_LOW |
Y Position LSB for the sprite |
0x00 |
R/W |
| POS_Y_HIGH |
Y Position MSB for the sprite |
0x01 |
R/W |
| POS_X_LOW |
X Position LSB for the sprite |
0x02 |
R/W |
| POS_X_HIGH |
X Position MSB for the sprite |
0x03 |
R/W |
| TILE |
Lower 8-bit index for the tile to use |
0x04 |
R/W |
| FLAGS |
Sprite's flags |
0x05 |
R/W |
| OPTIONS_LOW |
Options LSB for the sprite |
0x06 |
R/W |
| OPTIONS_HIGH |
Options HIGH for the sprite, must be written after LSB! |
0x07 |
WO |
7.5 Registers
POS_Y_LOW (0x00)
Y Position LSB for the sprite
Reset
POS_Y_LOW
LSB of sprite Y position minus 16. (R/W)
POS_Y_HIGH (0x01)
Y Position MSB for the sprite
Reset
POS_Y_HIGH
MSB of sprite Y position minus 16. Maximum value is 495. (R/W)
POS_X_LOW (0x02)
X Position LSB for the sprite
Reset
POS_X_LOW
LSB of sprite X position minus 16. (R/W)
POS_X_HIGH (0x03)
X Position MSB for the sprite
Reset
POS_X_HIGH
MSB of sprite X position minus 16. Maximum value is 655. (R/W)
TILE (0x04)
Lower 8-bit index for the tile to use
Reset
TILE_IDX
Index of the tile to use from the tileset. (R/W)
FLAGS (0x05)
Sprite's flags
Reset
PALETTE
Palette index to use in 4-bit mode. represents the uppe 4-bit of the colors to show the sprites with. (R/W)
FLIP_X
Flip the sprite on the X axis. (R/W)
FLIP_Y
Flip the sprite on the Y axis. (R/W)
BEHIND_FG
When set, renders the sprite behind the foreground, ignored in 4-bit mode. (R/W)
TILE_BIT9
9th bit of the tile index, ignored in 8-bit mode. (R/W)
OPTIONS_LOW (0x06)
Options LSB for the sprite
Reset
HEIGHT_32PX
Set the sprite height to 32px, two consecutive tiles will be used for the rendering. (R/W)
OPTIONS_HIGH (0x07)
Options HIGH for the sprite, must be written after LSB!
Reset
FLUSH
Empty area, must be written ater writing `OPTIONS_LOW` to flush the value. (WO)