ULA256 and PAL256 John Elliott, 7 November 2009
=============================================================================
ULA256 and PAL256 are utilities for Spectrum +3 CP/M to support the
256-colour ULA extension (see ).
At the time of writing, this feature is only available on +3 emulators.
Installation
~~~~~~~~~~~~
Copy ULA256.FID and PAL256.COM to a Spectrum +3 CP/M start-of-day disc and
boot from it. If all went well, you should see the sign-on message:
ULA256 v1.00 installed.
and, if you have a 256-colour ULA, the screen will go a slightly darker
blue. Be warned that if you _don't_ have a 256-color ULA, then installing
ULA256 will make colour selections behave very oddly.
In use
~~~~~~
All CP/M colour functions (PALETTE.COM, escape codes, and the TE_SET_INK
and TE_SET_BORDER system calls) will now use a 6-bit colour range, the
maximum that CP/M supports. So, whereas on an unexpanded Spectrum +3 the
commands
PALETTE 1 63 (bright white on dark blue)
PALETTE 2 63 (bright white on medium blue)
would both map to the same grey-on-blue scheme, on an expanded Spectrum with
ULA256, they would be visibly different -- and the white would be bright.
Colour reuse
~~~~~~~~~~~~
The 256-colour ULA has a limited palette; it can only display up to 64
unique colours on screen at any one time, 32 ink and 32 paper. ULA256
reserves one of the paper colours for the border. Moreover, in any character
square the ink and paper colours have to come from the same quarter of the
palette.
What this means in practice is that when ULA256 is asked to change to a new
colour scheme, an existing palette entry may have to be reused. ULA256 tries
to find one which is used in as few places as possible, but inevitably some
parts of the screen will be affected. The following Mallard BASIC program
demonstrates the effect:
10 WIDTH 255 'Stop BASIC trying to wrap lines
20 PRINT CHR$(27)"30" 'Select 24x32 mode
30 FOR n=0 TO 63 'Try to print with all 63 backgrounds
40 PRINT CHR$(27)"c"CHR$(32+n)"*"; 'Draw a star with colour n
50 i$=INPUT$(1) 'Wait for a keypress
60 NEXT 'Repeat
70 PRINT CHR$(27)"c"CHR$(34) 'Switch back to blue background
When run, the program will draw two rows of stars. When it begins the
second row, there will be no available slots in the palette, and it will
start to reuse slots. You will see already-drawn stars changing colour as
this happens.
PAL256
~~~~~~
CP/M uses 6-bit truecolour, whereas the ULA256 extension uses 8-bit. To
get the full colour range, you can use PAL256. The syntax is the same as
PALETTE:
PAL256
except that the background and foreground are 8-bit truecolour numbers,
not 6-bit.
Technical Details
~~~~~~~~~~~~~~~~~
ULA256 can be called from your code to manipulate the palette; this is what
PAL256 does, for example. To locate it, call FIND_FID:
ld de, fidname ;Must be above 0C000h
call userf
defw 00ECh ;FIND_FID
fidname:
defb 'ULA256 '
If FIND_FID returned with Carry set, then HL is the address of ULA256.FID
in bank 0. The following addresses within ULA256.FID may be of use:
FID + 20h: Palette. In-memory copy of the 64 palette registers, in the
same order as they are written.
FID + 60h: Update a single palette entry. E=entry, 0-63; A=ink, 0-255.
Corrupts BC D HL. Preserves E, A.
FID + 63h: Write all 64 values at FID + 20h to the ULA.
Corrupts AF BC DE HL.
FID + 66h: Truecolour version of TE_SET_INK. Parameters as for
TE_SET_INK, except colours are 8-bit truecolour:
A = ink number, 0 for background, 1 for foreground
B = colour, 0-255
C = flash colour (ignored)
Corrupts AF BC DE HL.
FID + 69h: Truecolour version of TE_SET_BORDER. Parameters as for
TE_SET_BORDER, except colours are 8-bit truecolour:
B = colour, 0-255
For example, to set the border using an 8-bit colour, you could use:
ld de, fidname ;Must be above 0C000h
call userf
defw 00ECh ;FIND_FID
jp nc, error
ld de, 69h
add hl, de ;HL -> border setting
ld (setbdr), hl
ld b, 0A0h ;Chosen colour
call userf
setbdr: defw 0
;
; As before, fidname is above 0C000h
;
fidname:
defb 'ULA256 '
Implementation
~~~~~~~~~~~~~~
ULA256 directly hooks into the following functions in the +3 CP/M screen
driver code:
* At 0EDBh, the function that resets screen attributes when TE RESET is
called.
* At 0EE7h, the function that is called when the foreground or background
colour is changed and calculates Spectrum attributes. This is called
internally by TE SET INK and the terminal emulator's escape code handler.
* At 0F2Ah, the function that is called when the border colour is set. This
is called internally by TE SET BORDER and the terminal emulator.
It also fixes a bug which appears to be present in all versions of Amstrad
CP/M, that stops TE SET INK working for inks 0 and 1.
Copying
~~~~~~~
Copyright (C) 2009 John Elliott
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.