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.