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 <http://sites.google.com/site/ulaplus/>).

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 <background> <foreground>



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 <jce@seasip.demon.co.uk>



    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.



