ULAplus

ULAplus is a 64-colour palette for the Spectrum’s attribute display, added as a replacement ULA on the classic machines and built into the Next. Bizmuth provides it on the 48K, 128K, +2A, +3 and Next. This page follows the official specification, version 1.1d, published by ZX Design and Media at zxdesign.info, and states where the Next adds to it.

Ports

PortR/WBehaviour
$BF3BWregister select: bits[7:6] the group, bits[5:0] the sub-group
$FF3BRWdata for the selected register. A read returns the last value written to it

Group 00 is the palette: the sub-group is the palette entry, 0 to 63, and a write to $FF3B sets its colour. Group 01 is the mode: bit 0 of a write to $FF3B turns the palette on (1) or off (0). Groups 10 and 11 are reserved.

On the Next, both ports decode only while internal port enable bit 24 is set (see IO Ports), and turning the palette on through $FF3B also sets nextreg $68 bit 3. Under 48K or 128K timing both ports are contended; see Machine Timing.

Palette entries

A palette entry is one byte, GGGRRRBB: green in bits[7:5], red in bits[4:2] and blue in bits[1:0]. The third blue bit is the OR of the two stored: 00 becomes 000, and any other value xx1.

If the entry for INK 2 is to be bright red, then $1C (00011100) gives red 7, green 0 and blue 0.

Attribute mapping

With the palette on, the attribute byte selects colours from four 16-entry tables. Bits 7 and 6, FLASH and BRIGHT, pick the table, and FLASH no longer flashes.

ink entry   = (FLASH × 2 + BRIGHT) × 16 + INK
paper entry = (FLASH × 2 + BRIGHT) × 16 + PAPER + 8

An attribute of $47 (BRIGHT, PAPER 0, INK 7) shows entry 23 as ink and entry 24 as paper.

The border is the paper colour of the first table: BORDER 2 shows entry 10.

In Timex hi-res mode, bits[5:3] of port $FF choose the ink, paper and border entries from the second table:

Bits 5–3InkPaper and border
0002431
0012530
0102629
0112728
1002827
1012926
1103025
1113124

Reset

A reset turns the palette off and clears the selected register. The 64 palette entries keep their values.

Example

The routine sets all 64 entries from a table and turns the palette on. HL points at the last of 64 entry bytes, followed by a 1 written to the mode register.

set_palette:
        ld      c,$3B
        ld      de,$00BF        ; E = register port high byte
        ld      hl,pal_end
        ld      a,65
.loop:  dec     a
        ld      b,e
        out     (c),a           ; select register A
        ld      b,d
        outd                    ; B becomes $FF, then (HL) goes to $FF3B
        and     a
        jr      nz,.loop
        ret
palette:
        incbin  "palette.bin"   ; 64 GGGRRRBB entries
pal_end:
        db      1               ; register 64 is the mode group: palette on

OUTD decrements B before it writes, so loading B with 0 reaches port $FF3B. The loop writes register 64, the mode group, first and register 0 last, since OUTD counts HL down.

← Reference