Skip to content

PICO9918 Programmers Reference

visrealm edited this page Apr 9, 2026 · 9 revisions

PICO9918 Programmer's Reference

This page documents programming features that are specific to the PICO9918 and are not present on the original F18A hardware. All features on this page require the F18A unlock sequence to be active.

For the full F18A-compatible register set, see F18A Programmers Reference.

Extended Row Modes (PICO9918)

The PICO9918 extends the F18A's row-30 mode with additional row counts, allowing 48-row and 60-row displays.

Row 30 (F18A Standard)

Set R49 bit 6 (ROW30) to enable 30-row mode (240 active lines). The sprite Y terminator changes from 0xD0 (208) to 0xF0 (240).

Row 48 and Row 60 (PICO9918)

These extended modes use R0 bit 3 (IE1) together with R49 bit 6 (ROW30) to select the row count:

R0 bit 3 (IE1) R49 bit 6 (ROW30) Rows Active Lines Vertical Scaling
0 0 24 192 2x
0 1 30 240 2x
1 0 48 384 1x (no doubling)
1 1 60 480 1x (no doubling)

In 48-row and 60-row modes, vertical scaling is disabled — each scanline is rendered once, not doubled. This gives access to the full 480 lines of the VGA output.

Note: In 48 and 60-row modes, R0 bit 3 is repurposed for row selection and is not available as a horizontal interrupt enable.

Opaque Sprites (PICO9918)

In standard TMS9918A and F18A sprite rendering, color 0 pixels within a sprite pattern are transparent. The PICO9918 adds an opaque sprite flag that causes color 0 pixels to be rendered using palette entry 0 instead.

The opaque flag is bit 4 of sprite attribute byte 3 (the color byte), and only applies in 16x16 sprite mode:

Bit Description
7 Early clock (EC)
6 Flip X
5 Flip Y
4 Opaque (PICO9918, 16x16 mode only)
3-0 Color / ECM palette select

When set, transparent pixels within the sprite are drawn as the background color from palette entry 0, making the sprite fully opaque.

Configuration Registers (PICO9918)

The PICO9918 exposes its configuration settings through two F18A extended registers (R58 and R59) and a status register (SR12), allowing software to read and modify configuration at runtime.

Register 58 (0x3A) - Configuration Option Index

Writing to R58 selects which configuration option to access. The current value of the selected option is immediately available in status register 12.

Register 59 (0x3B) - Configuration Option Value

Writing to R59 sets the value of the configuration option currently selected by R58. Only writable for option indices >= 8 (hardware info options 0-6 are read-only).

Status Register 12 - Configuration Mirror

Returns the current value of the configuration option selected by R58. Updated whenever R58 or R59 is written.

Configuration Option Map

Read-only hardware info (indices 0-6):

Index Name Values
0 Pico model 1 = RP2040, 2 = RP2350
1 Hardware version 0x03 = V0.3, 0x10 = V1.0+, 0x20 = V2.0+
2 Firmware version (major.minor) Upper nibble = major, lower = minor
3 Firmware patch version Patch number
4 Last tested clock preset 0-2
5 Display driver 0 = VGA, 1 = NTSC SCART, 2 = PAL SCART
6 Flash status Reserved

User-configurable (indices 8+):

Index Name Range Default
8 CRT scanlines 0-1 0 (off)
9 Scanline sprite limit 0-3 0 (no limit)
10 Clock preset 0-2 0 (252 MHz)
16 Diagnostic overlays master 0-1 0 (off)
17 Diagnostic overlay: registers 0-1 0
18 Diagnostic overlay: performance 0-1 0
19 Diagnostic overlay: palette 0-1 0
20 Diagnostic overlay: address 0-1 0
128-159 Palette entries 0-15 16 x 2 bytes Default TMS9918A palette
255 Save to flash Write 1 to trigger 0

Save / Load Mechanism

Configuration changes made via R59 take effect immediately but are not automatically persisted to flash. To save the current configuration permanently:

  1. Select option index 255 by writing 0xFF to R58
  2. Write 0x01 to R59 to trigger a flash save

The configuration is stored at the top of flash memory (address 0x1FF000) and survives firmware updates.

To read a configuration value:

  1. Write the option index to R58
  2. Read status register 12 (select SR12 via R15, then read the status port)

Example: Toggle CRT Scanlines

; Assumes F18A is unlocked

; Read current scanline setting
write 0x08 to R58          ; select option 8 (CRT scanlines)
write 0x0C to R15          ; select status register 12
value = read status port   ; current value (0 or 1)
write 0x00 to R15          ; restore S0 selection

; Toggle and write back
new_value = value XOR 1
write 0x08 to R58          ; select option 8
write new_value to R59     ; apply new value

; Save to flash
write 0xFF to R58          ; select option 255 (save trigger)
write 0x01 to R59          ; trigger flash save

Firmware Update via VDP (PICO9918)

The PICO9918 supports firmware updates through the VDP register interface, used by the Configurator on platforms with ROM banking support.

Register 63 (0x3F) - Firmware Update Control

Bit Description
7 Execute firmware update operation
6 Operation type (0 = verify, 1 = write)
5-0 Address for 256-byte page access

Writing to R63 reads one UF2 frame (512 bytes) from the data previously written to VRAM. The operation will not execute if the GPU is currently running.

Status Register 2 - Flash Operation Status

During firmware operations, SR2 reports progress:

Bits Field Values
7 Running Operation in progress
6-5 Retry count 0-3
4-2 Error code 0=OK, 1=Header, 2=Sequence, 3=Size, 4=Verify, 5=Busy
1-0 Status 0=Idle, 1=Validating, 2=Erasing, 3=Writing

Status Register 13 - Temperature (PICO9918)

Contains the RP2040/RP2350 core temperature encoded as (tempC * 4 + 0.5) as a uint8_t. Updated every 64 frames.

To decode: tempC = value / 4.0

Extended GPU RAM (PICO9918)

On the original F18A, the GPU address space has defined regions with gaps between them. On the PICO9918, the full 64KB address space is backed by RAM, making the gaps usable as additional GPU RAM:

Address Range Size Contents
0x6040-0x6FFF ~4 KB GRAM2
0x7002-0xAFFF ~16 KB GRAM3
0xB010-0xFFFF ~20 KB GRAM4

See F18A Programmers Reference#Memory Map (F18A Mode) for the full address space layout.

Clone this wiki locally