Display Output
--------------
Display Modes
--> Video Text and Blockgraphics
--> Video Pseudo Hi-Res Graphics
--> Video True Hi-Res Graphics
Video Text and Blockgraphics
----------------------------
Overview
This is the ZX standard video mode. The display area consists of 32x24
characters of 8x8 pixels each. The user cannot set single pixels though, only
64 predefined characters can be used. However, some of these characters are
split into 2x2 blocks (4x4 pixel each), allowing to display 64x48 block low
resolution graphics.
Video Memory
Video memory is addressed by the D_FILE pointer (400Ch) in ZX80/81 system area.
The first byte in VRAM is a HALT opcode (76h), followed by the data (one byte
per character) for each of the 24 lines, each line is terminated by a HALT
opcode also. In case that a line contains less than 24 characters, the HALT
opcode blanks (white) the rest of the line up to the right screen border. (Thus
left-aligned text will take up less memory than centered or right-aligned
text.)
Character Data, VRAM Size
Character data in range 00h..3Fh displays the 64 characters, normally black on
white. Characters may be inverted by setting Bit 7, ie. C0h..FFh represents the
same as above displayed white on black.
The fully expanded VRAM size is 793 bytes (32x24 + 25 HALTs, almost occupying
the whole 1Kbyte of internal RAM), an empty fully collapsed screen occupies
only 25 bytes (HALTs).
Character Set
The character set is addressed by the I register multiplied by 100h. In the
ZX81 this is 1Eh for 1E00h..1FFFh, in ZX80 0Eh for 0E00h..0FFFh. Setting
I=40h..7Fh in attempt to define a custom charset in RAM rather than ROM does
not work.
Display procedure Tech Details
The display data is more or less 'executed' by the CPU. When displaying a line,
the BIOS takes the address of the first character, eg. 4123h, sets Bit 15, ie.
C123h, and then jumps to that address.
The hardware now senses A15=HIGH and /M1=LOW (signalizing opcode read), upon
this condition memory is mirrored from C000-FFFF to 4000-7FFF. The 'opcode' is
presented to the databus as usually, the display circuit interpretes it as
character data, and (if Bit 6 is zero) forces the databus to zero before the
CPU realizes what is going on, causing a NOP opcode (00h) to be executed. Bit 7
of the stolen opcode is used as invert attribute, Bit 0-5 address one of the 64
characters in ROM at (I*100h+char*8+linecntr), the byte at that address is
loaded into a shift register, and bits are shifted to the display at a rate of
6.5MHz (ie. 8 pixels within 4 CPU cycles).
However, when encountering an opcode with Bit 6 set, then the video circuit
rejects the opcode (displays white, regardless of Bit 7 and 0-5), and the CPU
executes the opcode as normal. Usually this would be the HALT opcode - before
displaying a line, BIOS enables INTs and initializes the R register, which will
produce an interrupt when Bit 6 of R becomes zero.
In this special case R is incremented at a fixed rate of 4 CPU cycles (video
data executed as NOPs, followed by repeated HALT), so that line display is
suspended at a fixed time, regardless of the collapsed or expanded length of
the line.
As mentioned above, an additional register called linecntr is used to address
the vertical position (0..7) whithin a character line. This register is reset
during vertical retrace, and then incremented once per scanline. The BIOS thus
needs to 'execute' each character line eight times, before starting to
'execute' the next character line.
Video Pseudo Hi-Res Graphics
----------------------------
This method is used to display 256x192 pixels graphics, limited to max 128
combinations within each row of 8 pixels though. Even though not supported by
the BIOS, a couple of games are using this video mode: Rock Crush, Dans
Revenge, Rocketman, Forty Niner, Madjump II, Bipods, Micromouse, and possibly
others.
Basically it is working much like Text video mode, the character height is
reduced to a single scanline, so each tile consists of 8x1 pixels rather than
8x8 pixels. And the screen consists of 32x192 of these 'flat' characters, each
line usually terminated by a RET opcode (C9h), thus occupying 6176 bytes of
memory.
A special display procedure is required which forces the linecntr register to
zero by issuing a very short 'vertical retrace' signal each scanline
(preferably simultaneously to the hardware generated horizontal retrace
signal). In result, only the topmost row of each character will be displayed,
as the topmost row of most of the normal characters is just blank, it'd be
recommended to change the characterset pointer in the I register to another
address in ROM.
For example, setting I=0Ch would select the area 0C00h..0DFFh (in steps of
eight: topmost rows of chars #0, #1, #2 at C00h, C08h, C10h, etc). The machine
code bytes in this memory region are then used as 'randomly' predefined pixel
rows, which may or may not match the programmers requirements. Each of the 64
rows may be inverted as normal text characters, so theoretical a total of 128
different 8-pixel rows can be used, practically less because most likely a
couple of rows will be duplicated.
As the interrupt based BIOS display procedre at 0038h does not support above, a
raw software based handler is used in most cases, that's why each line is
terminated by a RET rather than HALT opcode.
Video True Hi-Res Graphics
--------------------------
This mode produces a 256x192 pix graphics screen, and, unlike Pseudo Hi-Res, it
allows to set each pixel separately. The downside is that it does not work with
most external RAM Paks (memory expansions can be quite easily upgraded by using
two diodes and a resistor though, see chapter Hardware Modifications for
details).
However, it does work with internal RAM and with modified RAM Paks.
When using internal RAM, take care about these two limitiations: Only a small
picture will fit into 1K memory (so the display procedure must increase
horizontal and/or vertical blanking times), and external RAM must be
disconnected (as it'd otherwise disable internal RAM).
The true hi-res technique is used by the games Guus Flater, Starfight, and by
some demos such like WRX1K.
The general idea is to move the character set into RAM at 4000h..7FFFh by
setting I to 40..7Fh. Now this does NOT work as expected, ie. as
(I*100h+char*8+linecntr) as for text mode. Both the executed opcode (character
number) and the linecntr value are ignored. Instead, pixels are directly read
from memory at (IR). Each eight bits of each byte represent eight pixels. The
picture is defined in form of a common monochrome bitmap.
The bitmap data can be located anywhere in RAM, and as it is not 'executed' as
in other display modes, only raw data is required (ie. and no HALT or RET
opcodes need to be attached to each line). Note that only the lower seven bits
of the R register are incremented by the CPU; care should be taken that it does
not overflow within a line. For example, a bitmap of 256 pixels width (32
bytes) should be aligned to 32 in memory.
The main display procedure should load the MSB of the current bitmap line into
the I register, and the LSB into the A register, then jump to a dummy D_FILE
display procedure in memory with A15=HIGH. This dummy procedure should copy the
LSB from A into R register, and then execute a stream of 32 NOP opcodes (00h:
Bit 7 indicates not inverted output, Bit 6 disables blanking, data is directly
read from (IR), so that the character number in Bit 0-5 is ignored), and return
to the main procedure - which'd then issue some delays, prepare new address in
I and A and start over with the next line (using the same dummy procedure
again), until the whole screen has been displayed.