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
| Port | R/W | Behaviour |
|---|---|---|
$BF3B | W | register select: bits[7:6] the group, bits[5:0] the sub-group |
$FF3B | RW | data 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 + 8An 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–3 | Ink | Paper and border |
|---|---|---|
000 | 24 | 31 |
001 | 25 | 30 |
010 | 26 | 29 |
011 | 27 | 28 |
100 | 28 | 27 |
101 | 29 | 26 |
110 | 30 | 25 |
111 | 31 | 24 |
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 onOUTD 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.