Unlocking
Write $1C to VR57. Twice, consecutively. Register 57 is register 1 on a stock TMS9918A, which only looks at the low three bits of a register number. $1C written to register 1 means 4 KB of VRAM, display blanked, interrupts off, both mode bits set at once — an illegal combination that makes the chip useless. No working program would write it once, let alone twice in a row. Any other register write between the two cancels it. On a stock card those two writes land in register 1 and blank the screen. Set register 1 back to something sane immediately afterwards, whether or not the unlock took.
Writing a register. Value to $9C01, then the register number with bit 7 set. Registers 0–7 always; 8–63 only once unlocked.
Which card is this? Status register 1 reads $E0 on a real F18A and $E8 on a Pico9918. Select it with VR15, read $9C01, then put VR15 back to 0.
Bit order. D7 is the most significant bit here. Hagerty’s own documents number the most significant bit as 0, so his tables read mirrored against these.
Display modes
| Graphics I | M1 0 · M2 0 · M3 0 · M4 0 |
| Graphics II | M1 0 · M2 0 · M3 1 · M4 0 |
| Multicolor | M1 0 · M2 1 · M3 0 · M4 0 |
| Text, 40 column | M1 1 · M2 0 · M3 0 · M4 0 |
| Text, 80 column | M1 1 · M2 0 · M3 0 · M4 1 |
Registers 0–7 (always available)
VR0 $00 / ctrl $80 — Mode control 1
| D7-D5 | — | Reserved, write 0 |
| D4 | IE1 | Horizontal interrupt enable — pairs with register 19 (needs unlocking) |
| D3 | M5 | Extended row mode (Pico9918) |
| D2 | M4 | 80-column text mode (needs unlocking) |
| D1 | M3 | Graphics II mode |
| D0 | EVD | External video enable |
VR1 $01 / ctrl $81 — Mode control 2
| D7 | RAM | VRAM size — 0 = 4 KB, 1 = 16 KB |
| D6 | BL | Display — 0 = blanked, 1 = active |
| D5 | IE0 | Vertical interrupt enable |
| D4 | M1 | Text mode |
| D3 | M2 | Multicolor mode |
| D2 | — | Reserved, write 0 |
| D1 | SIZE | Sprite size — 0 = 8×8, 1 = 16×16 |
| D0 | MAG | Sprite magnification — 0 = 1×, 1 = 2× |
VR2 $02 / ctrl $82 — Name table base address
| D7-D4 | — | Reserved, write 0 |
| D3-D0 | A13-A10 | Name table base |
VR3 $03 / ctrl $83 — Color table base address
On a 64-byte boundary. Becomes the tile attribute table in the enhanced color modes.
VR4 $04 / ctrl $84 — Pattern generator base address
On a 2 KB boundary. Shared by both tile layers.
VR5 $05 / ctrl $85 — Sprite attribute table base address
On a 128-byte boundary. 32 sprites, four bytes each.
VR6 $06 / ctrl $86 — Sprite pattern generator base address
On a 2 KB boundary. 4 KB in 2-bit color, 6 KB in 3-bit color.
VR7 $07 / ctrl $87 — Foreground / background color
Text color in the high nibble, backdrop in the low nibble.
Registers 10–34 (unlocked only)
VR10 $0A / ctrl $8A — Name table 2 base address
| D7-D4 | — | Reserved, write 0 |
| D3-D0 | A13-A10 | Tile layer 2 name table base |
VR11 $0B / ctrl $8B — Color table 2 base address
Tile layer 2's color / attribute table, same format and same rules as register 3.
VR15 $0F / ctrl $8F — Status register select and counter control
| D7 | — | Reserved, write 0 |
| D6 | CNT_RST | Reset the counter |
| D5 | CNT_SNAP | Latch the counter so it can be read, without stopping it |
| D4 | CNT_START | 1 = run, 0 = stop |
| D3-D0 | SR_SEL | Status register 0-15 the next status read returns |
VR19 $13 / ctrl $93 — Horizontal interrupt scan line
Raise an interrupt when the beam reaches this line. 0 disables it.
VR24 $18 / ctrl $98 — Palette select
| D7-D6 | — | Reserved, write 0 |
| D5-D4 | SPS | Sprite palette select, 0-3 |
| D3-D2 | T2PS | Tile layer 2 palette select, 0-3 |
| D1-D0 | T1PS | Tile layer 1 palette select, 0-3 |
VR25 $19 / ctrl $99 — Tile layer 2 horizontal scroll
| D7-D3 | HTO | Horizontal tile offset, 0-31 |
| D2-D0 | HPO | Horizontal pixel offset, 0-7 |
VR26 $1A / ctrl $9A — Tile layer 2 vertical scroll
0-255 pixels, added straight to the Y position. Past the bottom of the display it wraps, or swaps page if vertical paging is on.
VR27 $1B / ctrl $9B — Tile layer 1 horizontal scroll
| D7-D3 | HTO | Horizontal tile offset, 0-31 |
| D2-D0 | HPO | Horizontal pixel offset, 0-7 |
VR28 $1C / ctrl $9C — Tile layer 1 vertical scroll
Same as register 26, for the main tile layer.
VR29 $1D / ctrl $9D — Page sizes and pattern plane spacing
| D7-D6 | SPGS | Sprite pattern plane spacing — 00 = 2 KB, 01 = 1 KB, 10 = 512 B, 11 = 256 B |
| D5 | HPSIZE2 | Tile layer 2 horizontal pages — 0 = one, 1 = two (64 tiles wide) |
| D4 | VPSIZE2 | Tile layer 2 vertical pages |
| D3-D2 | TPGS | Tile pattern plane spacing, same encoding as SPGS |
| D1 | HPSIZE1 | Tile layer 1 horizontal pages |
| D0 | VPSIZE1 | Tile layer 1 vertical pages |
VR30 $1E / ctrl $9E — Maximum sprites per scan line
| D7-D5 | — | Reserved, write 0 |
| D4-D0 | SPRTMAX | Sprites per scan line |
VR31 $1F / ctrl $9F — Bitmap layer control
| D7 | BML_EN | Enable the bitmap layer |
| D6 | BML_PRI | 0 = below the tile layers, 1 = above them |
| D5 | BML_TRANS | Treat pixel value 0 as transparent |
| D4 | BML_FAT | 0 = 1×1 pixels, four colors; 1 = 2×1 pixels, sixteen colors |
| D3-D0 | BML_PAL | Palette select — shifted up two bits and combined with the pixel value |
VR32 $20 / ctrl $A0 — Bitmap layer base address
Where the bitmap lives in VRAM. Address = VR32 << 6, so a 64-byte boundary.
VR33 $21 / ctrl $A1 — Bitmap layer X position
0-255. The bitmap moves independently of everything else, and scroll registers do not touch it.
VR34 $22 / ctrl $A2 — Bitmap layer Y position
The first scan line the bitmap is drawn on. Nothing above it.