A UK TV comprises 625 scan lines displayed every fiftieth
of a second. To produce a stable picture, the ULA must generate
the synchronising signals that mark the beginning of every
line and frame and it must retrieve the video RAM in time
for it to be displayed. This means instant access to video
RAM. Unfortunately the CPU also needs access to the video
RAM in order for it to be changed. This is achieved by sharing
buses. Making the ULA wait would result in 'snow' (which is
what happens to other machines of this era).
The Spectrum uses a system of parallel attributes to obtain
an eight-colour display using not much more memory than is
required for a black and white display. The display is maintained
by the ULA which displays the information stored in a fixed
area of memory - the video memory - to produce a fixed format
(256 dots by 192 dots - or 32 characters per line for 24 rows).
Unfortunately the ULA is not programmable to display different
display modes, which could have been handy nowadays :)
The video RAM is always the first 6912 bytes in the lower
16K of RAM. While a TV picture is being displayed this area
is accessed by the ULA to display the next frame.
However, if the CPU were not allowed to use the video RAM
when in use by the ULA, it would not be allowed to use any
other RAM or ROM in the system because the address and data
buses would be in use by the ULA. Resulting in a very slow
This means that the ULA can use the lower 16K of RAM while
the CPU can simultaneously use all other memory above this.
If the CPU wants access to the lower 16K the ULA stops the
CPU until it is ready to yield control. For this reason code
requiring exact timing should be placed above the first 16K
An interesting fact of the genius of the Spectrum design
is that this video access is not controlled by a simple set
of resisters rather than multiplexing chips. When the CPU
is using memory above 16K the two buses work independently,
with the signals on one bus appearing at a much reduced level
on the other because of the voltage dropping action of the
resisters. However, when the ULA allows the CPU to access
its address space it stops 'driving' the buses and the voltage
drop is less, so the CPU's signals gain control.
Video Output Circuit
The ULA is responsible for taking data from the video RAM
and constructing the colour information as three video signals
- Y (luminance and synchronisation), U (blue-green), V (red-yellow).
The task of taking these three video signals and producing
a single PAL (UK) colour signal is the responsibility of a
LMI889N PAL encoder chip.
The PAL encoder takes the U and V signals and generates a
chroma (colour) signal that is mixed with the Y signal by
a two-transistor mixer to produce the final PAL video signal,
which is fed to the UHF modulator.
Colour and quality of the display can be adjusted by changing
the variable capacitor and resistors positioned in a line
on the left hand side of the printed circuit board. Adjusting
TC1 (video clock) improves sharpness by removing interference
patterns; Adjusting VR1 (colour balance red-yellow) and VR2
(colour balance blue-yellow) adjust the colour balance of
the display. TC2 (CPU clock) adjusts the frequency of the
CPU and should not be altered. The U, V and Y and the composite
colour video signals are available at the rear edge connector
and can be used to drive a colour monitor.
The video display is colour but takes little more memory
than a black and white display. This is achieved because of
the use of parallel attributes to control pixels and colour.
Normally a display encodes each pixel with a colour and stores
is at one memory location. For example, if this was the case
for the Spectrum, each pixel would require one bit for the
pixel and 4 bits for the colour, requiring about 30k. The
spectrum does not encode the colour with the pixel and so
the display requires 6k for the black and white pixels. The
video memory for the pixels are stored at the beginning of
RAM in locations 16384 to 22527. The colour attributes are
stored in locations 22528 to 23295. Each location represents
one whole character, rather than a pixel. This means that
the storage requirements for the colour display are 6192 bytes
plus 768 bytes (about 7k).
The drawback of this, as can be seen when playing games,
is that only two colours are allowed per 8x8 pixel block (1
character) - the foreground and the background.
The most obvious way of storing the pixel display would be
for the first 256 locations to represent the 256 pixels that
represent the first row, the next 256 locations to represent
the 256 pixels of the second row, and so on.
This is not the case for the spectrum. Each row of 256 pixels
is stored like this in contiguous memory locations but the
order of storage reflects the 24 lines of characters, i.e.
after the top row of pixels comes the top row pixels for the
second line of characters (i.e. 8 rows down) and so on for
the first eight rows. This means that the first third of video
memory represents the top third of the display, the middle
third of video memory represents the middle third of the display
and the last third of video memory represents the bottom third
of the display - with each block of 256 locations/pixels representing
alternate rows. This is the reason why a screen for a loading
game is displayed the way it is. The following program shows
10 FOR I=16384 TO 22527
20 POKE I,255
30 NEXT I
If L and C represented a character location (line and column),
and R represented a particular row within this character (1
to 8), the following code would return its starting address
Thus POKE FNm(10,12,3),255 would set row 3 of location 10,12.
The attributes are stored contiguously, i.e. 22527 is the
first character, 22528 is the second and 23295 is the last
character of the last row, thus DEF Fna(C,L)=22528+32*L+C
returns the location of location L,C.
Each attribute requires 1 byte of information that contains
the following bit-pattern:
Bits 0,1,2 represent ink (pixel) and the colours 0 to 7.
Bits 3,4,5 represent paper (the background - where there are
no pixels) and the colours 0 to 7
Bit 6 represents whether it is bright (1)
Bit 7 represents whether it is flashing (1)
Thus 128*f+64*b+8*paper+ink is the formula to set the attribute
The Spectrum contains two character tables that are used
to hold the dot patterns of the various printable characters
and are held mostly in ROM. However, the system variable CHARS
holds the address of the start of the character table and
so it is possible to change this by poking it with a new address.
The system variable UDG holds the start address of the alternate
character set which can be used to display a new character
The system variables are:
23677: CO ORDS (2 bytes) - represents the x/y co-ordinates
of the last plotted point. Can be used to draw lines, etc.
23688: S POSN (2 bytes) - represents the current text cursor
23684: DF CC (2 bytes) - represents the location within the
video display of S POSN
23692: SCR CT - holds a countdown to the next "Scroll?"
display message. Poking repeatedly with 255 will stop the
message from appearing.
23693: ATTR P - holds the value of the permanent attribute
code - i.e. the default paper colour
23695: ATTR T - as ATTR T for temporary attribute code - i.e.
for the duration of the current PRINT statement.
23694/23696: MASK P and MASK T hold the permanent/temporary
(as above) mask codes for transparency.
23624: BORDCR - sets the attribute code of the lower half
of the screen.
In ZX BASIC, the parameter of the USR function is normally
the address of a machine code program, however when the parameter
is a string, it is used to define the memory location of the
value within the character table, thus PRINT USR "A"
returns the address in memory address of 'A' (CHARS + n),
and POKE USR "A"+n,bitpattern with change row n
of character "A" to bit-pattern.
The following code will move the character table to memory
and invert it:
10 CLEAR 65536-1024 ;reserve 1k of memory
20 LET A=256+PEEK 23606+256*PEEK 23607 ;start of character
30 LET B=65536-1024+1 ;start of reserved memory
40 FOR I=0 TO 95 ;the printable characters
50 FOR J=0 TO 7 ;8 rows of each letter
60 LET D=PEEK(A+I*8+J) ;bit-pattern of row of character
70 POKE B+I*8+7-J,D ;set opposite row
80 NEXT J
90 NEXT I
95 POKE 23608,INT((B-256)/256) ;sets the new start address
99 POKE 23606,(B-256)-INT((B-256)/256)*256
To produce smooth scrolling messages within ZX BASIC, simply
store the message to the UDG area and moving the start address
of the table.