Every register
All of them, with their bits. The printable card is the same thing folded onto two sides of a sheet.
Bits are written D7 first, D7 being the most significant — the same way the rest of this site writes them, and the same way the Pico9918's own reference does. Matthew Hagerty's F18A documents number bits the other way around, with bit 0 as the most significant, so his tables read mirrored against these. The values are identical; only the labels are reversed.
How to write one
Two writes to $9C01: the value, then the register number with bit 7 set.
lda #$1C ; the value
sta $9C01
lda #$B9 ; register 57, with bit 7 set
sta $9C01The control byte column below is that second byte, worked out for you.
Registers 0–7 are always available. Everything else needs the card unlocked first, and is ignored until then — writes to it land in the register three bits down instead.
Registers 0 to 7
These exist on every TMS9918A. Two of them grew extra bits.
Register 0 $00 · control byte $80
Mode control 1
Mode bits, plus the horizontal interrupt enable.
| Bits | Name | What it does |
|---|---|---|
D7-D5 | — | Reserved, write 0 |
D4 | IE1 | Horizontal interrupt enable — pairs with register 19 — needs unlocking |
D3 | M5 | Extended row mode — Pico9918 only |
D2 | M4 | 80-column text mode — needs unlocking |
D1 | M3 | Graphics II mode |
D0 | EVD | External video enable |
Register 1 $01 · control byte $81
Mode control 2
VRAM size, display enable, vertical interrupt, mode bits, sprite size.
| Bits | Name | What it does |
|---|---|---|
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× |
Register 2 $02 · control byte $82
Name table base address
Tile layer 1 name table, on a 1 KB boundary. Address = (VR2 & $0F) << 10.
| Bits | Name | What it does |
|---|---|---|
D7-D4 | — | Reserved, write 0 |
D3-D0 | A13-A10 | Name table base |
- 768 bytes per page at 24 rows, 960 bytes at 30 rows.
- When paged scrolling is on, the extra pages are found by flipping bits in this address rather than by another register.
Register 3 $03 · control byte $83
Color table base address
On a 64-byte boundary. Becomes the tile attribute table in the enhanced color modes.
- 32 bytes in the original color mode.
- 256 bytes as a tile attribute table, one entry per pattern.
- 768 bytes to 4 KB in position-attribute mode, depending on page sizes.
Register 4 $04 · control byte $84
Pattern generator base address
On a 2 KB boundary. Shared by both tile layers.
- 2 KB for 256 patterns in the original color mode.
- 4 KB in 2-bit color, 6 KB in 3-bit color — the extra bitplanes follow the first.
Register 5 $05 · control byte $85
Sprite attribute table base address
On a 128-byte boundary. 32 sprites, four bytes each.
Register 6 $06 · control byte $86
Sprite pattern generator base address
On a 2 KB boundary. 4 KB in 2-bit color, 6 KB in 3-bit color.
Register 7 $07 · control byte $87
Foreground / background color
Text color in the high nibble, backdrop in the low nibble.
Choosing a display mode
The mode bits are spread across registers 0 and 1, which is a quirk of the original chip that F18A mode keeps.
| Mode | M1 | M2 | M3 | M4 |
|---|---|---|---|---|
| Graphics I | 0 | 0 | 0 | 0 |
| Graphics II | 0 | 0 | 1 | 0 |
| Multicolor | 0 | 1 | 0 | 0 |
| Text, 40 column | 1 | 0 | 0 | 0 |
| Text, 80 column | 1 | 0 | 0 | 1 |
Registers 8 to 63
Everything below needs the card unlocked.
Register 10 $0A · control byte $8A
Name table 2 base address
Tile layer 2's name table, same format as register 2.
| Bits | Name | What it does |
|---|---|---|
D7-D4 | — | Reserved, write 0 |
D3-D0 | A13-A10 | Tile layer 2 name table base |
The sources disagree. The forum documentation gives this register to a "fixed map" — a bitmap saying which tiles scroll — and describes it as 7 bits on a 128-byte boundary. The fixed map did not ship; the register became tile layer 2's name table.
Register 11 $0B · control byte $8B
Color table 2 base address
Tile layer 2's color / attribute table, same format and same rules as register 3.
Register 15 $0F · control byte $8F
Status register select and counter control
Picks which of the sixteen status registers the status port returns, and drives the on-card timer.
| Bits | Name | What it does |
|---|---|---|
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 |
- Selecting 0 gives the stock status byte, with the usual side effects: the interrupt flag clears, the collision and fifth-sprite bits reset, and palette write mode ends.
- Selecting anything else returns that register with none of those side effects — which is also the trap. Leave the selection pointing somewhere else and the machine's own interrupt handler reads the wrong byte and never acknowledges the interrupt.
Register 19 $13 · control byte $93
Horizontal interrupt scan line
Raise an interrupt when the beam reaches this line. 0 disables it.
- Register 0's IE1 bit must be set as well.
- There is only one interrupt line, so a handler has to work out which of the two fired by reading status register 1.
Register 24 $18 · control byte $98
Palette select
Which 16-color block of the 64 palette registers each layer draws from, in the lower color modes.
| Bits | Name | What it does |
|---|---|---|
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 |
- The selected value is shifted up four bits and combined with the color index to make the six-bit palette address.
- Unused for tiles and sprites in 2-bit color, where the pattern supplies those bits instead.
Register 25 $19 · control byte $99
Tile layer 2 horizontal scroll
Whole tiles in the high five bits, pixels within a tile in the low three.
| Bits | Name | What it does |
|---|---|---|
D7-D3 | HTO | Horizontal tile offset, 0-31 |
D2-D0 | HPO | Horizontal pixel offset, 0-7 |
Register 26 $1A · control byte $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.
Register 27 $1B · control byte $9B
Tile layer 1 horizontal scroll
Same format as register 25, for the main tile layer.
| Bits | Name | What it does |
|---|---|---|
D7-D3 | HTO | Horizontal tile offset, 0-31 |
D2-D0 | HPO | Horizontal pixel offset, 0-7 |
Register 28 $1C · control byte $9C
Tile layer 1 vertical scroll
Same as register 26, for the main tile layer.
Register 29 $1D · control byte $9D
Page sizes and pattern plane spacing
How wide and tall each tile layer's virtual screen is, and how far apart the extra color bitplanes sit.
| Bits | Name | What it does |
|---|---|---|
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 |
- Plane spacing is 0x800 >> the two-bit value.
- The page-size bits are what turn a scroll register from wrapping in place into scrolling onto new ground.
The sources disagree. The forum documentation puts the page-size bits in register 30 alongside a horizontal banner size, and uses register 29 for page-start bits. Neither arrangement shipped.
Register 30 $1E · control byte $9E
Maximum sprites per scan line
How many sprites the card will draw on one line before it gives up. The stock chip's answer is four.
| Bits | Name | What it does |
|---|---|---|
D7-D5 | — | Reserved, write 0 |
D4-D0 | SPRTMAX | Sprites per scan line |
- The Pico9918 defaults to 31. Writing 0 restores that default.
- On a real F18A, writing 0 restores whatever the card's jumper says.
Register 31 $1F · control byte $9F
Bitmap layer control
The whole of the bitmap layer's behavior in one byte.
| Bits | Name | What it does |
|---|---|---|
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 |
The sources disagree. The v1.8 sheet calls D6 priority over sprites, the v1.9 sheet calls it priority over tiles. The v1.9 reading is the one the layer-priority rules bear out: the bitmap layer is never drawn above a sprite.
Register 32 $20 · control byte $A0
Bitmap layer base address
Where the bitmap lives in VRAM. Address = VR32 << 6, so a 64-byte boundary.
Register 33 $21 · control byte $A1
Bitmap layer X position
0-255. The bitmap moves independently of everything else, and scroll registers do not touch it.
Register 34 $22 · control byte $A2
Bitmap layer Y position
The first scan line the bitmap is drawn on. Nothing above it.
Register 35 $23 · control byte $A3
Bitmap layer width
Width of one bitmap row, in bytes. Every byte is four pixels wide whichever pixel format is selected.
The sources disagree. The Pico9918 reference states the encoding as "0 = 64 bytes, otherwise VR35 >> 2". Hagerty's sheets call the register plain "bitmap width". Untested here either way.
Register 36 $24 · control byte $A4
Bitmap layer height
How many rows are drawn, starting from the row in register 34.
Register 47 $2F · control byte $AF
Palette control and data-port mode
Points the data port at palette memory instead of VRAM, and says which entry.
| Bits | Name | What it does |
|---|---|---|
D7 | DPM | Data port mode — 0 = writes go to VRAM, 1 = writes go to the palette |
D6 | AUTO | Step to the next palette entry after each complete entry |
D5-D0 | PAL_IDX | Palette entry, 0-63 |
- One entry is two writes to the data port.
- Without auto-increment, palette mode ends by itself after those two writes.
- With auto-increment it stays on until you clear it, or until the index rolls over past 63, or until any status register is read.
Register 48 $30 · control byte $B0
VRAM address increment
Signed byte added to the VRAM address after every read or write. Default 1.
- $FF steps backwards. 0 holds the address still. 2 and up skip — one write per pixel row, say, instead of one per byte.
Register 49 $31 · control byte $B1
Enhanced color modes and display options
Turns on tile layer 2, 30-row mode, and the enhanced color modes for tiles and sprites separately.
| Bits | Name | What it does |
|---|---|---|
D7 | T2_EN | Enable tile layer 2 |
D6 | ROW30 | 0 = 24 rows, 1 = 30 rows (240 lines) |
D5-D4 | ECMT | Tile color mode — 0 = original, 1 / 2 / 3 = one, two or three bits per pixel |
D3 | Y_REAL | Sprite Y is the real coordinate rather than the stock chip's off-by-one |
D2 | — | Reserved, write 0 |
D1-D0 | ECMS | Sprite color mode, same encoding as ECMT |
- D2 was a sprite-linking enable in v1.8, letting a sprite follow a parent sprite. It was dropped for v1.9 and is not in the Pico9918.
Register 50 $32 · control byte $B2
General control and GPU triggers
The odds and ends: reset, GPU triggers, layer disable, sprite reporting, scan lines, attribute mode, layer priority.
| Bits | Name | What it does |
|---|---|---|
D7 | VR_RST | Reset — relocks the card and restores register defaults; the palette survives |
D6 | GPU_HTRIG | Run the GPU at the start of every scan line |
D5 | GPU_VTRIG | Run the GPU once per frame |
D4 | TL1_OFF | Turn off tile layer 1 — sprites, the bitmap layer and tile layer 2 carry on |
D3 | RPT_MAX | 0 = report the fifth sprite the stock way, 1 = report against register 30's limit |
D2 | SCANLINES | Dim every other line for a CRT look |
D1 | POS_ATTR | 0 = attributes per pattern name, 1 = attributes per screen position |
D0 | T2_PRI | 0 = tile layer 2 always on top, 1 = tile layer 2 obeys per-tile priority |
- Writing $C0 resets the palette as well (Pico9918).
The sources disagree. The forum documentation uses registers 50-53 as scroll-limit registers defining a window that scrolling cannot leave. That design did not ship in this form.
Register 51 $33 · control byte $B3
Maximum sprites per frame
The highest sprite the card will process at all, 0-32. Default 32.
| Bits | Name | What it does |
|---|---|---|
D7-D6 | — | Reserved, write 0 |
D5-D0 | STOPSPRT | Sprites processed per frame |
- Independent of register 30, which is a per-line limit.
- It is also the only way to stop sprite processing early in 30-row mode, where the $D0 terminator is a legal Y coordinate.
Register 54 $36 · control byte $B6
GPU program counter, high byte
Default $40, which points at the GPU's own RAM.
Register 55 $37 · control byte $B7
GPU program counter, low byte
Writing this loads the program counter and starts the GPU running. It is the trigger, not just the low byte.
Register 56 $38 · control byte $B8
GPU control and status
Write 0 to load the program counter without running; write 1 to start. Reading it says whether the GPU is running.
| Bits | Name | What it does |
|---|---|---|
D7-D1 | — | Reserved, write 0 |
D0 | GPU OP | Write: 0 = reset and load the PC, 1 = run. Read: 1 = running |
Register 57 $39 · control byte $B9
Unlock
Write $1C twice in a row to unlock. Any write to it once unlocked locks it again.
Register 58 $3A · control byte $BAPico9918
Configuration option index
Selects a card configuration option. Writing it also mirrors that option's current value into status register 12.
- On a real F18A v1.8 this register was a GROM clock divider, which has nothing to do with the Pico9918's use of it.
Register 59 $3B · control byte $BBPico9918
Configuration option value
Writes the option selected by register 58. Options below index 8 are read-only hardware facts and refuse writes.
Register 63 $3F · control byte $BFPico9918
Firmware update control
How the card's own configuration tool updates its firmware through the video port.
| Bits | Name | What it does |
|---|---|---|
D7 | EXEC | Perform the operation |
D6 | OP | 0 = verify, 1 = write |
D5-D0 | PAGE | 256-byte page |
- Reads one 512-byte frame at a time, and refuses to run while the GPU is running.
Status registers
The card has one status port and sixteen things to say through it. Register 15 picks which.
Reading status register 0 has side effects — it clears the frame interrupt, the collision flag and the fifth-sprite flag, and it drops the data port out of palette mode. Reading any of the others has none of them.
Put register 15 back to 0 when you are done. The machine's interrupt handling reads this port, and anything but register 0 acknowledges nothing.
| Name | What it holds | |
|---|---|---|
| SR0 | Standard status | The stock TMS9918A status byte, and the only one a locked card will give you. |
| SR1 | Identity and horizontal interrupt | What the card is, and whether the horizontal interrupt fired. |
| SR2 | GPU status | D7 is set while the GPU is running. D6-D0 are seven bits the GPU program can set for the 6502 to read. |
| SR3 | Current scan line | Where the beam is. 0 outside the active display. |
| SR4 | Nanosecond counter, lowF18A only | 0-999. Not documented for the Pico9918. |
| SR5 | Nanosecond counter, highF18A only | The top two bits of the nanosecond count. |
| SR6 | Microsecond counter, low | 0-999. |
| SR7 | Microsecond counter, high | The top two bits. |
| SR8 | Millisecond counter, low | 0-999. |
| SR9 | Millisecond counter, high | The top two bits. |
| SR10 | Second counter, low | 0-65535. |
| SR11 | Second counter, high | The high byte of the second count. |
| SR12 | Configuration mirrorPico9918 | The value of whichever option register 58 last selected. |
| SR13 | TemperaturePico9918 | The Pico's core temperature, four counts per degree C. Updated every 64 frames. |
| SR14 | Version | Major and minor version, a nibble each. An ACE reads $1A. |
| SR15 | Select mirror | Reads back the status register selection written to register 15. |
SR0 — Standard status
| Bits | Name | What it does |
|---|---|---|
D7 | INT | Vertical interrupt — cleared by this read |
D6 | 5S | Too many sprites on a line |
D5 | C | Sprites collided |
D4-D0 | NUM | Which sprite |
- Reading it clears the interrupt flag, resets the collision and fifth-sprite bits, and ends palette write mode.
SR1 — Identity and horizontal interrupt
| Bits | Name | What it does |
|---|---|---|
D7-D5 | ID | 111 = F18A |
D4 | — | Reserved |
D3 | EMU | 1 = an F18A personality rather than F18A silicon |
D2 | — | Reserved |
D1 | BLANK | In a blanking period right now |
D0 | HF | Horizontal interrupt fired — stays set until this register is read |
Attribute bytes
The fourth byte of a sprite, and the color table entry of a tile, both change meaning once the card is unlocked.
Sprite attribute byte, card locked
| Bits | Name | What it does |
|---|---|---|
D7 | EC | Early clock — shift the sprite 32 pixels left |
D6-D4 | — | Unused on a stock chip |
D3-D0 | COLOR | One of sixteen colors |
Sprite attribute byte, card unlocked
| Bits | Name | What it does |
|---|---|---|
D7 | EC | Early clock, unchanged |
D6 | FLIP X | Mirror the sprite horizontally |
D5 | FLIP Y | Mirror it vertically |
D4 | SIZE | Per-sprite size — 0 takes register 1's global setting, 1 forces 16×16 |
D3-D0 | PS | Color, or palette select in the enhanced color modes |
The sources disagree. The Pico9918 reference calls D4 an opaque-sprite flag in 16×16 mode rather than a size override. Both documents agree the bit is new and that it concerns 16×16 sprites; they do not agree on what it does.
Tile attribute byte, enhanced color modes
In the enhanced color modes the color table stops being a color table. Each entry becomes an attribute byte for one pattern — or for one screen position, with position attributes on.
| Bits | Name | What it does |
|---|---|---|
D7 | PRI | This tile draws over sprites |
D6 | FLIP X | Mirror the tile horizontally |
D5 | FLIP Y | Mirror it vertically |
D4 | TRANS | Color index 0 is transparent rather than a color |
D3-D0 | PS | Palette select |
Attribute byte in 40- and 80-column text, position attributes on
| Bits | Name | What it does |
|---|---|---|
D7-D4 | FG | Foreground color for this cell |
D3-D0 | BG | Background color for this cell |

