problemkaputt.github.io/zxdocs.htm
2021-01-14 23:48:20 -08:00

9390 lines
529 KiB
HTML

<HTML><HEAD>
<TITLE>Sinclair ZX Specifications</TITLE>
<META NAME="GENERATOR" CONTENT="nocash XED2HTM converter">
</HEAD><BODY bgcolor="#ffffff" text="#000000" link="#0033cc" vlink="#0033cc" alink="#0033cc">
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="contents"></A><FONT SIZE=+2>&nbsp;Contents</FONT></TD></TR></TABLE><BR>
<B>Computer Specs</B><BR>
<A HREF="#zx80zx81">ZX80/ZX81</A><BR>
<A HREF="#zxspectrum">ZX Spectrum</A><BR>
<A HREF="#lambda8300">Lambda 8300</A><BR>
<A HREF="#jupiterace">Jupiter ACE</A><BR>
<BR>
<B>Z80 CPU</B><BR>
<A HREF="#z80cpuspecifications">Z80 CPU Specifications</A><BR>
<BR>
<B>The BASIC Interpreter</B><BR>
<A HREF="#basicinterpreter">BASIC Interpreter</A><BR>
<BR>
<B>About this doc</B><BR>
<A HREF="#aboutthisdocument">About this document</A><BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81</FONT></TD></TR></TABLE><BR>
<B>ZX80/ZX81 Technical Information</B><BR>
<A HREF="#zx80zx81models">ZX80/ZX81 Models</A><BR>
<A HREF="#zx80zx81keyboardassignment">ZX80/ZX81 Keyboard Assignment</A><BR>
<A HREF="#zx80zx81iomap">ZX80/ZX81 I/O Map</A><BR>
<A HREF="#zx80zx81ioports">ZX80/ZX81 I/O Ports</A><BR>
<A HREF="#zx80zx81videomodetextandblockgraphics">ZX80/ZX81 Video Mode Text and Blockgraphics</A><BR>
<A HREF="#zx80zx81videomodepseudohiresgraphics">ZX80/ZX81 Video Mode Pseudo Hi-Res Graphics</A><BR>
<A HREF="#zx80zx81videomodetruehiresgraphics">ZX80/ZX81 Video Mode True Hi-Res Graphics</A><BR>
<A HREF="#zx80zx81videoblankingandretrace">ZX80/ZX81 Video Blanking and Retrace</A><BR>
<A HREF="#zx80zx81videointerruptsintsandnmis">ZX80/ZX81 Video Interrupts (INTs and NMIs)</A><BR>
<A HREF="#zx80zx81videodisplaytimings">ZX80/ZX81 Video Display Timings</A><BR>
<A HREF="#zx80zx81videocharacterset">ZX80/ZX81 Video Character Set</A><BR>
<A HREF="#zx81videononstandardudgchrsexpansions">ZX81 Video Nonstandard UDG/CHRS Expansions</A><BR>
<A HREF="#zx81videononstandardhiresexpansions">ZX81 Video Nonstandard HIRES Expansions</A><BR>
<A HREF="#zx81videononstandardpicturesize">ZX81 Video Nonstandard Picture Size</A><BR>
<A HREF="#zx81videononstandardcolorexpansions">ZX81 Video Nonstandard Color Expansions</A><BR>
<A HREF="#zx81joystickexpansions">ZX81 Joystick Expansions</A><BR>
<A HREF="#zx81soundexpansions">ZX81 Sound Expansions</A><BR>
<A HREF="#zx80zx81memorymapandsystemarea">ZX80/ZX81 Memory Map and System Area</A><BR>
<A HREF="#zx80zx81memorymirrorsandexpansions">ZX80/ZX81 Memory Mirrors and Expansions</A><BR>
<A HREF="#zx80zx81memorybinarydatamachinecodeprograms">ZX80/ZX81 Memory Binary Data/Machine Code Programs</A><BR>
<A HREF="#zx80zx81cassettefileimages">ZX80/ZX81 Cassette File Images</A><BR>
<A HREF="#zx80zx81cassettefilecontent">ZX80/ZX81 Cassette File Content</A><BR>
<A HREF="#zx80zx81cassettesignals">ZX80/ZX81 Cassette Signals</A><BR>
<A HREF="#hardwareconnectorsupgrading">Hardware, Connectors, Upgrading</A><BR>
<BR>
<B>Z80 CPU</B><BR>
<A HREF="#z80cpuspecifications">Z80 CPU Specifications</A><BR>
<BR>
<B>The BASIC Interpreter</B><BR>
<A HREF="#basicinterpreter">BASIC Interpreter</A><BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81models"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81 Models</FONT></TD></TR></TABLE><BR>
<B>ZX81</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> CPU: NEC P1X108-144 D780C-1 (Z80 compatible) 3.25MHz
The clock frequency is gained from a high tolerance 6.5MHz
chewing gum, not exactly a quartz oscillator, in fact, my
oscilloscope tells me that my ZX81 is running at 3.33Mhz.
Effective CPU Speed in SLOW mode (when Display is enabled)
For 50Hz Display Refresh: 0.804600 MHz
For 60Hz Display Refresh: 0.536400 MHz
Custom: FERRANTI ULA 2C184E 8147
Combines the ZX80 video circuit in one chip, plus NMI-generator
Video Tech Data
Video: 32x24 Characters (256x192 pixels), 64x48 Dots Block Graphics
Characters: 64 Characters, defined in ROM area
Attributes: Normal and Inverted (separately for each char)
Memory
8 Kbytes ROM
1 KByte RAM built-in
Expanision RAM: 16KBytes (most popular) up to 56KBytes
</TD></TR></TABLE><BR>
<B>ZX80</B><BR>
Memory: 4 KBytes ROM, 1 KByte RAM<BR>
Video: Same as ZX81, but without NMI-generator, ie. not supporting SLOW
mode, thus cannot display a picture while program is operating.<BR>
Sinclair also sold an upgrade kit for it: The 8K ZX81 ROM bundled with a
ZX81-style keyboard overlay (but still lacking the NMI-generator).<BR>
<BR>
<B>TS1000</B><BR>
A ZX81 clone, distributed in USA by a company called Timex. Includes 2
KBytes RAM, and obviously 60Hz NTSC TV modulator, otherwise same as
ZX81. The BIOS is 1:1 the same as in ZX81.<BR>
<BR>
<B>TS1500</B><BR>
Same as above TS1000, but with 16 KBytes of RAM built-in, with rubber
keyboard, and slightly modified BIOS.<BR>
<BR>
<B>Microdigital TKs (Brazil)</B><BR>
Reportedly brazilian ZX81 clones are called the "TKs".<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> TK80 ZX80 clone with 4K ROM, 1K RAM, TTL-chips, without NMI
TK82 ZX80 clone with 4K ROM, 2K RAM, TTL-chips, without NMI
TK82-C ZX81 clone with 8K ROM, 2K RAM, TTL-chips, with NMI on daughterboard
TK83 ZX81 clone with 8K ROM, 2K RAM, ULA-chip, with NMI,joystick,new case
TK85 ZX81 clone with 10K ROM, 16K RAM, psg-solder-points, rubber keyb,
and other extras...
</TD></TR></TABLE>TK83/TK85 have DIN joystick connector<BR>
The C in TK82-C is for "Cientifico", or Scientific in English.<BR>
<BR>
____ ZX80 vs ZX81 Compatibility ____<BR>
<BR>
<B>Hardware</B><BR>
The ZX80 and ZX81 hardware is mostly the same, the same I/O address are used,
RAM is located at 4000h and up, and mirrored as VRAM at C000h and up. The
only relevant physical difference is that ZX81 includes an NMI generator,
which is (optionally) allowing to execute programs during vertical blanking
periods.<BR>
<BR>
<B>Firmware</B><BR>
Compatibility ends at the firmware side, the revised ZX81 BIOS version
dropped any compatibility issues. The content of cassette files is different,
some characters in the character set have been exchanged, the system area is
different, the BASIC interpreter 'opcodes' have different meanings, variables
and immediates are stored as floating point numbers (ZX81) instead as
integers (ZX80), and any addresses in the BIOS ROM are different also.<BR>
<BR>
<B>Software</B><BR>
As described above, ZX80 and ZX81 cassette files are completely incompatible
to each other. However, the ZX81 BASIC syntax is mostly compatible to ZX80
syntax, so that ZX80 software could be easily imported to ZX81 with little
changes; either by translation program that adjusts the file content, or by
manually entering the source code.<BR>
<BR>
<B>Performance</B><BR>
The main advantage of ZX81 hardware is the ability to execute program code
and to display a picture simultaneously in SLOW mode. As the name says, this
fancy feature is heavily slowing down effective CPU speed.<BR>
Otherwise ZX81 should be theoretically as fast as the trusty ZX80,
unfortunately the new BASIC interpreter uses floating point values rather
than integers, and thus ZX81 BASIC programs are ways slower even when using
FAST mode.<BR>
<BR>
<B>TS1500 BIOS</B><BR>
The inefficient RAM size detection function is removed, instead, the BIOS
uses a hardcoded RAM size of 16K, additionally it checks for "TS1510 Command
Cartridge Player" ROMs at location 2000h, and starts them if present (the
first opcode byte at 2000h must be 01h, ie. "ld bc,nnnn").<BR>
The TS1500 BIOS does fix the LPRINT bug, and it does (attempt) to increase
floating point conversion accurracy (the ZX81/TS1000 tends to round-down
values by accident, whilst the TS1500 tends to round-up values by accident,
which isn't any better, and in some cases it's even worse).<BR>
<BR>
____ Sinclair ZX81 Personal Computer ____<BR>
<BR>
<B>Multimedia</B><BR>
The first step to modern decadency was done by releasing the ZX81, this
computer had the ability to operate in a so called SLOW mode, during
which it could both execute a program AND display a picture on the
screen at the SAME time, while its predecessor the ZX80 could do only
either one at once. This older computer has been restricted to FAST
mode, offering high performance execution time.<BR>
<BR>
<B>Energy</B><BR>
Anyways, a very amazing thing's been the keyboard heating. Even though
the computer's been operated at 5 Volts, it's been delivered with
external 9V power supply. The cooling plate of the 7805 voltage
regulator's been located directly under the keyboard, whereas cooling
plate is a possibly misleading expression, it's been heating up after a
while, giving the keyboard an irritating feverish temparature. If
somebody'd claim that ZX81 are tough guys and that they'd never get cold
fingers - I could only confirm that.<BR>
<BR>
<B>Computers Today</B><BR>
Unfortunately, the rather ineffective new invention of animated pictures
has been adapted by newer computers, up to today!<BR>
As far as concerning power supplies, this has been another milestone in
home computer technology, and there's still nobody who stands up, takes
his ventilated heavy 200 Watts supply, and smashes it into the face of
the guy who has mass-manufactured it.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81keyboardassignment"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81 Keyboard Assignment</FONT></TD></TR></TABLE><BR>
Here's the ZX81 keyboard assignment. The Graphics column is meant to be
Shift+Graphics (Graphic without Shift just returns inverted 'normal'
characters).<BR>
The two columns to the right are for the ZX80, as there's no Function
mode, ZX80 function names (such like CHR$) can be (and must be) typed by
hand as single characters.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> &lt;-key-&gt; &lt;------------- ZX81 -----------&gt; &lt;------ZX80------&gt;
NORMAL COMMAND SHIFT FUNCTION GRAPHICS ZX80/CMD ZX80/SHFT
1 1 &lt;edit&gt; -- 1000 1 NOT
2 2 AND -- 0100 2 AND
3 3 THEN -- 0001 3 THEN
4 4 TO -- 0010 4 TO
5 5 &lt;left&gt; -- 0101 5 &lt;left&gt;
6 6 &lt;down&gt; -- 0011 6 &lt;down&gt;
7 7 &lt;up&gt; -- 1100 7 &lt;up&gt;
8 8 &lt;right&gt; -- 0101 8 &lt;right&gt;
9 9 &lt;graphics&gt; -- -- 9 &lt;hide???&gt;
0 0 &lt;rubout&gt; -- -- 0 &lt;rubout&gt;
Q PLOT "" SIN 0111 NEW 1010
W UNPLOT OR COS 1011 LOAD 0011
E REM STEP TAN 1110 SAVE 1000
R RUN &lt;= INT 1101 RUN 0100
T RAND &lt;&gt; RND 0110 " " 0022
Y RETURN &gt;= STR$ 1001 REM "
U IF $ CHR$ -- IF $
I INPUT ( CODE -- INPUT (
O POKE ) PEEK -- PRINT )
P PRINT " TAB -- "?" *
A NEW STOP ARCSIN 2222 LIST 2222
S SAVE LPRINT ARCCOS 2200 STOP 0110
D DIM SLOW ARCTAN 0022 DIM 0010
F FOR FAST SGN 2211 FOR 0001
G GOTO LLIST ABS 1122 GO TO 2200
H GOSUB ** SQR 2222 POKE **
J LOAD - VAL -- RANDOMISE -
K LIST + LEN -- LET +
L LET = USR -- "?" =
ENTER newline function -- newline &lt;edit&gt;
SHIFT -- -- -- -- -- --
Z COPY : LN -- "?" :
X CLEAR ; EXP -- CLEAR ;
C CONT ? AT -- CLS ?
V CLS / -- -- GO SUB /
B SCROLL * INKEY$ -- RETURN OR
N NEXT &lt; NOT -- NEXT &lt;
M PAUSE &gt; PI -- "?" &gt;
. , -- -- "." ,
SPACE BREAK pound -- 1111 BREAK pound
</TD></TR></TABLE><BR>
<B>40-key ZX80/ZX81 Keyboard</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> | 1 2 3 4 5 6 7 8 9 0 |
| Q W E R T Y U I O P |
| A S D F G H J K L ENTER|
|SHF Z X C V B N M . SPACE|
</TD></TR></TABLE><BR>
<B>Keyboard Translation</B><BR>
When the keyboard translation option is used, special characters such like
comma, quotes, plus, etc. are mapped to the respective PC keys. In result,
the meaning of the ZX key combinations SHIFT+1..4 changes also. The
respective functions are remapped to the following PC-keys:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE><B> ZX81 ZX80 PC</B>
EDIT NOT !
AND AND &
THEN THEN #
TO TO %
</TD></TR></TABLE>Some other remapped keys are Cursor=Cursor, Rubout=Backspace, Graphics=Alt,
Function/Symbol=Ctrl, Break=End.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81iomap"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81 I/O Map</FONT></TD></TR></TABLE><BR>
<B>I/O Ports</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> xx0Fh.W PSG data (Bi-Pak ZON-X81 Sound)
xx1Dh.R Zebra Joystick adapter
xx2Fh.R Memopak I/F Centronics Interface status (IN status,[dd3Fh]);dd=data
xx3Fh.R Memopak I/F Centronics Interface finish (IN dummy,[dd3Fh]) ;dd=data
FF7Eh.R Lambda - read PAL/NTSC flag (A7=row) (via diode from A7 to KEYB.0)
xx9Fh.W PSG index (Timedata ZXM Sound Box)
xxBFh.R PSG data (Timedata ZXM Sound Box/Joystick Read)
xxDFh.W PSG index (Bi-Pak ZON-X81 Sound) (default address) (sometimes CFh)
xxDFh.W PSG data (Timedata ZXM Sound Box)
xxDFh.R Mikro-Gen digital joystick
xxDFh.R AGB - JOYSTICK II (port A) (or B ?)
xxEFh.R AGB - JOYSTICK II (port B) (or A ?)
xxF5h.R Lambda - toggle sound output level
xxF5h.W Lambda - select charset line number (00..07)
xxF6h.R Lambda - read selected charset data (8 pixels)
xxF6h.W Lambda - select charset char number (00..3F)
xxFBh.R Sinclair Printer Status
xxFBh.W Sinclair Printer Output
xxFDh.W Disable NMI (ZX81 only)
xxFEh.W Enable NMI (ZX81 only)
NNFEh.R Keyboard read, when NMI=Off: also enter VSYNC and set CAS.OUT=Low
xxFFh.W Terminate Vsync and restart LINECNTR and set CAS.OUT=High
</TD></TR></TABLE><BR>
<B>Accidently Used I/O Port Mirrors</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0Eh.R Faulty mirror of FEh.R (used by a GRAND-PRIX game)
CFh.W PSG index (Bi-Pak ZON-X81 Sound) (used accidently in Bi-Pak manual)
CFh.W PSG index (Bi-Pak ZON-X81 Sound) (used by Lunar 10)
FEh.W Faulty mirror of FFh.W (used by animated Space Invaders for ZX80)
</TD></TR></TABLE><BR>
<B>Memory Mapped Ports</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 3E80h.R/W Mikro-Gen analog joystick A/D board
7FFFh.W PSG index (Quicksilva QS Sound board)
7FFEh.R/W PSG data (Quicksilva QS Sound board)
</TD></TR></TABLE><BR>
<B>IR Register</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> I=00h Pseudo HiRes (Madjump II)
I=08h Pseudo HiRes (Bipods, Micromouse)
I=0Ch Pseudo HiRes (Rock Crush, Dans Revenge, etc.)
I=1Eh ZX81 ROM Charset (or QS CHRS board RAM)
I=2xh dk'tronics UDG ROM (or unknown UDG RAM)
I=3xh dk'tronics UDG RAM
I=40h Xtricator IM2 vector at [40FFh] (with databus assumed to be FFh)
IR=x True hires bitmap address
R=x Interrupt counter for "compressed" text output (INT wired to A6)
R=x+EI Interrupt execution forces HSYNC (on ZX81: also resets NMI counter)
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81ioports"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81 I/O Ports</FONT></TD></TR></TABLE><BR>
<B>Output to Port FFh (or ANY other port)</B><BR>
Writing any data to any port terminates the Vertical Retrace period, and
restarts the LINECNTR counter. The retrace signal is also output to the
cassette (ie. the Cassette Output becomes High).<BR>
<BR>
<B>Input from Port FEh (or any other port with A0 zero)</B><BR>
Reading from this port initiates the Vertical Retrace period (and
accordingly, Cassette Output becomes Low), and resets the LINECNTR register
to zero, LINECNTR remains stopped/zero until user terminates retrace - In the
ZX81, all of the above happens only if NMIs are disabled.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bit Expl.
0-4 Keyboard column bits (0=Pressed)
5 Not used (1)
6 Display Refresh Rate (0=60Hz, 1=50Hz)
7 Cassette input (0=Normal, 1=Pulse)
</TD></TR></TABLE>When reading from the keyboard, one of the upper bits (A8-A15) of the I/O
address must be "0" to select the desired keyboard row (0-7).<BR>
(When using IN A,(nn), the old value of the A register is output as upper
address bits and &lt;nn&gt; as lower bits. Otherwise, ie. when using IN r,(C) or
INI or IND, the BC register is output to the address bus.)<BR>
<B>The ZX81/ZX80 Keyboard Matrix</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Port____Line____Bit__0____1____2____3____4__
FEFEh 0 (A8) SHIFT Z X C V
FDFEh 1 (A9) A S D F G
FBFEh 2 (A10) Q W E R T
F7FEh 3 (A11) 1 2 3 4 5
EFFEh 4 (A12) 0 9 8 7 6
DFFEh 5 (A13) P O I U Y
BFFEh 6 (A14) ENTER L K J H
7FFEh 7 (A15) SPC . M N B
</TD></TR></TABLE><BR>
<B>Port FDh Write (ZX81 only)</B><BR>
Writing any data to this port disables the NMI generator.<BR>
<BR>
<B>Port FEh Write (ZX81 only)</B><BR>
Writing any data to this port enables the NMI generator.<BR>
NMIs (Non maskable interrupts) are used during SLOW mode vertical blanking
periods to count the number of drawn blank scanlines.<BR>
<BR>
<B>ZX81 Printer</B><BR>
Below ports are for the printer. Both ZX80 and ZX81 aren't actually include
any printer connector or hardware, but the ZX81 BIOS supports three BASIC
instructions (LPRINT, LLIST, COPY) which access external printer hardware by
these I/O addresses.<BR>
<B>Port FBh Read - Printer Status</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bit Expl.
0 Data Request (0=Busy, 1=Ready/DRQ)
1-5 Not used
6 Printer Detect (0=Okay, 1=None)
7 Newline (0=Nope, 1=Begin of new line)
</TD></TR></TABLE><B>Port FBh Write - Printer Output</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bit Expl.
0 Not used
1 Undoc/Speed? (0=Normal, 1=used to slow-down last 2 scanlines)
2 Motor (0=Start, 1=Stop)
3-6 Not used
7 Pixel Output (0=White/Silver, 1=Black)
</TD></TR></TABLE>That serial 1-bit / 1-pixel protocol isn't compatible with normal character
based printers.<BR>
Uses thermal paper rolls with 100 (or 110 ?) mm width, max 25 meters length.<BR>
Horizontal resolution is 256 pixels (32 characters).<BR>
<BR>
<B>Note</B><BR>
Beside for the actual I/O ports, the IR register, the most significant bit of
the program counter, and (if that bit was set) the opcodes on the databus are
also relevant for video output. For details refer to chapters about Video.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81videomodetextandblockgraphics"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81 Video Mode Text and Blockgraphics</FONT></TD></TR></TABLE><BR>
<B>Overview</B><BR>
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.<BR>
<BR>
<B>Video Memory</B><BR>
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
32 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.)<BR>
<BR>
<B>Character Data, VRAM Size</B><BR>
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.<BR>
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).<BR>
<BR>
<B>Character Set</B><BR>
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.<BR>
<BR>
<B>Display procedure Tech Details</B><BR>
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.<BR>
<BR>
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).<BR>
<BR>
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.<BR>
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.<BR>
<BR>
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.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81videomodepseudohiresgraphics"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81 Video Mode Pseudo Hi-Res Graphics</FONT></TD></TR></TABLE><BR>
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.<BR>
<BR>
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.<BR>
<BR>
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.<BR>
<BR>
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.<BR>
<BR>
As the interrupt based BIOS display procedure 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.<BR>
<BR>
Observe that the TS1500 BIOS version contains some patched opcodes, so
graphics may appear different as with original ZX81/TS1000 BIOS (the most
commonly used region, with I=0Ch, is same in both BIOS versions).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81videomodetruehiresgraphics"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81 Video Mode True Hi-Res Graphics</FONT></TD></TR></TABLE><BR>
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).<BR>
<BR>
However, it does work with internal RAM and with modified RAM Paks.<BR>
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).<BR>
<BR>
The true hi-res technique is used by the games Guus Flater, Starfight,
and by some demos such like WRX1K.<BR>
<BR>
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<BR>
(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.<BR>
<BR>
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.<BR>
<BR>
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.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81videoblankingandretrace"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81 Video Blanking and Retrace</FONT></TD></TR></TABLE><BR>
Display becomes white during blanking time. That is: when Bit 15 of the
program counter (PC) is "0", and/or when Bit 6 of the current opcode is
"1". Theoretically the CPU could execute whatever program code during
blanking - however, as there is only limited interrupt feedback, this
time is usually spent on HALT opcodes or other delay loops, required to
keep the CPU synchronized to visible display output.<BR>
<BR>
<B>Vertical Blanking</B><BR>
Upper and lower screen borders are displayed above/below of the actual
picture, the height of these borders depends on the display refresh
rate. The BIOS permanently reads out the preferred refresh rate (50Hz or
60Hz) when checking for keystrokes, and uses this to re-calculate the
desired border height for each frame - allowing to export the ZX to
other countries without having to reboot it ;-)<BR>
<BR>
<B>ZX80 Vertical Blanking ("PAUSE")</B><BR>
The ZX80 points to a HALT opcode in the D_FILE area, which is repeatedly
executed to display blank upper and lower screen borders (much like
empty lines in a collapsed screen). The CPU thus wastes all its energies
just on drawing blank lines (and on decreasing a remaining lines
counter).<BR>
<BR>
<B>ZX81 Vertical Blanking ("SLOW")</B><BR>
Even though the ZX81 supports the above method either, it'd usually use
NMI based blanking which allows program code to be executed during
blanking time. NMIs (non maskable interrupts) are enabled by I/O, the
NMI handler is then called each scanline. The handler increases a
counter and (if the counter does not overflow) returns to the user
program, otherwise it executes a HALT opcode to synchronize the CPU to
the display at one-cycle resolution and terminates the blanking
procedure.<BR>
<BR>
<B>Horizontal Blanking</B><BR>
In both ZX80 and ZX81, the CPU cannot be used to execute user programs
during horizontal blanking periods - it is required to execute delays to
be kept synchronized to video hardware. This could be gained by a
hardcoded delay. However, ZX video is required to support variable
length blanking when using collapsed screens, in that case the width of
the right screen border must be increased when drawing an empty (or
incomplete) line. This is gained by loading a counter value into the R
register (before drawing the line), and terminating the line by a HALT
opcode which is kept executed until Bit 6 of R becomes zero.<BR>
<BR>
<B>Retrace</B><BR>
The cathode ray is moved back to the begin of the scanline / top of
display during horizontal / vertical retrace periods.<BR>
Horizontal retrace is generated by the video hardware, so care should be
taken to keep the display procedure synchronized to retrace signals.<BR>
Vertical retrace must be manually initiated and terminated by I/O, a
fixed length delay should be issued during v-retrace in order to produce
a stable display.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81videointerruptsintsandnmis"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81 Video Interrupts (INTs and NMIs)</FONT></TD></TR></TABLE><BR>
<B>INTs</B><BR>
Maskable Interrupts (INTs) are generated when Bit 6 of the R (refresh)
register becomes zero. As the R register is incremented once for each
opcode (twice for prefixed opcodes), there is no linear relationship
between clock cycles and refresh cycles.<BR>
In the ZX, INTs are used to terminate scanline drawing, the display data
is 'executed' identical as NOP instructions, followed by a HALT opcode
(which is identical as repeated NOPs), so that in this special case (as
both HALTs and NOPs increment R once per 4 clock cycles) INTs can be
used to produce a regular interval.<BR>
The above INT/HALT combination is used as variable length delay, which
is required for variable length scanlines (ie. mixed collapsed and
expanded scanlines) only. Fixed length scanlines could be terminated by
hardcoded delays.<BR>
In IM 1 (default), the INT handler is located at 0038h in BIOS ROM. INTs
are enabled by EI instruction, and are automatically disabled upon
execution (or when issuing DI instruction).<BR>
<BR>
<B>NMIs (ZX81 only)</B><BR>
Non maskable interrupts (NMIs) are requested during horizontal retrace
time (ie. at the end of each scanline), the CPU is forced into WAIT
state for the duration of NMI request (unless when executing a HALT
opcode which is allowed to complete without WAIT states).<BR>
NMIs are used to count the number of drawn scanlines during vertical
blanking periods. This is allowing the user program to be executed in
SLOW mode while drawing upper and lower screen borders, and to pass
control back to the display/retrace procedure once the NMI handler
decides to terminate the blanking period.<BR>
The NMI handler is located at 0066h in BIOS ROM (independently of IM
interrupt mode). NMIs are enabled/disabled by I/O instructions - the CPU
cannot disable NMIs (ie. DI/EI has no effect on NMIs).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81videodisplaytimings"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81 Video Display Timings</FONT></TD></TR></TABLE><BR>
<B>Horizontal Scanline Timings</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Horizontal Display 128 cycles (32 characters, 256 pixels)
Horizontal Blanking 64 cycles (left and right screen border)
Horizontal Retrace 15 cycles
Total Scanline Time 207 cycles
</TD></TR></TABLE>Horizontal retrace rate and duration are fixed. The display procedure
might increase or decrease the width of the display area (by
respectively adjusting the blanking time) even though larger screens
might exceed the visible dimensions of the attached TV set or monitor.<BR>
<BR>
<B>Vertical Timings (50Hz)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Upper Blanking 11592 cycles 56 scanlines (7 charlines)
Display Area 39744 cycles 192 scanlines (24 charlines)
Lower Blanking ca.11592 cycles ca. 56 scanlines (or a bit less)
Vertical Retrace 1235 cycles ca. 6 scanlines
</TD></TR></TABLE><BR>
<B>Vertical Timings (60Hz)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Upper Blanking 6624 cycles 32 scanlines (4 charlines)
Display Area 39744 cycles 192 scanlines (24 charlines)
Lower Blanking ca. 6624 cycles ca. 32 scanlines (or a bit less)
Vertical Retrace 1235 cycles ca. 6 scanlines
</TD></TR></TABLE><BR>
<B>User Available Blank Lines</B><BR>
Even though upper screen border consists of 56 scanlines (32 in 60Hz
mode), only 54 scanlines (60Hz: 30 scanlines) are available for user
program execution. The first of the remaining scanlines is occupied by a
HALT opcode (which is suspended by a NMI; providing exact retrace
synchronisation), and the next scanline is spent on a collapsed D_FILE
row. Lower screen borders are idientical as above, except that no
collapsed D_FILE line is drawn at the bottom. Instead, some cycles are
spent upon incrementing the FRAMES counter.<BR>
<BR>
<B>User Available Blanking Time</B><BR>
The total of 207 cycles per scanline isn't available for user program,
even during blanking periods: An NMI is generated each line, including
some NMI-waitstates, the CALL 66h execution, and the execution of the
NMI handler (which is counting the number of drawn scanlines).<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Item Original ZX81 Tuned ZX81
Total scanline time 207 cycles 207 cycles
NMI WAIT - 14 cycles - 0 cycles (WAITMOD by Wilf Rigter)
NMI CALL 66h - 12 cycles - 12 cycles
NMI handler - 32 cycles - 29 cycles (NMIPATCH by Nocash)
Remaining user time = 149 cycles = 166 cycles
</TD></TR></TABLE>Recursing both upper and lower border, 54*2 scanlines per frame are available
for user programs in 50Hz mode; only 30*2 in 60Hz mode.<BR>
<BR>
<B>Resulting User Available CPU Time</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> SLOW, 50Hz Effective Speed 0.804600 MHz (54*2*149 cycles, 50 frames) (ori)
SLOW, 50Hz Effective Speed 0.896400 MHz (54*2*166 cycles, 50 frames) (tuned)
SLOW, 60Hz Effective Speed 0.536400 MHz (30*2*149 cycles, 60 frames) (ori)
SLOW, 60Hz Effective Speed 0.597600 MHz (30*2*166 cycles, 60 frames) (tuned)
FAST, Total CPU Speed 3.250000 MHz (display disabled)
ZX80/PAUSE/INPUT 0.0 MHz (user program stopped)
</TD></TR></TABLE>For more info on tuning, see:<BR>
<A HREF="#hwmakingthezx81faster">HW Making the ZX81 Faster</A><BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81videocharacterset"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81 Video Character Set</FONT></TD></TR></TABLE><BR>
<B>First, here's the ZX81 character set (64 characters)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> ____0___1___2___3___4___5___6___7___8___9___A___B___C___D___E___F____
00 SPC [' ][ '][''][. ][: ][.'][:']{::}{..}{''} " GBP $ : ? 0F
10 ( ) &gt; &lt; = + - * / ; , . 0 1 2 3 1F
20 4 5 6 7 8 9 A B C D E F G H I J 2F
30 K L M N O P Q R S T U V W X Y Z 3F
</TD></TR></TABLE><B>For the ZX80, some characters are located at other positions:</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> ____0___1___2___3___4___5___6___7___8___9___A___B___C___D___E___F____
00 SPC " [: ][..][' ][ '][. ][ .][.']{::}{..}{''}GBP $ : ? 0F
10 ( ) - + * / = &gt; &lt; ; , . 0 1 2 3 1F
20 4 5 6 7 8 9 A B C D E F G H I J 2F
30 K L M N O P Q R S T U V W X Y Z 3F
</TD></TR></TABLE>For both ZX80 and ZX81, all characters can be displayed normal (Bit 7
cleared) or inverted (Bit 7 set). For SPC and GRA see below, GBP means
the 'pounds' currency symbol.<BR>
<BR>
<B>Block Graphics</B><BR>
For [solid] symbols, all 16 combinations of block graphics (with any number
of 4x4 pixel dots at any position within a 8x8 pixel character) can be
produced by using the invert-attribute bit. Only limited combinations are
possible for {dithered} symbols.<BR>
<BR>
ZX81 charset is stored at 1E00h-1FFFh in BIOS ROM (I register I=1Eh),
ZX80 charset at 0E00h-0FFFh (I=0Eh).<BR>
<BR>
The lower 9 bits (A8-A0) of the characterset are addressed by the 'display
controller' (overriding the CPU supplied address signals, which outputs the
whole IR register to the address bus) - the special address bits are output
to the ROM chip only (but not to RAM, nor to Expansion Port), so neither
internal, not external RAM can be used to store character data.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx81videononstandardudgchrsexpansions"></A><FONT SIZE=+2>&nbsp;ZX81 Video Nonstandard UDG/CHRS Expansions</FONT></TD></TR></TABLE><BR>
UDG/CHRS boards (User Defined Graphics / Character Set expansions)<BR>
<BR>
<B>Internal Expansions</B><BR>
The ZX80/ZX81 has two variants of A0-A8 address lines: The normal A0-A8 are
from the CPU, and are wired to RAM and Expansion Port. For character set
addressing A0'-A8' are generated by the ULA, and wired to the BIOS ROM.<BR>
The dk'tronics/kayde expansions are mounted as internal daughterboard,
plugged to the BIOS ROM chip. That method allows to use the A0'-A8' lines.<BR>
<BR>
<B>External Expansions</B><BR>
The QS expansion connects to expansion port. Accordingly, it must externally
reproduce some of the ULA functionality (latch the character number &
increment the LINECTR) in order to generate its own A0'-A8' signals. The QS
also takes the inverse flag as character MSB (aka A9'), allowing to use 128
different symbols rather than only 64.<BR>
<BR>
<B>dk'tronics 4K Graphics ROM (plus optional RAM)</B><BR>
Contains a 4K EPROM, mapped to 2000h-2FFFh, with seven new character sets (of
64 symbols each), the region at 2E00h-2FFFh is mainly FFh-filled, and
contains only a few USR functions for selecting the new character sets (each
one: "LD A,20h+N*2, LD I,A, RET", except N=7: selects the default ZX81
charset with I=1Eh). As an upgrade option, the board can be fitted with 1K or
2K SRAM, or 4K EPROM (mapped to 3000h-3xFFh). dk'tronics offered 6 programs
for use with the hardware:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Asteroids
Centipede
Defender
Meteor Storm
Space Invaders
Character Development System (aka UDG, User Defined Graphics editor)
</TD></TR></TABLE>The pre-defined ROM symbols are possibly useful for some games, but useless
for others. Only 64 symbols can be used at once, for example one cannot
simultaneously display lower-case letters and numeric digits. Many symbols
(like A-Z) are duplicated in several 64-character banks, so one gets far less
than 512 &lt;different&gt; characters.<BR>
Note: Of the above 6 programs, only Space Invaders and UDG are found in the
internet. There's also a Centipede version, but it doesn't support the
hardware (it can be somewhat tweaked by typing "RAND USR 11904" before "RUN",
but this causes its text screens to become distorted, only its game screen
looks more or less as it should).<BR>
<BR>
<B>Kayde 4K ROM (plus optional RAM)</B><BR>
This is a (probably unlicensed) clone of the dk'tronics 4K character board.
Locations 000h..7FFh and A00h..FFFh in the ROM are 1:1 byte-identical to the
dk'tronics ROM. Locations 800h..9FFh are modified: Containing inverse symbols
in dk'tronics ROM, and Pac-Man symbols in Kayde ROM. Kayde advertised three
games that support their hardware:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Centipede
Peckman (this one probably requires the Kayde-ROM with Pac-Man symbols)
Space Invaders
</TD></TR></TABLE>The circuit with three logic chips & three ROM/RAM sockets looks identical to
the dk'tronics board (aside from some cosmetic differences: top/bottom layers
exchanged, and Kayde text instead of dk'tronics text on the PCB). Even the
advert seems to be a shameless copy of the dk'tronics one (though with slight
mis-spellings in the 1st advert: saying it "fits nearly" instead of "fits
neatly"). dk'tronics had adverts in Sinclair User issues 1..8, Kayde had
adverts in the same magazine, issues 4..8.<BR>
Note: One or two years later, Kayde also (illegally) cloned Compusounds
patented "Telesound 84" (an add-on for amplifying the Spectrum's ULA sound
via TV).<BR>
<BR>
<B>QuickSilva QS CHRS board</B><BR>
Maps 1K RAM to 8400h-87FFh, allows to define and display 128 characters (64
normal, and, independently thereof, 64 inverted characters) (for example, the
inverse ones can be assigned as lowercase letters).<BR>
On power-up, the RAM is uninitialized, so garbage would be displayed.
Quicksilva has "solved" this problem by providing a mechanical switch, where
the user can (must) manually enable/disable the CHRS feature (there is no I/O
port to do this by software). Moreover, the board has 4 DIP switches,
presumably for adjusting HSYNC or so (should be all off for ZX81 in SLOW
mode, or switch 3,4 on for ZX80 and ZX81 in FAST mode) (whereas "FAST" mode
is probably meant to mean PAUSE/INPUT, accordingly software should avoid to
switch between SLOW mode and PAUSE/INPUT).<BR>
Depending on the invert bit, the first or second 512 bytes are mirrored to
1E00h on ULA access (however, the CPU is still able to read ROM from 1E00h;
though, eventually, ROM-reading MIGHT work only when the enable switch is
off?)<BR>
Emulating the QS CHRS board with its original crude manual enable switch is
easy, but automatically detecting and enabling it is more difficult, possible
ways are: Detect the original driver (won't work with custom drivers), or,
detect if 8400h..87FFh contains data whilst all other RAM at 8000h and up is
zero-filled (or filled with whatever values you stored there on power-up).<BR>
<BR>
<B>Haven Hardware chrs board</B><BR>
Another character thing. Seems to be able to map RAM (or ROM?) to 1E00h-1FFFh
and 3E00h-3FFFh. Low-level details are unknown? (sounds similar to the QS
board)<BR>
<BR>
<B>AGB UDG graphic card</B><BR>
Whatever. Reportedly mirrors 512 byte RAM to 1E00h.<BR>
<BR>
<B>Memotech UDG Interface</B><BR>
Whatever - if it does exist at all. It is mentioned only on one single
webpage.<BR>
<BR>
<B>Unknown UDG Type</B><BR>
There is a game called "FROGGER-HR" by "E LANTING". It sets I=20h and uses
character RAM at 2000h (similar to dk'tronics/kayde, but having RAM at that
location, not ROM). Unknown which hardware does support this (if any - it's
also possible that the game is homebrewn and works only with emulators).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx81videononstandardhiresexpansions"></A><FONT SIZE=+2>&nbsp;ZX81 Video Nonstandard HIRES Expansions</FONT></TD></TR></TABLE><BR>
<B>QuickSilva QS HI-RES screen board</B><BR>
Maps 2K ROM to 2800h-2FAFh (errr, more likely: 2800h..2FFFh or so), and 6K
RAM to A800h-BFFFh. Low-level details are unknown?<BR>
<BR>
<B>Memotech HRG</B><BR>
Maps 2K EPROM to 2000h-27FFh. The EPROM contains USR function for
high-resolution PLOT and LINE drawing functions. Supported resolution is
248x192. Seems to require a separate RAM expansion for use as video RAM.
Aside from the EPROM, it does contain an overkill of five 74LSxx chips, and
two PAL chips. Low-level details are unknown?<BR>
<BR>
<B>G007 Graphic Card</B><BR>
Whatever.<BR>
<BR>
<B>HRG-MS (Matthias Swatosch)</B><BR>
Technically same as Wilf Ritger's hires, but doesn't work unless first
loading an additional software driver from cassette, before loading the
actual program. The driver contains some USR functions for drawing LINEs from
within BASIC - in the BASIC era it would have been revolutionary, nowadays...
it isn't. The driver loading is more than uncomfortable, and BASIC is crap
anyways.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx81videononstandardpicturesize"></A><FONT SIZE=+2>&nbsp;ZX81 Video Nonstandard Picture Size</FONT></TD></TR></TABLE><BR>
The official picture size is 32x24 tiles (256x192 pixels) with huge borders.
However, on a PAL screen, the ZX81 can display 40x34 tiles (320x272 pixels).<BR>
<BR>
<B>34-lines Quicksilva Defender</B><BR>
Displays 31x32 tiles (the advert claims 34 lines, but it's actually only 32
lines). There's some glitch in the blanking/retrace that causes the topmost
lines to become ultra-bright and horizontally unstable (at least on my
Philips TV Set). Moreover, the framerate is only 43Hz (that part works fine
on my TV Set).<BR>
Note: The game was also announced for ZX80 and works without NMI (even the
ZX81 version doesn't use NMIs).<BR>
<BR>
<B>Wilf Ritger's WRX1K</B><BR>
A variant of Wilf Ritger's WRX hires. WRX1K works on an unexpanded ZX81 with
1K RAM, accordingly, the picture/bitmap is tiny.<BR>
<BR>
<B>MAXDEMO</B><BR>
Displays 40x32 tiles text and 320x256 pixels hires. There seems to be a
vertical centering glitch: No upper border visible, but 16 lines lower border
visible.<BR>
<BR>
<B>Mixed Video Modes</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Highres Chess (192 hires lines, plus 1-2 text lines)
Maxdemo (splits hires/text regions)
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx81videononstandardcolorexpansions"></A><FONT SIZE=+2>&nbsp;ZX81 Video Nonstandard Color Expansions</FONT></TD></TR></TABLE><BR>
<B>Lambda Color Module</B><BR>
External Color Module designed for the Lambda 8300. Contains 1K Color RAM
(with color attributes similar as on ZX Spectrum). Supports 8 colors, but the
palette is still unknown.<BR>
It should also work with ZX81, though with some restrictions: The normal ZX81
BIOS doesn't initialize the color attributes on power-up (upon power-on the
module is disabled, displaying a "white-on-white?" picture; to activate color
RAM one needs to init the RAM at 2000h-2FFFh and then enable it via write to
3001h) (the unit isn't re-disabled on warmboot via /RESET, only on power-on),
and the ZX81 doesn't have a composite video output (so one would need some
soldering to extract the monochrome video signal), and, compared to Lambda,
the ZX81 has black/white inverted, so ink/paper will be exchanged.<BR>
See Lambda 8300 for details.<BR>
<BR>
<B>Interface 8 x Couleurs / Carte Couleur (PCB: "DISTR.(C) par S.A.M. 001")</B><BR>
A french add-on for the ZX81. Sold by EREL Boutique.<BR>
The interface doesn't contain any RAM for storing color attributes. Instead,
it seems to watch the character numbers being read from D_FILE, and applies
one of the 8 colors when seeing CHR numbers 86h..8Dh (aka inverse [A]..[H]
symbols). The palette is unknown. Also unknown if it changes the foreground
and/or background color. Also unknown if the [A]..[H] symbols are displayed,
or if they are masked.<BR>
Video Output: Outputs UHF (SECAM) and Peritel (SCART, ie. probably RGB). UHF
output is done using ZX81's internal UHF modulator (requires some soldering)
(the signal can be adjusted by potentiometers on the interface, so colors
might be "user-selectable" rather than having a constant palette?). Peritel
requires a special cable that connects to a spare DIL socket on the interface
(the pin-outs of the socket are unknown, so without the original cable, one
could only guess which pins a R,G,B).<BR>
<BR>
<B>Carte couleur</B><BR>
Reportedly made by (provider: DIRECO International).<BR>
Claimed to support 16 colors with SCART.<BR>
Claimed to use ASCII... uh, ASCII, on a ZX81?<BR>
Said to be Chr $ 161 is the first color (pink).<BR>
<BR>
<B>the peripheral color (catalan translation)</B><BR>
As the highest town, the play calling this peripherique tour and see the iron
because Souder Souder had a cable on the peripheral of the anode of diode D9
ordinateur, fortunately, a printed circuit board with the plan had
branchement delivered with the peripheral.<BR>
The curseurs colored bands disappeared and became each other: the F curseur
became a green hand, the K a white band, G one side magenta and yellow L a
band. You could play with a palette of 16 colors:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> White plays 4 or CHR invested $ 160
Yellow key 5 or CHR $ 161
Light Blue plays 6 or CHR $ 162
Green light touch 7 or CHR $ 163
Fusch plays 8 or CHR $ 164
Red key 9 or CHR $ 165
Keyboard has blue or CHR $ 166
Dark gray or key B CHR $ 167
CHR turn gray or C $ 168
Kaki plays D or CHR $ 169
Cyan play E or CHR $ 170
Green plays or F CHR $ 171
Magenta G plays or CHR $ 172
Carmin playing H or CHR $ 173
And navy blue key or CHR $ 174
Black J key or CHR $ 175
</TD></TR></TABLE>Example:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 10 PRINT CHR $ 173
20 PRINT "THREE"
</TD></TR></TABLE>carmine dye gave the word THREE. So then each word you wanted color.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx81joystickexpansions"></A><FONT SIZE=+2>&nbsp;ZX81 Joystick Expansions</FONT></TD></TR></TABLE><BR>
<B>Joystick Ports and Data Bits (U=Up, D=Down, L=Left, R=Right, F=Fire)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Port_Joystick_Type___________________________7_6_5_4_3_2_1_0___Data Bits___
EFFE Nocash A12 joystick (keys 6,7,8,9,0) - - - D U R L F (0=Pressed)
EFFE AGF (cursor mode, A12, keys 6,7,8,0) - - - D U R - F (0=Pressed)
F7FE AGF (cursor mode, A11, key 5) - - - L - - - - (0=Pressed)
DFFE AGF (2nd Joystick, A13, keys Y,U,I,P) - - - D U R - F (0=Pressed)
FBFE AGF (2nd Joystick, A10, key T) - - - L - - - - (0=Pressed)
nnFE PC8300 (ZX81 clone using A9..A13, bit3) - - - - x - - - (0=Pressed)
xx1D Zebra Joystick - - - F R L D U (0=Pressed)
xxBF Timedata ZXM Sound Box, PSG Reg 14 0 F U D L R y x (0=Pressed)
xxDF Mikro-Gen (Digital joystick)(Frogs) - - - F L R D U (0=Pressed)
MEM Mikro-Gen (Analog joystick) F a a a a a a a (analog)
MEM Quicksilva Sound Board, PSG Reg 15 ? ? ? ? ? ? ? ? (?=Pressed)
???? Microdigital TK83/TK85 (DIN socket) ? ? ? ? ? ? ? ? (?)
</TD></TR></TABLE><BR>
<B>Quicksilva "Joystick" Games</B><BR>
As far as known, Quicksilva has NOT manufactured a joystick interface.
However, at least one Quicksilva game (Asteroids) allows to use PSG reg 15
(of the QS Sound board) as joystick port (where the user needs to wire the
joystick to the 16bit I/O port).<BR>
<BR>
<B>Micro Gen - for Micro Gen's "Space Raider" game (maybe also for "Bomber")</B><BR>
For several Micro Gen games. Requires their 4-channel A/D converter board.
Can be used with 2 joysticks - that is, apparently ANALOGUE joysticks.<BR>
Note: The company name is written with "c" or "k": Micro Gen (adverts and
catalog), or Mikro Gen (cassette inlays).<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> IN (xxDFh) -- bits 1,2 // lunar: bit2,3,4
xx == select something ?
</TD></TR></TABLE>scramble: LD A,(3E80h) others: LD HL,3E80h (3E80h is 16000 decimal)<BR>
scramble uses ONLY 3E80 (not DF), and supports up/dn/rt/fire<BR>
<BR>
<B>Mikro-Gen Analog Joystick (Memory 3E80h)</B><BR>
Memory mapped to address 3E80h (=16000 decimal). Write to 3E80h:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h Axis 0 (request vertical position, and bit7=not used)
01h Axis 1 (request horizontal position, and bit7=Fire button 1=Pressed)
??h Axis 2,3 (for second joystick) (not used by any games)
</TD></TR></TABLE>There must be a delay after writing (ld b,96h, djnz $). Thereafer, reading
from 3E80h:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> returns 7bit analog for selected axis (and bit7=fire, if any)
vertical: 00h..7Fh = up..down
horizontal: 00h..7Fh = left..right
</TD></TR></TABLE>Supported by several Mikro-Gen games (and one Quicksilva game):<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Space Invaders (Mikro-Gen) (uses analog value as screen position)
Scramble (Mikro-Gen) (converts analog value to digital move/no move)
Bomber (Mikro-Gen) (supports both digital and analog joysticks)
Croaka Crawler (aka Hopper) (Quicksilva)
</TD></TR></TABLE><BR>
<B>Mikro-Gen Digital Joystick (Port DFh)</B><BR>
This is the "inofficial" digital joystick used in several Mikro-Gen games.
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Lunar Rescue (Mikro-Gen)
Frogs (Mikro-Gen)
Bomber (Mikro-Gen) (supports both digital and analog joysticks)
Tempest (also does a single read from 3E80h, but otherwise supports DFh only)
</TD></TR></TABLE>Inofficial meaning that Mikro-Gen doesn't ever seem to have advertised the
digital joystick (either they did silently replace their analog joystick by
the digital one, or above games are homebrewn patches).<BR>
<BR>
<B>Thurnall Electronics - see advert from them</B><BR>
Spectrum Version advertised as "The Winners Joystick". Supports Cursor+Rubout
keys, and Q-A-Z-X keys.<BR>
<BR>
<B>AGF Joystick (from AGF Hardware)</B><BR>
Available for ZX81 and Spectrum. Both versions work as so:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 5-6-7-8-0 Joystick 1 (Cursor keys & rubout)
T-Y-U-I-P Joystick 2 (same data bits as above, but other address lines)
</TD></TR></TABLE>The joystick interface connects to expansion port. For some reason, only the
keyboard OR joystick can be operated at a time - there is a switch to select
between keyboard and joystick mode.<BR>
<BR>
<B>AGB - JOYSTICK II : [driver in the P_Tools directory]</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Reportedly: Use the $DF & $EF IN IRQ Port.
Port A: Press "5" LEFT "6" DOWN "7" UP "8" RIGHT "New/Line" FIRE
Port B: Press "A" LEFT "S" DOWN "W" UP "D" RIGHT "F" FIRE
</TD></TR></TABLE><BR>
<B>Timedata ZXM Sound Box - includes joystick port (PSG reg 14)</B><BR>
No known software supporting this.<BR>
<BR>
<B>Zebra Joystick (US) (Port 1Dh)</B><BR>
Supported by a homebrewn Hires Space Invaders game. Zebra also released some
patches for a handful of third-party games.<BR>
hrinvaders --&gt; zebra joystick, port 1Dh<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 up (0=Pressed)
1 down (0=Pressed)
2 left (0=Pressed)
3 right (0=Pressed)
4 fire (0=Pressed)
5-7
</TD></TR></TABLE>zebra listing<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 REM 123456789
2 POKE 16514,219 DB ;\IN A,[1Dh]
3 POKE 16515,29 1D ;/
4 POKE 16516,47 2F ;-CPL
5 POKE 16517,230 E6 ;\AND A,1Fh
6 POKE 16518,31 1F ;/
7 POKE 16519,6 06 ;\LD B,0
8 POKE 16520,0 00 ;/
9 POKE 16521,79 4F ;-LD C,A
10 POKE 16522,201 C9 ;-RET
20 PRINT USR 16514;
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx81soundexpansions"></A><FONT SIZE=+2>&nbsp;ZX81 Sound Expansions</FONT></TD></TR></TABLE><BR>
<B>ZON-X81 Sound (Bi-Pak)</B><BR>
Contains a PSG sound chip, built-in speaker with manual volume control. There
seems to be no user I/O port.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> F = 1625000 Hz / 16 / nnn
</TD></TR></TABLE>Parameters are poke'd to RAM, and then forwarded via USR call.<BR>
Uses "1 REM YYPEEK TO YYPEEK ?TAN"<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> OUT (CFh or DFh),A ;index
OUT (0Fh),A ;data (w)
</TD></TR></TABLE>The manual is unclear about the "index" port:<BR>
BASIC example suggests "TO" token = port DFh.<BR>
But ASM example suggests port CFh.<BR>
Maybe both are working. Anyways, the recommended address would be DFh
(assuming that the manual was mainly addressed to BASIC programmers, and the
ASM example being only a confused side note). The technical specs in the
french "Interface Sonore" manual uses DFh, too).<BR>
Note: The Spectrum version uses ports FFh and 7Fh, maybe these do work on
ZX81, too (though under BASIC, 7Fh cannot be entered via keyboard, which may
explain why the manual used other values)<BR>
Supported by<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Cosmic (brazilian magazine Revista Micro Sistemas, Oct/1986)
Lunar 10 (brazilian magazine Revista Micro Sistemas, Nov/1986)
</TD></TR></TABLE><BR>
<B>ZXM Sound Box (Timedata) (OUT 159/223)</B><BR>
For ZX81 and Spectrum.<BR>
Contains a 8912 PSG sound chip, built-in speaker with manual volume control,
can be optionally connected to external amplifier. There is a 9pin DSUB
atari/commodore joystick port; can be also used as 7bit user I/O port.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> F = 100000 Hz / nnn ;approximately, according to manual
</TD></TR></TABLE>the above 100kHz is probably meant to be 3.25MHz/32.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> OUT (159),A ;9F index ;\same addresses for ZX81 and Spectrum, ZX81
OUT (223),A ;DF data (w) ; accesses via POKE+USR, Spectrum via OUT token
IN A,(191) ;BF data (r) ;/ &lt;--- for joystick port
</TD></TR></TABLE>DSUB 9pin male Pin-outs<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Pin Bit
1 PSG.PortA.Bit5 up / forward
2 PSG.PortA.Bit4 down / back
3 PSG.PortA.Bit3 left
4 PSG.PortA.Bit2 right
5 PSG.PortA.Bit1 general purpose (usually 1) (C64: Pot Y)
6 PSG.PortA.Bit6 Fire
7 +5V
8 GND
9 PSG.PortA.Bit0 general purpose (usually 1) (C64: Pot X)
</TD></TR></TABLE>According to manual, PSG.PortA.Bit7 is always zero.<BR>
Supported by:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Sound Box Super Editor (Timedata) (zxm demo tape & type-in listing in manual)
</TD></TR></TABLE><BR>
<B>QS Sound Board (QuickSilva)</B><BR>
AY-3-8910. Two 8bit I/O ports. Reportedly memory mapped to 7FFEh..7FFFh (see
Sinclair User, Issue 2, May 1982, Page 24).<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 7FFFh index (W)
7FFEh data (R/W)
</TD></TR></TABLE>Supported by:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Cosmic Guerilla (Quicksilva)
Croaka (aka Hopper) (Quicksilva)
Defenda (Quicksilva)
Space Invaders
Asteroids (Quicksilva) (also supports PSG reg 15 as alternate joystick)
Scramble (Quicksilva)
</TD></TR></TABLE>PSG reg 15: used by asteroids (as OUTPUT, probably as pull-up)<BR>
<BR>
<B>William Stuart Systems ZX80/ZX81 Music Synthesiser</B><BR>
Three-part music and sound effects. 16-line control port for home security,
robot control, etc. Can be used with the "Composer" music program.<BR>
<BR>
Telesound 82 (ZX80/ZX81 version) - stops flicker (is THAT sound related?)<BR>
3-channel Sound with 16bit I/O port (Bolton Electronics)<BR>
Motherboard plus Sound-Card (Watford)<BR>
<BR>
<B>Interface Sonore</B><BR>
(assumed to be from Mageco Electronic)<BR>
(actually, seems to be same as the Bi-Pak thing)<BR>
AY-3-8912<BR>
Manual page 3 contains (distorted) instructions for "1 REM Y1PEEK TO Y2 ?TAB"<BR>
which would mean "LD A,index; OUT [DF],A; LD A,data; OUT [0F],A; RET"<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> But...
</TD></TR></TABLE>Manual page 79-80 contains "Carte Sonore QS" 7FFEh,7FFFh stuff.<BR>
These pages probably refer to a DIFFERENT and MEMORY MAPPED sound interface.<BR>
Namely, to the QS Sound Board (see above).<BR>
<BR>
<B>ZXS Speech Synthesiser (Timedata)</B><BR>
<B>DCP Microdevelopments Speech Pack (1982) for ZX81</B><BR>
Speech hardware. Both DCP and Timedata also released versions for ZX
Spectrum. ZXS might be allophone based (?), DCP isn't allophone based (it
uses a fixed digitized vocabulary stored in ROM).<BR>
<BR>
<B>Lambda 8300</B><BR>
ZX81 clone with built-in speaker. The speaker is software controlled (toggled
HIGH/LOW via IN A,[F5h]).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81memorymapandsystemarea"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81 Memory Map and System Area</FONT></TD></TR></TABLE><BR>
<B>Overview</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0000-1FFF BIOS ROM (8KBytes)
2000-3FFF not used
4000-43FF Internal RAM (1 KByte)
4000-7FFF External RAM (16 KBytes)
</TD></TR></TABLE>Internal RAM is disabled (and cannot be accessed) when external RAM is
installed.<BR>
<BR>
<B>ZX81 RAM Map</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 4000 System Area (see below)
407D BASIC Program
D_FILE Video Memory (BG Map)
VARS BASIC Variables
E_LINE-1 Byte 80h
E_LINE Input Buffer/Workspace
STKBOT BASIC Calculator Stack
STKEND Machine Stack/Free Memory
SP Machine Stack/In Use (SP is meant to be the CPUs SP register)
ERR_SP GOSUB Stack
RAMTOP USR Programs (Begin of unused/reserved memory)
</TD></TR></TABLE><BR>
<B>ZX81 System Area</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Addr. Name Expl
4000 ERR_NR Errorcode-1
4001 FLAGS Various BASIC Control flags
Bit0=used (purpose unknown)
Bit1=Redirect Output to printer
Bit2=used (purpose unknown)
Bit3-5=not used
Bit6=used (purpose unknown)
Bit7=used (purpose unknown)
4002 ERR_SP Pointer to top of Machine Stack / Bottom of GOSUB Stack
4004 RAMTOP Pointer to unused/free memory (Changes realized
at next NEW or CLS)
4006 MODE Selects [K], [L], [F], or [G] Cursor
4007 PPC Line Number of most recently executed BASIC line
---Begin of Save Area---
4009 VERSN Should be 00h to identify ZX81 cassette files (FFh=Lambda)
400A E_PPC Line Number of currently selected line [&gt;] Cursor
400C D_File Pointer to Video Memory (BG Map) / End of Basic Program
400E DF_CC Pointer to VRAM Address for PRINT
4010 VARS Pointer to BASIC Variables Area
4012 DEST Pointer to Variable when assigning a value to it
4014 E_LINE Pointer to Input Buffer/Workspace, and to --End of Save Area--
4016 CH_ADD Pointer to next interpreted character
4018 X_PTR Pointer to character prior to [S] Symbol (=Syntax Error) (or
ptr to aborted/breaked line)
401A STKBOT Pointer to BASIC Calculator Stack / End of
Input Buffer/Workspace
401C STKEND Pointer to bottom of Machine Stack / End of Calculator Stack
401E BERG Calculator B-Register
401F MEM Pointer to Calculator Memory (usually same as MEMBOT)
4021 - Not used
4022 DF_SZ Number of lines in lower display section (including 1 blank
line)
4023 S_TOP Line Number of first line for automatic LISTing
4025 LAST_K Keyboard - Recently pressed key (4025=row, 4026=shift/column)
4027 DEBOUN Keyboard - Debounce State (key release delay)
4028 MARGIN Vertical Border Height (55 lines at top/bottom for 50Hz,
31 for 60Hz)
4029 NXTLIN Address of next BASIC line which is to be executed,
pointing to a byte &gt;=40h when stopped, indicates
autostart address in cassette files.
402B OLDPPC Line Number for CONT
402D FLAGX Various Flags
Bit0 used (purpose unknown)
Bit1 used (purpose unknown)
Bit2-4 not used
Bit5 used (purpose unknown)
Bit6 used (purpose unknown)
Bit7 not used
402E STRLEN Length of string during assignment
4030 T_ADDR Pointer to next item in Syntax Table (or INPUT's old S_POSN)
4032 SEED Random Number Seed
4034 FRAMES Decrementing Video Frame Counter (Bit15: 0=PAUSE, ie.
display ON, program PAUSEd)
4036 COORDS X-Coordinate of last PLOT, Y-Coordinate of last PLOT
4038 PR_CC Least significant byte of PRBUFF printer buffer pointer
4039 S_POSN X-Coordinate for PRINT, Y-Coordinate for PRINT
403B CDFLAG Various Flags
Bit7: Current Speed (1=SLOW (Display Enable), 0=FAST)
Bit6: Requested Speed (or old speed during
pause/cassette io, etc)
Bit5-1: Not used
Bit0: Keystroke (0=None, 1=Yes)
403C PRBUFF Printer Buffer 32 characters + NEWLINE (76h)
405D MEMBOT Default workspace for BASIC Calculator
407B - Not used (2 bytes)
</TD></TR></TABLE><BR>
<B>ZX80 Memory Map</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 4000..4027 System Area
4028..(4008)-1 Basic Program
(4008)..(4004 or 400A)-1 VARS
(4004 or 400A)..(400C)-1 Input Buffer, and probably something else ???
(400C)... VRAM
...
</TD></TR></TABLE><BR>
<B>ZX80 System Area</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 4000 ERR_NR Error Number (one less than report code)
4001 FLAGS Various Flags to control BASIC System
7 1-Syntax off 0-Syntax on
6 1-Numeric result 0-String result
5 1-Evaluating function (not used)
3 1-K cursor 0-L cursor
2 1-K mode 0-L mode
0 1-No leading space 0-Leading space
4002 PPC Line number which is to be executed next (bit15: 1=stopped)
4004 P_PTR Position in RAM of [K] or [L] cursor
4006 E_PPC Line Number of current line with [&gt;] cursor (for LIST)
4008 VARS Address of start of variables area (end of BASIC Program)
400A E_LINE Address of start of Edit Line (end of VARS) (-save area end-)
400C D_FILE Start of Display File (VRAM) (end of Edit Line/Input Buffer)
400E DF_EA Address of the start of lower screen
4010 DF_END Display File End
4012 DF_SZ Number of lines in lower screen
4013 S_TOP The number of first line on screen
4015 X_PTR Address of the character preceding the [S] marker
4017 OLDPPC Line number to which CONTINUE jumps
4019 FLAGX More flags.
7 1-K mode 0-L mode
6 1-Numeric result 0-String result
5 1-Inputting 0-Editing
401A T_ADDR Address of next item in syntax table
401C SEED The seed for the random number
401E FRAMES Count of frames shown since start-up (incrementing)
4020 DEST Address of variable in statement
---Active/Basic:
4022 RESULT Value of the last expression
4024 S_POSN_X Column number for print position
4025 S_POSN_Y Line number for print position
4026 CH_ADD BASIC program pointer (address of next char/token)
---Pause/Input:
4022 - Keyboard debounce
4023 MARGIN Screen border height
4024 ?
4026 LAST_K Keyboard last key pressed (4026=row, 4027=column)
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81memorymirrorsandexpansions"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81 Memory Mirrors and Expansions</FONT></TD></TR></TABLE><BR>
<B>Memory Overview</B><BR>
RAM is originated at 4000h, for 1K RAM: at 4000h-43FFh; 48K: at 4000h-FFFFh,
the area below 4000h is used only when more than 48K are installed.<BR>
In the ZX world, memory accesses can be split into three categories: data
read, data write, and opcode read. Opcode read is sensed by the CPUs /M1
signal, and behaves different than normal data read in case that A15 is HIGH,
ie. for addresses in range from 8000h-FFFFh.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> address code read write
0000..1FFF ROM ROM --- ;all ZX81's
2000..3FFF RAM4 RAM4 RAM4 ;ZX81 with 56K only
4000..7FFF RAM1 RAM1 RAM1 ;ZX81 with 16K or more RAM
8000..BFFF VRAM2 RAM2 RAM2 ;ZX81 with 32K or more RAM
C000..FFFF VRAM1 RAM3 RAM3 ;ZX81 with 48K or more RAM (*)
(*) That, for the RAM3 part, VRAM1 is of course found in all ZX with 16K
</TD></TR></TABLE>The memory region 8000h-FFFFh cannot be used to execute machine code
programs; any opcodes in that region with Bit 6 cleared are treated as video
output (and are executed as NOPs).<BR>
Opcodes/video data at C000-FFFFh are read from memory at 4000h-7FFFh - the
software should usually write video data into memory at 4000h-7FFF, and
'execute' the data in the mirrored region at C000-FFFF.<BR>
<BR>
<B>1K RAM</B><BR>
Default ZX81 includes only 1K RAM at 4000h-43FFh. However, the default
RAM and ROM select signals are mirroring ROM across 0000h-3FFFh and
8000h-BFFFh, and RAM at 4000h-7FFFh and (including 'data read' accesses)
at C000h-FFFFh.<BR>
The ZX81 mainboard provides space for either two 1K x 4bit SRAM chips,
or one 1K x 8bit SRAM chip (with L1 jumper closed).<BR>
<BR>
<B>2K RAM</B><BR>
The american 'ZX81' (Timex TS1000) appears to have been delivered with 2K
internal memory. The socket for 1K x 8bit SRAM on the ZX81 mainboard may be
used (by closing L2 jumper) for a 2K x 8bit SRAM chip.<BR>
<BR>
<B>16K RAM</B><BR>
Even though above described 1K RAM signals are providing memory space
for up to 16K RAM, the Memotech expansions (not sure about Sinclair or
other expansions) are supplying their own RAM and ROM select signals;
ROM is then located at 0000-1FFF only, and RAM at 4000-7FFFh only, all
other areas are unused, typically 'FFh filled'. Except that, video
memory opcode reads (but not data reads) from C000h-FFFFh are mirrored
to 4000h-7FFFh as usually.<BR>
Timex TS1500 has been delivered with 16K built-in RAM.<BR>
<BR>
The 16K RAM configuration may be more or less treated as standard
configuration - programmers should recurse that below expansions of 32K
or more RAM haven't been very popular - thus any programs that require
more than 16K memory won't work on most ZX computers.<BR>
<BR>
<B>32K RAM</B><BR>
RAM is located at 4000h-BFFFh, whereas the upper half may be used to
store data and/or to 'execute' video code, but not for normal machine
code program code.<BR>
Note that the BIOS memory detection ends at 8000h, the BIOS will detect
only a maximum of 16K RAM - and the stack pointer will be then initiated
at 8000h. Thus, loading large cassette files will overwrite the stack.
When using more than 16K RAM, the RAMTOP identifier in the system area
must be changed manually by POKE instructions, and then applied by a NEW
instruction (or by a short program that moves stack data and stack
pointers to the new addresses).<BR>
Care should be taken that video memory may not cross the 7FFFh/8000h
boundary; Video data at 7FFFh is executed by addressing FFFFh, and thus
the next address will be 0000h instead 8000h! Ie. video memory may be
located in either one of the two 16K blocks, not in both.<BR>
<BR>
<B>48K RAM</B><BR>
RAM is located at 4000h-FFFFh, same restrictions as for 32K RAM apply.
The memory at C000h-FFFFh can be used as data storage only, but not for
machine code execution, and not for video data 'execution'.<BR>
When patching the RAMTOP value use the maximum of FFFFh (indicating 48K
minus one byte), as video memory must be below C000h, BASIC program code
is restricted to less than 32K as well, BASIC variables may use the
additional memory though.<BR>
Some 16K expansions can be combined with 32K expansions to gain a total
of 48K RAM.<BR>
<BR>
<B>64K RAM</B><BR>
Even though called "64K" expansions, most or all of these expansions do
not seem to support bank switching which'd allow to switch RAM into the
8K BIOS ROM area at 0000h-1FFFh, so only 56K of RAM at 2000h-FFFFh can
be used.<BR>
As for 48K RAM, the highest RAMTOP value would be FFFFh, the 'RAMBASE'
is fixed at 4000h, so that the additional memory at 2000h-3FFFh cannot
be used by the BIOS/BASIC interpreter.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81memorybinarydatamachinecodeprograms"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81 Memory Binary Data/Machine Code Programs</FONT></TD></TR></TABLE><BR>
<B>Depositing Binary Data/Program in Memory</B><BR>
The ZX81 does not directly support loading binary files from cassette,
when using LOAD, a memory image is loaded which contains the BIOS system
variables, the BASIC program, the video memory, and the BASIC variables.<BR>
The following are places that can be used as reserved area for binary
code.<BR>
<BR>
<B>Using a REM instruction (in the program area)</B><BR>
Preferably locate the REM in the first line number (ensuring that it is
located at a fixed memory address), the length of the comment must
provide enough space for the program, then use POKE or else to fill the
program code into it.<BR>
RESTRICTION: The comment may not contain the value 76h (the NEWLINE
character). Thus, the assembler program should not contain a "HALT"
instruction (opcode 76h), or any other opcodes with operand 76h such
like LD A,76h or JP 4276h etc., or any data definitions such like "DB
76h".<BR>
<BR>
<B>Using a string (in the variables area)</B><BR>
Define a string such like A$ and fill it by binary character numbers.
Note that all variables are saved by SAVE command, it is not necessary
that the program itself contains the LET A$=... definition.<BR>
RESTRICTION: The position of the string in memory may change when
(re-)defining other variables, when modifying the BASIC program, or when
altering video memory contents.<BR>
<BR>
<B>Using memory above RAMTOP (outside of the known memory)</B><BR>
By default, RAMTOP (4004h) points to the address following to the
detected RAM area (4400h for 1KByte RAM). The user can alter this
address by using POKE, then type NEW to let the BIOS realize the new
value, all memory above RAMTOP may now be used for whatever purposes.<BR>
RESTRICTION: The (standard) SAVE instruction does not save this area to
cassette.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81cassettefileimages"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81 Cassette File Images</FONT></TD></TR></TABLE><BR>
<B>.81 and .80 Files</B><BR>
These are 1:1 copies of the content of real ZX81 and ZX80 cassette files.<BR>
ZX81 files are copies of the memory area 4009h up to E_LINE-1, the
filename (which is usually part of ZX81 files) is not included in the
file.<BR>
ZX80 files are copies of the memory area 4000h up to E_LINE-1, the
filename is obviously not included as real ZX80 files do not have names.<BR>
<BR>
<B>.P and .O Files</B><BR>
Basically, these are identical as .81 (.P) and .80 (.O) files, except
that an unpredictable amount of garbage is meant to be attached to each
file.<BR>
Older versions of the Xtender emulator seem to have attached 1 byte of
garbage. The current Xtender version apparently dropped this behaviour,
and saves correct length. Files at ftp.nvg randomly contain between
28-38 bytes of garbage, probably caused by a cassette-to-disk transfer
program. And some files appear to have went through a CP/M filesystem,
which caused the length to be rounded up to multiples of 128 bytes.<BR>
Programs that deal with these files should determine the correct length
(by examining the header/system area), and truncate the extra bytes.<BR>
<BR>
<B>.P Files with Filename</B><BR>
Some .P files contain the original "FILENAME.P" (in ZX81 charset) at 003Fh
(within the PRBUFF area) (the purpose is probably to "preserve" long
filenames in MSDOS) (the preceeding bytes at 003Ch are usually 00-1A-1C, or
in FROGGER-HR: 00-1C-1C (unknown purpose)).<BR>
<BR>
<B>.TZX Files</B><BR>
This format was originally designed for the Spectrum, mainly intended to
encode nonstandard formats (copy-protections / turbo loaders). It can be also
used (via ID 19h) for ZX80/ZX81 programs. The format is quite complicated -
it's advantage is that it can contain more than one file (a feature required
for games that are split into two or more files).<BR>
<A HREF="#spectrumcassettetzxformat">Spectrum Cassette TZX Format</A><BR>
<BR>
<B>.C and .S and .V and .B or else</B><BR>
These are not actually real ZX files, programs that include such files won't
work on real ZX81 or ZX80, nor in no$zx. The Xtender emulator includes
several custom functions, allowing the user to create or delete directories
on the harddisk, probably as well as to format it, and to save these kind of
files.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81cassettefilecontent"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81 Cassette File Content</FONT></TD></TR></TABLE><BR>
<B>ZX81 Data Field (excluding filename)</B><BR>
The data field is loaded to address 4009h, and it contains the system
area (excluding the first 9 bytes), the basic program, the video memory,
and VARS area.<BR>
The system area should contain proper data. Some entries are of special
interest:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 4014h defines the end address (used to calculate the file length)
4029h points to the next executed (autostarted) BASIC line
403Bh indicates if program runs in SLOW or FAST mode (bit 6)
</TD></TR></TABLE>Memory at 403Ch and up may be misused for whatever purpose, video memory
is required to contain 25 HALT opcodes if the file was saved in SLOW
mode.<BR>
<BR>
<B>ZX80 Data Field</B><BR>
The data field is loaded to address 4000h, and it contains the whole
system area, the basic program, and VARS area. Video memory is NOT
included in ZX80 files.<BR>
The system area should contain proper data. The entry at 400Ah defines the
end address (used to calculate the file length). Memory at 4028h and up may
be misused for whatever purpose.<BR>
Normally, ZX80 files cannot be autostarted - except via "nocash LD H,L trick":<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> ;nocash LD H,L trick for autostarting ZX80 files, 9/2009 by martin korth
4000h 8 x 00h ;System area: Zerofilled stuff
4008h 402Ch ;System area: Pointer to VARS
400Ah nn3Dh ;System area: Pointer to End of file
400Ch 1Ch x 00h ;System area: Zerofilled stuff
4028h 00h,01h,65h,76h ;BASIC program: Line 0001, LD H,L opcode, NEWLINE
402Ch 80h ;VARS area: End code
402Dh 13h x 00h ;Unused/padding (for entryoint 4040h)
4040h ... ;Machine code (entrypoint at 4040h)
xxxxh (xx3Dh-$) x 00h ;Unused/padding (for end address xx3Dh)
xx3Dh ;End of file (must be at xx3Dh)
</TD></TR></TABLE>After loading, the BASIC line is LISTed on the screen. The ZX80 BIOS doesn't
replace invalid tokens in range of 40h..7Fh by question marks, so Token 65h
is written as-is to VRAM (ie. as LD H,L opcode). The file must end at
xx3Dh, so the first character line starts at xx40h, which is (normally)
excecuted 8 times via JP HL from inside of the IRQ handler. After first
execution, the LD H,L opcode changes HL=xx40h to HL=4040h, so the next IRQ
jumps to the autostart entryoint at 4040h. That is still done with IRQs
enabled, so the first opcode at 4040h should be a DI.<BR>
Note: Emulators that do not handle opcodes in VRAM should reproduce autostart
as "IF [402Ah]=7665h THEN JP 4040h" after loading the file (that, preferably
with registers and memory initialized as on real hardware).<BR>
<BR>
<B>Maximum File Length</B><BR>
Files should usually not exceed 16 KBytes. The memory detection
procedure in both ZX80 and ZX81 BIOS stops after 16 KBytes (at 8000h),
and initializes the stack pointer at that address, even if more memory
is installed. Thus loading files of 16K or more would destroy the stack
area (unless a separate loader has previously moved the stack area to
another location).<BR>
However, most ZXes don't have more than 16K RAM, so bigger files won't
work on most computers anyways.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zx80zx81cassettesignals"></A><FONT SIZE=+2>&nbsp;ZX80/ZX81 Cassette Signals</FONT></TD></TR></TABLE><BR>
<B>ZX81 Cassette File Structure</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> x seconds your voice, saying "filename" (optional)
x seconds video noise
5 seconds silence (only some clock cycles required for ZX81)
1-127 bytes filename (bit7 set in last char)
LEN bytes data, loaded to address 4009h, LEN=(4014h)-4009h.
1 pulse video retrace signal (only if display was enabled)
x seconds silence / video noise
</TD></TR></TABLE>The data field contains the system area, the basic program, the video
memory, and VARS area.<BR>
<BR>
<B>ZX80 Cassette File Structure</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> x seconds your voice, saying "filename" (optional)
x seconds video noise
5 seconds silence (at least 0.5 seconds REQUIRED for ZX80)
LEN bytes data, loaded to address 4000h, LEN=(400Ah)-4000h.
x seconds silence / video noise
</TD></TR></TABLE>ZX80 files do not have filenames, and video memory is not included in
the file.<BR>
<BR>
<B>File End</B><BR>
For both ZX80 and ZX81 the fileend is calculated as shown above. In
either case, the last byte of a (clean) file should be 80h (ie. the last
byte of the VARS area), not followed by any further signals except
eventually video noise.<BR>
<BR>
<B>Bits and Bytes</B><BR>
Each byte consists of 8 bits (MSB first) without any start and stop
bits, directly followed by the next byte. A "0" bit consists of four
high pulses, a "1" bit of nine pulses, either one followed by a silence
period.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0: /\/\/\/\________
1: /\/\/\/\/\/\/\/\/\________
</TD></TR></TABLE>Each pulse is split into a 150us High period, and 150us Low period. The
duration of the silence between each bit is 1300us. The baud rate is
thus 400 bps (for a "0" filled area) downto 250 bps (for a "1" filled
area). Average medium transfer rate is approx. 307 bps (38 bytes/sec)
for files that contain 50% of "0" and "1" bits each.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="hardwareconnectorsupgrading"></A><FONT SIZE=+2>&nbsp;Hardware, Connectors, Upgrading</FONT></TD></TR></TABLE><BR>
<B>Hardware Plugs'n'Pins</B><BR>
<A HREF="#hwexternalconnectors">HW External Connectors</A><BR>
<A HREF="#hwinternalpins">HW Internal Pins</A><BR>
<BR>
<B>Hardware Modifications</B><BR>
Below are some ideas of how to attack ZX hardware just by using a few
resistors, diodes and/or some wires. Ie. it's all very simple stuff, not
requiring special hardware or etched circuit boards, but nethertheless
quite useful and effective.<BR>
<BR>
<A HREF="#hwreplacingthezx81rombyaneprom">HW Replacing the ZX81 ROM by an EPROM</A><BR>
<A HREF="#hw56kramupgrade">HW 56K RAM Upgrade</A><BR>
<A HREF="#hwconnectingajoystick">HW Connecting a Joystick</A><BR>
<A HREF="#hwmakingthezx81faster">HW Making the ZX81 Faster</A><BR>
<A HREF="#hwupgradingrampaksfortruehiresgraphics">HW Upgrading RamPaks for True Hi-Res Graphics</A><BR>
<A HREF="#hwconnectingamonitor">HW Connecting a Monitor</A><BR>
<A HREF="#hwgettingridofthe9vdcpowersupply">HW Getting rid of the 9V DC Power Supply</A><BR>
<A HREF="#hwuploadingprogramsfromthepctothezx81">HW Uploading Programs from the PC to the ZX81</A><BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="hwexternalconnectors"></A><FONT SIZE=+2>&nbsp;HW External Connectors</FONT></TD></TR></TABLE><BR>
<B>TV - Video Output - UHF Channel 36 (Cinch, female)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Ring: Shield
Tip: TV Signal
</TD></TR></TABLE>Note that modern TV sets (such manufactured after 1981, especially such
with automatic channel-detection) might have problems to detect/handle
the signal. If necessary, adjust the contrast/brightness, and (as far as
supported) adjust the channel manually.<BR>
<BR>
<B>EAR - Cassette Input (from recorder earphone socket to ZX81)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Ring: Ground
Tip: Cassette Input
</TD></TR></TABLE><BR>
<B>MIC - Cassette Output (from ZX81 to recorder microphone socket)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Ring: Ground
Tip: Cassette Output
</TD></TR></TABLE>This is in fact the video signal, output through resistor and
capaciator, causing black and white stripes to be displayed during
cassette output.<BR>
<BR>
<B>9V DC - Power Supply</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Ring: Ground
Tip: 9V DC
</TD></TR></TABLE>Even though using the official 9V ZX power supply, the voltage is rather
11V than 9V in my computer. Internally, the ZX81 is operated at 5V,
generated from a 7805 voltage regulator, so the input voltage could be
anything in range from 7V up to I think 24V. However, a higher voltage
would heat up the regulator even more, and be aware that it is output to
the expansion port, possibly damaging attached hardware if it is too
high.<BR>
<BR>
<B>Power Consumption</B><BR>
Internal 5V, 0.31A, ie. 1.55W, without 16K RAM<BR>
Internal 5V, 0.39A, ie. 1.95W, with Memotech Mempak 16KB<BR>
<BR>
<B>Expansion Port (46 Pin Cartridge Slot, male)</B><BR>
Only 44 pins are actually used, the two ---SLOT--- marked pins are
cut-out, used as polarisation mark. When attaching a 46pin female plug,
note that you must cut off the plastic at the left and right ends,
preferably before doing any soldering work.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Upper Side Lower Side
1A D7 1B 5V DC
2A /RAM CS 2B 9V DC
3A ---SLOT--- 3B ---SLOT---
4A D0 4B 0V
5A D1 5B 0V
6A D2 6B CLK
7A D6 7B A0
8A D5 8B A1
9A D3 9B A2
10A D4 10B A3
11A /INT 11B A15
12A /NMI 12B A14
13A /HALT 13B A13
14A /MREQ 14B A12
15A /IORQ 15B A11
16A /RD 16B A10
17A /WR 17B A9
18A /BUSAK 18B A8
19A /WAIT 19B A7
20A /BUSRQ 20B A6
21A /RESET 21B A5
22A /M1 22B A4
23A /REFSH 23B /ROM CS
</TD></TR></TABLE>Expansion cartridges should have a male connector at the rear side - allowing
to connect further cartridge(s) - one to each other.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="hwinternalpins"></A><FONT SIZE=+2>&nbsp;HW Internal Pins</FONT></TD></TR></TABLE><BR>
<B>ZX81 Keyboard Connector</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Pin 1-8: A15, A14, A8, A13, A9, A12, A10, A11.
Pin 9-13: KBD0, KBD1, KBD2, KBD3, KBD4.
</TD></TR></TABLE><BR>
<B>Video Signal</B><BR>
The video output consists of a /SYNC signal (low during horizontal and
vertical retrace), and the actual VIDEO signal (low=black, high=white).
In the ZX81 both signals are internally mixed into a single signal, and
then output as shown below at Pin 16 of the Ferranti chip.<BR>
Reportedly these voltages are output on Pin 16 (no idea if/when that happens
in reality, maybe on US versions with VHF-modulator):<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0V sync
2.5V black
5V white
</TD></TR></TABLE>On my own ZX81 with UHF modulator (ie. without the VHF pulldown resistors):<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 2.5V sync
3.7V black
5.0V white
</TD></TR></TABLE>When connecting Pin16 directly to the AV-input of my television set:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0.0V sync
0.5V black
1.0V white
</TD></TR></TABLE><BR>
<B>50Hz/60Hz Refresh Rate Jumper</B><BR>
Even though the display refresh rate is actually software based, the
BIOS determines the local desired rate by reading from I/O port FEh. In
the ZX81, the setting depends on whether Pin 22 of the Ferranti chip is
shortcut to ground or not.<BR>
When it is grounded, by a 0 Ohm "resistor" called R 30, then vertical
blanking time is reduced for 60Hz timing - note that this heavily
reduces the user-available CPU time in SLOW mode.<BR>
<BR>
<B>ZX81 Ferranti ULA</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 A7'
2 A8'
3 A2'
4 A1'
5 A0'
6 /RD
7 /IORQ
8 /WR
9 /MREQ
10 M1
11 A14
12 /RAMCS
13 /ROMCS
14 OSC (EXPANSION)
15 /NMI
16 TV/TAPE
17 /HALT
18 A15
19 D7
20 TAPE.IN
21 D6
22 /NTSC
23 D5
24 D4
25 KDB4
26 D3
27 KDB3
28 D2
29 KDB2
30 D1
31 KDB1
32 D0
33 KBD0
34 GND
35 OSC (CERAM)
36 A3'
37 A4'
38 A5'
39 A6'
40 +5V
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="hwreplacingthezx81rombyaneprom"></A><FONT SIZE=+2>&nbsp;HW Replacing the ZX81 ROM by an EPROM</FONT></TD></TR></TABLE><BR>
Even though the ZX81 includes a 24 pin 8K ROM, it should be usually
delivered with a 28 pin socket - matching for an 28 pin 8K EPROM.
However, a few pins must be exchanged:<BR>
- Disconnect A11 from Pin 20.<BR>
- Disconnect A12 from Pin 23.<BR>
- Connect /OE Pin 22 to /CE Pin 20.<BR>
- Connect A11 to Pin 23.<BR>
(Each counted in 28 pin device units, ie. Pin 14 is lower left.)<BR>
Caution:<BR>
Best use a 2764 EPROM, CMOS chips (27C64) don't seem to work very well -
probably they are too fast and/or outputs aren't amplified enough.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="hw56kramupgrade"></A><FONT SIZE=+2>&nbsp;HW 56K RAM Upgrade</FONT></TD></TR></TABLE><BR>
<B>Upgrading to 56K RAM by krbaker</B><BR>
ROM is enabled at 0000h-1FFFh (8K), RAM at 2000h-FFFFh. /MREQ is for normal
memory access, /RFSH is for character pattern & hires bitmap memory fetches.<BR>
/M1 mirrors 0000h-7FFFh to 8000h-FFFFh on opcode fetches (aka BG map), in
result, memory at 8000h-FFFFh can be used for data storage only, machine code
cannot be executed in that area.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> ____ __________________________________
/M1 ----|AND \__|__ ____ ____ RAM A15
A15 ----|____/ |OR \______|INV \_____ ____
A14 ----|OR \_____|____/ | |____/ ___|OR \___ /RAMCS
A13 ----|____/ | | |____/
/MREQ --|AND \_____________ | ________|___|OR \___ /ROMCS
/RFSH --|____/ |_____________|____/
</TD></TR></TABLE><BR>
Parts List: 7404 hex inverter, 7408 quad 2-input AND gate, 7432 quad 2-input
OR gate, and 128Kx8bit static RAM. Notes: Remove the resistors in the /ROMCS
and /RAMCS lines on the board, connect RAM A16 to VCC or GND. Circuit tested
& working with either 74LSxx or 74HCxx chips.<BR>
<BR>
Caution: Mapping RAM to address 2000h works only with ZX80 and ZX81/TS1000
BIOSes (the TS1500 BIOS checks for [2000h]=01h, and if so, treats it as
expansion ROM).<BR>
<BR>
Compatibility Problem: Memopak expansions do allow d_file at 4000h-BFFFh (eg.
30K BASIC programs, followed by d_file at Bxxxh), but, above circuit supports
only 4000h-7FFFh. To fix this, RAM A15 should be also HIGH whenever A15=1 AND
A14=0.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="hwconnectingajoystick"></A><FONT SIZE=+2>&nbsp;HW Connecting a Joystick</FONT></TD></TR></TABLE><BR>
As far as I know, there isn't any (in-)official standard for sticks, nor
do any games support a standard keyboard/joystick control scheme.
Anyways, a digital four direction/one button joystick could be easily
connected to one of the keyboard rows.<BR>
<BR>
I'd personally vote for row 4, Bits 0-4 used as Fire, Left, Right, Up,
Down, and the A12-diode as /Select. Using this method, the Keys for
Right, Up, Down, comply with ZX cursor controls (Shift+8,7,6). As used
for my 'Starfight' game.<BR>
<BR>
Caution: When having a PC data transfer cable connected to the keyboard
lines as well, the joystick cable may disturb the data transfer. If so,
insert diodes (1N4148 or else) into each of the four direction lines,
ring pointing to the joystick side (nocash upload data lines), and if
necessary for fire button also (nocash upload clock line).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="hwmakingthezx81faster"></A><FONT SIZE=+2>&nbsp;HW Making the ZX81 Faster</FONT></TD></TR></TABLE><BR>
<B>Wilf Rigter's WAITMOD (7/2005) speedup 9%</B><BR>
The ZX81 generates a 14-cycle WAIT along with every NMI. However, the WAIT is
actually required only after the HALT opcode at 0079h (ie. on the final NMI
at the end of the upper/lower blanking period). Rewiring the R1 resistor, and
adding another 10K resistor and a PNP transistor (eg. BC557) causes the WAIT
to be generated only after HALT opcodes, and thus saves 14-cycles on all
other NMIs.<BR>
Before:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> ------- R1 ---------------- /HALT CPU.18
</TD></TR></TABLE>After:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> ----+-- R1 ------+--/cut/-- /HALT CPU.18
| ___ |
+-----|C | +--------- GND
| B|_____________
VCC--10K--|E__| /WAIT CPU.24
</TD></TR></TABLE>All basic/machine code software with video output enabled will run 9% faster,
there should be no compatibility problems, except, eventually with a few
unstable (bugged) programs.<BR>
<BR>
<B>Nocash NMI Patch (5/2010) speedup 2%</B><BR>
Removing the useless 10-cycle "JP @@blah" causes the 7-cycle "JR @@zero" to
be executed instead, thus saving 3-cycles per NMI. After the HALT, a final
NMI is executed, and in this case, the 10-cycle "JP @@blah" is required as
delay, this is solved by moving the JP @@blah after the HALT opcode.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> &lt;---- Original NMI Handler ----&gt; &lt;----- Tuned NMI Handler -----&gt;
0066 08 ex af,af 0066 08 ex af,af
0067 3C inc a 0067 3C inc a
0068 FA 6D 00 jp m,@@blah 0068 28 02 jr z,@@zero
006B 28 02 jr z,@@zero 006A 08 ex af,af
@@blah: 006B C9 ret
006D 08 ex af,af @@zero:
006E C9 ret 006C 08 ex af,af
@@zero: 006D F5 push af
006F 08 ex af,af 006E C5 push bc
0070 F5 push af 006F D5 push de
0071 C5 push bc 0070 E5 push hl
0072 D5 push de 0071 2A 0C 40 ld hl,[400Ch]
0073 E5 push hl 0074 CB FC set 7,h
0074 2A 0C 40 ld hl,[400Ch] 0076 76 halt
0077 CB FC set 7,h 0077 C3 7A 00 jp @@blah
0079 76 halt @@blah:
007A D3 FD out [0FDh],a 007A D3 FD out [0FDh],a
007C DD E9 jp ix 007C DD E9 jp ix
</TD></TR></TABLE>All basic/machine code software with video output enabled will run 2% faster,
there should be no compatibility problems, with a few exceptions: buggy
programs (with unstable timings), programs that jump to addresses 0068..0079,
and, pseudo-hires programs that use I=0 (only Madjump II does do that).<BR>
<BR>
<B>Nocash Increased Blanking Time - speedup around 50% possible</B><BR>
Finally, the CPU speed can be (greatly) improved by increasing the number of
blank lines. There are three ways to do this:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1) Decrease Vertical Picture Size, increase upper/lower blanking accordingly
2) Decrease Vertical Retrace Time, increase upper blanking accordingly
3) Decrease Frame Rate by increasing upper/lower blanking
</TD></TR></TABLE>Method 1) is perfectly legal and can be about 250% faster - but works only
with small pictures. Methods 2) and 3) can be around 50% faster, but might
cause problems with some TV sets, so, using them should be made optional. If
desired, Method 3) can be also implemented at BIOS level (increase the byte
at 02E2h) - that patch will speedup all BASIC programs & most machine code
programs.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="hwupgradingrampaksfortruehiresgraphics"></A><FONT SIZE=+2>&nbsp;HW Upgrading RamPaks for True Hi-Res Graphics</FONT></TD></TR></TABLE><BR>
When using "True Hi-Res" software, pixel data is read from RAM rather
than ROM area. Pixel data is requested by a /RFSH (refresh) signal,
rather than by a normal /RD (read) signal. So, RAM is required to output
data whenever when /RD or /RFSH are low.<BR>
<BR>
Internal RAM does support the above combination, but external RAM
usually generates its own read signal - which senses /RD only. Below
example for fixing this problem is taken from Wilf Ritgers ZX81VID.TXT
document:<BR>
<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> ZX81.+5V --------------------+-----+---- RAMPACK.+5V
| |
ZX81./RFSH ----|&lt;|---+--[4K7]--+ +---- RAMPACK./RFSH ;ALWAYS HIGH
|
ZX81./RD ----|&lt;|---+-------------------- RAMPACK./RD ;/RD AND /RFSH
</TD></TR></TABLE><BR>
The RAMPACK is modified to enable the data output at RFSH time by cutting the
RD and RFSH lines at the edge connector and installing 2 only 1N34A Germanium
diodes and a 4.7K pullup resistor.<BR>
<BR>
Note: ZX hardware often uses a couple of small RAM chips (instead of a
single 28 pin SRAM chip), anyways these are SRAM chips either (so
cutting the RFSH signal shouldn't cause problems). Ie. you can be quite
sure that no DRAM is used because the refresh register is used as
interrupt counter.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="hwconnectingamonitor"></A><FONT SIZE=+2>&nbsp;HW Connecting a Monitor</FONT></TD></TR></TABLE><BR>
Internally the ZX81 is producing a more or less crystal clear video
signal, which is normally converted into a TV signal by the UHF
modulator in the computer, and then re-decoded by the de-modulator in
the TV Set, most likey resulting in a more than bad display quality.<BR>
<BR>
Anyways, the 'raw' video signal can be found at pin 16 of the ZX81
Ferranti chip, that is: 0V=Sync, 2.5V=black, 5V=white, which might or
might not work with various types of computer displays. Some displays
might not understand the refresh rates, and others might require other
voltages - which might be adjusted by one or more resistors.<BR>
<BR>
I've currently only tried to connect a GT65 Green Monitor (for
Amstrad/Schneider CPC homecomputers): Connect Ground as such, and
connect the Video signal to both /Sync, and (preferably through a 1kOHm
resistor) to Luminance. The voltage is apparently much too high (not
actually blowing the display, but the picture appears very bright), the
resistor is more or less healing this.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="hwgettingridofthe9vdcpowersupply"></A><FONT SIZE=+2>&nbsp;HW Getting rid of the 9V DC Power Supply</FONT></TD></TR></TABLE><BR>
When connecting the ZX81 to the PC, the external ZX 9V power supply
becomes more or less useless, and it might be recommended to use the PC
supply instead. Two possible methods are:<BR>
<BR>
<B>Using 12V DC (Yellow cable in PCs)</B><BR>
The official ZX so-called-9V-supply actually outputs about 11V, thus the
slightly higher voltage wouldn't cause much more overheat, but keep in
mind that the voltage is forwarded to any connected hardware expansions,
if necessary lower the voltage to approx. 11V by inserting a 1N4004
diode into the 12V line.<BR>
<BR>
<B>Using 5V DC (Red cable in PCs)</B><BR>
The ZX81 is internally operated at 5V only, the additional volts are
just blown into heat by the 7805 voltage regulator. So, connecting 5V
directly to the 7805 output does work (and prevents the keyboard from
heating up). However, the "9V" voltage is output to the expansion port,
and some hardware expansions (including 16K Memotech RAM Paks) actually
require this voltage.<BR>
<BR>
A separate ground signal isn't forcefully required if the ZX is
connected to the PCs parallel port, as the existing ground/shield
connection could be badly mis-used as ground.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="hwuploadingprogramsfromthepctothezx81"></A><FONT SIZE=+2>&nbsp;HW Uploading Programs from the PC to the ZX81</FONT></TD></TR></TABLE><BR>
The Transmit function in no$zx Utility menu supports three different transfer
methods, each using the PCs parallel port to output data to the ZX (only into
that direction, not vice versa):<BR>
<BR>
<B>1) Nocash Highspeed (transmission time 100-1300ms)</B><BR>
This is a very simple six-diodes-network. The transmission rate is
approx. 12500 bytes/sec (about 300 times faster than 38 bytes/sec
cassette loading). The ZX is automatically reset and immediately
switched into read-mode, even a huge 16K file is transferred in less
than 1.5 seconds - ways faster than the unpatched ZX81/16K CLS boot
procedure.<BR>
However, this method requires a patched BIOS ROM, and it's thus
restricted to more or less serious users only. Data is transferred in
units of 4 Bits, synchronized by a separate clock signal, thus making
the timing rather uncritical, even when using a multitasking operating
system.<BR>
<BR>
<B>2) Mixed (transmission time 3-4 seconds)</B><BR>
This method combines the above/below protocols, but works well without
patched BIOS ROM. Before transmission, you'll have to type LOAD ""
manually on remote side, a small loader will be then transferred by
using the slow transfer method (approx 3 seconds), followed by the
actual file using highspeed transfer (approx 0-1 second).<BR>
<BR>
<B>3) ZXTAPE (transmission time up to 7 minutes)</B><BR>
This protocol is transferring data at original cassette speed (38 bytes per
second), similar to Wilf Ritger's ZXTAPE program. A possible advantage is
that you won't need to open the ZX81, and won't need to install any diodes,
just connect parallel port pin 2 and ground to the ZX EAR socket, and ignore
further instructions below.<BR>
Note that this method won't work very well with multi-tasking operating
systems.<BR>
<BR>
<B>You need:</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 PC with Parallel Port, and a normal Centronics Printer Cable
1 Centronics plug (36 pins, female)
1 EPROM (2764 non-CMOS) and EPROM burner (optional)
6 Diodes (for example 1N4148, ie. the most cheapest standard ones)
and some short isolated wires
</TD></TR></TABLE><BR>
<B>Schematic</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> ZX Mainboard Side Centronics Side
Cassette Input (EAR) ------------- Centr.Pin2 (D0)
Keyb Col0/Pin9 (CLK) -----|&gt;|----- Centr.Pin3 (D1)
Keyb Col1/Pin10 (D0) -----|&gt;|----- Centr.Pin4 (D2)
Keyb Col2/Pin11 (D1) -----|&gt;|----- Centr.Pin5 (D3)
Keyb Col3/Pin12 (D2) -----|&gt;|----- Centr.Pin6 (D4)
Keyb Col4/Pin13 (D3) -----|&gt;|----- Centr.Pin7 (D5)
Expansion 21A (RESET) -----|&gt;|----- Centr.Pin8 (D6)
ROM Pin26 (A13) ------------- Centr.Pin9 (D7) (LO=ZX80, HI=ZX81)
VCC ----[10K]---- Centr.Pin9 (D7)
Expansion 4B/5B (GND) ------------- Centr.Pin24 (GND)
_______
CPU.Pin36 (A6) --|D1 Q1|-- Centr.Pin10 (ACK)
CPU.Pin20 (/IORQ) --|CK1 |
CPU.Pin26 (/RESET) --|SET1 | 74LS74 FlipFlop
VCC ---------------------|RES1 |
|_______|
</TD></TR></TABLE><BR>
<B>Step 1 - The Diodes</B><BR>
Connect the diodes to Pin 3-8 of the Centronics plug. The end with the
black ring (or other color) must point to the plug, the other end will
be connected to the ZX81 mainboard. The diodes are required because
otherwise the strong PC LPT port pulls up the ZX81 address signals when
pressing a key. (Even though bi-directional LPT ports might be able to
avoid that.)<BR>
<BR>
<B>Step 2 - Connecting the Data Lines.</B><BR>
When looking on top of the ZX81 board, you will see the keyboard
connector in lower right. Counted from the right end, pin 1-8 are A8-A15
signals (in no specific order) - ignore these. Pin 9-13 are Keyboard
Columns 0-4 (in exactly that order) - connect these to the diodes at Pin
3-7 of the Centronics plug.<BR>
<BR>
<B>Step 3 - Connecting Ground, Reset and Cassette.</B><BR>
Connect Ground (found at Pin 4B and 5B of the expansion port) to Pin 24
or else of the Centronics plug. Connect Reset (Pin 21A of expansion
port) to the diode at Pin 8 of Centronics plug (the reset signal isn't
actually required, but it's quite comfortable if the transmission
program can reset the ZX81). Finally, connect the Cassette Input (EAR)
to Pin 2 of the Centronics plug (this is required only if you are not
using patched BIOS).<BR>
<BR>
<B>Step 4 - Connecting the ACK Flipflop (NEW, added 2010)</B><BR>
Connect the 74LS74 flipflop as shown above. This is allowing to send feedback
info and EPROM version string to the PC. It's making the circuit a little bit
more complicated than necessary, but it's rather useful to solve connection
problems.<BR>
<BR>
<B>Software</B><BR>
The transmit function (for uploading .P .O .81 .80 files to the ZX80/ZX81) is
found in no$zx's "Utility" menu. The "Utility" menu also contains a function
called Create Patched BIOS Image, which creates a file called XMITZX81.ROM,
which is to be stored in the EPROM; the ROM-image is 16K in size, containing
the original ZX80/ZX81 BIOSes, and the upload software.<BR>
Keep in mind that some pins of the ROM socket must be reconnected for
EPROM use (see chapter about replacing BIOS ROM by EPROM).<BR>
<BR>
<B>Joystick Compatibility</B><BR>
When having a joystick connected to the ZX keyboard lines as well, then
above nocash/mixed transfer methods may not work. This can be fixed by
disconnecting the joystick, or by inserting diodes (1N4148 or else) into
the joystick connectors data lines (Keyboard Bits 1-4).<BR>
Due to the rather high transfer rate, the incoming signal will run into
the joystick cable, and as there are no 'terminators' (resistors) at the
end of the cable (as for ethernet networks for example), the signal will
'bounce back' at the cable end and run back to the ZX, confusing the
transmission program that simultaneously wants to read arrived data.<BR>
<BR>
<B>History</B><BR>
2002 - original circuit for zx81<BR>
2010 - added feedback-flipflop, added zx80 support, changed eprom content<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="zxspectrum"></A><FONT SIZE=+2>&nbsp;ZX Spectrum</FONT></TD></TR></TABLE><BR>
<B>Spectrum</B><BR>
<A HREF="#spectrummodels">Spectrum Models</A><BR>
<A HREF="#spectrumiomap">Spectrum I/O Map</A><BR>
<A HREF="#spectrummemorymaps">Spectrum Memory Maps</A><BR>
<A HREF="#spectrumsystemvariables">Spectrum System Variables</A><BR>
<A HREF="#spectrumula">Spectrum ULA</A><BR>
<A HREF="#spectrumvram">Spectrum VRAM</A><BR>
<A HREF="#spectrumvideoconnectors">Spectrum Video Connectors</A><BR>
<A HREF="#spectrumtimings">Spectrum Timings</A><BR>
<A HREF="#spectrumsound">Spectrum Sound</A><BR>
<A HREF="#spectrumdiscandtapedrives">Spectrum Disc and Tape Drives</A><BR>
<A HREF="#spectruminterrupts">Spectrum Interrupts</A><BR>
<A HREF="#spectrumkeyboards">Spectrum Keyboards</A><BR>
<A HREF="#spectrumjoystickports">Spectrum Joystick Ports</A><BR>
<A HREF="#spectrummouseports">Spectrum Mouse Ports</A><BR>
<A HREF="#spectrumlightguns">Spectrum Light Guns</A><BR>
<A HREF="#spectrumprinterports">Spectrum Printer Ports</A><BR>
<A HREF="#spectrumserialport">Spectrum Serial Port</A><BR>
<A HREF="#spectrumexpansionports">Spectrum Expansion Ports</A><BR>
<A HREF="#spectrumromcartridges">Spectrum ROM Cartridges</A><BR>
<A HREF="#spectrumchipsetpinouts">Spectrum Chipset Pinouts</A><BR>
<A HREF="#spectrumxboo">Spectrum Xboo</A><BR>
<BR>
<B>Z80 CPU</B><BR>
<A HREF="#z80cpuspecifications">Z80 CPU Specifications</A><BR>
<BR>
<B>The BASIC Interpreter</B><BR>
<A HREF="#basicinterpreter">BASIC Interpreter</A><BR>
<BR>
<B>"What is a Computer Good For?</B><BR>
Your new Timex Sinclair 2000 computer is a very special instrument. It is a
tool that can increase the power of your mind as a hammer or a wheelbarrow
assists your muscles." - quoted from TS2068 User Manual<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrummodels"></A><FONT SIZE=+2>&nbsp;Spectrum Models</FONT></TD></TR></TABLE><BR>
<B>Original Spectrums (by Sinclair, later by Amstrad)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1982 Spectrum 16K - original low-cost version (only 16K RAM)
1982 Spectrum 48K - original full version (48K RAM)
1984 Spectrum + - new keyboard, reset button
1985 Spectrum 128 - 128K-RAM,PSG,MIDI,RS232,RGB,32K-ROM
1986 Amstrad +2 (typewriter keyboard, built-in cas drive, two joy ports)
1987 Amstrad +2A (manufactured in Taiwan) (+3 style mainboard, Centronics)
1987 Amstrad +2B (same as +2A but manufactured in China instead of Taiwan)
1987 Amstrad +3 (more ROM, RAM map-able at 0000h for CP/M, built-in disk)
</TD></TR></TABLE><BR>
<B>Timex (licensed Spectrum clones)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1983 TS2068 special video modes, timex bios, PSG, 48K RAM, NTSC (USA)
1984 TC2068 special video modes, timex bios, PSG, 48K RAM, PAL (Portugal)
1984 TC2048 special video modes, spectrum bios, no PSG, 16K RAM, PAL (Portu.)
</TD></TR></TABLE><BR>
<B>Unlicensed Spectrum Clones</B><BR>
There are about 50 unlicensed spectrum clones: Mass-produced clones (like
russian pentagon and scorpion), as well as homebrew modifications.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumiomap"></A><FONT SIZE=+2>&nbsp;Spectrum I/O Map</FONT></TD></TR></TABLE><BR>
The original spectrum did use only one I/O address (the ULA at port FEh). And
only one pre-assigned expansion I/O address (the ZX printer at port FDh).
Although that original design was very simple, the lack of further
pre-assigned addresses resulted in a mess. For example, there are at least 5
different "standards" for connecting joysticks, 3 for PSG sound chips
(probably more), many dozens of floppy and centronics standards, etc.<BR>
<BR>
<B>Spectrum I/O Ports (accessed via IN/OUT opcodes)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Port Binary Address Dir Description
xxFF ................ R Spectrum Current VRAM Data (dirt effect)
xxFE nnnnnnnn.......0 R Spectrum ULA (Keyboard, and CAS Input)
xxFE ...............0 W Spectrum ULA (Border Color, Speaker/CAS Output)
F7FE ....0..........0 R Spectrum +2/+2A/+3 Joystick 2
EFFE ...0...........0 R Spectrum +2/+2A/+3 Joystick 1
F7FE ...10..........0 R Interface 2 Joystick 2
EFFE ...01..........0 R Interface 2 Joystick 1
FFFD 11............0. W Spectrum 128K/+2/+2A/+3 PSG index register
FFFD 11............0. R Spectrum 128K/+2/+2A/+3 PSG data read (and RS232)
BFFD 10............0. W Spectrum 128K/+2/+2A/+3 PSG data write (and RS232)
7FFD 0.............0. W Spectrum 128K/+2 Memory Control
BFFD 10............0. R Spectrum +2A/+3 Mirror of Port FFFDh (+2A/+3 only)
7FFD 01............0. W Spectrum +2A/+3 Memory Control A
1FFD 0001..........0. W Spectrum +2A/+3 Memory Control B and Disk Motor
0FFD 0000..........0. Spectrum +2A/+3 Centronics
3FFD 0011..........0. R/W Spectrum +3 Floppy FDC NEC uPD765 data
2FFD 0010..........0. R Spectrum +3 Floppy FDC NEC uPD765 status
xxFB .............0.. R/W ZX Printer
xxF7 ...........10... R/W Interface 1 RS232/Network Data (1bit send/receive)
xxEF ...........01... R/W Interface 1 Microdrive/RS232/Network Control
xxE7 ...........00... R/W Interface 1 Microdrive Data (8bit send/receive)
xx1F ........000..... R Kempston joystick
</TD></TR></TABLE><BR>
<B>Timex I/O Ports</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> xxFF ........11111111 Timex Display Mode
xxFE nnnnnnnn11111110 R Timex ULA (Keyboard, and CAS Input)
xxFE ........11111110 W Timex ULA (Border Color, Speaker/CAS Output)
xxF4 ........11110100 Timex Memory Mapping
xxF6 ........11110110 R/W Timex TS2068/TC2068 PSG data R/W (sound registers)
x1F6 .......111110110 R/W Timex TS2068/TC2068 PSG data R/W (and joystick 1)
x2F6 ......1.11110110 R/W Timex TS2068/TC2068 PSG data R/W (and joystick 2)
xxF5 ........11110101 W Timex TS2068/TC2068 PSG index
xxFB ........11111011 R/W Timex Printer (TS2040 or Alphacom 32)
xx1F ..........0..... R Timex TC2048 joystick (kempston-style, A5-only)
xxEF ........???0???? R/W Timex FDD Interface (for FDD or FDD-3000 drive)
</TD></TR></TABLE><BR>
<B>Expansion I/O Stuff (Audio related)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0007 W Cheetah Sweet Talker - Speech Output (halts CPU)
007F 0 W DK'Tronics Speech Synthesiser - Speech Output
007F 0 R DK'Tronics Speech Synthesiser - Speech Status
xx7F ........011 R Fuller Box - Joystick port
xx3F ........00 W Fuller Box - PSG index (also DK'Tronics PSG)
xx3F ........00 R Fuller Box - PSG data read (maybe also DK'Tronics?)
xx5F ........010 W Fuller Box - PSG data write (also DK'Tronics PSG)
xx9F ........ 00 W Fuller Orator / Box Master Unit - Speech Output
xxBF ........ 01 R Fuller Orator / Box Master Unit - Speech Status
xx9F ........ 00 W William Stuart Systems Music Synthesiser PSG index
xxDF ........ 10 W William Stuart Systems Music Synthesiser PSG data
xxFF ........1..11111 W Bi-Pak ZON X Soundbox PSG index
xx7F ........0..11111 W Bi-Pak ZON X Soundbox PSG data write
0038 0000000000111000 R Currah uSpeech enable/disable BIOS (mirror)
</TD></TR></TABLE><BR>
<B>Expansion I/O Stuff (Storage, Centronics, etc.)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> xx7F ........01111111 Aerco Centronics Interface
xx8F ........10001111 JLO status/command
xx9F ........10011111 JLO track
xxAF ........10101111 JLO sector
xxBF ........10111111 JLO data
xxB7 ........10110111 JLO select
xxFB ........1....0.. ZX LPrint III Enable ROM, and Write=Data, Read=Busy
xx7B ........0....0.. ZX LPrint III Disable ROM
E3BF 0 W Kempston Centronics Ctrl (b0=0=Strobe)(0Eh,0Fh,81h)
E2BF 0 R Kempston Centronics Status (b0=1=Busy)
E0BF 0 W Kempston Centronics Data Output
xxBB ........ R DK'Tronics Centronics Status (b7=1=Busy)
xxBB ........ W DK'Tronics Centronics Ctrl (b1=0=Strobe) (02h,00h)
xx9B ........ W DK'Tronics Centronics Data
xxDB ........ W DK'Tronics Centronics Config 1 (set to 3Fh)
xxFB ........ W DK'Tronics Centronics Config 2 (set to FFh,80h)
dd0E dddddddd R Wafadrive Centronics Data Out ;via "IN A,(dd0Eh)"
x00A s R Wafadrive Centronics Strobe Out;via "IN A,(s00Ah)"
0002 R Wafadrive Centronics Busy In ;returned in bit5
xxFB ........ W Indescomp Centronics Data
xxFB ........ R Indescomp Status (b0=Busy,b1=Rs232Busy,b2=RxD)
xx7F ........ W Indescomp Control (b0=Strobe,b1=TxD,b2=CTS)
xx1B ........ 0 W Disciple FDC Command
xx1B ........ 0 R Disciple FDC Status
xx5B ........ 0 R/W Disciple FDC Track
xx9B ........ 0 R/W Disciple FDC Sector
xxDB ........ 0 R/W Disciple FDC Data
xx1F ........ W Disciple Control Register
xx1F ........ R Disciple Joystick/Printer/Network
xx3B ........ 0 ? Disciple Network Wait
F7FE 0 0 R Disciple Disciple Joystick
EFFE 0 0 R Disciple Disciple Joystick
xxBB ........ 0 R Disciple Enable Internal ROM/RAM
xxBB ........ 0 W Disciple Disable Internal ROM/RAM
xxFB ........ 0 W Disciple Centronics Data
xx7B ........ 0 R Disciple Map ROM=0000h, RAM=2000h
xx7B ........ 0 W Disciple Map ROM=2000h, RAM=0000h
xxE3 ........ 000 W PlusD FDC Command
xxE3 ........ 000 R PlusD FDC Status
xxE7 ........ 001 R PlusD Enable Internal ROM/RAM
xxE7 ........ 001 W PlusD Disable Internal ROM/RAM
xxEB ........ 010 R/W PlusD FDC Track
xxEF ........ 011 W PlusD Control Register
xxF3 ........ 100 R/W PlusD FDC Sector
xxF7 ........ 101 W PlusD Centronics Data
xxF7 ........ 101 R PlusD Centronics Busy
xxFB ........ 110 R/W PlusD FDC Data
xx1F ........ W Beta Disk FDC Command
xx1F ........ R Beta Disk FDC Status
xx3F ........ R/W Beta Disk FDC Track
xx5F ........ R/W Beta Disk FDC Sector
xx7F ........ R/W Beta Disk FDC Data
xxFF ........ R Beta Disk Status
xxFF ........ W? Beta Disk Control
</TD></TR></TABLE>And many more. See Floppy Disc and Centronics chapters for details on some
various further expansion ports.<BR>
<BR>
<B>Other</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> xx9F ........ Multiface I In
xx1F ........ Multiface I Out
xxBF ........ Multiface 128 In
xx9F ........ Multiface 128 In v2 (Disciple) (uh/what?)
xx3F ........ Multiface 128 Out
xx3F ........ Multiface III Button
xx3F ........ Multiface III In
xxBF ........ Multiface III Out
7F3F Multiface III P7FFD (uh?)
1F3F Multiface III P1FFD (uh?)
FF3F British Micro Grafpad Pen up/down
FFBF British Micro Grafpad Pen position X coordinate
FF7F British Micro Grafpad Pen position Y coordinate
FADF ......?0..0....? Kempston Mouse Buttons (b0=Right,b1=Left,b2=Mid)
FBDF .....0?1..0....? Kempston Mouse X
FFDF .....1?1..0....? Kempston Mouse Y
xx1F ........000..... R/W AMX Mouse Z80PIO Data A: X, CentronicsLSBs/Strobe
xx3F ........001..... R/W AMX Mouse Z80PIO Data B: Y, CentronicsMSBs/Busy
xx5F ........010..... AMX Mouse Z80PIO Ctrl A: X, CentronicsLSBs/Strobe
xx7F ........011..... AMX Mouse Z80PIO Ctrl B: Y, CentronicsMSBs/Busy
xxDF ........110..... R AMX Mouse 74LSXX Logic: Mouse Buttons (R)
xxDF ........ R Stack Light Rifle (R) (light gun trigger/sensor)
</TD></TR></TABLE><BR>
<B>Memory Mapped Ports (eg. triggered on opcode fetches from that addresses)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0008h,1708h Interface 1 - Enable external ROM
0700h Interface 1 - Disable external ROM
0008h Wafadrive - Enable external ROM
0008h,0048h,1708h Discovery - Enable external ROM/RAM/WD/PIA
1748h Discovery - Disable external ROM/RAM/WD/PIA
2800h..2803h Discovery - WD1770 registers (disk)
3000h..3003h Discovery - PIA6821 registers (centronics, etc.)
0000h,0008h,0066h,028Eh Disciple and PlusD - Enable external ROM/RAM
0000h,0008h Timex FDD Interface - Enable ROM/RAM
0604h Timex FDD Interface - Disable ROM/RAM
0038h.Read Currah uSpeech enable/disable BIOS
1000h.Read Currah uSpeech Status (R)
1000h.Write Currah uSpeech Output (W)
3C00h..3CFFh Beta/BetaPlus Disk - Enable ROM and I/O Ports
3D00h..3DFFh Beta128 Disk - Enable ROM and I/O Ports
4000h..FFFFh Beta/BetaPlus/Beta128 - Disable ROM and I/O Ports
</TD></TR></TABLE>Note: Disciple and PlusD do only have the &lt;enable&gt; functions mapped to memory
(whilst &lt;disable&gt; is done via I/O ports).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrummemorymaps"></A><FONT SIZE=+2>&nbsp;Spectrum Memory Maps</FONT></TD></TR></TABLE><BR>
<B>Spectrum 16K Memory Map</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0000h-3FFFh ROM (BASIC)
4000h-7FFFh RAM (Work RAM and VRAM) (with waitstates)
8000h-FFFFh N/A
</TD></TR></TABLE><BR>
<B>Spectrum 48K/Spectrum + Memory Map</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0000h-3FFFh ROM (BASIC)
4000h-7FFFh RAM (Work RAM and VRAM) (with waitstates)
8000h-FFFFh Additional RAM
</TD></TR></TABLE><BR>
<B>Spectrum 128K/+2 Memory Map</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0000h-3FFFh ROM0 (EDITOR) or ROM1 (BASIC) (see Port 7FFDh.Bit4)
4000h-7FFFh RAM Page 5 (VRAM) (with waitstates)
8000h-BFFFh RAM Page 2 (Work RAM)
C000h-FFFFh RAM Page 0..7 (see Port 7FFDh.Bit0-2) (Page1,3,5,7=waitstates)
</TD></TR></TABLE><BR>
<B>Spectrum +2A/+3 Memory Map (in normal mode)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0000h-3FFFh ROM0..ROM3 (see Port 7FFDh.Bit4 and 1FFDh.Bit2)
4000h-7FFFh RAM Page 5 (VRAM) (with waitstates)
8000h-BFFFh RAM Page 2 (Work RAM)
C000h-FFFFh RAM Page 0..7 (see Port 7FFDh.Bit0-2) (Page 4-7 with waitstates)
</TD></TR></TABLE><BR>
<B>Spectrum +2A/+3 Memory Map (in special mode) (with RAM at 0000h for CP/M)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0000h-3FFFh RAM Page 0, 4, 4, or 4 (see Port 1FFDh.Bit0-2)
4000h-7FFFh RAM Page 1, 5, 5, or 7 (see Port 1FFDh.Bit0-2)
8000h-BFFFh RAM Page 2, 6, 6, or 6 (see Port 1FFDh.Bit0-2)
C000h-FFFFh RAM Page 3, 7, 3, or 3 (see Port 1FFDh.Bit0-2)
</TD></TR></TABLE><BR>
<B>Timex TC2048 Memory Map (see Port F4h, and Port FFh)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Address HOME EX-ROM DOCK
0000h-1FFFh BIOS Expansion Bank 0 N/A
2000h-3FFFh BIOS Expansion Bank 1 N/A
4000h-5FFFh VRAM (Screen 0) Expansion Bank 2 N/A
6000h-7FFFh VRAM (Screen 1) Expansion Bank 3 N/A
8000h-9FFFh N/A Expansion Bank 4 N/A
A000h-BFFFh N/A Expansion Bank 5 N/A
C000h-DFFFh N/A Expansion Bank 6 N/A
E000h-FFFFh N/A Expansion Bank 7 N/A
</TD></TR></TABLE><BR>
<B>Timex TC2068/TS2068 Memory Map (see Port F4h, and Port FFh)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Address HOME EX-ROM DOCK
0000h-1FFFh BIOS Extended BASIC ROM Cartridge Bank 0
2000h-3FFFh BIOS Expansion Bank 1 Cartridge Bank 1
4000h-5FFFh VRAM (Screen 0) Expansion Bank 2 Cartridge Bank 2
6000h-7FFFh VRAM (Screen 1) Expansion Bank 3 Cartridge Bank 3
8000h-9FFFh RAM (Work RAM) Expansion Bank 4 Cartridge Bank 4
A000h-BFFFh RAM (Work RAM) Expansion Bank 5 Cartridge Bank 5
C000h-DFFFh RAM (Work RAM) Expansion Bank 6 Cartridge Bank 6
E000h-FFFFh RAM (Work RAM) Expansion Bank 7 Cartridge Bank 7
</TD></TR></TABLE>EX-ROM bank 0 is reportedly mirrored to EX-ROM banks 1-7 (which conflicts
with external EX-ROM banks) (external DOCK banks have no such problems).<BR>
<BR>
<B>Spectrum 128K/+2/+2A/+3 Memory Banks</B><BR>
The RAM pages are used as:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> RAM Page 0 - Main RAM at C000h-FFFFh
RAM Page 2 - Main RAM at 8000h-BFFFh
RAM Page 5 - Main RAM at 4000h-7FFFh (with first VRAM block and system area)
RAM Page 7 - Second VRAM block and Editor variables
RAM Page 1,3,4,6 - RAM Disk
</TD></TR></TABLE>Upon Reset, ROM0 is mapped.<BR>
<BR>
<B>Expansion ROM/RAM</B><BR>
On Spectrum machines, the 16K ROM at 0000h-3FFFh (or smaller portions of it)
can be externally disabled by dragging the /ROMCS pin HIGH, allowing to
replace that region by external ROM and/or RAM. (Eg. Interface 1 ROM or
Interface 2 ROM, or Interface 2 Cartridge ROM) (also external disk drives
usually contain both ROM and RAM).<BR>
Timex machines don't have external /ROMCS pin, instead, the memory mapping is
handled via the internal Port F4h and FFh registers. And, Timex machines can
map external memory anywhere at 0000h..FFFFh (rather than at 0000h-3FFFh
only).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumsystemvariables"></A><FONT SIZE=+2>&nbsp;Spectrum System Variables</FONT></TD></TR></TABLE><BR>
<B>Spectrum RAM Map</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 4000h VRAM Bitmap (256x192 pixels)
5800h VRAM Attributes (32x24 characters)
5B00h System Area
5CB6h Memory (starting with CHANS)
</TD></TR></TABLE>Memory<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> CHANS channels (usually at 5CB6h)
PROG basic program (usually at 5CCBh)
VARS basic variables
E_LINE input buffer
WORKSP temporary work space
STKBOT bottom of calculator stack (same as WORKSP when empty)
STKEND start of spare space (same as STKBOT when empty)
RAMTOP CPU stacktop+1 (usually FF57h)
UDG User-defined graphics (charset) (usually FF58h)
P_RAMT physical RAM top (FFFFh for 48K RAM, or 7FFFh for 16K RAM)
</TD></TR></TABLE>Variants<BR>
Expansion hardware like Interface 1 and Beta Disk may allocate memory between
5CB6h and CHANS. Other hardware like Currah uSpeech may allocate memory
between RAMTOP and UDG.<BR>
<BR>
<B>TS2068 Memory Map</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0000h..3FFFh BIOS ROM
4000h..57FFh VRAM Bitmap (1800h bytes)
5800h..5AFFh VRAM Attr (300h bytes)
5B00h..5BFFh Printer Buffer
5C00h..5FFFh System Variables
</TD></TR></TABLE>Next, for 1 Display File:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 6000h..61FFh Machine Stack (200h bytes)
6200h..683Fh OS RAM-Resident Code
6840h..ARSBUF (Machine Code Variables)
ARSBUF
CHANS
PROG
VARS
E_LINE
WORK_SP
STKBOT
STKEND
RAMTOP..P_RAMT UDG (user defined graphics)
</TD></TR></TABLE>Or, for 2 Display Files:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 6000h..77FFh VRAM Bitmap 2 (1800h bytes)
7800h..7AFFh VRAM Attr 2 (300h bytes)
7B00h..ARSBUF (Machine Code Variables)
ARSBUF..RAMTOP (as above)
RAMTOP..F7BFh UDG (user defined graphics)
F7C0h..F9BFh Machine Stack (200h bytes)
F9C0h..P_RAMT OS RAM-Resident Code
</TD></TR></TABLE><BR>
<B>Spectrum System Area (parts accessed via IY=5C3Ah)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 5B00h 256 PRBUFF LPRINT Buffer (32x8 pixel bitmap)
(On Spectrum 128/+2/+2A/+3, PRBUFF is used
as Extended System Area, see below)
5C00h 8 KSTATE Used in reading the keyboard.
5C08h 1 LASTK Stores newly pressed key.
5C09h 1 REPDEL Time (in 50ths of a second) that a key
must be held down before it
repeats. This starts off at 35, but
you can POKE in other values.
5C0Ah 1 REPPER Delay (in 50ths of a second) between
successive repeats of a key held down - initially 5.
5C0Bh 2 DEFADD Address of arguments of user defined
function (if one is being evaluated), otherwise 0.
5C0Dh l K_DATA Stores 2nd byte of colour controls entered from keyboard.
5C0Eh 2 TVDATA Stores bytes of colour, AT and TAB controls going to TV.
5C10h 38 STRMS Addresses of channels attached to streams.
(16bit pointers for Stream FDh..FFh, and 00..0Fh)
5C36h 2 CHARS 256 less than address of character set
(which starts with space and carries
on to (C)). Normally in ROM, but you
can set up your down in RAM and make
CHARS point to it.
5C38h 1 RASP Length of warning buzz.
5C39h 1 PIP Length of keyboard click.
5C3Ah 1 ERRNR 1 less than the report code. Starts
off at 255 (for -1) so 'PEEK 23610' gives 255.
5C3Bh 1 FLAGS Various flags to control the BASIC system.
5C3Ch 1 TVFLAG Flags associated with the TV.
5C3Dh 2 ERRSP Address of item on machine stack to be used as error return
5C3Fh 2 LISTSP Address of return address from automatic listing.
5C41h 1 MODE Specifies 'K', 'L', 'C', 'E' or 'G' cursor.
5C42h 2 NEWPPC Line to be jumped to.
5C44h 1 NSPPC Statement number in line to be jumped to. Poking first
NEWPPC and then NSPPC forces a jump to a specified
statement in a line.
5C45h 2 PPC Line number of statement currently being executed.
5C47h 1 SUBPPC Number within line of statement currently being executed.
5C48h 1 BORDCR Border colour multiplied by 8; also
contains the attributes normally used
for the lower half of the screen.
5C49h 2 E_PPC Number of current line (with program cursor).
5C4Bh 2 VARS Address of variables. (End of BASIC Program)
5C4Dh 2 DEST Address of variable in assignment.
5C4Fh 2 CHANS Address of channel data (usually 5CB6h)
5C51h 2 CURCHL Address of current I/O channel (CHANS+n)
5C53h 2 PROG Address of BASIC program. (End of CHANS)
5C55h 2 NXTLIN Address of next line in program. (PROG+n, or 0000h=None)
5C57h 2 DATADD Address of terminator of last DATA item. (initially PROG-1)
5C59h 2 E_LINE Address of input buffer (aka line editor) (End of VARS)
5C5Bh 2 K_CUR Address of cursor in input buffer (E_LINE+n)
5C5Dh 2 CH_ADD Address of the next character to be interpreted
(the character after the argument of PEEK,
or the NEWLINE at the end of a POKE statement)
5C5Fh 2 X_PTR Address of the character after the [] marker. (or 00D7h?)
5C61h 2 WORKSP Address of temporary work space.
5C63h 2 STKBOT Address of bottom of calculator stack.
5C65h 2 STKEND Address of start of spare space.
5C67h 1 BREG Calculator's B register.
5C68h 2 MEM Address of area used for calculator's memory
(usually MEMBOT, but not always).
5C6Ah 1 FLAGS2 More flags. (Bit3 set when CAPS SHIFT or CAPS LOCK is on.)
5C6Bh 1 DF_SZ Number of lines in lower part of screen (including one
blank line)
5C6Ch 2 S_TOP The number of the top program line in automatic listings.
5C6Eh 2 OLDPPC Line number to which CONTINUE jumps.
5C70h 1 OSPPC Number within line of statement to which CONTINUE jumps.
5C71h 1 FLAGX Various flags.
5C72h 2 STRLEN Length of string type destination in assignment.
5C74h 2 T_ADDR Address of next item in syntax table.
5C76h 2 SEED The seed for RND. This is set by RANDOMIZE.
5C78h 3 FRAMES Frame counter incremented at 50Hz (or 60Hz) (24bit)
5C7Bh 2 UDG Address of first user-defined graphic (usually FF58h)
5C7Dh 2 COORDS X,Y coordinates of last point plotted.
5C7Fh 1 P_POSN 33-column number of printer position.
5C80h 2 PRCC Address of Current Column in PRBUFF (5B00h..5B1Fh)
[Not used in 128K mode or when certain peripherals
are attached]
5C82h 2 ECHO_E 33-column number and 24-line number
(in lower half) of end of input buffer.
5C84h 2 DF_CC Address in display file of PRINT position.
5C86h 2 DF_CCL Like DF_CC for lower part of screen.
5C88h 1 S_POSN 33-column number for PRINT position.
5C89h 1 24-line number for PRINT position.
5C8Ah 2 SPOSNL Like S_POSN for lower part.
5C8Ch 1 SCR_CT Counts scrolls - it is always 1 more
than the number of scrolls that will
be done before stopping with
'scroll?'. If you keep poking this
with a number bigger than 1 (say 255),
the screen will scroll on and on
without asking you.
5C8Dh 1 ATTR_P Permanent current colours, etc., (as
set up by colour statements).
5C8Eh 1 MASK_P Used for transparent colours, etc. Any
bit that is 1 shows that the
corresponding attribute bit is taken
not from ATTR_P, but from what is
already on the screen.
5C8Fh 1 ATTR_T Temporary current colours, etc., (as
set up by colour items).
5C90h 1 MASK_T Like MASK_P, but temporary.
5C91h 1 P_FLAG More flags.
5C92h 30 MEMBOT Calculator's memory area - used to
store numbers that cannot conveniently
be put on the calculator stack.
5CB0h 2 NMIADD Holds the address of the users NMI service routine.
NOTE - On previous machines, this did
not work correctly and these two bytes
were documented as 'Not used.'
Programs that used these two bytes for
passing values may need to be
modified.
5CB2h 2 RAMTOP Address of last byte of BASIC system area.(usually FF57h)
5CB4h 2 P_RAMT Address of last byte of physical RAM. (usually FFFFh)
</TD></TR></TABLE><BR>
<B>Timex 2068 - Extended System Area</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 5CB6h 2 ERRLN Line number to GOTO on error
5CB8h 2 ERRLN Line number in which error occurred
5CBAh 1 ERRS Statement number within line in which error occurred
5CBBh 1 ERRT Error number (Report Code)
5CBCh 2 SYSCON Pointer to System Configuration Table
5CBEh 1 MAXBNK Number of Expansion Banks in System
5CBFh 1 CURCBN Current Channel Bank Number
5CC0h 2 MSTBOT Address of location above machine stack
5CC2h 1 VIDMOD Video Mode (non-zero if 2nd display file is used)
5CC3h 1 &lt;undocumented/unused byte&gt; ?
5CC4h 7 "Various variables used for BASIC cartridges" ...details?
5CCBh 1 STRMNM Current Stream number
5CCCh 334h - Not used (except, some stuff at 5EF3h..5EF6h is used?)
</TD></TR></TABLE><BR>
<B>Spectrum 128/+2/+2A/+3 - Extended System Area (formerly Printer buffer)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Addr Siz Name Expl.
<B> Below is for Spectrum 128/+2:</B>
5B00h 20 SWAP Paging subroutine.
5B14h 9 YOUNGER Paging subroutine.
5B1Dh 18 ONERR Paging subroutine.
5B2Fh 5 PIN
5B34h 22 POUT
5B4Ah 14 POUT2
<B> Below is for Spectrum +3:</B>
5B00h 16 SWAP Paging subroutine.
5B10h 17 STOO Paging subroutine. Entered with IRQs disabled, AF,BC pushed
5B21h 9 YOUNGER Paging subroutine.
5B2Ah 16 REGNUOY Paging subroutine.
5B3Ah 24 ONERR Paging subroutine.
5B52h 2 OLDHL Temporary register store while switching ROMs.
5B54h 2 OLDBC Temporary register store while switching ROMs.
5B56h 2 OLDAF Temporary register store while switching ROMs.
<B> Below is for both Spectrum 128 and +3:</B>
5B58h 2 TARGET Subroutine address in ROM 3.
5B5Ah 2 RETADDR Return address in ROM 1.
5B5Ch 1 BANKM Copy of last byte output to I/O port 7FFDh.
5B5Dh 1 RAMRST RST 8 instruction. Used by ROM 1 to
report old errors to ROM 3.
5B5Eh 1 RAMERR Error number passed from ROM 1 to ROM
3. Also used by SAVE/LOAD as temporary drive store.
5B5Fh 2 BAUD RS232 bit period in T states/26. Set by FORMAT LINE.
5B61h 2 SERFL Second-character-received-flag, and data.
5B63h 1 COL Current column from 1 to width.
5B64h 1 WIDTH Paper column width. Defaults to 80. (on +3 at least)
5B65h 1 TVPARS Number of inline parameters expected by RS232.
5B66h 1 FLAGS3 Various flags. Bits 0, 1, 6 and 7
unlikely to be useful. Bit 2 is set
when tokens are to be expanded on
printing. Bit 3 is set if print output
is RS232. The default (at reset) is
Centronics (on +3) and whatever? (on 128/+2).
Bit 4 is set if a disk
interface is present. Bit 5 is set if
drive B: is present.
<B> Below is for Spectrum 128/+2:</B>
5B67h 10 NSTR1
5B71h 1 HD00
5B72h 2 HD0B
5B74h 2 HD0D
5B76h 2 HD0F
5B78h 2 HD11
5B7Ah 1 SC00
5B7Bh 2 SC08
5B7Dh 2 SC0D
5B7Fh 2 SC0F
5B81h 2 OLDSP
5B83h 2 SFNEXT
5B85h 3 SPSPACE
5B88h 1 ROW01
5B89h 1 ROW23
5B8Ah 1 ROW45
5B8Bh 2 SYNRET
5B8Dh 5 LASTV
5B92h 2 RNLINE
5B94h 2 RNFIRST
5B96h 2 RNSTEP
5B98h 8 STRIP1
5BA0h 8 STRIP2
5BA8h 87 TSTACK
5BFFh 1 N/A
<B> Below is for Spectrum +3:</B>
5B67h 1 BANK678 Copy of last byte output to I/O port 1FFDh.
5B68h 1 XLOC Holds X location when using the unexpanded COPY command.
5B69h 1 YLOC Holds Y location when using the unexpanded COPY command.
5B6Ah 2 OLDSP Old SP (stack pointer) when TSTACK is in use.
5B6Ch 2 SYNRET Return address for ONERR.
5B6Eh 5 LASTV Last value printed by calculator.
5B73h 2 RCLINE Current line being renumbered.
5B75h 2 RCSTART Starting line number for renumbering. The default is 10.
5B77h 2 RCSTEP Incremental value for renumbering. The default is 10.
5B79h 1 LODDRV Holds 'T' if LOAD, VERIFY, MERGE are
from tape, otherwise 'A', 'B' or 'M'.
5B7Ah 1 SAVDRV Holds 'T' if SAVE is to tape, otherwise 'A', 'B' or 'M'.
5B7Bh 1 DUMPLF Holds the number of 1/216ths inch used for
line feeds in 'COPY EXP'. This is
normally set to 9. If problems are
experienced fitting a dump onto a
sheet of A4 paper, POKE this
location with 8. This will reduce the
size of the dump and improve the
aspect ratio slightly.
5B7Ch 8 STRIP1 Stripe one bitmap. ;\allowed to be destroyed by
5B84h 8 STRIP2 Stripe two bitmap. ;/Temporary stack
5B8Ch 115 TSTACK Temporary stack (when RAM7 is mapped to C000h-FFFFh)
5BFFh 1 N/A Not used
</TD></TR></TABLE><BR>
In 48 BASIC mode, all the variables and routines below 5C00h (23552) do not
exist; instead there is a buffer between 5B00h (23296) and 5C00h (23552)
which is used for controlling the printer. This was quite a popular location
for small machine code programs on the old 48K Spectrum, and if any of these
routines are tried in +3 BASIC, the computer will invariably crash. Any old
program that uses PEEK, POKE and USR is therefore a safer bet if it is run in
48 BASIC mode (although it can be entered in +3 BASIC mode and transferred
using the SPECTRUM command). If there is a chance that a program might
inadvertently address the added I/O ports of the +3, then 'OUT 32765,48' will
set bit 5 in port 7FFDh to disable further use of the added ROM/RAM
switching.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumula"></A><FONT SIZE=+2>&nbsp;Spectrum ULA</FONT></TD></TR></TABLE><BR>
<B>Port nnFEh - Sinclair ULA (R)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-4 Keyboard Inputs (0=Pressed, 1=Released)
5 Not used
6 EAR Input (CAS LOAD)
7 Not used
A8..A15 Keyboard Address Output (0=Select)
</TD></TR></TABLE><BR>
<B>Port FEh - Sinclair ULA (W)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-2 Border Color (0..7) (always with Bright=off)
3 MIC Output (CAS SAVE) (0=On, 1=Off)
4 Beep Output (ULA Sound) (0=Off, 1=On)
5-7 Not used
</TD></TR></TABLE><BR>
<B>Port FFh (or other) (R) Spectrum Current VRAM Data (dirt effect)</B><BR>
Reading from an unused port (eg. Port FFh) does return the byte being most
recently read from VRAM via video DMA. During Vblank and Hblank, the return
value is always FFh. During the scanline drawing periods, the return value
may be FFh, or bitmap data, or attribute data (depending on when exactly the
port is read).<BR>
Some games are using this dirt effect to synchronize the program with the
cathode ray beam (eg. Arkanoid is using display timings to generate in-game
sound frequencies).<BR>
The method does NOT work on all computers: All Timex machines are using Port
FFh for something else, though the effect may still work with other unused
ports (if there are any unused ports). And, newer Spectrum machines (eg.
Spectrum +3) don't produce the effect at all.<BR>
<BR>
<B>Port FFh - Timex Video and Memory Control</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-2 Screen mode. 000=screen 0, 001=screen 1, 010=hi-colour, 110=hi-res
3-5 INK color in hi-res mode (INK=0..7) (with PAPER=INK XOR 7, BORDER=PAPER)
6 Disable Frame Interrupt (0=Normal, 1=Disable)
7 External memory mode (0=DOCK/Cartridge Slot, 1=EX-ROM/Expansion Port)
</TD></TR></TABLE>Screen 0 is the normal screen at 4000h. Screen 1 uses the same format but at
6000h.<BR>
<BR>
<B>Port F4h - Timex Memory Mapping</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 Memory at 0000h-1FFFh (0=HOME, 1=DOCK or EX-ROM) ;HOME=BIOS, EX-ROM=BASIC
1 Memory at 2000h-3FFFh (0=HOME, 1=DOCK or EX-ROM) ;HOME=BIOS
2 Memory at 4000h-5FFFh (0=HOME, 1=DOCK or EX-ROM) ;HOME=VRAM
3 Memory at 6000h-7FFFh (0=HOME, 1=DOCK or EX-ROM) ;HOME=VRAM
4 Memory at 8000h-9FFFh (0=HOME, 1=DOCK or EX-ROM) ;HOME=RAM
5 Memory at A000h-BFFFh (0=HOME, 1=DOCK or EX-ROM) ;HOME=RAM
6 Memory at C000h-DFFFh (0=HOME, 1=DOCK or EX-ROM) ;HOME=RAM
7 Memory at E000h-FFFFh (0=HOME, 1=DOCK or EX-ROM) ;HOME=RAM
</TD></TR></TABLE>The TC2048 has only 16K BIOS, the TS2068/TC2068 have an additional 8K BASIC
extension in the first EX-ROM bank. Whether DOCK (Cartridge) or EX-ROM
(Expansion) is mapped depends on Port FFh.Bit7.<BR>
Note: This register is often called "Horizontal Select Register", that name
has nothing to do with video resolution or coordinates, instead, the name is
based on treating the memory as a two-dimensional array (with y=16bit Z80
memory address, and x=bank number).<BR>
<BR>
<B>Port 7FFDh - Spectrum 128K/+2/+2A/+3 Memory Bank Register (W) (and RAM 5B5Ch)</B><BR>
(initially 00h)<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-2 RAM Page to be mapped to C000h-FFFFh (0..7=Page 0..7)
3 RAM Page to be used as VRAM (0=Page 5, 1=Page 7)
4 ROM Page (0=New "128K" ROM0, 1=Old "48K" ROM1)
5 Lock Port 7FFDh (0=Normal/No change, 1=Lock/Until Reset)
6-7 Not used
</TD></TR></TABLE>On +2A/+3:<BR>
RAM Pages 0..3 are "uncontended" (aka accessed solely by the Z80)<BR>
RAM Pages 4..7 are "contended" (aka accessed by both the Z80, and by the ULA)<BR>
On 128/+2:<BR>
RAM Pages 0,2,4,6 are "uncontended" (aka accessed solely by the Z80)<BR>
RAM Pages 1,3,5,7 are "contended" (aka accessed by both the Z80, and by ULA)
(ie. the ULA can access Page 5 or 7 as VRAM; although the ULA accesses only
ONE of that two pages at a time, and NEVER accesses Page 4 or 6, the whole
Page 4..7 region is treated as "contended", meaning that the whole region
suffers under video waitstates).<BR>
<BR>
<B>Port 1FFDh - Spectrum +2A/+3 Memory (W) (and RAM 5B67h=R/W)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 Paging mode (0=Normal; ROM and RAM, 1=Special; RAM only)
1-2 In special mode: RAM mapping mode (RAM only, for CP/M)
Mode 0000h..3FFFh 4000h..7FFFh 8000h..BFFFh C000h..FFFFh
0 Bank0 Bank1 Bank2 Bank3
1 Bank4 Bank5/Screen1 Bank6 Bank7/Screen2
2 Bank4 Bank5/Screen1 Bank6 Bank3
3 Bank4 Bank7/Screen2 Bank6 Bank3
1 In normal mode, ignored.
2 In normal mode, MSB of ROM selection (LSB is in Port 7FFDh.Bit4)
The four ROMs banks are (mapped to 0000h..3FFFh):
ROM 0: 128k editor, menu system and self-test program
ROM 1: 128k syntax checker
ROM 2: +3DOS
ROM 3: 48 BASIC
3 Disk motor; 1=on, 0=off
4 Printer port strobe.
5-7 Not used
</TD></TR></TABLE>RAM banks 1,3,4 and 6 are used for the disc cache and RAMdisc, while Bank<BR>
7 contains the second VRAM bank, editor scratchpads, and +3DOS workspace.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumvram"></A><FONT SIZE=+2>&nbsp;Spectrum VRAM</FONT></TD></TR></TABLE><BR>
<B>Bitmap Area (4000h..57FFh) (1800h bytes) (6K)</B><BR>
Bitmap Address<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> A0..A4 Horizontal Coordinate in 8-pixel steps (0..31)
A5..A7 Vertical Coordinate in 8-pixel steps (0..7) ;Vertical Charline
A8..A10 Vertical Coordinate in 1-pixel steps (0..7) ;Vertical Scanline
A11..A12 Vertical Coordinate in 64-pixel steps (0..2) ;Vertical Block
</TD></TR></TABLE>Bitmap Data<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> D0..D7 Pixels (0=Paper, 1=Ink) (D7=Left-most ... D0=Right-most)
</TD></TR></TABLE>Note: A0..A7 are arranged that a single /RAS signal can be used for reading
both Bitmap and Attribute via DMA. A8..A10 are arranged that an address in HL
can be vertically manipulated via INC H opcodes.<BR>
<BR>
<B>Attribute Area (5800h..5AFFh) (300h bytes) (0.75K)</B><BR>
Attribute Address<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> A0..A4 Horizontal Coordinate in 8-pixel steps (0..31)
A5..A9 Vertical Coordinate in 8-pixel steps (0..23)
</TD></TR></TABLE>Attribute Data<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> D0..D2 Ink (0..7 = color used for "1" bits in bitmap data)
D3..D5 Paper (0..7 = color used for "0" bits in bitmap data)
D6 Bright (brightness for both Ink and Paper) (0=Dark, 1=Bright)
D7 Flash (0=Normal, 1=Blink; 16 frames normal, 16 frames inverted)
</TD></TR></TABLE>Note: The Screen Border color can be set via Port FEh (the border is always
having Bright=off). Except, the Timex hi-res mode sets the border equal to
the paper color (which is the inverse of the hi-res INK value in Port FFh,
and which is always having Bright=on, for both INK and PAPER/BORDER).<BR>
<BR>
<B>Color Palette (via TV Modulator or Composite Video)</B><BR>
Below table shows the normal TV palette (as seen on Spectrum 48K Issue 2).
Whereas, "r,g,b" = basic Red/Green/Blue intenstity on color display, "i" =
basic intensity on monochrome display, "R,G,B,I" = additional intensity when
the Bright bit is set.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 Black ............... ............... ............... .......
1 Blue g.............. r.............. bbbbbbbbB...... i......
2 Red gg............. rrrrrrrrRR..... bb............. ii.....
3 Magenta ggG............ rrrrrrrrrRR.... bbbbbbbbbBB.... iiI....
4 Green gggggggggGGG... rrrR........... bbbB........... iiiI...
5 Cyan ggggggggggGGG.. rrrrR.......... bbbbbbbbbbBBB.. iiiiI..
6 Yellow ggggggggggGGGG. rrrrrrrrrrRRRR. bbbbBB......... iiiiII.
7 White gggggggggggGGGG rrrrrrrrrrrRRRR bbbbbbbbbbbBBBB iiiiiII
</TD></TR></TABLE>On a color display, there would be theoretically 16 colors possible, however,
Dark Black is exactly same as Bright Black, so there are only 15 different
colors (also, Dark Blue isn't much different than Bright Blue). Note: If the
color isn't 100% properly adjusted via VR1 and VR2 on the mainboard, then
White/Gray tend to appear a bit yellowish.<BR>
On a monochrome display, only the eight Bright colors are relevant, and the
Dark colors are just duplicating some bright colors (for example, Dark Blue
is almost same as Bright Blue, and Dark Cyan or Dark Yellow are almost same
as Bright Green).<BR>
<BR>
<B>Palette on CGA Monitors (via TTL output on TS2068/TC2068 or Spectrum 128)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> TS2068 outputs only R,G,B (but NOT intensity, ie. bright is ignored)
TC2068 and Spectrum 128 do output R,G,B,I (with intensity)
CGA shows intensity=1 as FULL intensity (unlike darker blue/red on TV)
CGA shows intensity=0 as HALF intensity or so (unlike 80% of bright on TV)
CGA shows dark-yellow as brown (unlike Dark-Yellow on TV)
CGA shows bright-black as dark-gray (unlike Black on TV)
</TD></TR></TABLE>The bright-black effect may be fixed by masking I when R,G,B are all zero.<BR>
<BR>
<B>Palette on TVs with RGB input (via Analogue output on Spectrum +2A/+3)</B><BR>
Spectrum +2A/+3 have a RGB output with analog levels, which can be wired to
21pin Scart connectors (most TVs with Scart sockets support only Composite
A/V, but not RGB though), and which may (or may not?) produce same colors as
the standard TV output.<BR>
<BR>
<B>Second Screen</B><BR>
Spectrums with 128K RAM (Spectrum 128/+2/+2A/+3) can use two frame buffers,
the normal one at 4000h..5AFFh, and the second one in RAM Page 7; which can
be mapped to CPU addresses C000h..DAFFh (see Port 7FFDh).<BR>
All Timex machines (TC2048/TC2068/TS2068) can use two frame buffers, too. The
normal one at 4000h..5AFFh, and the second one at 6000h..7AFFh (see Port
FFh).<BR>
<BR>
<B>Timex Hi-Color (Timex only, not supported on any Spectrums)</B><BR>
In this mode, the 32x24 attributes (per 8x8 pixels) at 5800h..5AFFh are
unused, and instead 32x192 attributes are read from 6000h..77FFh (per 8x1
pixels). The Attribute Data is same as in Standard mode, but the Attribute
Address bits are arranged in the same way as the Bitmap address.<BR>
<BR>
<B>Timex Mono Hi-Res (Timex only, not supported on any Spectrums)</B><BR>
In this mode, the horizontal resolution is doubled, ie. instead of reading 1
bitmap and 1 attribute byte, it reads 2 bitmap bytes. The colors (for the
whole screen) can be set via Port FFh. The bitmap data is located at
4000h..57FFh and 6000h..77FFh. The data is horizontally interlaced, each 8
pixels at 4000h, 6000h, 4001h, 6001h, and so on, the vertical addresses are
same as in the other modes.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumvideoconnectors"></A><FONT SIZE=+2>&nbsp;Spectrum Video Connectors</FONT></TD></TR></TABLE><BR>
<B>Spectrum 128 - RGB Connector</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 Composite PAL (75 Ohms, 1.2 Volts pk-pk) .. ..
2 GND (0 Volts DC) / '-' \
3 Bright output (TTL) . 7 6 .
4 Composite sync (TTL) | 3 8 1 |
5 Vertical sync (TTL) ' 5 4 '
6 Green (TTL) \ 2 /
7 Red (TTL) '---'
8 Blue (TTL)
</TD></TR></TABLE>128K Composite Video Output:<BR>
Pin 1 is composite PAL, 2 is GND. The picture is a bit dull unless your TV's
video input is High Z (high impedance) However, that's quite unlikely.
Normally the impedance of the video input is around 75 Ohms. To alleviate
this problem, short the 68 Ohms resistor inside the Speccy that's in series
with pin 1 (follow the track on the PCB). Or you can hook it directly to the
input of the RF modulator.<BR>
There's no audio on any pin of the RGB connector. The audio can be taken from
the MIC socket but a better balance between 48K and 128K sound is obtained
directly from pin 5 of IC38.<BR>
<BR>
<B>Spectrum +2A/+3 - RGB Connector</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 +12V .. ..
2 GND (0V) / '-' \
3 Audio Out . 7 6 .
4 /Composite Sync (TTL) | 3 8 1 |
5 +12V ' 5 4 '
6 Green (Analogue 1.67V p-p) \ 2 /
7 Red (Analogue 1.67V p-p) '---'
8 Blue (Analogue 1.67V p-p)
</TD></TR></TABLE><BR>
TS2068: If the RGB output is used, BRIGHT is ignored.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumtimings"></A><FONT SIZE=+2>&nbsp;Spectrum Timings</FONT></TD></TR></TABLE><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE><B> Maker Spectrum Spectrum Spectrum Timex Timex</B>
<B> Version 16K/48K/+ 128/+2 +2A/+3 TC2048/2068 TS2068</B>
CPU Osc 14.000MHz 17.73447MHz ? ? 14.112MHz
Color Osc 4.4336MHz CPU Osc/4 CPU Osc/n ? 3.579545MHz
CPU Clock 3.500000MHz 3.54690MHz 3.54690MHz 3.50000MHz 3.52800MHz
PSG Clock N/A 1.7734MHz 1.7734MHz ? (if any) 1.764(75)?
HorizontalTotal 224 clks 228 clks 228 clks ? 224 clks
HorizontalDraw 128 clks 128 clks 128 clks 128 clks 128 clks
HorizontalBlank 96 clks 100 clks 100 clks ? ?
Vertical Total 312 lines 311 lines ? ? 262 lines
Screen 192 lines 192 lines 192 lines 192 lines 192 lines
Upper Border 64 lines 63 lines ? ? ?
Lower Border 56 lines 56 lines ? ? ?
Frame Rate 50.08Hz/PAL 50.01Hz/PAL 50.?Hz/PAL 50.?Hz/PAL 60.11Hz/NTSC
Flash Rate 50/32=1.6Hz 50/32=1.6Hz 50/32=1.6Hz 50/32=1.6Hz 60/32=1.9Hz
First Delay at 14335 clks ? 14361 clks ? ?
Delay Pattern 6..1,0,0 ? 1,0,7..2 ? ?
Port FEh Delay Yes Yes No Yes Yes
VRAM Delay at 4000h-7FFFh RAM1,3,5,7 RAM4,5,6,7 4000h-7FFFh 4000h-7FFFh
Snow Effect Yes Yes/Crash ? No? Yes/No?
</TD></TR></TABLE><BR>
<B>Some Clones</B><BR>
The russian Scorpion seems to have same timings as Spectrum 48K. The russian
Pentagon has 320 lines total (64+192+48+16), and, it generates INT at begin
of its 16-lines Vsync period (all other computers have INT at end of Vsync,
aka begin of upper border). Horizontal total is 224 clks on both Pentagon and
Scorpion, but hsync position is slightly different on each. Both Scorpion and
Pentagon do not have slow (contended) memory.<BR>
<BR>
<B>VRAM Waitstates (aka "contended memory" waitstates)</B><BR>
Within each 8 cycles, the ULA reads 2 bitmap bytes and 2 attribute bytes via
video DMA (which takes up 4 clks), followed by 4 cycles where bus is free for
the CPU. Although there are 4 free cycles, the ULA allows the CPU to invoke a
RAM access (or a Port FEh access) only during 2 of that 4 cycles:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> UUUUUUccUUUUUUccUUUUUUcc.. ;&lt;--- U=Blocked by ULA, c=Free for CPU access
654321006543210065432100.. ;&lt;--- Number of waitstates (0=none)
</TD></TR></TABLE>For whatever reason, the access pattern is different on the +2A/+3:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> UcUUUUUUUcUUUUUUUcUUUUUU.. ;&lt;--- U=Blocked by ULA, c=Free for CPU access
107654321076543210765432.. ;&lt;--- Number of waitstates (0=none)
</TD></TR></TABLE>Waitstates occur only during drawing, ie. not during Vblank and Hblank. The
first ULA access appears 14335 (or 14361) cycles after the Vsync IRQ (or
unknown number of cycles on NTSC and others). The above access pattern is
then repeated throughout the 128 cycles drawing time, and pauses throughout
the 96 (or 100) cycles hblank time.<BR>
Although a screen with attributes consists of only 6.75Kbytes, the waitstates
apply on any access to memory chips that are connected to the ULA (ie. the
whole 16K at 4000h..7FFFh) (or one half of RAM on 128K machines, either in
banks 1,3,5,7 on Spectrum 128/+2, or in banks 4,5,6,7 on Spectrum +2A/+3).
Other portions of RAM (and ROM) can be accessed without waitstates.<BR>
<BR>
<B>Details on VRAM-DMA Access Timings</B><BR>
As said above, within each 8 cycles, the ULA reads 2 bitmap bytes and 2
attribute bytes, the LSBs of the bitmap address are the same as of the
attribute address, so two bytes (1x bitmap, and 1x attr) can be fetched with
a single long /RAS signal (1.5 clks low) and two short /CAS signals (0.5 clks
low):<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> |-----8 clks----||-----8 clks----|-----H/V-Blank...------
/RAS (RAM.Pin4) -___-___---------___-___--------------------------------
/CAS (RAM.Pin15) -_-_-_-_---------_-_-_-_--------------------------------
</TD></TR></TABLE>During drawing, the ULA outputs all /RAS addresses in range 00h..7Fh (though
not in linear order) to the memory, so the above /RAS signals do also serve
as refresh signals.<BR>
<BR>
<B>Details on CPU Access Timings</B><BR>
CPU memory accesses are slower than video DMA (the CPU outputs /CAS and /RAS
low for 1.5 clks, while DMA uses only 0.5 clks for /CAS). Normally, the CPU
does also output a "dummy" /RAS for refresh (1.0 clks low), so a stream of
NOP opcodes would look like so:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> |-----8 clks----||-----8 clks----|
/RAS (RAM.Pin4) -___-__--___-__--___-__--___-__- ;four NOP opcodes
/CAS (RAM.Pin15) -___-----___-----___-----___----
</TD></TR></TABLE>When accessing "contended" memory, the ULA takes care of refresh, so the
CPU's refresh signal can be suppressed, and a stream of NOP opcodes would
look like so (assuming that no VRAM-DMA is taking place, eg. during Hblank):<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> |-----8 clks----||-----8 clks----|
/RAS (RAM.Pin4) -___-----___-----___-----___---- ;four NOP opcodes
/CAS (RAM.Pin15) -___-----___-----___-----___----
</TD></TR></TABLE><BR>
<B>Scanline Effects</B><BR>
The Spectrum doesn't have a Scanline interrupt, so changing video attributes
in specfic scanlines (for using more than 2 colors per 8x8 pixels), or
changing the horizontal resolution in a given scanline (on Timex machines)
can be implemented only by waiting so-and-so-many clock cycles after the
Vsync interrupt has occurred. That method wastes a lot of CPU load, and its
difficult to get it compatible with all computers (due to different
horizontal and vertical timings, and different waitstates).<BR>
Another approach would be reading from Port FFh (or other unused ports), and
to wait until contains a specific color attribute, that method is more
flexible than hardcoded delays, but, it doesn't work on all computers (see
Port FFh info in ULA chapter for details).<BR>
<BR>
<B>Refresh and Snow</B><BR>
The Z80 CPU generates refresh signals used for the non-contended RAM only.<BR>
The contended VRAM uses a different refresh signal generated from the ULA.<BR>
Although contended VRAM doesn't use CPU refresh signal, the ULA can get
"confused" when the CPU refresh occurs with the address bus containing a
contended memory address (ie. when the IR register pair points to
4000h..7FFFh; aka when the I register is 40h..7Fh), in that case the ULA
thinks that the CPU wants to access memory, causing the ULA not to load new
data from VRAM (and to re-use old data), which results in "snow" on the
screen. On Spectrum 128K/+2, the snow effect does exist, but it does
reportedly "crash the machine shortly after I is set to point to contended
memory".<BR>
Hmmm.......... assuming that the effect doesn't just block VRAM reads, but
also VRAM refresh.... then it actually CRASH programs (and BIOS code) that
have code/data located in the "contended" memory regions.... eg. the 16K
spectrum has ONLY contended memory, so the program would survive on a few
seconds or so.... the reported crash on 128K/+2 might have the same reason
(but could be simply avoided by using only uncontended memory)...?<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumsound"></A><FONT SIZE=+2>&nbsp;Spectrum Sound</FONT></TD></TR></TABLE><BR>
<B>Standard ULA Beeper</B><BR>
<A HREF="#spectrumsoundula">Spectrum Sound ULA</A><BR>
<A HREF="#spectrumsoundspeakeramplifiermodulator">Spectrum Sound Speaker/Amplifier/Modulator</A><BR>
<BR>
<B>Programmable Sound Generator</B><BR>
The 3-channel PSG is used in the Spectrum 128/+2/+2A/+3 (and occassionally
supported by newer games).<BR>
<A HREF="#spectrumsoundpsgprogrammablesoundgenerator">Spectrum Sound PSG (Programmable Sound Generator)</A><BR>
The same PSG chip is also used in Timex TS2068/TC2068 computers and in
various expansion boxes (but at different I/O addresses, and rarely supported
by any games).<BR>
<BR>
<B>Speech Hardware</B><BR>
<A HREF="#spectrumsoundspeechoverview">Spectrum Sound Speech Overview</A><BR>
<A HREF="#spectrumsoundspeechioports">Spectrum Sound Speech I/O Ports</A><BR>
<A HREF="#spectrumsoundspeechsp0256voicegenerator">Spectrum Sound Speech SP0256 Voice Generator</A><BR>
<A HREF="#spectrumsoundspeechsp0256instructionset">Spectrum Sound Speech SP0256 Instruction Set</A><BR>
<A HREF="#spectrumsoundspeechsp0256allophoneswords">Spectrum Sound Speech SP0256 Allophones/Words</A><BR>
<A HREF="#spectrumsoundspeechsp0256pinouts">Spectrum Sound Speech SP0256 Pin-Outs</A><BR>
<BR>
<B>Digital Sound (Playback/Recording)</B><BR>
<A HREF="#spectrumsounddigitalplaybacksampling">Spectrum Sound Digital Playback/Sampling</A><BR>
<BR>
<B>MIDI Interfaces</B><BR>
Cheetah MIDI Interface (Cheetah)<BR>
EMR MIDI Interface (Electro Music Research)<BR>
MIDISYNC (Icon Design Ltd.)<BR>
MIDI Sync Boxes (XRI Systems)<BR>
Siel MIDI Interface (Siel UK Ltd)<BR>
Upstream MIDI Interface (Upstream Computer Systems Ltd)<BR>
XRI Micon MIDI Interface (XRI Systems)<BR>
ZX Spectrum 128 +2 to MIDI Lead (Cheetah)<BR>
Music Machine (see Digial Sound chapter for details)<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumsoundula"></A><FONT SIZE=+2>&nbsp;Spectrum Sound ULA</FONT></TD></TR></TABLE><BR>
<B>Sound Frequency vs Video Waitstates</B><BR>
Observe that video waitstates occur when drawing the bitmap area (but not
during Hblank and Vblank), so the presence/absence of waitstates can have
some nasty effects on software generated sound frequencies.<BR>
Basically, do not use code/data in RAM at 4000h..7FFFh when generating
sounds. Waitstates do also occur on accessing Port FEh, which may become a
problem with high-frequency PWM sounds, a workaround would be to access Port
FEh only within multiples of 8 clock cycles (so it runs in sync with video
DMA).<BR>
Aside from waitstates, it may be also good to disable IRQs to prevent the
sound to get paused during IRQ handling (or at least to use a custom fast IRQ
handler).<BR>
<BR>
<B>Sound Volume via Bit3 (not recommended / unstable results)</B><BR>
The ULA has two separate control bits for Sound and Cassette output:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Port FEh.Bit4 = Audio Output (0 = 0.3 Volts, 1 = 3.7 Volts)
Port FEh.Bit3 = Cassette Output (0 = 0.3 Volts, 1 = 0.7 Volts)
</TD></TR></TABLE>However, it does output both signals on the same pin.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Port FEh = 18h --&gt; 3.7V
Port FEh = 10h --&gt; 3.6V
Port FEh = 08h --&gt; 0.7V
Port FEh = 00h --&gt; 0.3V
</TD></TR></TABLE>Below are examples for a Spectrum 48K with Issue 2 mainboard; one column
shows results for the internal speaker, the other column shows results for
the MIC output passed to an external amplifier (eg. to the Audio Input of a
TV set). Furthermore, results may differ on other mainboards (after issue 2,
Sinclair seem to have added a transistor as internal amplifier).<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Toggle between Internal Speaker External Amplifier
00h and 10h Volume = ##### Volume = ##### ;normal
00h and 08h Volume = ..... Volume = ##... ;unpredictable
10h and 18h Volume = ##... Volume = #.... ;unpredictable
</TD></TR></TABLE>Normally, sound should be generated by toggling bit4 of Port FEh. As shown
above, messing with bit3 has rather unpredictable results; toggling between
00h and 08h has a good voltage difference which is audible on external
amplifiers, but not enough amperes to drive the internal speaker; for
toggling between 10h and 18h it's vice versa, the voltage difference is
smaller, but there are more amperes (it becomes audible on internal speaker,
but the volume drops with external amplifier).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumsoundspeakeramplifiermodulator"></A><FONT SIZE=+2>&nbsp;Spectrum Sound Speaker/Amplifier/Modulator</FONT></TD></TR></TABLE><BR>
<B>Internal Speaker (Spectrum 16K/48K/Plus and Timex TS/TC20xx)</B><BR>
Older Spectrums with 16K/48K RAM are containing an internal speaker, used to
output the ULA sound (and PSG sound in case of the Timex 2068). The
dimensions (and volume) of the internal speaker would be more suitable for
headphones. The TV modulator generates a raw video signal (so the TV speaker
is not used).<BR>
<BR>
<B>Internal Audio UHF Modulator (Spectrum 128/+2/+2A/+3)</B><BR>
Newer Spectrums with 128K RAM don't include an internal speaker, instead, the
ULA sound (and PSG sound) is passed to the TV set via the UHF modulator.<BR>
<BR>
<B>External Speakers/Amplifiers and Modulators</B><BR>
To "boost" the volume, several companies offered external amplifiers with
bigger external speakers. Most external PSG/Speech devices do also mix and
amplify the ULA sound with the PSG/Speech sound.<BR>
For using the TV speakers, several companies have offered internal and
external UHF modulators which mixed the audio signal with the video signal
(for modern TVs with A/V inputs sets it'd be easier/cheaper to pass MIC/VID
to A/V input of the TV set, which'd also give better picture quality than
UHF).<BR>
<BR>
<B>External Sound Connectors</B><BR>
In general, sound can be obtained from the MIC port (or anywhere from the
mainboard). The Timex TS2068 does also output PSG/ULA on the expansion port.
The Spectrum expansion Port doesn't have a sound output (however, external
hardware could easily reconstruct ULA sound by latching D4 upon /IORQULA and
/WR). The analogue RGB output on the Spectrum +2A/+3 does also include an
audio pin (unlike the TTL RGB output on the Spectrum 128).<BR>
<BR>
<B>Mono/Stereo Sound</B><BR>
The standard spectrum hardware supports only mono sound output. Some of the
external PSG devices allow to produce stereo sounds by passing one PSG
channel to left, one to right, and the third channel to both left and right
speakers; but, external PSG devices are rarely supported by any games, and
there's no real standard which channel is passed to which speaker.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumsoundpsgprogrammablesoundgenerator"></A><FONT SIZE=+2>&nbsp;Spectrum Sound PSG (Programmable Sound Generator)</FONT></TD></TR></TABLE><BR>
<B>I/O Ports of known PSG devices</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Model Index.W Data.W Data.R Chip Year
Spectrum 128/+2/+2A/+3 FFFDh BFFDh FFFDh 8912 1985
Didaktik Melodik (spectrum 128 style) FFFDh BFFDh FFFDh 891x 19xx
Timex TS2068 (NTSC) xxF5h xxF6h xxF6h 8912 1983
Timex TC2068 (PAL) xxF5h xxF6h xxF6h 8912 1984
Fuller Box xx3Fh xx5Fh xx3Fh 8912 1983
Fuller Box Master Unit (with Orator) xx3Fh xx5Fh xx3Fh 8912 1983
DK'Tronics 3 Channel Sound Synthesiser xx3Fh xx5Fh ? 8912 1984
Timedata ZXM Soundbox (ZX81) xx9Fh xxDFh xxBFh 8912 198x
Timedata ZXM Soundbox (Spectrum) xx9Fh xxDFh xxBFh 8912 198x
William Stuart Systems Music Synthesiser xx9Fh xxDFh ? 891x 1983
Bi-Pak ZON X81 Soundbox (ZX81) xxDFh xx0Fh N/A? 891x 198x
Bi-Pak ZON X Soundbox (Spectrum) xxFFh xx7Fh N/A 8912 1982
Ricoll RISG Sound Generator ? ? ? 8910 1983
Ricoll RIFG Sound Generator with filters ? ? ? 8910 1983
Petron Trichord (includes PROM) ? ? ? 8910 1983
Signpoint Sound Synthesiser Plus ? ? ? 8910 1984
Datel 3 Channel Sound Synthesiser ? ? ? ? 1989
Investronica INAXEL Sound & Joystick ? ? ? ? ?
</TD></TR></TABLE><BR>
<B>Clock Frequency</B><BR>
The "3.5xxMHz/32" in the formulas are meant to be the CPU clock divided by 32
(externally divided by 2 on the mainboard, and internally divided by 16
inside of the PSG). The CPU clock for different models is:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Model CPU Clock Divide by
Spectrum 128/+2/+2A/+3 3.54690MHz / 32
Timex TC2068 (PAL) 3.50000MHz / 32
Timex TS2068 (NTSC) 3.52800MHz / 32
</TD></TR></TABLE>For Spectrum 16K/48K/Plus and Timex TC2048, external PSGs are available, but
in most cases the clock and divider is unknown (the CPU clock on the
expansion port gets stopped on VRAM waitstates, so it isn't suitable for
sound, and the expansion hardware requires to include its own oscillator):<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> ZON X81 Soundbox (ZX81) 3.25MHz / 32
ZON X Soundbox (Spectrum) 3.5MHz / ?
Other Models... ? MHz / ?
Timedata ZXM Soundbox (ZX81) approx 100000 Hz (probably means 3.25/32)
Timedata ZXM Soundbox (Spectrum) approx 100000 Hz (probably means 3.xx/32)
</TD></TR></TABLE><BR>
<B>00h = Tone Frequency channel A, low (0-255)</B><BR>
<B>01h = Tone Frequency channel A, high (0-15)</B><BR>
<B>02h = Tone Frequency channel B, low (0-255)</B><BR>
<B>03h = Tone Frequency channel B, high (0-15)</B><BR>
<B>04h = Tone Frequency channel C, low (0-255)</B><BR>
<B>05h = Tone Frequency channel C, high (0-15)</B><BR>
The actual listened frequency in Hertz is calculated as follows:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> F = 3.5xxMHz / 32 / nn ;with nn in range 1..4095 (nn=0 acts as nn=1)
</TD></TR></TABLE><BR>
<B>06h = Noise Frequency (0-31)</B><BR>
The actual noise frequency in Hertz is calculated as follows:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> F = 3.5xxMHz / 32 / nn ;with nn in range 1..31 (nn=0 acts as nn=1)
</TD></TR></TABLE>Noise can be output on all 3 channels, but there is only one noise generator
(so all channels share the same noise frequency). The noise generator
consists of 17bit shift register, and a 1bit noise level (0=LOW or 1=HIGH).
These are updated at the selected frequency as follows:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> noise_level = noise_level XOR shiftreg.bit0
newbit = shiftreg.bit0 XOR shiftreg.bit3
shiftreg = (shiftreg SHR 1) + (newbit SHL 16)
</TD></TR></TABLE>Note that level isn't set equal to bit0, instead, it toggles when bit0=1.<BR>
<BR>
<B>07h = Mixer Control</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bit Expl.
0 Channel A tone enable (0=Enable, 1=Disable)
1 Channel B tone enable (0=Enable, 1=Disable)
2 Channel C tone enable (0=Enable, 1=Disable)
3 Channel A noise enable (0=Enable, 1=Disable)
4 Channel B noise enable (0=Enable, 1=Disable)
5 Channel C noise enable (0=Enable, 1=Disable)
6 I/O port A mode (0=Input, 1=Output)
7 I/O port B mode (0=Input, 1=Output)
</TD></TR></TABLE>If both Tone and Noise are disabled on a channel, then a constant HIGH level
is output (useful for digitized speech). If both Tone and Noise are enabled
on the same channel, then the signals are ANDed (the signals aren't ADDed)
(ie. HIGH is output only if both are HIGH).<BR>
<BR>
<B>08h = Volume channel A (0-15, 16=Envelope)</B><BR>
<B>09h = Volume channel B (0-15, 16=Envelope)</B><BR>
<B>0Ah = Volume channel C (0-15, 16=Envelope)</B><BR>
Defines the volume, 0=off, 15=max. If bit4=1, then the volume is taken from
the envelope generator. The volume is non-linear:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> amplitude = max / sqrt(2)^(15-nn) ;(according to datasheet)
eg. 15 --&gt; max/1, 14 --&gt; max/1.414, 13 --&gt; max/2, etc.
</TD></TR></TABLE>The volume affects only HIGH levels. LOW levels are always NULL. Ie. sound
output toggles between +VOL and NULL (not between +VOL and -VOL).<BR>
Digitized samples can be written to the volume registers (mind that volume is
non-linear). When doing that, it's best to switch the channel to constant
HIGH level (by disabling both Tone and Noise). Another method would be to set
tone frequency to 000h or 001h (the resulting frequency is too high to be
audible, so the HIGH/LOW levels sound like a constant HALF level).<BR>
<BR>
<B>0Bh = Volume Envelope Frequency, low (0-255)</B><BR>
<B>0Ch = Volume Envelope Frequency, high (0-255)</B><BR>
Envelope step frequency (tone or noise) calculated as follows:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> F = 3.5xxMHz / 32 / nn ;with nn in range 0..65535 (nn=0 acts as nn=1)
</TD></TR></TABLE>Depending on the envelope shape, the volume is incremented from 0 to 15,
or decremented from 15 to 0. In either case it takes 16 steps to complete,
the completion time for 16 steps is therefore:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> T = nn*512 / 3.5xxMHz ;with nn in range 1..65535 (0 .. ca. 9.5 seconds)
</TD></TR></TABLE><BR>
<B>0Dh = Volume Envelope shape (0-15)</B><BR>
Writing to this register (re-)starts the envelope. Additionally, the written
value specifies the envelope shape, the four bits have the following meaning:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> CONT ATT ALT HLD
0 0 X X \_________ 0-3 (same as 9)
0 1 X X /_________ 4-7 (same as F)
1 0 0 0 \\\\\\\\\\ 8 (Repeating)
1 0 0 1 \_________ 9
1 0 1 0 \/\/\/\/\/ A (Repeating)
1 0 1 1 \""""""""" B
1 1 0 0 ////////// C (Repeating)
1 1 0 1 /""""""""" D
1 1 1 0 /\/\/\/\/\ E (Repeating)
1 1 1 1 /_________ F
</TD></TR></TABLE><BR>
<B>0Eh = I/O port A (with external pinouts on AY-3-8910 and AY-3-8912)</B><BR>
<B>0Fh = I/O port B (with external pinouts on AY-3-8910 only)</B><BR>
These are two general purpose 8bit I/O ports (direction can be set via
register 7). Port A exists on both AY-3-8910 and AY-3-8912 chips. Port B
exists on AY-3-8910 only (or actually, it does internally exist even on the
smaller AY-3-8912, but it doesn't have external pinouts).<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Model Port A Port B
Timex TC2068 and TS2068 Joysticks (*) N/A (uses 8912 chip)
Spectrum 128/+2/+2A/+3 RS232/Keypad N/A (uses 8912 chip)
Fuller Box ? N/A (uses 8912 chip)
DK'Tronics Unused? N/A (uses 8912 chip)
Timedata ZXM Soundbox Joystick/User Port N/A (uses 8912 chip)
Signpoint ioport ioport
Other expansions...? ? ? (some do use 8910 chip)
</TD></TR></TABLE>(*) Timex also passes Bit5 of Port A to Expansion Port Pin 30 on upper side.<BR>
<BR>
<B>Spectrum 128/+2/+2A/+3 PSG Software</B><BR>
Some newer games (made after the Spectrum 128 was released in 1985) do
support its PSG hardware (eg. Cybernoid, Exolon, Into the Eagles Nest, Head
Over Heels), but many other newer games don't do so.<BR>
<BR>
<B>Fuller Box and DK'Tronics PSG Software (compatible with each other)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Fuller Box Demonstration Program (Fuller)
Sound Designer (DK'Tronics)
Invasion of the Body Snatchas
</TD></TR></TABLE>Aside from the Fuller Box and DK'Tronics demonstration tapes, there seems to
be almost no other software that supports these PSGs (even DK'Tronics didn't
support their own hardware in their own games).<BR>
<BR>
<B>William Stuart Systems Music Synthesiser Software</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Composer (William Stuart Systems)
</TD></TR></TABLE><BR>
<B>Timex 2068 Software</B><BR>
The TS2068 (USA) wasn't very popular, and the TC2068 (Portugal/Poland) was
mainly used with 'normal' european Spectrum 48K software - so there are
probably not too many (if any?) commercial games that support the PSG in
Timex computers.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumsoundspeechoverview"></A><FONT SIZE=+2>&nbsp;Spectrum Sound Speech Overview</FONT></TD></TR></TABLE><BR>
<B>Known "General Instrument SP0256-AL2 Narrator" Speech devices</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Currah MicroSpeech (1983) - uses SP0256-AL2 speech processor, output via TV
Fuller Orator - Speech Synthesis (1984) - uses G1-SP0256 AL voice chip
Fuller Box Master Unit (PSG and Orator)
Cheetah Sweet Talker (1983) (crude thing that HALTs the CPU during speech)
DK'Tronics Speech Synthesiser (1985) - uses the SLO/256 chip
</TD></TR></TABLE>The Currah MicroSpeech (aka Currah uSpeech) seems to be the most popular
speech device, possibly because of it's easy to use BIOS extension, although
that extension causes very serious compatibility problems with other
software.<BR>
<BR>
<B>Other known Speech devices</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Spirit Instruments - Spectrum Speech Synthesiser (1983)
SS1 Speech Synthesiser (1983)
VTR Vocal Synthesizer (1985)
Timedata ZXS Speech Synthesiser (1983)
William Stuart Systems Chatterbox (1983)
William Stuart Systems Chatterbox II (1985) (with intonation)
Zebra Talker Speech Synthesiser (for Timex)
Datel Vox Box (1984) (allophone)
DCP Microdevelopments S-Pack (1983) - vocabulary of 71 words (upgradeable)
DCP Microdevelopments Speech Pack (1982) for ZX81
</TD></TR></TABLE>There isn't much known about these devices, most are probably containing
SP0256-AL2 chips, too. One exception are the devices from DCP, which contain
Digitalker chips from National Semiconductor, and which use a fixed
vocabulary instead of allophones. Not too sure if Datel has actually
manfactured any hardware (possibly they've just renamed and redistributed
hardware from other companies).<BR>
<BR>
<B>Cheetah Sweet Talker Software</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Chatbox (Demonstration Program by Cheetah Marketing Ltd.)
</TD></TR></TABLE><BR>
<B>Fuller Orator / Master Unit Speech Software</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Spectrum Voice Chess (Fuller Box version; ie. NOT the ULA version) (Artic)
</TD></TR></TABLE><BR>
<B>DK'Tronics Speech Software</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Speech Software (Demonstration Program by DK'Tronics Ltd.)
</TD></TR></TABLE><BR>
<B>Currah MicroSpeech Software</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Title Publisher
3-D Monster Chase Romik Software
All or Nothing Abbex Electronics
Arrow of Death Part 1 Digital Fantasia
Arrow of Death Part 2 Digital Fantasia
Atic Atac Ultimate Play The Game
Auf Wiedersehen Pet Tynesoft
Bingo Tynesoft
Birds and the Bees, The Bug-Byte Software Ltd
Blade Alley PSS
Blastermind! Martech Games Ltd
Blob, The 16/48 Tape Magazine
Bongo Anirog Software
Cagara Players Software
Colour Clash Romik Software
Connect 4 John Westhead
Covenant, The PSS
Crazy Golf Mr. Micro Ltd
Currah MicroSpeech Currah Computer Components Ltd
Currah MicroSpeech Software Cecomsa
Evil Dead, The Palace Software
Fruit Snapper LiveWire Software
Giant's Revenge Thor Computer Software
Golden Baton Digital Fantasia
Grand Prix Driver Britannia Software Ltd
Gremlins Thor Computer Software
Harlequin Mr. Micro Ltd
Hunchback Ocean Software Ltd
Insult Generator Greg Fox
Island, The Crystal Computing
Jack and the Beanstalk Thor Computer Software
Learn with Ted Playground Software
Lunar Jetman Ultimate Play The Game
Lunar Rescue Lyversoft
Max Headroom Quicksilva Ltd
Maze of Terror Kevin Hillyer
Maziacs DK'Tronics Ltd
Mega Fruit Thor Computer Software
Mined-Out Quicksilva Ltd
Moon Alert Ocean Software Ltd
Mr. Wimpy Ocean Software Ltd
Mystic Tower Aardvark Software
Night Stalker Thor Computer Software
Pi-Balled Automata UK Ltd
Pogo Ocean Software Ltd
Pontoon Oxford Computer Publishing
Psi-Spy Postern Ltd
Punchy Mr. Micro Ltd
Rainy Day CCS
Rockfall Crash
Rockfall II Crash
Roulette Oxford Computer Publishing
Sexy Black Jack Load 'n' Run [Ita]
Shark Attack Romik Software
Skelby - The Schizophrenic Droid Q Bit
Spectrum Voice Chess Artic Computing Ltd
Spiders Web Thor Computer Software
Sport of Kings Mastertronic Added Dimension
Spyship SOS Dynamic Software
Starbike The Edge Software
Steve Davis Snooker CDS Microsystems
Terrahawks CRL Group PLC
Timebomb CDS Microsystems
Time Machine, The Digital Fantasia
Titanic R&R Software Ltd
Twin Kingdom Valley Bug-Byte Software Ltd
War of the Worlds, The CRL Group PLC
Xavior PSS
Zepherus National Software Library
Zig Zag DK'Tronics Ltd
</TD></TR></TABLE>Not verified if the above list is correct (Spectrum Voice Chess seems to be
wrong, versions that support ULA and Fuller speech do exist, but there seems
to be no Currah version).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumsoundspeechioports"></A><FONT SIZE=+2>&nbsp;Spectrum Sound Speech I/O Ports</FONT></TD></TR></TABLE><BR>
<B>xx9Fh - Fuller Orator / Fuller Box Master Unit - Speech Output (W)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-5 SP0256-AL2 Allophone number
6-7 Unknown
</TD></TR></TABLE><BR>
<B>xxBFh - Fuller Orator / Fuller Box Master Unit - Speech Status (R)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-6 Unknown
7 Load Request (LRQ) (0=Buffer full, 1=Ready to receive data)
</TD></TR></TABLE><BR>
<B>007Fh - DK'Tronics Speech Synthesiser - Speech Output (W)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-5 SP0256-AL2 Allophone number
6-7 Unknown
</TD></TR></TABLE><BR>
<B>007Fh - DK'Tronics Speech Synthesiser - Speech Status (R)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-6 Unknown
7 Load Request (LRQ) (0=Ready to receive data, 1=Not ready)
</TD></TR></TABLE><BR>
<B>DK'Tronics Speech Synthesiser - Software Driver</B><BR>
The DK'Tronics hardware doesn't include a BIOS/BASIC extension ROM, but, the
BASIC demonstration program includes a machine code driver, which allows the
LPRINT command with backslash to be used to output speech, eg.:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> LPRINT "\d k tronics"
LPRINT "print this\speak this"
</TD></TR></TABLE>the DK'Tronics driver does attempt to properly pronounce words automatically,
without needing to use special codes like (aa) (dth) as used by Currah.<BR>
<BR>
<B>0007h - Cheetah Sweet Talker - Speech Output (halts CPU) (W)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-5 SP0256-AL2 Allophone number
6-7 Unknown
</TD></TR></TABLE>This poor piece of hardware doesn't seem to have a status register that
indicates when new data can be sent, instead, it does simply HALT the CPU
when speech is busy. Not sure if halting is bound to the SBY or /LRQ pin (?)
(in the latter case one could still execute some program code when
implementing complex timings in software).<BR>
<BR>
<B>Read from Memory Address 0038h - Enable/Disable Currah uSpeech BIOS</B><BR>
Reading from this memory address enables/disables the 2K uSpeech BIOS (and
probably also the uSpeech command/status register), ie. on each second read
it gets enabled (at 0000h..07FFh), on each other read it gets disabled.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-7 Data/Opcode from the (newly) activated ROM
</TD></TR></TABLE>Usually the enable takes place when the CPU jumps to the vblank IRQ handler
at 0038h, which is then redirected to the uSpeech BIOS, which does then do
it's job, and jumps to 0038h, which re-enables the Spectrum BIOS and executes
the normal IRQ handler.<BR>
There are no further BIOS hooks; initialization (upon reset) is also done
from inside of the hooked IRQ handler.<BR>
<BR>
<B>Read from Memory Address 1000h - Currah uSpeech Status (R)</B><BR>
This port is probably accessible only when enabled via address 0038h.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 Load Request (LRQ) (1=Buffer full, 0=Ready to receive data)
1-7 Unknown/unused
</TD></TR></TABLE>Bit0 seems to be the /LRQ pin of the SP0256 chip. Unknown if the SBY pin
(indicating when all data is finished) is also found in this register?<BR>
The size of the buffer is unknown, maybe it can only hold only a single value
(additionally to the sound being currently played)...?<BR>
<BR>
<B>Write to Memory Address 1000h - Currah uSpeech Output (W)</B><BR>
This port is probably accessible only when enabled via address 0038h.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-5 SP0256-AL2 Allophone Number (00h..3Fh)
6 Intonation (0=Decrease Pitch, 1=Increase Pitch)
7 Unknown/unused (should be zero)
</TD></TR></TABLE>Data can be written to this register when the Status.Bit0 indicates ready
(not sure happens when it doesn't). The last allophone should be followed by
a pause (eg. 00h=Pause10ms), otherwise the SP0256 does reportedly gets stuck
repeating the last allophone (not sure what gets repeated exactly, maybe it
repeats only the end of the last allophone, ie. "shhhhhhh" for "sh", or maybe
the whole last allophone, ie. "shshshsh"?)<BR>
The intonation bit seems to be a special feature of the Currah hardware (not
a feature of the SP0256 voice chip itself). Unknown how it is implemented...
it might modify the CLK passed to the SP0256... so, aside from the frequency,
this would also alter the durations, ie. the length of a "100ms" pause would
vary... or it might modify whatever kind of external low-pass and/or
high-pass filter...? The intonation does increase step-by-step (rather than
changing abruptly from low to high)... the stepping rate, and the max/min
values are unknown?<BR>
<BR>
<B>Currah uSpeech Mirrors of 0038h and 1000h and ROM</B><BR>
Reads from memory address 0038h are also mirrored to reads from I/O address
0038h (used by Rockfall to detect the uSpeech), apparently the port is
decoded by checking only A0..A15 and /RD.<BR>
For address 1000h it's still unknown if there are mirrors, possibly, only
/RD, /WR, A12, A14, A15 are decoded (probably together with the uSpeech BIOS
enable flag which gets set/cleared via 0038h); if so, mirrors would occur at
1000h-1FFFh and 3000h-3FFFh in both memory and I/O region? If so, using the
I/O mirrors would be not too recommended since they could conflict with other
internal/external I/O ports.<BR>
For the ROM it's unknown if it's mirrored, too. Might be mirrored to
800h..FFFh and 2000h-2FFFh?<BR>
<BR>
<B>Currah uSpeech BIOS/BASIC extension</B><BR>
Unlike most or all other speech devices, the Currah hardware includes a BIOS
extension. Currah related BASIC commands are:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> LET keys=0 ;disable spoken keystrokes (recommended for LOAD/SAVE)
LET keys=1 ;enable spoken keystrokes (default)
LET s$="he(ll)(oo)" ;say hello (normal lowercase)
LET s$="hE(ll)(oO)" ;say hello (with raised intonation on "e" and "(oo)")
PAUSE 1 ;wait for Vblank IRQ (where s$ is processed)
CLEAR n ;change RAMTOP (speech buffer is between RAMTOP and UDG)
IF PEEK(65364)=81 ;buffer pointer LSB, [FF54h]=51h=buffer_empty (on 48K)
IF s$(TO 1)="*" ;check if s$ was processed (copied to speech buffer)
IF s$(TO 1)="?" ;check if s$ was rejected (contained invalid characters)
IF s$(TO 1)=other ;check if s$ was not yet processed (or buffer full)
</TD></TR></TABLE>On power up, the Currah BIOS allocates 256 bytes between RAMTOP and UDG,
containing a 6-byte "header", and a 250-byte buffer; which contains allophone
numbers (and intonation flag in bit6), in the format as written to address to
1000h (ie. not in ASCII format as used in the BASIC s$ variable). On the
Spectrum this region is at FFxxh (on Spectrum 16K it's at 7Fxxh):<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> FF57h - Flag byte
FF56h - Spare (unused general purpose byte; NOT reserved for anything)
FF55h - Hi byte of buffer pointer ;\contains FF51h when empty
FF54h - Lo byte of buffer pointer ;/
FF53h - Spare (unused general purpose byte; NOT reserved for anything)
FF52h - Spare (unused general purpose byte; NOT reserved for anything)
FF51h..FE58h - Speech buffer (default size=250) [FF51h]=next allophone
</TD></TR></TABLE>In BASIC, the spoken keystrokes and s$ strings are good for a first "oh it
does really speak" impression, although after soon, the keystroke feature may
become annoying, and the automatic modification of the first character in s$
may cause compatibility problems with various BASIC programs that do use s$
for other purposes.<BR>
Moreover, allocating 256 bytes between RAMTOP and UDG may cause problems with
many machine code programs. And, hooking the IRQ handler changes Vblank
handling timings which may also cause problems with a few programs.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumsoundspeechsp0256voicegenerator"></A><FONT SIZE=+2>&nbsp;Spectrum Sound Speech SP0256 Voice Generator</FONT></TD></TR></TABLE><BR>
<B>Voice Generator</B><BR>
The voice generator relies on the Amplitude, Pitch, F0..F5, and B0..B5
registers, which are processed like so:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Amplitude --&gt; F0 --&gt; F1 --&gt; F2 --&gt; F3 --&gt; F4 --&gt; F5 --&gt; PWM --&gt; External
Pitch/Noise B0 B1 B2 B3 B4 B5 5kHz Filter
</TD></TR></TABLE>Another important register is the Repeat counter, which indicates when the
next opcode shall be executed (and which may then load new values into the
above registers).<BR>
<BR>
<B>Sample Rate and Repeat Timings</B><BR>
The SP0256 is (usually) driven by a 3.12MHz oscillator, and it uses 7bit PWM
output, which is clocked at 3.12MHz/2. To obtain a 10kHz sample rate, the
chip issues some dummy steps with constant LOW level additionally to the 128
steps needed for 7bit PWM, making it a total number of 156 steps per sample.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Sample Rate = 3.12MHz/2/156 = 10.0kHz ;100us per sample
</TD></TR></TABLE>Which means one sample is 100us long, that value multiplied by 64 or 91 gives
the following timings per repeat:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 6.4ms per repeat (noise and pause), or
9.1ms per repeat (tone with pitch=91)
</TD></TR></TABLE>Note: Some speech interfaces have the chip overclocked to 4MHz, resulting in
higher pitch & sample rate, and shorter timings as with the normal 3.12MHz.<BR>
<BR>
<B>Amplitude/Pitch/Repeat</B><BR>
The 8bit amplitude register defines the volume in floating point form,<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Amplitude = lower5bit SHL upper3bit
</TD></TR></TABLE>The pitch defines the frequency, counted in numbers of samples per period.<BR>
For pitch=91, one HIGH sample (amplitude) is output, followed by 90 zero
samples (null). That pattern is repeated as many times as specified in the
repeat count, for example, with repeat=3:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> __ Amplitude level (+)
| | |
|________|________|________ __ Zero level PITCH
</TD></TR></TABLE><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> &lt;-Pitch-&gt; __ Amplitude level (-)
&lt;--------repeat=3---------&gt;
</TD></TR></TABLE>As shown above, the generated waveform is NOT a square wave (which would have
50% high, and 50% low). After applying filters, the final waveform may look
somewhat like so:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> __ Amplitude level (+)
| | |
|_|_.____|_|_.____|_|_.____ __ Zero level PITCH+FILTERS
| | | | | |
| | | __ Amplitude level (-)
</TD></TR></TABLE>Note that (aside from noise) the AL2 ROM uses only one pitch value: 5Bh aka
91 decimal (meaning that all vowels are using the same base frequency, and
they differ only by using different filter settings).<BR>
<BR>
<B>Amplitude/Noise/Repeat</B><BR>
Noise is activated when setting pitch=0. The timings are then same as when
pitch=64, but instead of outputting HIGH and NULL levels, the hardware does
now randomly output HIGH or LOW levels, for example, pitch=0 and repeat=5:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> __ Amplitude level (+)
||| || | | | || | || ||| |
|||_|| |__|_|__||_|___|| |||_| __ Zero level NOISE
| | || | || | ||| | |
&lt;-64-&gt;| || | || | ||| | | __ Amplitude level (-)
&lt;----------repeat=5----------&gt;
</TD></TR></TABLE>The exact random algorithm is unknown (probably some shift/xor stuff?), the
random levels seem to be output on each sample (not only on the first sample
of a repeat). Like normal pitch, the noise is passed to the 6 filters.<BR>
<BR>
<B>Pause/Repeat</B><BR>
The pause command sets amplitude=0. The timings are then same as when
pitch=64, but the output is always NULL, for example, pause and repeat=5:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> __ Amplitude level (+)
</TD></TR></TABLE><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> ______________________________ __ Zero level PAUSE (SILENCE)
</TD></TR></TABLE><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> &lt;-64-&gt; __ Amplitude level (-)
&lt;----------repeat=5----------&gt;
</TD></TR></TABLE>Pause does reset the filters to 0, so the silence is not affected by filters.<BR>
<BR>
<B>Digital Filters</B><BR>
As shown above, the amplitude/pitch/noise output is passed through six
digital filter stages (using the F0..F5 and B0..B5 registers), each stage
looks like so:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> _____ _____
------------------&gt;| |-------------------&gt;| |-----+-----&gt;
_____ | SUB | ______ | SUB | |
+---&gt;| *B |---&gt;|_____| +---&gt;| *2*F |--&gt;|_____| |
| |_____| _____ | |______| _____ |
+---------------|OLDER|&lt;---+---------------| OLD |&lt;----+
|_____| |_____|
</TD></TR></TABLE>Ie. the incoming samples are adjusted like so:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> for i=0 to 5 ;filter number
sample = sample - quant_table[F.i] * OLD.i * 2 ;F0..F5 registers
sample = sample - quant_table[B.i] * OLDER.i ;B0..B5 registers
OLDER.i = OLD.i
OLD.i = sample
next i
</TD></TR></TABLE>Whereas, quant_table is a non-linear translation table that translates the
signed 8bit registers to signed 10bit factors (with 9bit fractional part, ie.
511 means 0.99), with following entries:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 ,9 ,17 ,25 ,33 ,41 ,49 ,57 ,65 ,73 ,81 ,89 ,97 ,105,113,121
129,137,145,153,161,169,177,185,193,201,209,217,225,233,241,249
257,265,273,281,289,297,301,305,309,313,317,321,325,329,333,337
341,345,349,353,357,361,365,369,373,377,381,385,389,393,397,401
405,409,413,417,421,425,427,429,431,433,435,437,439,441,443,445
447,449,451,453,455,457,459,461,463,465,467,469,471,473,475,477
479,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495
496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511
</TD></TR></TABLE>Above shows only positive values for index 0..127. Values for index -1..-128
should be 0..-511, or maybe -9..-512.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumsoundspeechsp0256instructionset"></A><FONT SIZE=+2>&nbsp;Spectrum Sound Speech SP0256 Instruction Set</FONT></TD></TR></TABLE><BR>
<B>Memory</B><BR>
The SP0256 can address 60Kbytes (480Kbits) of internal or external ROM,
however, usally the ROMs are only 2Kbytes (16Kbit). The ROM contains plain
program code, without any kind of data arrays.<BR>
The upper 4bit of the program counter cannot be zero, so the memory starts at
byte-address 1000h, and ends at FFFFh. The first 512 bytes are entrypoints,
usually containing JUMP opcodes for up to 256 allophones or words.<BR>
The opcodes and their parameters are transferred serially, LSB first (except,
for some reason, the JUMP/CALL/SETPAGE "Target" values are MSB first).<BR>
The JUMP/CALL/RET opcodes can address only byte-aligned addresses, however,
opcodes aren't always multiples of 8bits in size, so following opcodes may
begin on any bit boundary.<BR>
<BR>
<B>Opcode Summary</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0000b SETPAGE/RET Set Page for JUMP/CALL, or Return from CALL
0001b SETMODE Set the MODE bits and Repeat MSBs
0010b LOAD_23 Load Pitch, Amplitude, 2-3 Coefficients
0011b LOAD_56 Load Pitch, Amplitude, 5-6 Coefficients
0100b LOAD_56D Load Pitch, Amplitude, 5-6 Coefficients, Delta
0101b SETMSB_3 Load Amplitude, MSBs of 3 Coefficients
0110b SETMSB_23 Load Amplitude, MSBs of 2 or 3 Coeffcients
0111b LOAD_PA Load Pitch, Amplitude
1000b LOAD_ALL Load All Parameters (at full 8bit precision)
1001b DELTA_56 Add Delta to Amplitude, Pitch, 5 or 6 Coefficients
1010b SETMSB_3P Load Amplitude, MSBs of 3 Coefficients, Pitch
1011b DELTA_23 Add Delta to Amplitude, Pitch, 2 or 3 Coefficients
1100b SETMSB_3D Load Amplitude, MSBs of 3 Coefficients, Delta
1101b CALL Jump to Subroutine (12-bit PAGE-Relative Address)
1110b JUMP Jump to 12-bit PAGE-Relative Address
1111b PAUSE Silent Pause
</TD></TR></TABLE>Each opcode starts with a 4bit parameter field, followed by the 4bit opcode
number, eventually followed by further Nbit parameter(s).<BR>
<BR>
<B>Opcode 1110b - JUMP - Jump to 12-bit PAGE-Relative Address</B><BR>
<B>Opcode 1101b - CALL - Jump to Subroutine (12-bit PAGE-Relative Address)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 4 Target bit8-11 (in reversed bit-order!)
4 Opcode (must be 1110b or 1101b)
8 Target bit0-7 (in reversed bit-order!)
0..7 Byte-alignment for next opcode (should be padded with 0 bits)
</TD></TR></TABLE>Jumps to the specified memory address, Target bit12-15 are taken from the
PAGE register (which is usually 01h, set like so on power up, but can be set
to other values in range 01h..0Fh via SETPAGE).<BR>
CALL pushes the 16bit byte-aligned return address onto stack, and marks the
stack as not empty. The previous contents of the stack are lost (the stack is
only one entry deep).<BR>
<BR>
<B>Opcode 0000b with Zero-Operand - RET - Return from Subroutine (or HALT)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 4 Zero for RET (00h=Return)
4 Opcode (must be 0000b)
0..7 Byte-alignment for next opcode (should be padded with 0 bits)
</TD></TR></TABLE>If the stack was not empty: Jumps to the pushed return address (ie. to the
next byte after the most recent CALL opcode), and marks the stack as empty.<BR>
If the stack was already empty: Enters HALT state until/unless new data
is/was input via /ALD pin. As soon as new data is available, it jumps to
1000h+data*2.<BR>
Note: HALT state stops program execution, but does not stop the sound
generator - to obtain silence, issue a short PAUSE (or another opcode that
sets amplitude=0).<BR>
<BR>
<B>Opcode 0000b with Nonzero-Operand - SETPAGE - Set the PAGE register</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 4 Target bit12-15 (in reversed bit-order!) (01h..0Fh=Page)
The above target bits are used for ALL following JUMP/CALL opcodes
4 Opcode (must be 0000b)
</TD></TR></TABLE>The PAGE register retains its setting until the next SETPAGE is encountered.<BR>
(Note that address loads via ALD appear to ignore PAGE, and set the four MSBs
to $1000. They do not modify the PAGE register, so subsequent JUMP/CALL
instructions will jump relative to the current value in PAGE.)<BR>
<BR>
<B>Opcode 0001b - SETMODE - Set the MODE bits and Repeat MSBs</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 2 Repeat Count bit4-5 (expands the next ONE opcode that uses 4bit repeat)
1 WIDTH for ALL following opcodes (0=Smaller, 1=Bigger bit-width)
1 EXTRA for ALL following opcodes (0=Exclude, 1=Include optional params)
4 Opcode (must be 0001b)
</TD></TR></TABLE>Some opcodes have coefficient parameters of variable width (for example "3/6"
means 3bit or 6bit), the smaller width is used when WIDTH=0, the bigger when
WIDTH=1.<BR>
Some opcodes have optional parameters (for example "(8)" means an optional
8bit parameter), which is included in the opcode only when EXTRA=1.<BR>
<BR>
<B>Opcode 1111b - PAUSE - Silent Pause</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 4 Repeat Count
4 Opcode (must be 1111b)
</TD></TR></TABLE>Provides a silent pause of varying length. The pause behaves identially to a
pitch with Amplitude=0 and Period=64. All coefficients are cleared, as well.<BR>
<BR>
<B>Opcode 0111b - LOAD_PA - Load Pitch, Amplitude</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 4 Repeat Count
4 Opcode (must be 0111b)
6 Amplitude MSBs (upper 3bit are exponent)
8 Pitch (00h=Noise)
</TD></TR></TABLE><BR>
<B>Opcode 1000b - LOAD_ALL - Load All Parameters (at full 8bit precision)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 4 Repeat Count
4 Opcode (must be 1000b)
8 Amplitude unsigned (upper 3bit are exponent)
8 Pitch unsigned (00h=Noise)
8 Coeff B0 signed ;\coeff pair 0
8 Coeff F0 signed ;/
8 Coeff B1 signed ;\coeff pair 1
8 Coeff F1 signed ;/
8 Coeff B2 signed ;\coeff pair 2
8 Coeff F2 signed ;/
8 Coeff B3 signed ;\coeff pair 3
8 Coeff F3 signed ;/
8 Coeff B4 signed ;\coeff pair 4
8 Coeff F4 signed ;/
8 Coeff B5 signed ;\coeff pair 5
8 Coeff F5 signed ;/
(8) Amplitude Interpolation, signed ;\when EXTRA=1 only
(8) Pitch Interpolation, signed ;/
</TD></TR></TABLE>Notes: The pitch and amplitude deltas that are available when EXTRA=1 are
applied every pitch period, not just once. Wraparound may occur. If the Pitch
goes to zero, the periodic excitation switches to noise.<BR>
<BR>
<B>Opcode 0010b - LOAD_23 - Load Pitch, Amplitude, 2-3 Coefficients</B><BR>
<B>Opcode 0011b - LOAD_56 - Load Pitch, Amplitude, 5-6 Coefficients</B><BR>
<B>Opcode 0100b - LOAD_56D - Load Pitch, Amplitude, 5-6 Coefficients, Delta</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 4 Repeat Count
4 Opcode (must be 0010b or 0011b or 0100b)
6 Amplitude MSBs (upper 3bit are exponent)
8 Pitch (00h=Noise)
3/6 Coeff B0 Bit4/1..6 unsigned ;\coeff pair 0 ;\
5/6 Coeff F0 Bit3/2..7 signed ;/ ;
3/6 Coeff B1 Bit4/1..6 unsigned ;\coeff pair 1 ; opcode LOAD_56D,
5/6 Coeff F1 Bit3/2..7 signed ;/ ; and LOAD_56 only
3/6 Coeff B2 Bit4/1..6 unsigned ;\coeff pair 2 ;
5/6 Coeff F2 Bit3/2..7 signed ;/ ;/
4/6 Coeff B3 Bit3/1..6 unsigned ;\coeff pair 3
6/7 Coeff F3 Bit2/1..7 signed ;/
7/8 Coeff B4 Bit1/0..7 signed ;\coeff pair 4
6/8 Coeff F4 Bit2/0..7 signed ;/
(8) Coeff B5 Bit0..7 signed ;\coeff pair 5 ;\when EXTRA=1 only
(8) Coeff F5 Bit0..7 signed ;/ ;/
5 Amplitude Interpolation LSBs, unsigned ;\opcode LOAD_56D only
5 Pitch Interpolation LSBs, unsigned ;/
</TD></TR></TABLE>Sets the unspecified coefficients to 0. The "unsigned" B0,B1,B2,B3 values are
zero-expanded from N bits to (N+1) bits, and are then copied to the upper
(N+1) bits of the register.<BR>
<BR>
<B>Opcode 0110b - SETMSB_23 - Load Amplitude, MSBs of 2 or 3 Coeffcients</B><BR>
<B>Opcode 0101b - SETMSB_3 - Load Amplitude, MSBs of 3 Coefficients</B><BR>
<B>Opcode 1010b - SETMSB_3P - Load Amplitude, MSBs of 3 Coefficients, Pitch</B><BR>
<B>Opcode 1100b - SETMSB_3D - Load Amplitude, MSBs of 3 Coefficients, Delta</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 4 Repeat Count
4 Opcode (must be 0101b or 0110b or 1010b or 1100b)
6 Amplitude MSBs (upper 3bit are exponent)
[8] Pitch (00h=Noise) ;-Opcode SETMSB_3P only
5/6 New F0 MSBs signed ;\
5/6 New F1 MSBs signed ; Opcode SETMSB_3/3P/3D only
5/6 New F2 MSBs signed ;/
6/7 New F3 MSBs signed ;\
6/8 New F4 MSBs signed ; Opcode SETMSB_23 only
(8) New F5 MSBs signed (when EXTRA=1 only) ;/
(0) Set F5=0 and B5=0 (when EXTRA=0 only)
[5] Amplitude Interpolation LSBs, unsigned ;\Opcode SETMSB_3D only
[5] Pitch Interpolation LSBs, unsigned ;/
</TD></TR></TABLE>All other coefficient bits are unaffected (ie. all coefficients that aren't
accessed by the specific opcode, as well as LSBs of accessed coefficients).<BR>
<BR>
<B>Opcode 1001b - DELTA_56 - Add Delta to Amplitude, Pitch, 5 or 6 Coefficients</B><BR>
<B>Opcode 1011b - DELTA_23 - Add Delta to Amplitude, Pitch, 2 or 3 Coefficients</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 4 Repeat Count
4 Opcode (must be 1001b or 1011b)
4 Amplitude Interpolation 6 MSBs signed
5 Pitch Interpolation LSBs signed
3/4 B0 4,7 MSBs signed ;\ ;\
3/4 F0 5,6 MSBs signed ;/ ;
3/4 B1 4,7 MSBs signed ;\ ; opcode DELTA_56 only
3/4 F1 5,6 MSBs signed ;/ ;
3/4 B2 4,7 MSBs signed ;\ ;
3/4 F2 5,6 MSBs signed ;/ ;/
3/4 B3 5,7 MSBs signed ;\
4/5 F3 6,7 MSBs signed ;/
4/5 B4 x,8 MSBs signed ;\ &lt;---- DELTA_56: x=6, and DELTA_23: x=7 (?)
4/5 F4 6,8 MSBs signed ;/
(5) B5 (8) MSBs signed ;\ ;\when EXTRA=1 only
(5) F5 (8) MSBs signed ;/ ;/
</TD></TR></TABLE>Performs a delta update, adding small 2s complement numbers to a series of
coefficients. The 2s complement updates for the various filter coefficients
only update some of the MSBs -- the LSBs are unaffected. The exact bits which
are updated are noted above.<BR>
Normal 2s complement arithmetic is performed, and no protection is provided
against overflow. Adding 1 to the largest value for a bit field wraps around
to the smallest value for that bitfield.<BR>
Notes: The delta update is applied only once (even if the repeat count is
bigger than 1).<BR>
The delta updates are applied to the 8-bit encoded forms of the coefficients,
not the 10-bit decoded forms.<BR>
The update to the amplitude register is a normal 2s complement update to the
entire register. This means that any carry/borrow from the mantissa will
change the value of the exponent. The update doesn't know anything about the
format of that register.<BR>
<BR>
<B>Program Counter and Stack Note</B><BR>
As seen in the datasheets for external speech ROMs, the Program Counter &
Stack seem to be part of the ROM (not of the microprocessor). So, when using
external ROMs, one would theoretically have separate stacks for each ROM. NB.
this explains why the Target values are reversed; apparently the ROMs use
different bit-order (for memory addresses) than the microprocessor does for
its own values (ie. the opcodes and voice-parameters).<BR>
<BR>
<B>Credits</B><BR>
The SP0256 opcodes were reverse engineered by Joe Zbiciak and Frank Palazzolo.<BR>
<BR>
<B>Repeat Count = 0</B><BR>
According to Joe and Frank, a repeat count of zero "causes the instruction to
not execute" (and not to fetch any of its following paramters, so the opcode
becomes only 8bits long; or to fetch, but not apply them?), however, they've
also mentioned that "conflicting documentation suggests there's more going
on".<BR>
<BR>
<B>XXX...</B><BR>
Bit fields narrower than 8 bits are MSB justified unless specified otherwise,
meaning that the least significant bits are the ones that are missing. These
LSBs are filled with zeros.<BR>
<BR>
When updating filter coefficients with a delta-update, the microsequencer
performs plain 2s-complement arithmetic on the 8-bit value in the coefficient
register file. No attention is paid to the format of the register.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumsoundspeechsp0256allophoneswords"></A><FONT SIZE=+2>&nbsp;Spectrum Sound Speech SP0256 Allophones/Words</FONT></TD></TR></TABLE><BR>
<B>SP0256-AL2 Allophone List</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Num Name Example Funny Actual Num Name Example Funny Actual
00h PA1 PAUSE 10ms 6.4ms 20h /AW/ Out 370ms 254.8ms
01h PA2 PAUSE 30ms 25.6ms 21h /DD2/ Do 160ms 72.1ms
02h PA3 PAUSE 50ms 44.8ms 22h /GG3/ Wig 140ms 110.5ms
03h PA4 PAUSE 100ms 96.0ms 23h /VV/ Vest 190ms 127.4ms
04h PA5 PAUSE 200ms 198.4ms 24h /GG1/ Got 80ms 72.1ms
05h /OY/ Boy 420ms 291.2ms 25h /SH/ Ship 160ms 198.4ms
06h /AY/ Sky 260ms 172.9ms 26h /ZH/ Azure 190ms 134.1ms
07h /EH/ End 70ms 54.6ms 27h /RR2/ Brain 120ms 81.9ms
08h /KK3/ Comb 120ms 76.8ms 28h /FF/ Food 150ms 108.8ms
09h /PP/ Pow 210ms 147.2ms 29h /KK2/ Sky 190ms 134.4ms
0Ah /JH/ Dodge 140ms 98.4ms 2Ah /KK1/ Can't 160ms 115.2ms
0Bh /NN1/ Thin 140ms 172.9ms 2Bh /ZZ/ Zoo 210ms 148.6ms
0Ch /IH/ Sit 70ms 45.5ms 2Ch /NG/ Anchor 220ms 200.2ms
0Dh /TT2/ To 140ms 96.0ms 2Dh /LL/ Lake 110ms 81.9ms
0Eh /RR1/ Rural 170ms 127.4ms 2Eh /WW/ Wool 180ms 145.6ms
0Fh /AX/ Succeed 70ms 54.6ms 2Fh /XR/ Repair 360ms 245.7ms
10h /MM/ Milk 180ms 182.0ms 30h /WH/ Whig 200ms 145.2ms
11h /TT1/ Part 100ms 76.8ms 31h /YY1/ Yes 130ms 91.0ms
12h /DH1/ They 290ms 136.5ms 32h /CH/ Church 190ms 147.2ms
13h /IY/ See 250ms 172.9ms 33h /ER1/ Letter 160ms 109.2ms
14h /EY/ Beige 280ms 200.2ms 34h /ER2/ Fir 300ms 209.3ms
15h /DD1/ Could 70ms 45.5ms 35h /OW/ Beau 240ms 172.9ms
16h /UW1/ To 100ms 63.7ms 36h /DH2/ Bath 240ms 182.0ms
17h /AO/ Aught 100ms 72.8ms 37h /SS/ Vest 90ms 64.0ms
18h /AA/ Hot 100ms 63.7ms 38h /NN2/ No 190ms 136.5ms
19h /YY2/ Yes 180ms 127.4ms 39h /HH2/ Hoe 180ms 126.0ms
1Ah /AE/ Hat 120ms 81.9ms 3Ah /OR/ Store 330ms 236.6ms
1Bh /HH1/ He 130ms 89.6ms 3Bh /AR/ Alarm 290ms 200.2ms
1Ch /BB1/ Business 80ms 36.4ms 3Ch /YR/ Clear 350ms 245.7ms
1Dh /TH/ Thin 180ms 128.0ms 3Dh /GG2/ Guest 40ms 69.4ms
1Eh /UH/ Book 100ms 72.8ms 3Eh /EL/ Saddle 190ms 136.5ms
1Fh /UW2/ Food 260ms 172.9ms 3Fh /BB2/ Business 50ms 50.2ms
</TD></TR></TABLE>Mind that completion of an allophone doesn't mute the voice generator (it'll
keep repeating the end of the allophone until receiving a new allophone). To
mute the voice generator, output a short pause (eg. PA1) after your last
allophone.<BR>
The "Funny" timings are from the SP0256-AL2 data sheet (these values are
totally wrong). The "Actual" timings are calculated from the pitch/repeat
values in the AL2 ROM (these values should be 100% correct, when clocked at
3.12MHz).<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> &lt;--------------- Currah Codes ---------------&gt;
Num ASCII Num ASCII Num ASCII Num ASCII
18h a 27h r 14h (aa)/(ay) 29h (ck)
1Ch b 37h s 13h (ee) 3Ch (ear)
08h c 11h t 06h (ii) 1Ah (eh)
15h d 0Fh u 35h (oo)/(eau) 33h (er)
07h e 23h v 3Fh (bb) 34h (err)
28h f 2Eh w 21h (dd) 2Ch (ng)
24h g - x "ks" 3Dh (gg) 3Ah (or)
1Bh h 31h y 22h (ggg) 16h (ou)
0Ch i 2Bh z 39h (hh) 1Fh (ouu)
0Ah j 3Eh (ii) 20h (ow)
2Ah k 36h N/A 38h (nn) 05h (oy)
2Dh l 00h EOL 0Eh (rr) 25h (sh)
10h m 01h ' 0Dh (tt) 1Dh (th)
0Bh n 02h N/A 19h (yy) 12h (dth)
17h o 03h SPACE 3Bh (ar) 1Eh (uh)
09h p 04h , 2Fh (aer) 30h (wh)
- q "kw" 04hx2 . 32h (ch) 21h (zh)
</TD></TR></TABLE><BR>
<B>Other Allophone/Word Sets</B><BR>
For curiosity, below are some other SP0256-xx variants (none of the known
Spectrum devices is using that variants though).<BR>
<BR>
<B>SP0256-012 Word List</B><BR>
This chip is used in the "Intellivoice" expansion module for Mattel's
Intellivision.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h (SPB640 08h One 14h Thirteen 20h Seventy
Speech 09h Two 15h Fourteen 21h Eighty
FIFO) 0Ah Three 16h Fifteen 22h Ninety
01h pause4 0Bh Four 17h Sixteen 23h Hundred
02h pause3 0Ch Five 18h Seventeen 24h Thousand
03h pause2 0Dh Six 19h Eighteen 25h -teen
04h pause1 0Eh Seven 1Ah Nineteen 26h -ty
05h pause0 0Fh Eight 1Bh Twenty 27h Press
06h "Mattel 10h Nine 1Ch Thirty 28h Enter
Electronics 11h Ten 1Dh Fourty 29h Or
Presents" 12h Eleven 1Eh Fifty 2Ah And
07h Zero 13h Twelve 1Fh Sixty
</TD></TR></TABLE>There isn't much known about the SPB640 FIFO, as far as I understand, it does
have three functions: It can hold up to 64 word/allophone numbers (to be
injected to A1..A8 pins of the SP0256), it can hold opcodes/parameters (to be
injected to SER IN pin of the SP0256), and it includes a general purpose I/O
port.<BR>
<BR>
<B>SP0256-017 Word List</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h Oh 09h Nine 12h Eighteen 1Bh Hour
01h One 0Ah Ten 13h Nineteen 1Ch Minute
02h Two 0Bh Eleven 14h Twenty 1Dh Hundred Hour
03h Three 0Ch Twelve 15h Thirty 1Eh Good Morning
04h Four 0Dh Thirteen 16h Forty 1Fh Attention Please
05h Five 0Eh Fourteen 17h Fifty 20h Please Hurry
06h Six 0Fh Fifteen 18h It is 21h Melody A
07h Seven 10h Sixteen 19h A.M. 22h Melody B
08h Eight 11h Seventeen 1Ah P.M. 23h Melody C
</TD></TR></TABLE><BR>
<B>SP0256-019 (or rather SP0256B-019) Allophone/Word/Phrase List</B><BR>
This chip is used in "The Voice", an expansion module for the Odyssey 2. The
chip contains the following allophones and words:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 80h..BFh Allophones (same as 00h..3Fh on SP0256-AL2) C0h "Enemy"
C1h "All clear" C2h "Please" C3h "Get off" C4h "Open fire"
C5h "Watch out" C6h "Mercy" C7h "Hit it" C8h "You blew it"
C9h "Do it again" CAh "Incredible" FAh "U.F.O." FBh "Monster!"
</TD></TR></TABLE>Not sure why bit7 is set in the codes (it should be written like so to the O2
I/O ports, but maybe the bit isn't actually passed to the SP0256 chip)?<BR>
Additionally, the expansion module contains 3 built-in speech ROMs with sound
effects and various words/phrases like "Amazing", "Come on", "Outch", etc.
Moreover, Odyssey 2 game cartridges can contain up to 5 external speech ROMs.
For details see "Odyssey 2 Technical Specs" from Daniel Boris.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumsoundspeechsp0256pinouts"></A><FONT SIZE=+2>&nbsp;Spectrum Sound Speech SP0256 Pin-Outs</FONT></TD></TR></TABLE><BR>
<B>SP0256 - Speech chip</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 GND
2 /RESET
3 ROM DISABLE
4 C1
5 C2
6 C3
7 VCC1
8 SBY
9 /LRQ
10 A8
11 A7
12 SER OUT
13 A6
14 A5
15 A4
16 A3
17 A2
18 A1
19 SE
20 /ALD
21 SER IN
22 TEST
23 VCC2
24 PWM OUT
25 /SBY RESET
26 ROM CLK
27 OSC1
28 OSC2
</TD></TR></TABLE>The oscillator should be 3.12MHz<BR>
Allows to output sounds up to 5kHz (ie. the output is updated at 10kHz rate).<BR>
The SP0256 is reportedly expandable to "491 K of ROM" (probably bullshit).<BR>
The SP0256B is reportedly expandable to "480 K of ROM" (probably K=Kbits).<BR>
The TEST pin of the SP0256 chip can be used (among others) to dump its
internal ROM. Note: Details on TEST are found in the "SP0256B" datasheet -
but not in the "SP0256" datasheet - not sure if the pin works identical for
both chip types, nor if there's a difference between them at all.<BR>
<BR>
<B>SPR16 (16kbit) and SPR32 (32kbit) - External Serial-bus Speech ROM</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 GND
2 C3
3 NC
4 ROM CLK
5..6 NC
7 CS1
8 /CS2
9 /ROM ENABLE
10 SERIAL OUT
11 VCC
12..13 NC
14 SERIAL IN
15 C1
16 C2
</TD></TR></TABLE><BR>
<B>SPR128 (128kbit) - External Serial-bus Speech ROM</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 GND
2 C3
3 NC
4 ROM CLK
5..10 NC
11 CS1
12 /CS2
13 /ROM ENABLE
14 SERIAL OUT
15 VCC
16..21 NC
22 SERIAL IN
23 C1
24 C2
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumsounddigitalplaybacksampling"></A><FONT SIZE=+2>&nbsp;Spectrum Sound Digital Playback/Sampling</FONT></TD></TR></TABLE><BR>
<B>Cheetah Specdrum (Playback)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> OUT DFh ;output unsigned sample data (80h=silence)
</TD></TR></TABLE>Advertised as Drum machine, although hardware-wise it's simply a general
purpose D/A playback device. Supported by the included SpecDrum software, and
by additional Afro Kit, Electro Kit, Latin Kit tapes. Functionally same as
the Cheetah Sound Sampler's playback, but using a different port address.<BR>
<BR>
Latin/Electro/Afro-KitSideB --&gt; OUTs to DF,FF,9F,BF<BR>
<BR>
<B>Cheetah - Sound Sampler (Playback/Recording)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> OUT 7Fh ;write any data to start sampling (to be followed by delay)
IN BFh ;read sampled data (after OUT 7Fh)
OUT BFh ;output (unsigned?) sample data (write twice?)
</TD></TR></TABLE>Supported only by the included software. Functionally same as Datel's
sampler, but with port addresses BFh and 7Fh exchanged.<BR>
<BR>
<B>Datel - Digital Sound Sampler (Playback/Recording)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> OUT BFh ;write any data to start sampling (to be followed by delay)
IN 7Fh ;read sampled data (after OUT BFh)
OUT 7Fh ;output (unsigned?) sample data (output)
</TD></TR></TABLE>Supported only by the included software. Functionally same as Cheetah's
sampler, but with port addresses BFh and 7Fh exchanged.<BR>
<BR>
<B>RAM Electronics - Music Machine (Playback/Recording/MIDI)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> IN DFh ;dummy read to start sampling (followed by delay, and then IN BFh)
IN BFh ;read sampled data (unsigned, 80h=silence) (after IN DFh)
OUT 9Fh ;output 8bit unsigned sample data (80h=silence)
OUT 5Fh ;maybe MIDI (used 4 times with values 00h,01h) ;-INTERRUPT?
OUT FC7Fh ;maybe MIDI (used 5 times with values 03h,91h,31h,11h) ;\
OUT FD7Fh ;maybe MIDI (used 1 time with variable value) ; ACIA?
-- FE7Fh ;maybe MIDI (not used by existing software?) ;
IN FF7Fh ;maybe MIDI (used 1 time) ;/
</TD></TR></TABLE>Note: The Amstrad CPC version has these MIDI ports:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> &F8E8(Write only) INTERUPT SEL Writing 01 to this port disables internal
Amstrad interrupts and replaces the IRQ signal from ACIA.
Writing 00 restores normality.
&F8EC(Write only) ACIA Control See 6850 ACIA chip for details
&F8ED(Write only) ACIA Data write See 6850 ACIA chip for details
&F8EE(Read only) ACIA Status See 6850 ACIA chip for details
&F8EF(Read only) ACIA Data read See 6850 ACIA chip for details
</TD></TR></TABLE>Supported only by the included software.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumdiscandtapedrives"></A><FONT SIZE=+2>&nbsp;Spectrum Disc and Tape Drives</FONT></TD></TR></TABLE><BR>
<B>Disc and Tape Overviews</B><BR>
<A HREF="#spectrumdiscandtapedrivesummary">Spectrum Disc and Tape Drive Summary</A><BR>
<A HREF="#spectrumdiscandtapecommands">Spectrum Disc and Tape Commands</A><BR>
<BR>
<B>Standard Audio Cassette Drives</B><BR>
<A HREF="#spectrumcassette">Spectrum Cassette</A><BR>
<A HREF="#spectrumcassettetzxformat">Spectrum Cassette TZX Format</A><BR>
<BR>
<B>Some other more or less popular Disc and Tape drives</B><BR>
<A HREF="#spectruminterface1microdrivenetworkrs232">Spectrum Interface 1 (Microdrive, Network, RS232)</A><BR>
<A HREF="#spectrumdiscspectrum3disccontrollernecupd765">Spectrum Disc Spectrum +3 Disc Controller (NEC uPD765)</A><BR>
<A HREF="#spectrumdiscopusdiscovery">Spectrum Disc Opus Discovery</A><BR>
<A HREF="#spectrumdiscdiscipleandplusd">Spectrum Disc Disciple and Plus D</A><BR>
<A HREF="#spectrumdiscbetabetaplusbeta128diskinterfacetrdos">Spectrum Disc Beta/BetaPlus/Beta128 Disk Interface (TRDOS)</A><BR>
<B>XXX</B><BR>
x--&gt; Spectrum Disc I/O Ports<BR>
x--&gt; Spectrum Disc Formats<BR>
<BR>
<B>Disc Controllers</B><BR>
<A HREF="#spectrumdisccontrollerwesterndigitalwd177x">Spectrum Disc Controller (Western Digital WD177x)</A><BR>
<A HREF="#spectrumdiscspectrum3disccontrollernecupd765">Spectrum Disc Spectrum +3 Disc Controller (NEC uPD765)</A><BR>
<A HREF="#spectrumdisccontrollerother">Spectrum Disc Controller (Other)</A><BR>
<BR>
<B>Timex FDD Interface</B><BR>
The interface uses a logic circuit to page in the 4KB FDD ROM whenever there
is a call to 0x0000 or 0x0008 and page it out again whenever there is a call
to 0x0604. When it is needed the FDD ROM is paged in at 0x0000 and 0x1000 and
the area 0x2000-0x3fff holds eight copies of 1K of RAM or four copies of 2K
of RAM. The disk drive is controlled by port 0xef<BR>
<BR>
<B>NMI Snapshot Button</B><BR>
Many disk interfaces have a NMI button, allowing to save a snapshot of the
RAM and CPU registers to disk. Since most spectrum programs are sold on
cassettes, this is a useful feature; allowing to "copy" the program to disk,
it can be also useful for saving game postition on disks in games that don't
support saving (or that only support saving to cassette).<BR>
<BR>
<B>Floppy I/O Ports</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Interface Chip Type Cmd/Stat Track Sector Data Misc
MFT PlusD 1772 IO E3h EBh F3h FBh EFh,E7h,F7h
MFT Disciple 1772 IO 1Bh 5Bh 9Bh DBh 1Fh,3Bh,7Bh,BBh,FBh
Beta Disk 1793 IO 1Fh 3Fh 5Fh 7Fh FFh
Didaktik D80 ? IO 81h 83h 85h 87h 89h
JLO ? IO 8Fh 9Fh AFh BFh B7h
Putnik 1991 1772 IO F1h F3h F5h F7h DFh/1Fh
Putnik 1998 1772 IO 73h F3h 77h F7h DFh/1Fh
Opus Discovery 1770 MEM 2800h 2801h 2802h 2803h 3000h-3003h, IO:1Fh
Spectrum +3 765 IO N/A N/A N/A 3FFDh 2FFDh,1FFDh
</TD></TR></TABLE>IO: Accessed via IN/OUT opcodes, MEM: Accessed via LD opcodes (memory mapped).<BR>
The first 4 ports are used to access the disc controller.<BR>
The "Misc" port(s) can have various (non-standarized) purposes: Reading the
controllers DRQ or IRQ signal (not supported by all interfaces), outputting
Drive Select signals (or Drive Number), Motor enable (done automatically by
WD1770/WD1772), Side Select, and/or non-disk related add-ons like joysticks,
centronics ports, etc.<BR>
<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Stepping Compatible MotorOn Pin20
WD179x Slow No
WD1770 Slow Yes(Pin20) MO
WD1772 Faster Yes(Pin20) MO
WD1773 Slow WD1793 No END/RDY
</TD></TR></TABLE>The newer WD177x chips contain a digital data separator and write
precompensation circuitry (meaning that they require less external components
than the older WD179x chips).<BR>
<BR>
<B>28pin 177x Pinouts</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 /CS 28 INTRQ -&gt;
2 R/W 27 DRQ -&gt;
3 A0 26 /DDEN &lt;- Double Density Enable
4 A1 25 /WRPT &lt;-
5 D0 24 /IP &lt;- Index Hole
6 D1 23 /TR00 &lt;-
7 D2 22 WD Write Data -&gt;
8 D3 21 WG Write Gate -&gt;
9 D4 20 MO Motor On -&gt;
10 D5 19 /RD Read Data &lt;-
11 D6 18 CLK 8MHz &lt;-
12 D7 17 SD Step-Direction -&gt;
13 /RES 16 STEP Step -&gt;
14 GND 15 +5V
</TD></TR></TABLE><BR>
<B>40pin 179x Pinouts</B><BR>
...?<BR>
<BR>
<B>Putnik Port 1Fh/DFh (decoded via A5)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-4 Kempston Joystick
5 Not used (always 0)
6 INTRQ (from FDC chip)
7 DRQ (from FDC chip)
</TD></TR></TABLE>The interface contains a manual side select switch. The interface doesn't
include a ROM, maybe it's intended to be used with a patched BASIC ROM, or
additional ROM cartridge, or with a boot cassette.<BR>
(Note: There's also a "Putnik RomSwitch" circuit, which uses Port A9h,
probably that's intended to be used in combination with the floppy circuit.)<BR>
<BR>
<B>IDE Interface I/O Ports</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Type divIDE Vehmaa Vehmaa 1-Chip Putnik Putnik Putnik Putnik SAfri
ZXCF ZXATASP 8bitv1 8bitv2 16bitv1 16bitv2 16bit
Data &xxA3 &00BF &039F? &00EF &xx2B &00BF &xx69 &xx2B &xx59
Error &xxA7 &01BF &039F? &01EF &xx2F &01BF &xx79 &xx2F &xx5B
Count &xxAB &02BF &039F? &10EF &xx6B &10BF &xx6B &xx6B &xx5D
Sector &xxAF &03BF &039F? &11EF &xx6F &11BF &xx7B &xx6F &xx5F
CylinderLo &xxB3 &04BF &039F? &20EF &xxAB &20BF &xx6D &xxAB &xx79
CylinderHi &xxB7 &05BF &039F? &21EF &xxAF &21BF &xx7D &xxAF &xx7B
Drive &xxBB &06BF &039F? &30EF &xxEB &30BF &xx6F &xxEB &xx7D
Command &xxBF &07BF &039F? &31EF &xxEF &31BF &xx7F &xxEF &xx7F
DataLo &08BF &009F?
DataHi &09BF &019F?
Error &0EBF
AltStatus &0FBF
Control &xxE3
</TD></TR></TABLE><BR>
<B>ROM selection</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Type Vehmaa Vehmaa Putnik JGH Sinclair
ZXCF ZXATSP RomSwitch ROMBox Spectrum128
Range &00-&3F &00-&3F &00-&03 &00-&F0 &00-&10
Page ROM &10BF,n &029F,n &xxA9,n &xxFD,16*n &7FFD,16*n
ZX ROM &10BF,&80+x &xxFD,&10 &7FFD,&10
RESET ROM &00 &00 &03 &00 &00
</TD></TR></TABLE><BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumdiscandtapedrivesummary"></A><FONT SIZE=+2>&nbsp;Spectrum Disc and Tape Drive Summary</FONT></TD></TR></TABLE><BR>
The standard media for Spectrum software are regular Audio Cassettes. Instead
of supporting disk drives, Sinclair has focused on selling Microdrive
Cartridges as alternative media, until, finally Amstrad released an
"official" disk drive in the Spectrum +3. However, at that time third-party
companies have had already produced various disk drives, all incompatible
with each other, using different controllers, I/O ports, BIOSes, file
systems, and different physical dimensions (2.8", 3", 3.5", and 5.25").<BR>
<BR>
<B>Standard Audio Cassette Drives</B><BR>
Any standard data or audio Cassette Recorder connected to MIC/EAR sockets<BR>
Spectrum +2/+2A with internal cassette recorder<BR>
Challenge Research Ltd: Challenge Sprint (quad-speed "audio" cassette drive)<BR>
Challenge Research Ltd: Challenge Sprint Mk II (new: Interface 1 compatible)<BR>
Evesham Micro Centre: Doubler (external tape input for tape-to-tape copy)<BR>
Evesham Micro Centre: Doubler Mk II (new: more compatible with more tape decks)<BR>
<BR>
<B>Sequential Disk/Tape Drives</B><BR>
Sinclair Microdrive (endless tape drive) (85K..100K) (requires Interface 1)<BR>
Rotronics Wafadrive (endless tape drive) (16K, 64K, 128K)<BR>
Crescent Quick Disk (2.8" disk, with single spiral-track, 128K or 256K)<BR>
Triton Quick Disk (2.8" disk, with single spiral-track, 100K)<BR>
<BR>
<B>Floppy Disk Drives/Interfaces</B><BR>
Opus: Discovery (1985) (centronics, video out, kempston stick, intern 3.5" drv)<BR>
Opus: Spectra Disc Interface (1984) (centronics, external 3.5" or 5.25" drive)<BR>
Miles Gordon Technology: MGT Plus D Interface (for MGT Lifetime Drive) (1988)<BR>
Miles Gordon Technology/Rockford Products: Disciple (1987)<BR>
Spectrum +3 (internal 3" disk drive) (1987)<BR>
Technology Research: Beta Disk Interface (1984)<BR>
Technology Research: Beta Plus Disk Interface (1985) (magic button)<BR>
Technology Research: Beta 128 Disk Interface (1986)<BR>
Timex FDD and FDD-3000 Disk Drives (with external Z80 CPU)<BR>
Omnitronix Ltd: Pacer Disk Interface<BR>
John Oliger Company: JLO TS2068 Disk System<BR>
Ramex Millenia K disk interface (SPDOS, or alternately LKDOS)<BR>
Acme Electric Robot Company: AERCO FD-68 (for TS2068) (Aerco DOS, or LKDOS)<BR>
LarKen: Disk Interface and LKDOS cartridge (for TS2068)<BR>
Kempston: Disc Interface (KDOS)<BR>
Logitek: Disc Interface (connect a Commodore 1541 drive to spectrum)<BR>
Sixword Ltd.: Swift Disc<BR>
Circuit Design: CS-DISK Interface<BR>
Haytech: Cyborg Disk Drive with Spectrum Personality Module<BR>
Statacom: Datafax Disk System<BR>
Cumana Ltd: Double Density Disk Interface<BR>
Dove Microtronix Ltd: Dove Disk Interface<BR>
8BC: MB-02+ Disk Interface<BR>
Morex Peripherals Ltd: Morex Floppy Disk System<BR>
Saga Systems Ltd: Saga Disk Interface<BR>
Saga Systems Ltd: Saga Disk Interface II (with printer port)<BR>
Thurnall Electronics Ltd: Thurnall Disk System (MCD-1)<BR>
Interactive Instruments Ltd: Viscount Disk Drive System<BR>
ITL & Tyrell Systems: Byte Drive 500<BR>
Ergo Systems Ltd/Video Vault Ltd: Clive Drive<BR>
Didaktik D40<BR>
Didaktik D80<BR>
Putnik 1991 (homebrew schematic) (uses A1, incompatible with Spectrum 128)<BR>
Putnik 1998 (homebrew schematic) (uses A7, now compatible with Spectrum 128)<BR>
<BR>
<B>Compact Disc Interface</B><BR>
Code Masters CD Games Pack (load games from Audio CD via joystick port)<BR>
<BR>
<B>Other Interfaces</B><BR>
Additonally, there are a number of newer harddisk and compact flash
interfaces, though they are probably rather rarely used.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumdiscandtapecommands"></A><FONT SIZE=+2>&nbsp;Spectrum Disc and Tape Commands</FONT></TD></TR></TABLE><BR>
<B>General Spectrum Load/Save commands (cas/disk)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> LOAD "" ;load basic program (by wildcard)
LOAD &lt;filename&gt; ;load basic program (by name)
LOAD "picture.bin" CODE ;load binary to original addr
LOAD "picture.bin" CODE dest(,len_verify) ;load binary to other addr
LOAD "picture.bin" CODE SCREEN$ ;load binary to VRAM
LOAD &lt;filename&gt; DATA a () ;load numeric array
LOAD &lt;filename&gt; DATA a$ () ;load character array
SAVE &lt;filename&gt; ;save basic program
SAVE &lt;filename&gt; LINE &lt;linenumber&gt; ;save basic program with autostart
SAVE "picture.bin" CODE SCREEN$ ;save binary file (VRAM at 4000h)
SAVE "picture.bin" CODE 16384,6912 ;save binary file (same as SCREEN$)
SAVE "picture.bin" CODE start,length ;save binary file (custom area)
SAVE &lt;filename&gt; DATA a () ;save numeric array
SAVE &lt;filename&gt; DATA a$ () ;save character array
VERIFY &lt;filename&gt; ;compare file with program in in RAM
MERGE &lt;filename&gt; ;merge file with program in in RAM
</TD></TR></TABLE><BR>
<B>Disk commands (Spectrum +3)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> filename="DISK" ;default name for "loader" option in +3 BIOS menu
filename="filename.ext" ;max 8.3 characters (for CP/M-style filesystem)
MOVE oldname newname ;rename (or move to other drive)
MOVE oldname TO attr ;change attr "+p" "+s" "+a" or "-p" "-s" "-a"
COPY oldname newname ;copy
COPY textfile TO SCREEN$
COPY textfile TO LPRINT
COPY binfile TO SPECTRUM FORMAT ;creates binfile.HED (with binary HEaDer)
LOAD "d:" ;set default load drive (a:disk1, b:disk2, m:ramdisk, t:tape)
SAVE "d:" ;set default save drive (a:disk1, b:disk2, m:ramdisk, t:tape)
CAT (#stream),"filename" ;show directory (on stream #n)
ERASE filename ;delete
FORMAT drive
FORMAT LINE baudrate ;set RS232 baudrate
FORMAT LPRINT "r" ;redirect printer ("p") to RS232 ("r") stream
</TD></TR></TABLE>Streams:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> OPEN #n,"k" ;keyboard (default=#1)
OPEN #n,"s" ;screen (default=#2)
OPEN #n,"p" ;printer (default=#3)
</TD></TR></TABLE><BR>
<B>RAM-Disk (Spectrum 128/+2/+2A/+3)</B><BR>
On the Spectrum 128/+2/+2A/+3, 64Kbytes of RAM are used as RAM-Disk, which
can be accessed by appending an exclamation mark to cassette commands,<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> LOAD! SAVE! MERGE! CAT! ERASE! --&gt; access RAM disk
</TD></TR></TABLE>On the Spectrum +2A/+3, one can additionally/alternately access the RAM-Disk
by specifying drive letter M as part of the filename, eg. LOAD "m:filename".<BR>
<BR>
<B>Microdrive (Sinclair Interface I)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> LOAD * "m" ;1; "filename"
SAVE * "m" ;1; "filename"
FORMAT "m" ;1; "filename"
CAT 1
</TD></TR></TABLE>The microdrive syntax is also used by the Opus Discovery.<BR>
<BR>
<B>Rotronics Wavadrive</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> CAT * ;directory for default drive
CAT * "a:" ;directory for drive A
CAT # "a:" ;set A as default drive and load (but do not show) directory
POKE 23767,n ;set default drive (0=A, 1=B)
SAVE * "a:name" ;save on drive A
SAVE * "name" ;save on default drive
</TD></TR></TABLE>The thing also has a one-directional centronics port (stream "c"), and a
RS232 port with RXD,TXD,RTS,CTS lines (stream "r").<BR>
Extended System Area occupies 102 bytes of RAM (starting at 23734),
read/write buffer occupies 1026 bytes (at 23836), directory A and B occupy
582 bytes each (at 24862 and 25444).<BR>
<BR>
<B>Opus Discovery</B><BR>
Uses microdrive-style syntax. Additional commands are:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> FORMAT "j";1 ;enable kempston joystick port in opus discovery
FORMAT "j";0 ;disable kempston joystick port in opus discovery
</TD></TR></TABLE>Includes a kempston joystick port (which must be enabled as described above),
and a centronics port. The centronics port can be also use as network
interface, via LOAD/SAVE/VERIFY * "b".<BR>
<BR>
<B>Technology Research - Beta Disk Interface (TRDOS)</B><BR>
In BASIC:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> LET DOS=15360 ;=3C00h ;for Beta and Beta Plus (TRDOSv1 or TRDOSv4)
LET DOS=15616 ;=3D00h ;for Beta 128 (TRDOSv5)
RANDOMIZE USR DOS+3:REM:LOAD"D:FILENAME" ;load from drive D
RANDOMIZE USR DOS+0 ;switch from BASIC to TRDOS
</TD></TR></TABLE>In TRDOS:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> LIST (K-key) ;show directory ;&lt;B&gt;=bootable
LOAD (J-key) or RUN (R-key) ;load a file
USR ;set disk password
RETURN (Y-key) ;switch from TRDOS to BASIC
</TD></TR></TABLE><BR>
<B>Kempston Disk Interface (K-DOS)</B><BR>
Uses a rather strange syntax where disk-commands are preceeded by "PRINT
#4:", and in some cases followed by ":PRINT parameter(s)", eg:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> PRINT #4:LOAD"filename"
PRINT #4:CAT:PRINT d ;d=drive number (1..4)
</TD></TR></TABLE><BR>
<B>Larken (LARKEN DOS aka LKDOS)</B><BR>
Uses similar syntax as Kempston, but must be first initialized as:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> RANDOMIZE USR 100: OPEN# 4, "dd"
</TD></TR></TABLE>Thereafter, "PRINT #4:" can be used to preceed disk-commands, eg.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> PRINT #4:LOAD"filename"
</TD></TR></TABLE>The built-in joystick port is accessed via IN 31 (kempston style).<BR>
There are also LKDOS versions for use with Ramex and Aerco disk interfaces.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumcassette"></A><FONT SIZE=+2>&nbsp;Spectrum Cassette</FONT></TD></TR></TABLE><BR>
The cassette is accessed via bits in ULA Port FEh (see ULA chapter). Cassette
input is received from EAR port, output is passed to MIC port. For the
bizarre part, the MIC and EAR leads cannot be simultaneously connected, so
one of the leads must be disconnected/reconnected for loading/saving. There
is no Motor On signal, so PLAY/STOP must be pressed manually.<BR>
<BR>
<B>Spectrum Cassette Blocks</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Silence (low level)
8063 (Header) or 3223 (Data) Pilot Pulses (2168 clks/pulse) (619us/pulse)
1st Sync Pulse (667 clks/pulse) (190us/pulse)
2nd Sync Pulse (735 clks/pulse) (210us/pulse)
Blocktype Byte (00h=Header, FFh=Data)
Data Byte(s) (two 855 or 1710 clks/pulse per bit) (244 or 488 us/pulse)
Checksum Byte (above Blocktype and Data Bytes XORed with each other)
End pulse (opposite level of last pulse)
Silence (low level)
</TD></TR></TABLE><BR>
<B>Spectrum Pilot/Sync/Bits/Bytes</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> /"""\__/ Sync Pulses (1st=667, 2nd=735 clks/pulse)
/""""\____/ "0"-Bit (two pulses, 855 clks/pulse)
/"""""""""\_________/ "1"-Bit (two pulses, 1710 clks/pulse)
/""""""""""""\____________/ etc. Pilot Pulses (2168 clks/pulse)
</TD></TR></TABLE>Bytes are transferred MSB (Bit7) first. Signals may be inverted.<BR>
<BR>
<B>Spectrum Header Block</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Pre 1 Blocktype (aka Flag Byte) (must be 00h for Header blocks)
0 1 Filetype (0..3, see below)
1 10 Filename (padded with blanks, ie. chr(20h))
11 2 Length of following Data Block (LEN)
13 4 Parameters (depends on Filetype, see below)
Post 1 Checksum (above 18 bytes XORed with each other)
</TD></TR></TABLE><BR>
<B>Spectrum Data Block</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Pre 1 Blocktype (aka Flag Byte) (must be FFh for Data Blocks)
0 LEN Data
Post 1 Checksum (above LEN+1 bytes XORed with each other)
</TD></TR></TABLE><BR>
<B>Spectrum Filetypes/Parameters (Bytes 13..16 of Header Blocks)</B><BR>
For Filetype=00h / BASIC Program File (Program and Variables):<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 13 2 Autostart LINE Number (or 8000h..FFFFh if no autostart)
15 2 Size of the PROG area aka start of the VARS area
</TD></TR></TABLE>For Filetype=01h / BASIC Number Array, or Filetype=02h / BASIC Character Array:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 13 1 Unknown
14 1 Name of the variable
15 2 Unknown
</TD></TR></TABLE>For Filetype=03h / Binary CODE File (or SCREEN$ file):<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 13 2 Memory Address
15 2 Unused (Should be 8000h)
</TD></TR></TABLE>A SCREEN$ file is a CODE file with Memory Address 4000h and LEN=1B00h.<BR>
<BR>
<B>.TAP Files (Standard Cassette-Image for normal unprotected files)</B><BR>
A .TAP file can contain one or more spectrum file(s). Each file should
usually consist of two blocks (header and data). Each block is preceeded by a
16bit length value (eg. 0013h for Header blocks), followed by "length" bytes
which contain the same information as stored on real cassettes (including the
leading Blocktype byte, and ending Checksum byte).<BR>
TAP files do not contain pilot/sync pulses, nor baudrate information, so they
can be used only for standard files (as used by the BIOS functions), not for
copyprotected software.<BR>
<BR>
<B>.TZX Files (Standard Cassette-Image for copy-protected files)</B><BR>
<A HREF="#spectrumcassettetzxformat">Spectrum Cassette TZX Format</A><BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumcassettetzxformat"></A><FONT SIZE=+2>&nbsp;Spectrum Cassette TZX Format</FONT></TD></TR></TABLE><BR>
For some general definitions, see:<BR>
<A HREF="#spectrumcassettetzxnotes">Spectrum Cassette TZX Notes</A><BR>
<BR>
<B>TZX Header (length: 0Ah bytes)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 8 TZX signature ("ZXTape!",1Ah)
08h 1 TZX major revision number (currently 01h, for v1.20)
09h 1 TZX minor revision number (currently 1Ah, for v1.20)
</TD></TR></TABLE><BR>
<B>ID 10h - Standard Speed Data Block (length: [02h..03h]+4)</B><BR>
This block must be replayed with the standard Spectrum BIOS timings - see the
values in curly {} brackets in block ID 11h.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 2 Pause after this block (ms) (0=none) {1000}
02h 2 Length of data that follow (N)
04h N Data as in .TAP files (first byte implies number of pilot pulses)
</TD></TR></TABLE>The pilot tone consists of 8063 pulses if the first data byte (flag byte)
(aka block_type) is &lt; 128, or 3223 pulses otherwise. This block can be used
for the BIOS loading routines AND for custom loading routines that use the
same timings as BIOS ones do.<BR>
<BR>
<B>ID 11h - Turbo Speed Data Block (length: [0Fh..11h]+12h)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 2 Length of PILOT pulse {2168} ;-occurs P times at begin
02h 2 Length of SYNC first pulse {667} ;-occurs ONCE after above
04h 2 Length of SYNC second pulse {735} ;-occurs ONCE after above
06h 2 Length of ZERO bit pulse {855} ;-occurs TWICE per bit
08h 2 Length of ONE bit pulse {1710} ;-occurs TWICE per bit
0Ah 2 Number of PILOT pulses (P) {8063 for header, 3223 for data)
0Ch 1 Number of used bits in the last byte {8}
(e.g. if this is 6, then the bits used (x) in the last byte are:
xxxxxx00, where MSb is the leftmost bit, LSb is the rightmost bit)
0Dh 2 Pause after this block (ms) (0=none) {1000}
0Fh 3 Length of data that follow (N)
12h N Data as in .TAP files {block_type, data[N-2], chksum}
</TD></TR></TABLE>This block is very similar to the normal TAP block but with some additional
info on the timings and other important differences. The same tape encoding
is used as for the standard speed data block. If a block should use some
non-standard sync or pilot tones (i.e. all sorts of protection schemes) then
use the next three blocks to describe it.<BR>
<BR>
<B>ID 12h - Pure Tone (length: 04h)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 2 Length of one pulse in T-states
02h 2 Number of pulses
</TD></TR></TABLE>This will produce a tone which is basically the same as the pilot tone in the
ID 10h, ID 11h blocks. You can define how long the pulse is and how many
pulses are in the tone.<BR>
<BR>
<B>ID 13h - Pulse sequence (length: [00h]*2+1)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 1 Number of pulses (N)
01h 2*N Pulse lengths (16bit each)
</TD></TR></TABLE>This will produce N pulses, each having its own timing. Up to 255 pulses can
be stored in this block; this is useful for non-standard sync tones used by
some protection schemes.<BR>
<BR>
<B>ID 14h - Pure Data Block (length: [07h..09h]+0Ah)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 2 Length of ZERO bit pulse
02h 2 Length of ONE bit pulse
04h 1 Used bits in last byte (other bits should be 0)
(e.g. if this is 6, then the bits used (x) in the last byte are:
xxxxxx00, where MSb is the leftmost bit, LSb is the rightmost bit)
05h 2 Pause after this block (ms) (0=none)
07h 3 Length of data that follow (N)
0Ah N Data as in .TAP files
</TD></TR></TABLE>Same as in the turbo loading data block, but without pilot and sync pulses.<BR>
<BR>
<B>ID 15h - Direct Recording (length: [05h..07h]+08h)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 2 Number of T-states per sample-bit (usually 158 or 79)
02h 2 Pause after this block (ms) (0=none)
04h 1 Used bits (samples) in last byte of data (1..8)
(eg. 2 means only first two samples of the last byte will be played)
05h 3 Length of sample data in bytes (N)
08h N Sample data. Each bit represents a state on the EAR port
(i.e. one sample). MSb is played first.
</TD></TR></TABLE>This block is used for tapes which have some parts in a format such that the
turbo loader block cannot be used. This is not like a VOC file, since the
information is much more compact. Each sample value is represented by one bit
only (0 for low, 1 for high) which means that the block will be at most 1/8
the size of the equivalent VOC.<BR>
The preferred sampling frequencies are 22050 or 44100 Hz (158 or 79
T-states/sample), this will ensure correct playback when using PC's
soundcards. Please, if you can, don't use other sampling frequencies.<BR>
Please use this block only if you cannot use any other block.<BR>
<BR>
<B>ID 16h - C64 BIOS Type Data Block (length: [00h..03h]+0 or 4?) (v1.13 only)</B><BR>
<B>ID 17h - C64 Turbo Tape Data Block (length: [00h..03h]+0 or 4?) (v1.13 only)</B><BR>
These two blocks were defined (although rarely/never used) in TZX version
v1.13 only, intended to support Commodore 64 files.<BR>
Bug: Blocks invented after v1.10 are stated to have a length of
"[00h..03h]+4" bytes, while the C64 blocks invented in v1.13 were ALSO stated
by "[00h..03h]" in length, so it's somewhat unclear how to the C64 blocks.
Anyways, they should never show up in Spectrum files, and as far as I know
the format wasn't actually used in the C64 world either.<BR>
<BR>
<B>ID 18h - CSW Recording (length: [00h..03h]+4) (v1.20 and up)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 4 Block length (without these four bytes) (10h+N)
04h 2 Pause after this block (ms) (0=none)
06h 3 Sampling rate
09h 1 Compression type (01h=RLE, 02h=Z-RLE)
0Ah 4 Number of stored pulses (after decompression, for validation purposes)
0Eh N CSW data, encoded according to the CSW file format specification.
</TD></TR></TABLE>This block contains a sequence of raw pulses encoded in Ramsoft's CSW format
v2 (Compressed Square Wave). The encoding of the RLE and Z-RLE data is
undocumented. It can reportedly compress a 12MB 44kHz VOC file to 1MB, which
is still very bloated, so better don't use the CSW stuff.<BR>
<BR>
<B>ID 19h - Generalized Data Block (length: [00h..03h]+4) (v1.20 and up)</B><BR>
This block has been specifically developed to represent an extremely wide
range of data encoding techniques.<BR>
<A HREF="#spectrumcassettetzxformatid19h">Spectrum Cassette TZX Format ID 19h</A><BR>
<BR>
<B>ID 20h - Pause (silence) or 'Stop the Tape' command (length: 2)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 2 Pause after this block (ms) (or 0=stop tape, ie. infinite pause)
</TD></TR></TABLE>This will make a silence for a given time in milliseconds. If the value is 0
then the emulator or utility should (in effect) STOP THE TAPE, ie. it should
make a pause of infinite length (until the user or emulator requests to
restart the tape motor). As usually, the first 1 ms of the pause must be
opposite of the old level, the remaining milliseconds must be low level.<BR>
<BR>
<B>ID 21h - Group start (length: [00h]+1)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00 1 Length of the group name string (L)
01 L Group name in ASCII format (please keep it under 30 characters long)
</TD></TR></TABLE>This block marks the start of a group of blocks which are to be treated as
one single (composite) block. This is very handy for tapes that use lots of
subblocks like Bleepload (which may well have over 160 custom loading
blocks). You can also give the group a name (example 'Bleepload Block 1').<BR>
For each group start block, there must be a group end block. Nesting of
groups is not allowed.<BR>
<BR>
<B>ID 22h - Group end (length: 0)</B><BR>
This indicates the end of a group. This block has no body.<BR>
<BR>
<B>ID 23h - Jump to block (length: 2)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 2 Relative jump value (number of blocks, from current block)
</TD></TR></TABLE>This block will enable you to jump from one block to another within the file.
Some examples:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Jump +0 = Loop Forever ;this should never happen
Jump +1 = Go to the next block ;acts as a NOP in assembler
Jump +2 = Skip one block
Jump -1 = Go to the previous block
</TD></TR></TABLE>All blocks are included in the block count!<BR>
<BR>
<B>ID 24h - Loop start (length: 2) (v1.10 and up)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 2 Number of repetitions (greater than 1)
</TD></TR></TABLE>If you have a sequence of identical blocks, or of identical groups of blocks,
you can use this block to tell how many times they should be repeated. This
block is the same as the FOR statement in BASIC.<BR>
For simplicity reasons don't nest loop blocks!<BR>
<BR>
<B>ID 25h - Loop end (length: 0) (v1.10 and up)</B><BR>
This is the same as BASIC's NEXT statement. It means that the utility should
jump back to the start of the loop if it hasn't been run for the specified
number of times. This block has no body.<BR>
<BR>
<B>ID 26h - Call sequence (length: [00h..01h]*2+2) (v1.10 and up)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 1 Number of calls to be made (N)
02h 2*N Array of call block numbers (relative-signed 16bit offsets)
</TD></TR></TABLE>This block is an analogue of the CALL Subroutine statement. It basically
executes a sequence of blocks that are somewhere else and then goes back to
the next block. Because more than one call can be normally used you can
include a list of sequences to be called. The 'nesting' of call blocks is
also not allowed for the simplicity reasons. You can, of course, use the CALL
blocks in the LOOP sequences and vice versa. The value is relative for the
obvious reasons - so that you can add some blocks in the beginning of the
file without disturbing the call values. Please take a look at 'Jump To
Block' for reference on the values.<BR>
<BR>
<B>ID 27h - Return from sequence (length: 0) (v1.10 and up)</B><BR>
This block indicates the end of the Called Sequence. The next block played
will be the block after the last CALL block (or the next Call, if the Call
block had multiple calls). This block has no body.<BR>
<BR>
<B>ID 28h - Select block (length: [00h..01h]+2) (v1.10 and up)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 2 Length of the whole block (without these two bytes)
02h 1 Number of selections (N)
03h .. List of selections
</TD></TR></TABLE>Each selection has the following format:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00 2 Relative Offset (16bit)
02 1 Length of description text (L)
03 L Description text in ASCII (please use single line and max 30 chars)
</TD></TR></TABLE>This block is useful when the tape consists of two or more
separately-loadable parts. With this block, you are able to select one of the
parts and the utility/emulator will start loading from that block. For
example you can use it when the game has a separate Trainer or when it is a
multiload. Of course, to make some use of it the emulator/utility has to show
a menu with the selections when it encounters such a block. All offsets are
relative signed words.<BR>
<BR>
<B>ID 2Ah - Stop the tape if in 48K mode (length: 4) (v1.xx? and up)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 4 Length of the block without these four bytes (=0)
</TD></TR></TABLE>When this block is encountered, the tape will stop ONLY if the machine is an
48K Spectrum. This block is to be used for multiloading games that load one
level at a time in 48K mode, but load the entire tape at once if in 128K
mode.<BR>
This block has no body of its own, but follows the extension rule.<BR>
<BR>
<B>ID 2Bh - Set signal level (length: 5) (v1.20 and up)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 4 Block length (without these four bytes) (=1)
04h 1 Signal level (0=low, 1=high)
</TD></TR></TABLE>This block sets the current signal level to the specified value (high or
low). It should be used whenever it is necessary to avoid any ambiguities,
e.g. with custom loaders which are level-sensitive.<BR>
<BR>
<B>ID 30h - Text description (length: [00h]+1)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 1 Length of the text description (N)
01h N Text description in ASCII format
</TD></TR></TABLE>This is meant to identify parts of the tape, so you know where level 1
starts, where to rewind to when the game ends, etc. This description is not
guaranteed to be shown while the tape is playing, but can be read while
browsing the tape or changing the tape pointer.<BR>
The description can be up to 255 characters long but please keep it down to
about 30 so the programs can show it in one line (where this is appropriate).<BR>
Please use 'Archive Info' block for title, authors, publisher, etc.<BR>
<BR>
<B>ID 31h - Message block (length: [01h]+2)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 1 Time (in seconds) for which the message should be displayed
01h 1 Length of the text message (N)
02h N Message that should be displayed in ASCII format
</TD></TR></TABLE>This will enable the emulators to display a message for a given time. This
should not stop the tape and it should not make silence. If the time is 0
then the emulator should wait for the user to press a key.<BR>
The text message should:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> stick to a maximum of 30 chars per line;
use single 0x0D (13 decimal) to separate lines;
stick to a maximum of 8 lines.
</TD></TR></TABLE>If you do not obey these rules, emulators may display your message in any way
they like.<BR>
<BR>
<B>ID 32h - Archive info (length: [00h..01h]+2)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 2 Length of the whole block (without these two bytes)
02h 1 Number of text strings (N)
03h N List of Text Structures
</TD></TR></TABLE>Text Structure format:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 1 Text identification byte (see list below)
01h 1 Length of text string (L)
02h L Text string in ASCII format
</TD></TR></TABLE>Text identification byte values:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h Full title
01h Software house/publisher
02h Author(s)
03h Year of publication (eg. 1982) (in ASCII, too)
04h Language (v1.10 and up) (eg. English) (=default)
05h Game/utility type (v1.12 and up) (eg. arcade adventure, puzzle)
06h Price with currency (v1.12 and up) (eg. GBP 5.99, or chr(A3h)=GBP)
07h Protection scheme/loader (v1.12 and up) (eg. Speedlock 1, Alkatraz)
08h Origin (v1.12 and up) (eg. Original, Budget re-release)
FFh Comment(s)
xxh Reserved for future (decoders should skip any unknown entries)
</TD></TR></TABLE>When using this block, store it at the beginning of the tape. The information
about what hardware the tape uses is in the 'Hardware Type' block, so no need
for it here. According to the tzx format release notes, v1.10 and up allows
multiple lines in the 'Archive info' (ID 32h) block.<BR>
<BR>
<B>ID 33h - Hardware type (length: [00h]*3+1)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 1 Number of machines and hardware types for which info is supplied (N)
01h 3*N List of machines and hardware
</TD></TR></TABLE>This blocks contains information about the hardware that the programs on this
tape use. For details, see:<BR>
<A HREF="#spectrumcassettetzxformathw">Spectrum Cassette TZX Format HW</A><BR>
This feature is (theoretically) the main advantage of the TZX format over the
TAP format, however, in practice, most (or all) existing TZX files don't use
this feature. So, for that matter, one could as well keep using normal TAP
files.<BR>
<BR>
<B>ID 34h - Emulation info (length: 8) (up to v1.13 only)</B><BR>
This block was defined (although rarely used) in TZX versions up to v1.13
only.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 2 General emulation flags:
bit 0 : R-register emulation [1]
bit 1 : LDIR emulation [1]
bit 2 : high resolution colour emulation with true interrupt freq. [1]
bit 3,4 : video synchronisation (1=high, 3=low, 0,2=normal) [0]
bit 5 : fast loading when BIOS load routine is used [1]
bit 6 : border emulation [1]
bit 7 : screen refresh mode (0=off, 1=on) [1]
bit 8 : start playing the tape immediately (0=no, 1=yes) [0]
bit 9 : auto type LOAD"" or press ENTER when in 128k mode [0]
02h 1 Update screen every N frames (1..255) (used only when flags.bit7=1)
03h 2 Interrupt Frequency in Hertz (0..999)
05h 3 Reserved for future expansion
</TD></TR></TABLE>This is a special block that would normally be generated only by emulators.<BR>
Those bits that are not used by the emulator that stored the info, should be
left at their [default] values.<BR>
<BR>
<B>ID 35h - Custom info block (length: [10h..13h]+14h) (works in v1.01 and up)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 16 Identification string (in ASCII) (usually padded with spaces)
10h 1 Length of the custom info (L)
14h L Custom info
</TD></TR></TABLE>This block can be used to save any information you want. For example, it
might contain some information written by a utility, extra settings required
by a particular emulator, or even poke data.<BR>
<A HREF="#spectrumcassettetzxformatcustom">Spectrum Cassette TZX Format Custom</A><BR>
Note: The Length of the ID string was accidently documented as 15 bytes in
v1.00 (although it should have been 16), this has been fixed in v1.01.<BR>
<BR>
<B>ID 40h - Snapshot block (length: [01h..03h]+4) (v1.10..v1.13 only)</B><BR>
This block was defined (although rarely used) in tzx versions v1.10..v1.13
only.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 1 Snapshot type (00h=.Z80 format, 01h=.SNA format)
01h 3 Snapshot length (L)
04h L The Snapshot itself
</TD></TR></TABLE>Allows to snapshot the game at the start and still have all the tape blocks
(level data, etc.) in the same file. The emulator should take care of that
the snapshot is not taken while the actual Tape loading is taking place. When
an emulator encounters the snapshot block it should load it and then continue
with the next block.<BR>
<BR>
<B>ID 5Ah (aka "Z") - Glue block (length: 09h)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 9 ZXTape Header (excluding the "Z", ie. "XTape!",1Ah,MajR,MinR)
</TD></TR></TABLE>This block is generated when you merge two ZX Tape files together. It is here
so that you can easily copy the files together and use them. Of course, this
means that resulting file would be 10 bytes longer than if this block was not
used. If you can avoid using this block for this purpose, then do so; it is
preferable to use a utility to join the two files and ensure that they are
both of the higher version number.<BR>
<BR>
<B>ID xxh - Reserved (length [00h..03h]+4)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 4 Block length (32bit) (without these four bytes)
04h .. Reserved
</TD></TR></TABLE>Reserved for future. As shown above, all new blocks added after v1.10 should
begin with a 32bit Block length entry in the first 4 bytes; the length value
should exclude that first 4 bytes). With that definition, decoders may skip
unknown blocks - and may still work (if the blocks contain only comments or
so).<BR>
A special case are the C64 blocks (ID 16h and ID 17h) where the TZX format
does "clearly" define BOTH to include AND to exclude first 4 bytes in the
length entry (that blocks should never show up in Spectrum files, so it
should be no problem, as far as I know they even weren't ever actually used
for the C64).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumcassettetzxformathw"></A><FONT SIZE=+2>&nbsp;Spectrum Cassette TZX Format HW</FONT></TD></TR></TABLE><BR>
<B>ID 33h - Hardware type (length: [00h]*3+1)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 1 Number of machines and hardware types for which info is supplied (N)
01h 3*N List of machines and hardware (HWINFO)
</TD></TR></TABLE>HWINFO structure format:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 1 Hardware type (00h..10h; see the headlines of the ID lists)
01h 1 Hardware ID (00h..xxh; see the ID list entries)
02h 1 Hardware information (00h..03h; see the small table below)
</TD></TR></TABLE>This blocks contains information about the hardware that the programs on this
tape use. Please include only machines and hardware for which you are 100%
sure that it either runs (or doesn't run) on or with, or you know it uses (or
doesn't use) the hardware or special features of that machine.<BR>
If the tape runs only on the ZX81 (and TS1000, etc.) then it clearly won't
work on any Spectrum or Spectrum variant, so there's no need to list this
information.<BR>
If you are not sure or you haven't tested a tape on some particular
machine/hardware combination then do not include it in the list.<BR>
The list of hardware types and IDs is somewhat large, and may be found at the
end of the format description.<BR>
<BR>
<B>Hardware information (3rd byte)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h The tape RUNS on this hardware (and may or may not use its features)
01h The tape RUNS and DOES use the special features of the hardware
02h The tape RUNS but DOES-NOT use the special features of the hardware
03h The tape DOES-NOT-WORK on this hardware
</TD></TR></TABLE><BR>
<B>Hardware information reference</B><BR>
This is the list of all hardware types and hardware identification ID's that
are used in the 'Hardware info' block. Please send any additions you might
have to the TZX maintainers so that they can be included.<BR>
By default you don't have to write any of the information if the game is made
for the ZX Spectrum and complies with the following:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> - runs on ZX Spectrum 48K
- runs on, but doesn't use any of the special hardware of ZX Spectrum 128K
- doesn't run on ZX Spectrum 16K
</TD></TR></TABLE>If, for example, game works on BOTH ZX 48K and 128K, and uses the hardware of
the 128K Spectrum, then you would just include the 128K Spectrum in the list
(because by default it has to work on 48K too).<BR>
If the game is 128K ONLY then you would include two entries: The game works
on AND uses the hardware of a 128K Spectrum AND the game DOESN'T work on a
48K Spectrum.<BR>
If the game works on both 48K and 128K Spectrum, but it only uses the sound
chip (AY) of the 128K Spectrum and none of its extra memory then you would
only include the entry that says that the game uses the 'Classic AY hardware
(Spectrum 128 compatible sound device)'.<BR>
These were only some examples of the usage of this block.<BR>
<BR>
<B>Computer Types (first byte = 00h)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h ZX Spectrum 16k
01h ZX Spectrum 48k, Plus
02h ZX Spectrum 48k ISSUE 1
03h ZX Spectrum 128k + (Sinclair)
04h ZX Spectrum 128k +2 (grey case)
05h ZX Spectrum 128k +2A, +3
06h Timex Sinclair TC-2048
07h Timex Sinclair TS-2068
08h Pentagon 128
09h Sam Coupe
0Ah Didaktik M
0Bh Didaktik Gama
0Ch ZX-80 (via ID 19h, generalized data block, supported in v1.20 and up)
0Dh ZX-81 (via ID 19h, generalized data block, supported in v1.20 and up)
0Eh ZX Spectrum 128k, Spanish version
0Fh ZX Spectrum, Arabic version
10h Microdigital TK 90-X
11h Microdigital TK 95
12h Byte
13h Elwro 800-3
14h ZS Scorpion 256
</TD></TR></TABLE>Below in v1.02 and up (For Amstrad, use extension .CDT instead of .TZX)<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 15h Amstrad CPC 464
16h Amstrad CPC 664
17h Amstrad CPC 6128
18h Amstrad CPC 464+
19h Amstrad CPC 6128+
</TD></TR></TABLE>Below in v1.12 and up<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1Ah Jupiter ACE
1Bh Enterprise
</TD></TR></TABLE>Below in v1.13 only<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1Ch (was intended for Commodore 64)
1Dh (was intended for Commodore 128)
</TD></TR></TABLE>Below in v1.20 and up<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1Eh Inves Spectrum+
1Fh Profi
20h GrandRomMax
21h Kay 1024
22h Ice Felix HC 91
23h Ice Felix HC 2000
24h Amaterske RADIO Mistrum
25h Quorum 128
26h MicroART ATM
27h MicroART ATM Turbo 2
28h Chrome
29h ZX Badaloc
2Ah TS-1500
2Bh Lambda
2Ch TK-65
2Dh ZX-97
</TD></TR></TABLE><BR>
<B>External storage types (first byte = 01h)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h ZX Microdrive
01h Opus Discovery
02h MGT Disciple
03h MGT Plus-D
04h Rotronics Wafadrive
05h TR-DOS (BetaDisk)
06h Byte Drive
07h Watsford
08h FIZ
09h Radofin
0Ah Didaktik disk drives
0Bh BS-DOS (MB-02)
0Ch ZX Spectrum +3 disk drive
0Dh JLO (Oliger) disk interface
0Eh Timex FDD3000
0Fh Zebra disk drive
10h Ramex Millenia
11h Larken
</TD></TR></TABLE>Below in v1.20 and up<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 12h Kempston disk interface
13h Sandy
14h ZX Spectrum +3e hard disk
15h ZXATASP
16h DivIDE
17h ZXCF
</TD></TR></TABLE><BR>
<B>ROM/RAM type add-ons (first byte = 02h)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h Sam Ram
01h Multiface ONE
02h Multiface 128k
03h Multiface +3
04h MultiPrint
05h MB-02 ROM/RAM expansion
</TD></TR></TABLE>Below in v1.20 and up<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 06h SoftROM
07h 1k
08h 16k
09h 48k
0Ah Memory in 8-16k used
</TD></TR></TABLE><BR>
<B>Sound devices (first byte = 03h)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h Classic AY hardware (compatible with 128k ZXs)
01h Fuller Box AY sound hardware
02h Currah microSpeech
03h SpecDrum
04h AY ACB stereo (A+C=left, B+C=right); Melodik
05h AY ABC stereo (A+B=left, B+C=right)
</TD></TR></TABLE>Below in v1.20 and up<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 06h RAM Music Machine
07h Covox
08h General Sound
09h Intec Electronics Digital Interface B8001
0Ah Zon-X AY
0Bh QuickSilva AY
0Ch Jupiter ACE
</TD></TR></TABLE><BR>
<B>Joysticks (first byte = 04h)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h Kempston
01h Cursor, Protek, AGF
02h Sinclair 2 Left (12345)
03h Sinclair 1 Right (67890)
04h Fuller
</TD></TR></TABLE><BR>
<B>Mice (first byte = 05h)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h AMX mouse
01h Kempston mouse
</TD></TR></TABLE><BR>
<B>Other controllers (first byte = 06h)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h Trickstick
01h ZX Light Gun
02h Zebra Graphics Tablet
</TD></TR></TABLE>Below in v1.20 and up<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 03h Defender Light Gun
</TD></TR></TABLE><BR>
<B>Serial ports (first byte = 07h)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h ZX Interface 1
01h ZX Spectrum 128k
</TD></TR></TABLE><BR>
<B>Parallel ports (first byte = 08h)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h Kempston S
01h Kempston E
02h ZX Spectrum +3
03h Tasman
04h DK'Tronics
05h Hilderbay
06h INES Printerface
07h ZX LPrint Interface 3
08h MultiPrint
09h Opus Discovery
0Ah Standard 8255 chip with ports 31,63,95
</TD></TR></TABLE><BR>
<B>Printers (first byte = 09h)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h ZX Printer, Alphacom 32 & compatibles
01h Generic printer
02h EPSON compatible
</TD></TR></TABLE><BR>
<B>Modems (first byte = 0Ah)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h Prism VTX 5000
01h T/S 2050 or Westridge 2050
</TD></TR></TABLE><BR>
<B>Digitizers (first byte = 0Bh)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h RD Digital Tracer
01h DK'Tronics Light Pen
02h British MicroGraph Pad
</TD></TR></TABLE>Below in v1.20 and up<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 03h Romantic Robot Videoface
</TD></TR></TABLE><BR>
<B>Network adapters (first byte = 0Ch)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h ZX Interface 1
</TD></TR></TABLE><BR>
<B>Keyboards & keypads (first byte = 0Dh)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h Keypad for ZX Spectrum 128k
</TD></TR></TABLE><BR>
<B>AD/DA converters (first byte = 0Eh)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h Harley Systems ADC 8.2
01h Blackboard Electronics
</TD></TR></TABLE><BR>
<B>EPROM programmers (first byte = 0Fh)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h Orme Electronics
</TD></TR></TABLE><BR>
<B>Graphics (first byte = 10h)</B><BR>
Below in v1.20 and up<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h WRX Hi-Res
01h G007
02h Memotech
03h Lambda Colour
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumcassettetzxformatid19h"></A><FONT SIZE=+2>&nbsp;Spectrum Cassette TZX Format ID 19h</FONT></TD></TR></TABLE><BR>
<B>ID 19h - Generalized Data Block (length: [00h..03h]+4) (v1.20 and up)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 4 Block length (without these four bytes)
04h 2 Pause after this block (ms) (0=none)
06h 4 Total number of symbols in pilot/sync block (can be 0) (TOTP) ;\pilot
0Ah 1 Maximum number of pulses per pilot/sync symbol (NPP) ; hdr
0Bh 1 Number of pilot/sync symbols in alphabet table (0=256) (ASP) ;/
0Ch 4 Total number of symbols in data stream (can be 0) (TOTD) ;\data
10h 1 Maximum number of pulses per data symbol (NPD) ; hdr
11h 1 Number of data symbols in the alphabet table (0=256) (ASD) ;/
12h .. Pilot/Sync symbols definition table (only if TOTP&gt;0) ;\pilot
.. .. Pilot/Sync RLE-compressed stream (PRLE) (only if TOTP&gt;0) ;/stream
.. .. Data symbols definition table (only if TOTD&gt;0) ;\data
.. .. Data stream (as in .TAP files) (only if TOTD&gt;0) ;/stream
</TD></TR></TABLE>Can be used to encode nonstandard copy-protected files. Also used for ZX81
files.<BR>
<BR>
<B>Symbol Definition Table entry format (for both Pilot/Sync and Data)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 1 Symbol flags (b0-b1: starting symbol polarity)
0: opposite to current level (make an edge, as usual) - default
1: same as current level (no edge - prolongs previous pulse)
2: force low level
3: force high level
01h 2*MAXP Pulse lengths (16bit) (padded with 0000h if less than MAXP used)
</TD></TR></TABLE>The number of table entries is ASP or ASD. The size per entry is 1+2*MAXP,
where MAXP is NPP or NPD.<BR>
<BR>
<B>Run-Length Encoded Pilot/Sync Stream format (PRLE)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 1 Symbol to be output (eg. a symbol that defines the Pilot pulse)
01h 2 Number of repetitions (eg. number of Pilot pulses)
</TD></TR></TABLE>The number of entries is TOTP, each entry is 3 bytes in size.<BR>
<BR>
<B>Data Stream format</B><BR>
Most commonly, 2 symbols are used, so the 1st symbol is in bit7 of 1st byte.<BR>
If 3 or 4 symbols are used, then the 1st symbol is in bit7-6 of 1st byte.<BR>
<BR>
<B>Example (Standard Spectrum Block)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 0000xxxxh ;Total block length (28h+LEN)
04h 03E8h ;Pause after this block (ms)
06h 00000002h ;Total number of pilot/sync symbols TOTP;\
0Ah 02h ;Max pulses per symbol NPP ; pilot header
0Bh 02h ;Number of symbols in pilot/sync alphabet ASP ;/
0Ch LEN*8 ;Total number of data symbols TOTD;\
10h 02h ;Max pulses per data symbol NPD ; data header
11h 02h ;Number of symbols in data alphabet ASD ;/
12h 00h,02168,00000 ;Pilot Symbol 0 (single pilot pulse)
17h 00h,00667,00735 ;Pilot Symbol 1 (two sync pulses)
1Ch 00h,08063 ;PRLE: take Pilot-Symbol 0, and repeat it 8063 times
1Fh 01h,00001 ;PRLE: take Pilot-Symbol 1, and repeat it 1 times
22h 00h,00855,00855 ;Data Symbol 0
27h 00h,01710,01710 ;Data Symbol 1
2Ch Data (LEN bytes: block_type, data[LEN-2], chksum)
</TD></TR></TABLE><BR>
<B>Example (Standard ZX81 Block)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 0000xxxxh ;Total block length (58h+LEN)
04h 03E8h ;Pause after this block (ms)
06h 00000000h ;Total number of pilot/sync records TOTP;\no pilot
0Ah 00h ;Max pulses per symbol NPP ; for zx81
0Bh 00h ;Number of symbols in pilot/sync alphabet ASP ;/
0Ch LEN*8 ;Total number of data symbols TOTD;\
10h 12h ;Max pulses per data symbol NPD ; data header
11h 02h ;Number of symbols in data alphabet ASD ;/
12h 3,530,520,530,520,530,520,530 ;\Data Symbol 0
4689,0,0,0,0,0,0,0,0,0,0 ;/
37h 3,530,520,530,520,530,520,530 ;\Data Symbol 1
520,530,520,530,520,530,520,530,520,530,4689 ;/
5Ch Data (LEN bytes: ZX81 filename, followed by memory [4009h..E_LINE-1])
</TD></TR></TABLE>Note: As usually, data symbol definitions are referred to spectrum-style
3.5MHz clock frequency (ie. not to ZX81-style 3.25MHz).<BR>
<BR>
<B>ZX80/ZX81 Filetype Detection</B><BR>
ZX80/ZX81 files SHOULD have a Hardware Info block (ID 33h) that identifies
them as ZX80/ZX81 file. Unfortunately, in practice, they usually do NOT
contain that information. So, to detect a ZX80/ZX81 file, one would need to
check if the first data block has ID 19h, and if so, if it contains the above
Symbols. To separate between ZX80 and ZX81 one may need to examine the
presence of the ZX81 filename, and the values in the System Area.<BR>
<BR>
<B>ZX80/ZX81 Leading Silence</B><BR>
ZX80/ZX81 files are preceeded by leading silence (instead of a pilot tone).
For the ZX80 this leading silence is REQUIRED (must be at least around
500ms). For ZX81, it can be shorter, and it is required only if the signal is
preceeded by noise (if loading starts at the exact time when the 1st pulse is
output, then the ZX81 BIOS doesn't need the silence).<BR>
The ID 19h block itself doesn't support leading silence, so ZX80 files MUST
have it preceeded by Pause block (ID 20h) - one could almost expect that
people will violate that rule, if so, software must automatically insert the
leading pause.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumcassettetzxformatcustom"></A><FONT SIZE=+2>&nbsp;Spectrum Cassette TZX Format Custom</FONT></TD></TR></TABLE><BR>
<B>Custom Info Blocks...</B><BR>
Some of the most common uses of the Custom info block (ID 35h) have become
standardized in the past revisions, although now they are deprecated:<BR>
<BR>
<B>POKEs block (v1.10..v1.13 only)</B><BR>
The purpose of this custom block is to hold any amount of different trainers
for the game.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 16 Custom block ID ("POKEs" + 11 spaces)
10h 4 Length of data that follow
14h 1 General description length (L)
15h L General description in ASCII format
15h+L 1 Number of trainer definitions (N)
15h+L+1 .. Trainer definitions
</TD></TR></TABLE>Each trainer can have its own description and any number of POKEs.<BR>
TRAINER structure format<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 1 Trainer description length (L)
01h L Trainer description in ASCII format
01h+L 1 Number of poke definitions in this trainer (N)
01h+L+1 .. POKEs definitions
</TD></TR></TABLE>For each POKE entry you can supply the memory page number and/or the original
value of the address (if you want to restore it some way through the game).
Normally you would enter these pokes with the help of some freezer-type tool
like Multiface, but hopefully in the future the emulators will support this
block directly, in which case you could use the 'User inserts the POKE value'
feature. You can specify the point at which to insert the POKEs in the
'General description' field.<BR>
NOTE: All ASCII Descriptions can use more than one line. Please use only up
to 30 characters per line and separate the lines by one CR (13 decimal).<BR>
POKE structure format<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 1 POKE type:
bit 0-2 : memory page number
bit 3 : ignore memory page number
bit 4 : user inserts the POKE value
bit 5 : unknown original value
01h 2 POKE address
03h 1 POKE value (leave 0 if 'user inserts' bit set)
04h 1 POKE original value (leave 0 if 'unknown' bit set)
</TD></TR></TABLE><BR>
<B>Instructions block (v1.10..v1.13 only)</B><BR>
This block can hold any general .TXT file, with the main purpose of storing
the instructions to the program or game that is in the tape.<BR>
To ensure consistency with all other ASCII texts in this format please use a
single CR character (13 decimal, 0Dh) to separate lines; also please use only
up to 80 characters per line.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 16 Custom block ID ("Instructions" + 4 spaces)
10h 4 Length of the following data (L)
14h L Instructions text in ASCII format
</TD></TR></TABLE><BR>
<B>Spectrum screen block (v1.10..v1.13 only)</B><BR>
If the game on the tape is not an original and lacks the original loading
screen then you can supply it separately within this block. This is also very
handy when you want the loading screen stored separately because the original
is either encrypted (like with the 'Speedlock' or 'Alkatraz' loaders) or it
is corrupted by some on-screen info (like the 'Bleepload' loader). Of course
not only loading screens can be stored here... you can use it to store maps
or any other picture that is in Spectrum Video format (that's why the
Description is there for), but because the Loading Screen will be the most
common you can just set the description length field to 0 when you use it for
that. Also the border colour can be specified.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 16 Custom block ID ("Spectrum Screen" + 1 space)
10h 4 Length of data that follow
14h 1 Description length (L) (if 0 then handle it as 'Loading Screen')
15h L Description of the picture in ASCII format
15h+L 1 BORDER Colour in Spectrum colour format (0=black, 1=blue, ...)
15h+L+1 6912 Screen in standard Spectrum video format
</TD></TR></TABLE><BR>
<B>ZX-Edit document block (v1.12..v1.13 only)</B><BR>
This block can hold files created with the new utility called ZX-Editor. This
utility gives documents the look and feel of ZX-Spectrum and its documents
can contain text, graphics (with Spectrum attributes), different type faces,
colours, etc. Normally these files use extension .ZED. Also the description
is added, in case you want to use it for something else than 'Instructions' -
you can use it for MAPs, etc.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 16 Custom block ID ("ZX-Edit document")
10h 4 Length of data that follow
14h 1 Description length (L) (if 0 then handle it as 'Instructions')
15h L Description of the document in ASCII format
15h+L .. The ZX-Editor document (.ZED file)
</TD></TR></TABLE><BR>
<B>Picture block (v1.12..v1.13 only)</B><BR>
Finally you can include any picture (in supported formats) in the TZX file
too. So cover pictures, maps, etc. can now be included in full colour (or
whatever the formats supports). The best way for utilities to use this block
is to spawn an external viewer, or the authors can write their own viewers
(yeah, right ;) ). For inlay cards and other pictures that have zillions of
colours use the JPEG format, for more simple pictures (drawing, maps, etc.)
use the GIF format.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00h 16 Custom block ID ("Picture" + 9 spaces)
10h 4 Length of data that follow
14h 1 Picture format (00h=GIF, 1=JPEG)
15h 1 Description length (L) (if 0 then handle it as 'Inlay Card')
16h L Description of the document in ASCII format
16h+L .. The picture itself
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumcassettetzxnotes"></A><FONT SIZE=+2>&nbsp;Spectrum Cassette TZX Notes</FONT></TD></TR></TABLE><BR>
Format revision: v1.20, 19 Dec 2006<BR>
<BR>
<B>Introduction</B><BR>
TZX is a file format designed to preserve all (hopefully) of the tapes with
turbo or custom loading routines. Even though some of the newer and 'smarter'
emulators can find most of the info about the loader from the code itself,
this isn't possible if you want to save the file to tape, or to a real
Spectrum. And with all this information in the file, the emulators don't have
to bother with finding out the timings and other things.<BR>
This file format is explicitly targeted to the ZX Spectrum compatible
computers only. Specialized versions of the TZX format have been defined for
other machines too, e.g. the Amstrad CPC and C64, but they are now available
as distinct file formats with other filename extensions.<BR>
At the end of this document you can find a description of encoding
differences between these machines and a table which displays timings used by
their respective BIOS loading routines (some of them are not official). If
you know of any other machines that have similar encoding that could be
represented with this file format then let us know.<BR>
<BR>
If you're looking for TZX files, you can find an extensive collection at
Martijn van der Heide's 'World of Spectrum'.<BR>
<BR>
The format was first started off by Tomaz Kac who was maintainer until
revision 1.13, and then passed to Martijn v.d. Heide. After that, Ramsoft
were the maintainers for a brief period during which the v1.20 revision was
put together. If you have any questions about the format, visit the forums at
World of Spectrum and ask.<BR>
<BR>
The default format file extension is "TZX" and hopefully this won't have to
change in the future; for RISC OS, the current TAP file type will be used.
Amstrad CPC files should use the extension "CDT" to distinguish them from the
ZX Spectrum files, otherwise the inner structure is totally the same.<BR>
<BR>
<B>Rules and definitions</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> - All values are stored in little endian format (i.e. LSB first)
- All unused bits should be set to zero
- All timings are given in 3.5MHz clock cycles (unless otherwise stated)
- All ASCII texts use the ISO 8859-1 (Latin 1) encoding
- Some ASCII texts can have several lines, to be separated by chr(0Dh)
- MSB = most significant byte, LSB = least significant byte
- MSb = most significant bit, LSb = least significant bit
- The values in curly brackets {} are the default values as used by BIOS
</TD></TR></TABLE><BR>
<B>High and low levels</B><BR>
This document refers to 'high' and 'low' pulse levels. Whether this is
implemented as ear=1 and ear=0 respectively or the other way around is not
important, as long as it is done consistently.<BR>
Zeros and ones in 'Direct recording' blocks mean low and high pulse levels
respectively. The 'current pulse level' after playing a Direct Recording
block of CSW recording block is the last level played.<BR>
The 'current pulse level' after playing the blocks ID 10h,11h,12h,13h,14h or
19h is the opposite of the last pulse level played, so that a subsequent
pulse will produce an edge.<BR>
An emulator should put the 'current pulse level' to 'low' when starting to
play a TZX file, either from the start or from a certain position. The writer
of a TZX file should ensure that the 'current pulse level' is well-defined in
every sequence of blocks where this is important, i.e. in any sequence that
includes a 'Direct recording' block, or that depends on edges generated by
'Pause' blocks. The recommended way of doing this is to include a Pause after
each sequence of blocks.<BR>
<BR>
<B>Silence (pause, stop, end of tzx file)</B><BR>
Some blocks allow to define a pause of N milliseconds (ms) duration. If the
old level was low, then the first 1 ms of that pause should be high (required
to terminate the last pulse), and the remaining N-1 ms should be low. If the
old level was high, then the full N ms should be low.<BR>
The same requirement applies also when stopping the tape (on stop command, or
at end of tzx file): if the old level was low, then output 1ms high before
stopping the motor (required because some files do not include a pause after
the last data block which would imply the 1ms thing)<BR>
Pause of 0 ms duration is completely ignored, so the 'current pulse level'
will NOT change in this case. If there is no pause between two data blocks
then the second one should follow immediately; not even so much as one T
state between them.<BR>
<BR>
<B>Machine specific information</B><BR>
Currently supported machines are: ZX Spectrum, Amstrad CPC, SAM Coupe, ZX-81
Jupiter ACE and Enterprise. Only ZX-81 (or the old Timex 1000) and Jupiter
ACE use different tape encoding than the others.<BR>
<BR>
<B>Jupiter ACE encoding</B><BR>
See a dedicated site.<BR>
<BR>
<B>ZX Spectrum, Amstrad CPC, SAM Coupe & Enterprise tape encoding</B><BR>
These computers share the same tape encoding, which is normal frequency type
encoding. Each bit is represented by one 'wave' of different duration for bit
0 and bit 1. Normally bit 1 is twice as big as bit 0. In the blocks, the
timings are presented with Z80 T-states (cycles) per pulse. One wave is made
from two pulses.<BR>
The standard data blocks have always the same structure: first there is the
PILOT tone, then the two SYNC pulses (one wave) and after that the actual
DATA (which can include a FLAG byte at the beginning and a CHECKSUM byte at
the end).<BR>
Here is a table showing the pulse timings for each part of the standard BIOS
load/save routine for each of these machines. If you have more accurate
information then we would be glad to include it here. Enterprise has two
loading speeds so timings for both are included.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Machine Pilot pulse Length Sync1 Sync2 Bit 0 Bit 1
ZX Spectrum 2168 (1) 667 735 855 1710
SAM Coupe' 58+19*W 6000 58+9*W 113+9*W 10+8*W 42+15*W (*)
Amstrad CPC Bit 1 4096 Bit 0 Bit 0 (2) (2)
Enterprise (fast) 742 ? 1280 1280 882 602 (**)
Enterprise (slow) 1750 ? 2800 2800 1982 1400 (**)
</TD></TR></TABLE>Notes:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> (1) The Spectrum uses different pilot lengths for header and data blocks.
Header blocks have 8063 and data blocks have 3223 pilot pulses.
(2) Amstrad CPC BIOS load/save routine can use variable speed for loading,
so the bit 1 pulse must be read from the pilot tone and bit 0 can be
read from the sync pulses, and is always half the size of bit 1. The
checksum is also different than the other two machines. The speed can
vary from 1000 to 2000 baud.
(*) The SAM Coupe' timings can be user selected by a system variable. The
standard value is 112, which is VERY close to ZX Spectrum loading
speed, and therefore the 'Standard Speed Data' block can be used for
those blocks. However if this system variable is changed then the
timings will change accordingly. In the above table the value of this
variable is given as 'W', the 'H' value is 'W/2'. Of course the best
way to determine it is to calculate it from the timings you get when
sampling the Pilot tone. The values in the table could be by a
fraction of the real ones, but it should not matter. Note: All timings
are written in 3.5MHz clock. Also, there might be some junk bits
(usually 7 or 8) AFTER the checksum (XOR) byte at the end of the
block, but they can just be ignored.
(**) The Enterprise stores data in a different way than all other computers
do. It stores the LSb first, but the data blocks require the data to
be MSb first. This might lead to some confusion, but if the same
mechanism is used to replay data for all machines then there will be
no problem. Just store the data as MSb first, but if you want to view
the raw data in the TZX file then you will have to mirror each byte to
get the correct values.
</TD></TR></TABLE>IMPORTANT: The ZXTape format has ALL timings written according to a 3.5MHz
clock (the standard Spectrum 16/48K clock), so if the tape should be used on
an Amstrad CPC with 4MHz clock then you should multiply ALL timings with
4/3.5 when you use that tape (this should be trivial). Similarly goes for SAM
Coupe, that uses a 6MHz clock and Jupiter ACE that uses 3.2448 MHz and
Enterprise that uses 4 MHz!<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectruminterface1microdrivenetworkrs232"></A><FONT SIZE=+2>&nbsp;Spectrum Interface 1 (Microdrive, Network, RS232)</FONT></TD></TR></TABLE><BR>
<B>Sinclair Interface 1 Features</B><BR>
Allows to connect up to 8 Microdrives (endless tape drives), allows to set up
a network with up to 64 computers, allows to connect a RS232 printer.<BR>
<BR>
<B>Memory Mapped Ports</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0008h,1708h - Interface 1 - Enable external ROM (8K) (error and close#)
0700h - Interface 1 - Disable external ROM (8K) (ret)
</TD></TR></TABLE><BR>
<B>Port E7h (R/W)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-7 Microdrive Data (send/receive)
</TD></TR></TABLE>Accessing this port will HALT the Z80 until the Interface I has collected 8
bits from the microdrive head; therefore, if the microdrive motor isn't
running, or there is no formatted cartridge in the microdrive, the Spectrum
hangs. This is the famous 'IN 0 crash'.<BR>
<BR>
<B>Port EFh (R)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 Microdrive Write Protected
1 Microdrive Sync
2 Microdrive Gap
3 RS232 DTR
4 Busy (what busy?)
5-7 Not used
</TD></TR></TABLE><BR>
<B>Port EFh (W)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 Microdrive Comms Data (and Mode for Write to PortF7.Bit0)
1 Microdrive Comms Clk
2 Microdrive R/W
3 Microdrive Erase
4 RS232 CTS
5 Network Wait (used to synchronize)
6-7 Not used
</TD></TR></TABLE><BR>
<B>Port F7h (R)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 Network Input
1-6 Not used
7 RS232 TXDATA
</TD></TR></TABLE><BR>
<B>Port F7h (W)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 Network Output or RS232 RXDATA (depending on Port EFh.Bit0.Write)
1-7 Not used
</TD></TR></TABLE>If the microdrive is not being used, the COMMS DATA output selects the
function of bit0 of out-port F7h.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumdiscspectrum3disccontrollernecupd765"></A><FONT SIZE=+2>&nbsp;Spectrum Disc Spectrum +3 Disc Controller (NEC uPD765)</FONT></TD></TR></TABLE><BR>
The Spectrum +3 uses Plus3DOS (which is based on AMSDOS for Amstrad CPC),
like the CPC it's using a NEC uPD765 floppy disk controller.<BR>
<BR>
Port 1FFDh - Spectrum +2A/+3 Memory Control B and Disk Motor (W)<BR>
Port 2FFDh - Spectrum +3 Floppy FDC NEC uPD765 status (R)<BR>
Port 3FFDh - Spectrum +3 Floppy FDC NEC uPD765 data (R/W)<BR>
<BR>
<B>Accessing the FDC 765</B><BR>
The Data Register (Port 3FFDh) is used to write Commands and Parameters, to
read/write data bytes, and to receive result bytes. These three operations
are called Command-, Execution-, and Result-Phase. The Main Status Register
signalizes when the FDC is ready to send/receive the next byte through the
Data Register.<BR>
<BR>
<B>Command Phase</B><BR>
A command consists of a command byte (eventually including the MF, MK, SK
bits), and up to eight parameter bytes.<BR>
<BR>
<B>Execution Phase</B><BR>
During this phase, the actual data is transferred (if any). Usually that are
the data bytes for the read/written sector(s), except for the Format Track
Command, in that case four bytes for each sector are transferred.<BR>
<BR>
<B>Result Phase</B><BR>
Returns up to seven result bytes (depending on the command) that are
containing status information. The Recalibrate and Seek Track commands do not
return result bytes directly, instead the program must wait until the Main
Status Register signalizes that the command has been completed, and then it
must (!) send a Sense Interrupt State command to 'terminate' the
Seek/Recalibrate command.<BR>
<BR>
<B>FDC Command Table</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Command Parameters Exm Result Description
02+MF+SK HU TR HD ?? SZ NM GP SL &lt;R&gt; S0 S1 S2 TR HD NM SZ read track
03 XX YY - specify spd/dma
04 HU - S3 sense drive state
05+MT+MF HU TR HD SC SZ LS GP SL &lt;W&gt; S0 S1 S2 TR HD LS SZ write sector(s)
06+MT+MF+SK HU TR HD SC SZ LS GP SL &lt;R&gt; S0 S1 S2 TR HD LS SZ read sector(s)
07 HU - recalib.seek TP=0
08 - - S0 TP sense int.state
09+MT+MF HU TR HD SC SZ LS GP SL &lt;W&gt; S0 S1 S2 TR HD LS SZ wr deleted sec(s)
0A+MF HU - S0 S1 S2 TR HD LS SZ read ID
0C+MT+MF+SK HU TR HD SC SZ LS GP SL &lt;R&gt; S0 S1 S2 TR HD LS SZ rd deleted sec(s)
0D+MF HU SZ NM GP FB &lt;W&gt; S0 S1 S2 TR HD LS SZ format track
0F HU TP - seek track n
11+MT+MF+SK HU TR HD SC SZ LS GP SL &lt;W&gt; S0 S1 S2 TR HD LS SZ scan equal
19+MT+MF+SK HU TR HD SC SZ LS GP SL &lt;W&gt; S0 S1 S2 TR HD LS SZ scan low or equal
1D+MT+MF+SK HU TR HD SC SZ LS GP SL &lt;W&gt; S0 S1 S2 TR HD LS SZ scan high or eq.
</TD></TR></TABLE><BR>
Parameter bits that can be specified in some Command Bytes are:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> MT Bit7 Multi Track (continue multi-sector-function on other head)
MF Bit6 MFM-Mode-Bit (Default 1=Double Density)
SK Bit5 Skip-Bit (set if secs with deleted DAM shall be skipped)
</TD></TR></TABLE><BR>
Parameter/Result bytes are:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> HU b0,1=Unit/Drive Number, b2=Physical Head Number, other bits zero
TP Physical Track Number
TR Track-ID (usually same value as TP)
HD Head-ID
SC First Sector-ID (sector you want to read)
SZ Sector Size (80h shl n) (default=02h for 200h bytes)
LS Last Sector-ID (should be same as SC when reading a single sector)
GP Gap (default=2Ah except command 0D: default=52h)
SL Sectorlen if SZ=0 (default=FFh)
Sn Status Register 0..3
FB Fillbyte (for the sector data areas) (default=E5h)
NM Number of Sectors (default=09h)
XX b0..3=headunload n*32ms (8" only), b4..7=steprate (16-n)*2ms
YY b0=DMA_disable, b1-7=headload n*4ms (8" only)
</TD></TR></TABLE><BR>
Format Track: output TR,HD,SC,SZ for each sector during execution phase<BR>
Read Track: reads NM sectors (starting with first sec past index hole)<BR>
Read ID: read ID bytes for current sec, repeated/undelayed read lists all IDs<BR>
Recalib: walks up to 77 tracks, 80tr-drives may need second recalib if failed<BR>
Seek/Recalib: All read/write commands will be disabled until succesful senseint<BR>
Senseint: Set's IC if unsuccesful (no int has occured) (until IC=0)<BR>
<BR>
<B>FDC Status Registers</B><BR>
The Main Status register can be always read through Port 2FFDh. The other four
Status Registers cannot be read directly, instead they are returned through
the data register as result bytes in response to specific commands.<BR>
<BR>
<B>Main Status Register (Port 2FFDh)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> b0..3 DB FDD0..3 Busy (seek/recalib active, until succesful sense intstat)
b4 CB FDC Busy (still in command-, execution- or result-phase)
b5 EXM Execution Mode (still in execution-phase, non_DMA_only)
b6 DIO Data Input/Output (0=CPU-&gt;FDC, 1=FDC-&gt;CPU) (see b7)
b7 RQM Request For Master (1=ready for next byte) (see b6 for direction)
</TD></TR></TABLE><B>Status Register 0</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> b0,1 US Unit Select (driveno during interrupt)
b2 HD Head Adress (head during interrupt)
b3 NR Not Ready (drive not ready or non-existing 2nd head selected)
b4 EC Equipment Check (drive failure or recalibrate failed (retry))
b5 SE Seek End (Set if seek-command completed)
b6,7 IC Interrupt Code (0=OK, 1=aborted:readfail/OK if EN, 2=unknown cmd
or senseint with no int occured, 3=aborted:disc removed etc.)
</TD></TR></TABLE><B>Status Register 1</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> b0 MA Missing Adress Mark (Sector_ID or DAM not found)
b1 NW Not Writeable (tried to write/format disc with wprot_tab=on)
b2 ND No Data (Sector_ID not found, CRC fail in ID_field)
b3,6 0 Not used
b4 OR Over Run (CPU too slow in execution-phase (ca. 26us/Byte))
b5 DE Data Error (CRC-fail in ID- or Data-Field)
b7 EN End of Track (set past most read/write commands) (see IC)
</TD></TR></TABLE><B>Status Register 2</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> b0 MD Missing Address Mark in Data Field (DAM not found)
b1 BC Bad Cylinder (read/programmed track-ID different and read-ID = FF)
b2 SN Scan Not Satisfied (no fitting sector found)
b3 SH Scan Equal Hit (equal)
b4 WC Wrong Cylinder (read/programmed track-ID different) (see b1)
b5 DD Data Error in Data Field (CRC-fail in data-field)
b6 CM Control Mark (read/scan command found sector with deleted DAM)
b7 0 Not Used
</TD></TR></TABLE><B>Status Register 3</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> b0,1 US Unit Select (pin 28,29 of FDC)
b2 HD Head Address (pin 27 of FDC)
b3 TS Two Side (0=yes, 1=no (!))
b4 T0 Track 0 (on track 0 we are)
b5 RY Ready (drive ready signal)
b6 WP Write Protected (write protected)
b7 FT Fault (if supported: 1=Drive failure)
</TD></TR></TABLE><BR>
<B>Motor On/Off Flipflop</B><BR>
The motor is controlled via a bit in Port 1FFDh (see ULA chapter), the bit
controls motors for ALL drive(s), it is not possible to turn on/off the motor
of a specific drive separately.<BR>
<BR>
<B>Notes:</B><BR>
Before accessing a disk you should first Recalibrate the drive, that'll move
the head backwards until it reaches Track 0 (that's required to initialize
the FDCs track counter). On a 80 track drive you may need to repeat that in
case that the first recalibration attempt wasn't successful (that's because
the FDC stops searching after 77 steps).<BR>
<BR>
Now if you want to format, read or write a sector on a specific track you
must first Seek that track (command 0Fh). That'll move the read/write head to
the physical track number. If you don't do that, then the FDC will attempt to
read/write data to/from the current physical track, independendly of the
specified logical Track-ID.<BR>
<BR>
The Track-, Sector-, and Head-IDs are logical IDs only. These logical IDs are
defined when formatting the disk, and aren't required to be identical to the
physical Track, Sector, or Head numbers. However, when reading or writing a
sector you must specify the same IDs that have been used during formatting.<BR>
<BR>
Despite of the confusing name, a sector with a "Deleted Data Address Mark"
(DAM) is not deleted. The DAM-flag is just another ID-bit, and (if that
ID-bit is specified correctly in the command) it can be read/written like
normal data sectors.<BR>
<BR>
At the end of a successful read/write command, the program should send a
Terminal Count (TC) signal to the FDC. However, in the CPC (and probably also
in the Spectrum) the TC pin isn't connected to the I/O bus, making it
impossible for the program to confirm a correct operation. For that reason,
the FDC will assume that the command has failed, and it'll return both Bit 6
in Status Register 0 and Bit 7 in Status Register 1 set. The program should
ignore this errormessage.<BR>
<BR>
The CPC doesn't support floppy DMA transfers, and the FDCs Interrupt signal
isn't used in the CPC also.<BR>
<BR>
Usually single sided 40 Track 3" disk drives are used in CPCs, whereas 40
tracks is the official specification, practically 42 tracks could be used.
The FDC controller can be used to control 80 tracks, and/or double sided
drives also, even though AMSDOS isn't supporting such formats. AMSDOS is
supporting a maximum of two disk drives only.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumdiscopusdiscovery"></A><FONT SIZE=+2>&nbsp;Spectrum Disc Opus Discovery</FONT></TD></TR></TABLE><BR>
<B>MEM:0008h,0048h,1708h - Discovery - Enable external ROM/RAM/WD/PIA</B><BR>
<B>MEM:1748h - Discovery - Disable external ROM/RAM/WD/PIA</B><BR>
Opcode fetches from these addresses enable/disable the Discovery hardware,
when enabled, the following is mapped to first 16K of memory:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0000-1FFF ROM (8K)
2000-27FF RAM (2K)
2800-2803 WD 1770 Ports (floppy controller)
3000-3003 PIA 6821 Ports (drive/side select, centronics etc.)
</TD></TR></TABLE><BR>
<B>DRQ (Data Request)</B><BR>
The DRQ output from WD 1770 is inverted and connected to /NMI input (unlike
as most other drives which map DRQ to a status register bit, and which use
/NMI as snapshot button).<BR>
<BR>
<B>MEM:2800h - FDC Command (W)</B><BR>
<B>MEM:2800h - FDC Status (R)</B><BR>
<B>MEM:2801h - FDC Track (R/W)</B><BR>
<B>MEM:2802h - FDC Sector (R/W)</B><BR>
<B>MEM:2803h - FDC Data (R/W)</B><BR>
<A HREF="#spectrumdisccontrollerwesterndigitalwd177x">Spectrum Disc Controller (Western Digital WD177x)</A><BR>
<BR>
<B>MEM:3000h when CRA.Bit2=1 - PIA Peripheral Interface A (PA0..7)</B><BR>
<B>MEM:3000h when CRA.Bit2=0 - PIA Data Direction Reg. A (0=Input, 1=Output)</B><BR>
<B>MEM:3001h - PIA Control Register A (CRA)</B><BR>
<B>MEM:3002h when CRB.Bit2=1 - PIA Peripheral Interface B (PA0..7)</B><BR>
<B>MEM:3002h when CRB.Bit2=0 - PIA Data Direction Reg. B (0=Input, 1=Output)</B><BR>
<B>MEM:3003h - PIA Control Register B (CRB)</B><BR>
The PIA 6821 lines are connected as such:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> PA0 drive 2 select (and enable motors for both drives)
PA1 drive 1 select (and enable motors for both drives)
PA4 side select
PA5 double density enable
PA6 centronics busy (input)
PA7 enable kempston joystick port on A5=0 (from BASIC: type FORMAT "j";1)
PB0..7 centronics data
CA2 centronics ack
CB2 centronics strobe
</TD></TR></TABLE>The PA2,PA3,CA1,CB1,/IRQA,/IRQB pins are not used.<BR>
<BR>
<B>PIA Control Register A (CRA)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 CA1 Input Control (0..3)
0 = Set IRQA1 when CA1=Negative, but do not trigger /IRQA
1 = Set IRQA1 when CA1=Negative, and do trigger /IRQA
2 = Set IRQA1 when CA1=Positive, but do not trigger /IRQA
3 = Set IRQA1 when CA1=Positive, and do trigger /IRQA
2 DDRA Access (0=Data Direction Register A, 1=Data Register A)
3-5 CA2 Input/Output Control (0..7)
0 = Set IRQA2 when CA2=Negative, but do not trigger /IRQA
1 = Set IRQA2 when CA2=Negative, and do trigger /IRQA
2 = Set IRQA2 when CA2=Positive, but do not trigger /IRQA
3 = Set IRQA2 when CA2=Positive, and do trigger /IRQA
4 = Handshake Output Mode (CA2=High on CA1, CA2=Low on "Read A Data")
5 = Pulse Output Mode (CA2=Low for 1 clk after "Read A Data")
6 = Manual Output, set CA2=Low
7 = Manual Output, set CA2=High
6 IRQA2 Flag (CA2 input)
7 IRQA1 Flag (CA1 input)
</TD></TR></TABLE><BR>
<B>PIA Control Register B (CRB)</B><BR>
Same as CRA, but using Port B, CB1, CB2, IRQB, etc. And, CRB handshake/pulse
modes are bound to "Write B Data" instead of "Read A Data" conditions.<BR>
<BR>
<B>IO:1Fh - Discovery Joystick Port (uses A5 only, eg. mirrored to DFh)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-4 Kempston Joystick (disabled by default)
5-7 Not used
</TD></TR></TABLE>Unlike normal kempston joystick ports this port is disabled by default
(presumably for best compatibility with other hardware that uses Port 1Fh, or
mirrors like DFh, for something else). The port can be enabled via PA7 bit,
or by typing FORMAT "j";1 in BASIC (type ;0 to disable it again).<BR>
<BR>
<B>PIA 6821 Pin-Outs</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 VSS 6 PA4 11 PB1 16 PB6 21 R/W 26 D7 31 D2 36 RS1(A1)
2 PA0 7 PA5 12 PB2 17 PB7 22 CS0 27 D6 32 D1 37 /IRQB
3 PA1 8 PA6 13 PB3 18 CB1 23 /CS2 28 D5 33 D0 38 /IRQA
4 PA2 9 PA7 14 PB4 19 CB2 24 CS1 29 D4 34 /RES 39 CA2
5 PA3 10 PB0 15 PB5 20 VCC 25 PHI2 30 D3 35 RS0(A0) 40 CA1
</TD></TR></TABLE><BR>
<B>DOS Replacement for Opus Discovery</B><BR>
The MegaSoft QuickDOS package consists of a disc, manual, and replacement ROM
which contains faster load/save routines than the original Opus ROM.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumdiscdiscipleandplusd"></A><FONT SIZE=+2>&nbsp;Spectrum Disc Disciple and Plus D</FONT></TD></TR></TABLE><BR>
The Disciple and PlusD are both developed by Miles Gordon Technology, both
contain 16K ROM, 8K RAM, a Snapshot/NMI button (works only when SHIFT held
down?), a Western Digital disk controller, and a centronics port (although
using different I/O addresses).<BR>
The older Disciple (1987) does additionally contain Joystick and Network
ports, and a feature to swap ROM and RAM addresses, and a Inhibit button (to
lock out the interface). The newer PlusD (1988) does not include these extras
(so the "Plus D" is actually a "Disciple Minus Extras").<BR>
<BR>
<B>1Bh/E3h Disciple/PlusD - FDC Command (W)</B><BR>
<B>1Bh/E3h Disciple/PlusD - FDC Status (R)</B><BR>
<B>5Bh/EBh Disciple/PlusD - FDC Track (R/W)</B><BR>
<B>9Bh/F3h Disciple/PlusD - FDC Sector (R/W)</B><BR>
<B>DBh/FBh Disciple/PlusD - FDC Data (R/W)</B><BR>
<A HREF="#spectrumdisccontrollerwesterndigitalwd177x">Spectrum Disc Controller (Western Digital WD177x)</A><BR>
<BR>
<B>EFh PlusD only - PlusD Control Register (W)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 Drive A Select
1 Drive B Select
2 Single/double density
3 ROM bank select (first/second 8K of total 16K ROM)
4 Not used
5 Ext. select (?)
6 Centronics Strobe
7 Side select
</TD></TR></TABLE><BR>
<B>1Fh Disciple only - Disciple Control Register (W)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 Drive select
1 Side select
2 Single/double density
3 ROM bank select (first/second 8K of total 16K ROM)
4 Inhibit switch control
5 Ext. select (?)
6 Centronics Strobe
7 Network Data Output (0=0V, 1=5V)
</TD></TR></TABLE><BR>
<B>1Fh Disciple only - Disciple Joystick 2 aka Kempston, and Printer/Network (R)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-4 Kempston Joystick Port (also mapped to Port F7FEh)
5 Not used
6 Centronics Busy
7 Network Data Input (0=0V, 1=5V)
</TD></TR></TABLE><BR>
<B>3Bh Disciple only - Network Wait when Network Input is 1=5V (R or W ?)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Port 3Bh is used for network synchronization (same as bit 5 of Interface
One's port EFh). Any OUT to port 3Bh will halt the Spectrum until the
logic level on the network is 0. It is used to wait for the start bit
of a transmission frame.
The network bus carries TTL logic levels (0 = 0 Volts, 1 = 5 Volts).
The bit rate is 87.5 Kbps and data is exchanged in packets of max 256
bytes using a simple data-link level protocol.
Network is an Interface 1 compatible net.
</TD></TR></TABLE><BR>
<B>F7FEh Disciple only - Disciple Joystick 1 aka Sinclair Joystick 2 (R)</B><BR>
<B>EFFEh Disciple only - Disciple Joystick 2 aka Sinclair Joystick 1 (R)</B><BR>
These are standard Sinclair joystick ports (although numbered in opposite
order, otherwise same as in Interface 2 and Spectrum +2/+2A/+3). Disciple
Joystick 1 aka Sinclair Joystick 2 is also mapped to Port 1Fh.<BR>
<BR>
<B>FBh/F7h Disciple/PlusD - Centronics Data (W)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-7 Printer Data
</TD></TR></TABLE><BR>
<B>F7h PlusD Only - Centronics Busy (R)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-6 Not used
7 Printer Busy
</TD></TR></TABLE><BR>
<B>BBh/E7h Disciple/PlusD - Enable Internal ROM/RAM (R)</B><BR>
<B>BBh/E7h Disciple/PlusD - Disable Internal ROM/RAM (W)</B><BR>
<B>MEM:0000h,0008h,0066h,028Eh - Enable Internal ROM/RAM (R)</B><BR>
Reading/Writing from these Ports (or opcode fetches from MEM addresses)
enables/disables the internal ROM/RAM (instead of the Spectrum BIOS).<BR>
In the PlusD, the ROM is always at 0000h-1FFFh, and RAM at 2000h-3FFFh. In
the Disciple it is the same on reset, but can be changed via Port 7Bh.<BR>
<BR>
<B>7Bh Disciple only - Map ROM at 0000h, RAM at 2000h (R) (default on Boot)</B><BR>
<B>7Bh Disciple only - Map ROM at 2000h, RAM at 0000h (W) (default in GDOS)</B><BR>
Allows to swap ROM and RAM locations.<BR>
<BR>
<B>DOS versions</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> GDOS --&gt; Built-in in Disciple
G+DOS --&gt; Built-in in PlusD
Beta DOS --&gt; Third-party DOS Replacement for PlusD
UniDOS --&gt; Third-party DOS Replacement for PlusD and Disciple
</TD></TR></TABLE>Beta DOS (from Beta Soft / Andy Wright) is an alternate DOS for the Plus D
(from MGT), it doesn't have anything to do with the "Beta Disk Interface"
(from Technology Research). Beta DOS boots from diskette (it doesn't seem to
require a ROM replacement).<BR>
UniDOS is another DOS replacement that can be used on both Disciple and
PlusD, it consists of a software diskette and a replacement ROM (there are
two ROM versions, one for PlusD, and one for Disciple).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumdiscbetabetaplusbeta128diskinterfacetrdos"></A><FONT SIZE=+2>&nbsp;Spectrum Disc Beta/BetaPlus/Beta128 Disk Interface (TRDOS)</FONT></TD></TR></TABLE><BR>
The Beta (1984), Beta Plus (1985), and Beta 128 (1987) Disk Interfaces with
TRDOS ROM were developed by Technology Research and may have been more or
less popular in Europe.<BR>
In Russia, it became the standard disk interface (even more popular than
cassettes), the Beta I/O addresses, and TRDOS ROM were used in Spectrum
clones like Pentagon (1989) and Scorpion.<BR>
<BR>
<B>Versions</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Interface Year TRDOS Description
Beta 1984 v1 original version
Beta Plus 1985 v4 auto-boot, drive-detect, magic-button, seq/rnd access
Beta 128 1986 v5.0x changed USR addresses, auto-boot-disable-switch
Pentagon 1989 v5.0x russian spectrum clone with beta 128 disk interface
</TD></TR></TABLE><BR>
<B>Features</B><BR>
The Interface is quite simple, it consists of the TRDOS ROM, the FDC chip,
and eventually a Magic button and/or Reset button. It doesn't include RAM,
nor any extras like Centronics or Joystick ports.<BR>
Since there's no built-in RAM, it allocates 70h bytes at 5CB6h (or at higher
address if other hardware like Interface 1 has already allocated memory).
Additionally, it does temporarily allocate a 100h bytes as sector buffer
while accessing the disk.<BR>
<BR>
<B>MEM:3C00h..3CFFh - Enable ROM & I/O Ports (Beta/TRDOSv1 and BetaPlus/TRDOSv4)</B><BR>
<B>MEM:3D00h..3DFFh - Enable ROM & I/O Ports (Beta128/TRDOSv5.0x)</B><BR>
The enable region was originally at 3Cxxh (which is FFh-filled in Spectrum
16K/48K/Plus BIOSes), and was invoked via RANDOMIZE USR 15360 and 15363 from
BASIC. For compatibility with the Spectrum 128 (which contains BIOS code in
that region), the region was moved to 3Dxxh (which contains only character
set data, but no program code) and is now invoked via USR 15616 and 15619.
The first address is used to enter TRDOS,<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> RANDOMIZE USR 15360 or 15616 --&gt; switch from BASIC to TRDOS ;3C00h/3D00h
RETURN (aka Y-key) --&gt; switch from TRDOS to BASIC
</TD></TR></TABLE>The second address is used as prefix to normal BASIC commands, eg.:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> RANDOMIZE USR 15363 or 15619:REM:LOAD"filename" ;3C03h/3D03h
</TD></TR></TABLE><BR>
<B>MEM:4000h..FFFFh - Disable ROM & I/O Ports (all versions)</B><BR>
Opcode fetches outside of the ROM region (ie. at 4000h..FFFFh) do
automatically disable the TRDOS ROM and I/O ports.<BR>
<BR>
<B>MEM:0000h? - Enable ROM & I/O Ports (BetaPlus/TRDOSv4 and Beta128/TRDOSv5.0x)</B><BR>
The Beta Plus and Beta 128 have an Auto-Boot feature that automatically
enters TRDOS instead of BASIC on power-up. Unknown which opcode address
activates TRDOS... probably 0000h.<BR>
The Auto-Boot feature works only on Spectrum 48K/Plus, but isn't compatible
with the Spectrum 128 (the Beta 128 includes a "system switch" that allows to
disable auto-boot for Spectrum 128 compatibility, ie. on the Spectrum 128
TRDOS can be started only manually via RANDOMIZE USR 15616).<BR>
<BR>
<B>MEM:0066h? - Enable ROM & I/O Ports (BetaPlus/TRDOSv4 and Beta128/TRDOSv5.0x)</B><BR>
The Beta Plus and Beta 128 have a Magic button, presumably triggering an /NMI
and thus needing to enable ROM on address 0066h (?) although in poor quality
schematics it looks more like /RESET than /NMI. The button does usually allow
to save snapshots (except, on the Scorpion, it launches a Service-Monitor
program).<BR>
<BR>
<B>I/O Port Activation</B><BR>
Below I/O ports are enabled only while the ROM is enabled, too. Ie. when
disabled, there's no conflict with Kempston Joysticks (Port 1Fh) or with the
VRAM Garbage effect (Port FFh). Mind that ROM and I/O ports are automatically
disabled when accessing opcodes at 4000h..FFFFh (so the I/O ports can be
accessed ONLY from inside of the TRDOS ROM).<BR>
<BR>
<B>1Fh - Beta Disk FDC Command (W)</B><BR>
<B>1Fh - Beta Disk FDC Status (R)</B><BR>
<B>3Fh - Beta Disk FDC Track (R/W)</B><BR>
<B>5Fh - Beta Disk FDC Sector (R/W)</B><BR>
<B>7Fh - Beta Disk FDC Data (R/W)</B><BR>
<A HREF="#spectrumdisccontrollerwesterndigitalwd177x">Spectrum Disc Controller (Western Digital WD177x)</A><BR>
According to some untitled schematics, the interface uses a FD1793-02 chip
(which is maybe correct), according to Sinclair User magazine it uses a 1771
chip (such a thing probably doesn't exist at all), according to russian
source it uses a KR1818VG93 aka VG93 chip (which is probably a 1793 clone).<BR>
<BR>
<B>FFh - Beta Disk Status (R)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-5 Unused?
6 DRQ (data request)
7 INTRQ (command completion)
</TD></TR></TABLE><BR>
<B>FFh - Beta Disk Control (W?)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-1 Drive select (0..3 = Drive A..D)
2 Hardware microcontroller reset (0=reset, 1=normal)
3 Blocks signal HLT of microcontroller (=disk controller?) (1=normal)
4 Head select (0=First/bottom, 1=Second/Top)
5 Density select (0=FM, 1=MFM)
6-7 Unused
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumdisccontrollerwesterndigitalwd177x"></A><FONT SIZE=+2>&nbsp;Spectrum Disc Controller (Western Digital WD177x)</FONT></TD></TR></TABLE><BR>
<B>Command description</B><BR>
Commands should only be loaded in the Command Register when the Busy status
bit is off (Status bit 0). The one exception is the Force Interrupt command.
Whenever a command is being executed, the Busy status bit is set.<BR>
At the completion of every command an INTRQ is generated. INTRQ is reset by
either reading the status register or by loading the command register with a
new command. In addition, INTRQ is generated if a Force Interrupt command
condition is met.<BR>
When a command is completed, an interrupt is generated and the busy status
bit is reset. The Status Register indicates whether the completed command
encountered an error or was fault free.<BR>
<BR>
<B>Command Summary (models 1791, 1792, 1793, 1794) (and 1770,1772,1773)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Type Command b7 b6 b5 b4 b3 b2 b1 b0
I Restore 0 0 0 0 h/M V r1 r0
I Seek 0 0 0 1 h/M V r1 r0
I Step 0 0 1 T h/M V r1 r0
I Step-In 0 1 0 T h/M V r1 r0
I Step-Out 0 1 1 T h/M V r1 r0
II Read Sector 1 0 0 m S/M E C/0 0
II Write Sector 1 0 1 m S/M E C/P a0
III Read Address 1 1 0 0 0/M E 0 0
III Read Track 1 1 1 0 0/M E 0 0
III Write Track 1 1 1 1 0/M E 0/P 0
IV Force Interrupt 1 1 0 1 i3 i2 i1 i0
</TD></TR></TABLE><BR>
<B>Flag Summary</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> r1,r0 Stepping Motor Rate (0..3 = 6ms,12ms,20ms,30ms) (WD179X,WD1770/WD1773)
r1,r0 Stepping Motor Rate (0..3 = 2ms,3ms,5ms,6ms) (WD1772 Preliminary docs)
r1,r0 Stepping Motor Rate (0..3 = 6ms,12ms,2ms,3ms) (WD1772 Other docs... ?)
V Track Number Verify Flag (0: no verify, 1: verify on dest track)
h Head Load Flag (1: load head at beginning, 0: unload head) (WD179X)
T Track Update Flag (0: no update, 1: update Track Register)
a0 Data Address Mark (0: FB, 1: F8 (deleted DAM))
C Side Compare Flag (0: disable, 1: enable) (WD179X only) (and WD1773?)
E 15 ms delay (0: no 15ms delay, 1: 15 ms delay)
S Side Compare Flag (0: compare for side 0, 1: compare for side 1)
m Multiple Record Flag (0: single record, 1: multiple records)
P Write Precompensation (0=On, 1=Off) (WD1770/WD1772 only) (and WD1773?)
M Motor On (0=on, 1=off) (WD1770/WD1772 only)
</TD></TR></TABLE>Interrupt Condition Flags<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> i3-i0 0 = Terminate with no interrupt (INTRQ)
i3 1 = Immediate interrupt, requires a reset
i2 1 = Index pulse
i1 1 = Ready to not ready transition (Not used on WD1770/WD1772)
i0 1 = Not ready to ready transition (Not used on WD1770/WD1772)
</TD></TR></TABLE><BR>
<B>Type I commands (Restore, Seek, Step-Out, Step-In, Step)</B><BR>
Used to move the read/write head. The stepping motor rate should be usally
set to 6ms (r1 and r0 bits set to zero) for a 3.5-inch floppy disk drive. An
optional verification of head position can be performed by setting bit 2
(V=1) in the command word.<BR>
<BR>
When V=1: When the seek is completed, the drive automatically goes into read
mode, the track number from the first encountered Sector ID Field is then
compared against the contents of the Track Register (or Data Register?), if
the track numbers compare (and the ID Field CRC is correct) the verify
operation is complete and an INTRQ is generated with no errors. If these
track numbers do not match, the Seek Error bit of the status register is set.<BR>
<BR>
When V=0: When the seek is completed, the track position is not verified
(this mode is required for unformatted disks). The command ends once the last
step pulse is output. Since the result is that there is not enough time for
step stability, the host system must use its software to make the floppy disk
wait a certain period before reading or writing the track just arrived at.<BR>
<BR>
When the seek command is complete, the interrupt request is set and at the
same time, the Busy bit in the status register is set to 0. When the CPU
reads the status register, it resets the interrupt request signal.<BR>
<BR>
<B>Restore (Seek Track 0)</B><BR>
If TR00 is not active, stepping pulses are issued until the TR00 input
is activated. The Track Register is set to zero, and an interrupt is
generated when track 0 has been reached.<BR>
<BR>
<B>Seek</B><BR>
This command assumes that the Track Register contains the &lt;current&gt; position
of the head, and that the Data Register contains the &lt;desired&gt; destination
track number. The FD179X will update the Track Register and issue stepping
pulses in the appropriate direction until the contents of the Track and Data
Register are equal to each other. An interrupt is generated at the completion
of the command.<BR>
<BR>
<B>Step-Out, Step-In, Step</B><BR>
Issues one stepping pulse to the disk drive. Step-Out: towards track 0.
Step-In: towards track 76 (that feature is not useful for 80-track drives).
Step: same direction as for previous step command. The track register is
updated (ie. incremented or decremented) only if the "T" bit has been set in
the command word. An interrupt is generated at the end of each command.<BR>
<BR>
<B>Type II commands (Read Sector, Write Sector)</B><BR>
Prior to loading the Type II command into the Command Register, the
computer must load the Sector Register with the desired sector number.
Upon receipt of the Type II command, the busy status bit is set. The
FD179X must find an ID field with a matching Track number and Sector
number, otherwise the Record not found status bit is set and the command
is terminated with an interrupt.<BR>
Each of the Type II commands contains an m flag which determines if
multiple records (sectors) are to be read or written. If m=0, a single
sector is read or written and an interrupt is generated at the
completion of the command. If m=1, multiple records are read or written
with the sector register internally updated so that an address
verification can occur on the next record. The FD179X will continue to
read or write multiple records and update the sector register in
numerical ascending sequence until the sector register exceeds the
number of sectors on the track or until the Force Interrupt command is
loaded into the Command Register.<BR>
The Type II commands for 1791-94 also contain side select compare flags.
When C=0 (bit 1), no comparison is made. When C=1, the LSB of the side
number is read off the ID Field of the disk and compared with the
contents of the S flag.<BR>
<BR>
<B>Read Sector</B><BR>
Upon receipt of the command, the head is loaded, the busy status bit set
and when an ID field is encountered that has the correct track number,
correct sector number, correct side number, and correct CRC, the data
field is presented to the computer.<BR>
An DRQ is generated each time when the CPU must read a byte from the
data register, the Lost Data bit is set if the CPU didn't read data in
time, and the Read operation continues until the end of sector is
reached.<BR>
At the end of the Read operation, the type of Data Address Mark
encountered in the data field is recorded in the Status Register (bit
5).<BR>
<BR>
<B>Write Sector</B><BR>
Upon receipt of the command, the head is loaded, the busy status bit set
and when an ID field is encountered that has the correct track number,
correct sector number, correct side number, and correct CRC, a DRQ is
generated.<BR>
The FD179X counts off 22 bytes (in double density) from the CRC field
and the Write Gate output is made active if the DRQ is serviced (ie. the
DR has been loaded by the computer). If DRQ has not been serviced, the
command is terminated and the Lost Data status bit is set. If the DRQ
has been serviced, 12 bytes of zeroes (in double density) are written to
the disk, then the Data Address Mark as determined by the a0 field of
the command.<BR>
The FD179X then writes the data field and generates DRQ's to the
computer. If the DRQ is not serviced in time for continuous writing the
Lost Data Status bit is set and a byte of zeroes is written on the disk
and the command continues until the last byte of the sector is reached.<BR>
After the last data byte has been written on the disk, the two-byte CRC
is computed internally and written on the disk followed by one byte of
logic ones.<BR>
<BR>
<B>Type III commands</B><BR>
<BR>
<B>Read Address</B><BR>
Upon receipt of the Read Address command, the head is loaded and the
Busy Status bit is set. The next encountered ID field is then read in
from the disk, and the six data bytes of the ID field are assembled and
transferred to the DR, and a DRQ is generated for each byte. The six
bytes of the ID field are : Track address, Side number, Sector address,
Sector Length, CRC1, CRC2. Although the CRC bytes are transferred to the
computer, the FD179X checks for validity and the CRC error status bit is
set if there is a CRC error. The track address of the ID field is
written into the sector register so that a comparison can be made by the
user. At the end of the operation, an interrupt is generated and the
Busy status bit is reset.<BR>
<BR>
<B>Read Track</B><BR>
Upon receipt of the Read Track command, the head is loaded, and the busy
status bit is set. Reading starts with the leading edge of the first
encountered index pulse and continues until the next index pulse. All
gap, header, and data bytes are assembled and transferred to the data
register and DRQ's are generated for each byte. The accumulation of
bytes is synchronized to each address mark encountered. An interrupt is
generated at the completion of the command. The ID Address Mark, ID
field, ID CRC bytes, DAM, Data and Data CRC bytes for each sector will
be correct. The gap bytes may be read incorrectly during write-splice
time because of synchronization.<BR>
<BR>
<B>Write Track (formatting a track)</B><BR>
Upon receipt of the Write Track command, the head is loaded and the Busy
Status bit is set. Writing starts with the leading edge of the first
encountered index pulse and continues until the next index pulse, at
which time the interrupt is activated. The Data Request is activated
immediately upon receiving the command, but writing will not start until
after the first byte has been loaded into the DR. If the DR has not been
loaded by the time the index pulse is encountered, the operation is
terminated making the device Not Busy, the Lost Data status bit is set,
and the interrupt is activated. If a byte is not present in the DR when
needed, a byte of zeroes is substituted. This sequence continues from
one index mark to the next index mark.<BR>
Normally, whatever data pattern appears in the data register is written
on the disk with a normal clock pattern. However, if the FD179X detects
a data pattern of F5 thru FE in the data register, this is interpreted
as data address marks with missing clocks or CRC generation. The CRC
generator is initialized when an F5 data byte is about to be transferred
(in MFM). An F7 pattern will generate two CRC bytes. As a consequence,
the patterns F5 thru FE must not appear in the gaps, data fiels, or ID
fiels. Tracks may be formatted with sector lengths of 128, 256, 512 or
1024 bytes. See "Formatting" below for more info and example.<BR>
<BR>
<B>Type IV command (Force Interrupt)</B><BR>
The Forced Interrupt command is generally used to terminate a multiple
sector read or write command or insure Type I status register. This
command can be loaded into the command register at any time. If there is
a current command under execution (busy status bit set), the command
will be terminated and the busy status bit reset.<BR>
<BR>
<B>Status Register</B><BR>
Upon receipt of any command, except the Force Interrupt command, the
Busy Status bit is set and the rest of the status bits are updated or
cleared for the new command.<BR>
The user has the option of reading the status register through program
control or using the DRQ line with DMA or interrupt methods. When the DR
is read the DRQ bit in the Status register and the DRQ line are
automatically reset. A write to the DR also causes both DRQ's to reset.
The busy bit in the status may be monitored with a user program to
determine when a command is complete, in lieu of using the INTRQ line.
When using the INTRQ, a busy status check is not recommended because a
read of the status register to determine the condition of busy will
reset the INTRQ line.<BR>
<BR>
<B>Status for Type I commands</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bit Expl.
0 Busy (1=Command is in progress)
1 Index (1=Index mark detected from drive)
2 Track 0 (1=Read/Write head is positioned to Track 0)
3 CRC Error (1=CRC encountered in ID field)
4 Seek Error (1=Desired track was not verified) (reset 0 when updated)
5 Head Loaded (1=Head loaded an engaged) (WD1770/WD1772: Spin-up ready)
6 Protected (1=Disk write protected)
7 Not Ready (1=Drive not ready) (WD1770/WD1772: Motor On)
</TD></TR></TABLE><BR>
<B>Status for type II & III commands</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bit Expl.
0 Busy (1=Command is under execution)
1 Data Request (1=CPU must read/write next data byte) (DRQ)
2 Lost Data (1=CPU did not respond to DRQ in one byte time)
3-4 Error Code (1=Bad Data CRC, 2=Sector not found, 3=Bad ID Field CRC)
5 Fault/Type (Any Write:1=Write Fault, Read Sector:1=Deleted Data Mark)
6 Protected (Any Write:1=Write Protect, Any Read:Not used)
7 Not Ready (1=Drive not ready) (WD1770/WD1772: Motor On)
</TD></TR></TABLE>Notes: Bit 1-6 are reset when updated. Bit 3-4 not used for read/write track.<BR>
<BR>
<B>Status for type IV command</B><BR>
If the Force Interrupt command is received while a command is under
execution, the Busy status bit is reset and the rest of the status bits
are unchanged.<BR>
If the Force Interrupt command is received when there is no command
under execution, the Busy Status bit is reset and the rest of the status
bits are updated or cleared. In this case, Status reflects the Type I
commands.<BR>
<BR>
<B>External Circuit</B><BR>
The floppy disk controller itself cannot select the drive number, side,
disk density, and it cannot turn on/off the drive motor(s). These
settings must be set up by an external circuit, which are (as far as
they aren't set to a fixed setting) controlled through separate I/O
addresses. For details have a look at the MSX FDC I/O addresses.<BR>
<BR>
Note that the FDC contains only one track register which is used for all
drives. The current track position for each drive should be backed up in
memory, and the track register should be updated each time when changing
the current drive number.<BR>
<BR>
The external circuit might also use the INTRQ and DRQ lines to handle
FDC operations by DMA transfers, and/or to produce interrupts upon
completion. In the MSX these methods are not used, however, most MSX
adapters allow to read out the state of INTRQ and DRQ from a custom I/O
address (this isn't actually required because INTRQ is just a inverted
copy of the Status Busy bit, and DRQ can be read out from the normal
Status register either.<BR>
<BR>
<B>Formatting</B><BR>
This table shows DATA PATTERNs and their FD179X interpretation in MFM.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 00-F4 Write 00 thru F4
F5 Write A1, preset CRC
F6 Write C2
F7 Generate 2 CRC bytes
F8-FF Write F8 thru FF
</TD></TR></TABLE><BR>
<B>Formatting Example</B><BR>
The example below shows the data stream that must be presented to the
Write Track command for the "IBM system 34 format" (256 bytes/sector),
note that the MSX usually uses 512 bytes/sector. The left values in the
tables below identify the write-repeat count (in decimal) for the values
to the right. First the Track Header must be written, followed by Sector
ID and Sector Data Fields (for each sector). Finally 4E bytes must be
written until the command has completed.<BR>
<BR>
Track Header<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 80 x 4E
12 x 00
3 x F6 (writes C2)
1 x FC (index mark)
50 x 4E
</TD></TR></TABLE>1st Sector ID Field<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 12 x 00
3 x F5 (writes A1, preset CRC)
1 x FE (ID address mark)
1 x Track number
1 x Side number
1 x Sector number
1 x 01 (sector length=256)
1 x F7 (write 2 CRC bytes)
22 x 4E
</TD></TR></TABLE>1st Sector Data Field<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 12 x 00
3 x F5 (writes A1, preset CRC)
1 x FB (data address mark)
256 x DATA
1 x F7 (write 2 CRC bytes)
54 x 4E
</TD></TR></TABLE>2nd Sector ID Field (as above)<BR>
2nd Sector Data Field (as above)<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> etc.
</TD></TR></TABLE>Track End (Fill unused bytes)<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> .. x 4E (padding until index hole interrupt)
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumdisccontrollerother"></A><FONT SIZE=+2>&nbsp;Spectrum Disc Controller (Other)</FONT></TD></TR></TABLE><BR>
<B>Challenge Research Ltd: Challenge Sprint and Sprint Mk II</B><BR>
This is a quad-speed "audio" cassette drive, it connects to the expansion
port, apparently spins faster than normal cassette drives, and works with
existing cassette software (that was recorded at slow speed). The included
BIOS replaces the normal cassette functions by faster functions, works only
with software that uses the BIOS functions, eg. not with copyprotected games.<BR>
<BR>
<B>Evesham Micro Centre: Doubler Mk I / Double Mk II</B><BR>
External input for 2nd tape drive, for tape-to-tape transfers. The included
software executes an endless loop that forwards input from the Double I/O
port to the normal ULA cassette port.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Version Hardware Software
Mk I : Port BFh, Bit0 I.R.Lavell (quite efficently coded)
Mk II : Port 1Fh, Bit3 Draysoft (less efficiently coded)
</TD></TR></TABLE>The Mk II version is advertised to be more compatible with different tape
decks.<BR>
<BR>
<B>Sinclair: Microdrive (endless tape drive)</B><BR>
<B>Rotronics Wafadrive (endless tape drive) (not Microdrive compatible)</B><BR>
These are tape-drives, so, obviously, they don't use standard floppy disk
controllers.<BR>
Unlike normal cassette recorders, these drives can seek files (or free space)
automatically (without needing to press any play/stop/forward buttons), ie.
they do have a disk-like filesystem, however, they must wind the tape until
it reaches the desired location, so the seek-time is relative slow. Wafadrive
cartridges are manufactured with 16K, 64K, 128K capacity (of which 16K has
the shortest tape, and therefore fastest seek-time).<BR>
<BR>
<B>Crescent Quick Disk (2.8" disk, with single spiral-track, 128K or 256K)</B><BR>
<B>Triton Quick Disk (2.8" disk, with single spiral-track, 100K)</B><BR>
Quick Disks (also used by Nintendo's Famicom Disk System) have only a single
spiral-shaped track (like CDROMs and music records), so, obviously, they
don't use standard floppy disk controllers.<BR>
Note: Quick Disk drives don't have a stepping motor for random access,
instead the head is following the spiral windings in sequential access
fashion (giving it a relative slow seek-time; similar to endless tape
drives).<BR>
<BR>
<B>Timex FDD and FDD-3000</B><BR>
These drives are using standard a Western Digital controller, but, the
controller is connected to a separate Z80 CPU. So the spectrum is
communicating with that external Z80 CPU rather than directly with the WD
chip.<BR>
<BR>
<B>Logitek: Disc Interface (connect a Commodore 1541 drive to spectrum)</B><BR>
An adaptor for communicating with Commodore 1541 drive (the standard disk
drive for the C64) via serial data cable. The 1541 doesn't contain any
standard disk controller (it consists of a 6502 CPU and a bunch of TTL
logic). Although the drive uses standard 5.25" disks, the sector encoding
isn't compatible with that used by Western Digital WD177x and NEC uPD765 disk
controllers.<BR>
<BR>
<B>Spectrum CD Games Pack (Code Masters) (1989)</B><BR>
The pack consists of a Audio CD with about 30 spectrum games (each one
recorded twice), and a connection cable (cd player's 3.5mm (or 6.3mm via
adapter) stereo headphone socket to spectrum 9pin DSUB joystick port) (for
Spectrum 128/+2/+3 or 48K with Kempston interface), and loading software on
tape, once when a game is loaded one can press Q,U,I,T on keyboard to load a
new game (without needing to load tape loader again).<BR>
No info if/how the stereo signal is used (maybe one channel used as CLOCK,
and the other channel as DATA...?) The cable does reportedly contain a 1bit
A/D converter, which is probably a single transistor or so (so it's mono, not
stereo?). The CD capacity is said to be "12 Megs" (presumably meaning 12
Megabit = 60 tracks with 25Kbytes each).<BR>
<BR>
<B>Unknown Controllers</B><BR>
For most spectrum disk interfaces it is still unknown if they do contain a
standard disk controller chip, and if so, which one (the WD177x chips seem to
be quite popular in the spectrum world, so many of the unknown interfaces are
probably using that chips, too).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectruminterrupts"></A><FONT SIZE=+2>&nbsp;Spectrum Interrupts</FONT></TD></TR></TABLE><BR>
The IRQ is triggered on each vsync.<BR>
With IM1 opcode, the interrupt handler is at 0038h in BIOS ROM.<BR>
With IM2 opcode, the interrupt handler is at [I*100h+databus].<BR>
<BR>
<B>IRQ (IM1)</B><BR>
The normal IM1 handler does solely execute in ROM (without redirecting to a
RAM vector), so, since ROM is read-only, the IM1 vector cannot be hooked
(unless by external hardware that replaces the BIOS by other data, as done in
the Currah uSpeech).<BR>
To wait for an interrupt, one can use the HALT opcode, and/or check if the
FRAMES system variable has changed.<BR>
<BR>
<B>IRQ (IM2)</B><BR>
This mode allows to use a custom IRQ handler at [I*100h+databus]. Because of
the Display Snow bug, the table may not be at 4000h..7FFFh.<BR>
Normally [I*100h+databus] would be table in RAM at 8000h..FFFFh, however,
some games have it in ROM: Spectrum 48K has [3B00h..3C00h]=FFh, and Spectrum
128 and up have [3BFFh..3C00h]=FFh filled, the handler is then at FFFFh,
which would be usually set to 18h (a JR opcode) whose parameter byte is read
from address 0000h in BIOS, which is F3h (a DI opcode), thus forming a JR
FFF4h opcode.<BR>
Assuming that the databus contains a "random" number in range of 00h..FFh
upon IRQs, it requires a table with 101h bytes at [I*100h+0..100h]. On the
Spectrum 128 and up the databus seems to be stable FFh, needing only a 2
bytes at [I*100h+FFh..100h].<BR>
<BR>
<B>External IRQ</B><BR>
The /IRQ signal is available on the expansion port, eventually allowing
external hardware to sense when vblanks occur, or allowing external hardware
to inject additional IRQs (done by the AMX Mouse in IM2), though it's
problematic to distingush external IRQs from normal vblank IRQs, especially
if they occur simultaneously.<BR>
<BR>
<B>External NMI</B><BR>
The NMI handler is at 0066h in BIOS. On the Spectrum 16K/48K/+/128/+2, and on
Timex TC2048/TC2068/TS2068, the BIOS handler does (accidently) do this:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> IF [5CB0h]=0000h then JMP [5CB0h] ;ie. jump to 0000h (bullshit)
</TD></TR></TABLE>On the Spectrum +2A/+3, the bug was fixed, and it does:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> IF [5CB0h]&lt;&gt;0000h then JMP [5CB0h]
</TD></TR></TABLE>A couple of disk-interfaces are hooking address 0066h (or address 0000h,
which can be easier decoded and which works too, due to the bug, except in
the bug-fixed Spectrum +2A/+3 versions), the most common use is a Snapshot
function, allowing to load/save the entire RAM to/from disk (useful because
most spectrum programs support only cassette loading/saving). Some disk
interfaces are using NMI to handle data requests (not so useful as that could
be also done without NMIs).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumkeyboards"></A><FONT SIZE=+2>&nbsp;Spectrum Keyboards</FONT></TD></TR></TABLE><BR>
<A HREF="#spectrumkeyboardassignment">Spectrum Keyboard Assignment</A><BR>
<BR>
<B>Keyboard Matrix</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Port Bit4 Bit3 Bit2 Bit1 Bit0
FEFEh A8 V C X Z SHIFT
FDFEh A9 G F D S A
FBFEh A10 T R E W Q
F7FEh A11 5 4 3 2 1
EFFEh A12 6 7 8 9 0
DFFEh A13 Y U I O P
BFFEh A14 H J K L ENTER
7FFEh A15 B N M SYM SPACE
</TD></TR></TABLE><BR>
<B>40-key Spectrum Keyboard (like ZX80/ZX81, but with SYM instead DOT)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> | 1 2 3 4 5 6 7 8 9 0 |
| Q W E R T Y U I O P |
| A S D F G H J K L ENTER|
|SHF Z X C V B N M SYM SPACE|
</TD></TR></TABLE><BR>
<B>42-key TC2048/TS2068 Keyboard</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> | 1 2 3 4 5 6 7 8 9 0 |
| Q W E R T Y U I O P |
| A S D F G H J K L ENTER|
|SHF Z X C V B N M SYM BRK SHF|
| [---------SPACE---------] |
</TD></TR></TABLE>The two SHIFT keys are probably the same in the matrix, and BRK is probably
just SHIFT+SPC or so, so the matrix has only 40 keys.<BR>
<BR>
<B>58-key Spectrum +/128/+2/+3 Keyboard, and 18-key Spectrum 128 Keypad</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> |TRUE INV 1 2 3 4 5 6 7 8 9 0 ESC| | / * ( ) |
|DEL TAB Q W E R T Y U I O P | | 7 8 9 - |
|EXT COPY A S D F G H J K L RET| | 4 5 6 + |
|SHIFT CAPS Z X C V B N M . SHIFT| | 1 2 3 RET|
|SYM ; " LEFT RIGHT SPACE UP DOWN , SYM| | 0 . |
</TD></TR></TABLE>In 48K mode: TAB=GRAPH, COPY=EDIT.<BR>
Concerning the keyboard matrix, the keyboard has only 40 real keys, plus two
duplicated SHIFT/SYM keys, plus 16 keys with SHIFT/SYM+key combinations (eg.
UP=SHIFT+7).<BR>
The external 18-key numeric keypad can be connected via a special serial
cable, it was shipped only with early Spectrum 128 models in Spain, but soon
discontinued.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumkeyboardassignment"></A><FONT SIZE=+2>&nbsp;Spectrum Keyboard Assignment</FONT></TD></TR></TABLE><BR>
<B>Spectrum</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> NORMAL SHIFT CMD SYMBOL EXT EXT+SYM EXT+SHIFT GRAPH GRAPH+SHFT
1 EDIT 1 ! P=BLUE DEF FN I=BLUE [ '] [:.]
2 CAPS 2 @ P=RED FN I=RED [' ] [.:]
3 TRUE_V 3 # P=MAGENT.LINE I=MAGENT. [''] [..]
4 INV_V 4 $ P=GREEN OPEN# I=GREEN [ .] [:']
5 LEFT 5 % P=CYAN CLOSE# I=CYAN [ :] [: ]
6 DOWN 6 & P=YELLOW MOVE I=YELLOW ['.] [.']
7 UP 7 ' P=WHITE ERASE I=WHITE [':] [. ]
8 RIGHT 8 ( (BRIGHT) POINT FLASH=OFF [ ] [::]
9 GRAPH 9 ) (DARK) CAT FLASH=ON GRA=OFF GRA=OFF
0 DELETE 0 _ P=BLACK FORMAT I=BLACK DELETE DELETE
q Q PLOT &lt;= SIN ASN ASN USR.Q USR.Q
w W DRAW &lt;&gt; COS ACS ACS INKEY$ INKEY$
e E REM &gt;= TAN ATN ATN USR.E USR.E
r R RUN &lt; INT VERIFY VERIFY USR.R USR.R
t T RAND &gt; RND MERGE MERGE USR.T USR.T
y Y RETURN AND STR$ [ [ FN FN
u U IF OR CHR$ ] ] USR.U USR.U
i I INPUT AT CODE IN IN USR.I USR.I
o O POKE ; PEEK OUT OUT USR.O USR.O
p P PRINT " TAB RESET (C) RESET (C) USR.P USR.P
a A NEW STOP READ FREE ~ FREE ~ USR.A USR.A
s S SAVE NOT RESTORE STICK | STICK | USR.S USR.S
d D DIM STEP DATA \ \ \ \ USR.D USR.D
f F FOR TO SGN ON_ERR { ON_ERR { USR.F USR.F
g G GOTO THEN ABS SOUND } SOUND } USR.G USR.G
h H GOSUB ^ SQR CIRCLE CIRCLE USR.H USR.H
j J LOAD - VAL VAL$ VAL$ USR.J USR.J
k K LIST + LEN SCREEN$ SCREEN$ USR.K USR.K
l L LET = USR ATTR ATTR USR.L USR.L
ENTER ENTER ENTER ENTER ENTER ENTER ENTER ENTER ENTER
SHIFT SHIFT SHIFT EXT=ON SHIFT EXT=OFF SHIFT SHIFT SHIFT
z Z COPY : LN BEEP BEEP POINT POINT
x X CLEAR pound EXP INK INK PI PI
c C CONT ? LPRINT PAPER PAPER USR.C USR.C
v V CLS / LLIST FLASH FLASH RND RND
b B BORDER * BIN BRIGHT BRIGHT USR.B USR.B
n N NEXT , INKEY$ OVER OVER USR.N USR.N
m M PAUSE . PI INVERSE INVERSE USR.M USR.M
SYMBOL EXT=ON SYMBOL SYMBOL SYMBOL SYMBOL EXT=OFF SHIFT EXT=ON
SPACE SPACE SPACE SPACE SPACE SPACE SPACE SPACE SPACE
</TD></TR></TABLE><BR>
<B>Timex TS2068 and TC2068</B><BR>
The DELETE, RESET, FREE, STICK, ON_ERR, SOUND keywords exist on Timex TS2068
and TC2068 only. FREE/STICK are premanently mapped (not allowing to use "~"
and "|" on these computers). The other four commands are mapped only when the
[K] cursor is shown (to use the backspace function with [K] cursor: Keep
Shift+1 held down for 2-3 seconds, the key-repeat does then act as backspace
instead of repeatedly showing up the DELETE keyword).<BR>
<BR>
<B>Spectrum 128/+2/+2A/+3</B><BR>
On the Spectrum 128/+2/+2A/+3 all keywords must be entered letter-by-letter
(ie. type P,L,O,T instead of pressing Q), letters and punctuation marks are
kept at the same locations as in the above table, the EDIT key shows the
options menu (which includes a RENUMBER function).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumjoystickports"></A><FONT SIZE=+2>&nbsp;Spectrum Joystick Ports</FONT></TD></TR></TABLE><BR>
<B>Joystick Ports and Data Bits (U=Up, D=Down, L=Left, R=Right, F=Fire)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Port_Joystick_Type___________________________7_6_5_4_3_2_1_0___Data Bits___
xx1F Kempston (and Timex TC2048) ? ? ? F U D L R (1=Pressed)
xx7F Fuller Box F ? ? ? R L D U (0=Pressed)
EFFE Protek (cursor mode, A12, keys 6,7,8,0) - - - D U R - F (0=Pressed)
F7FE Protek (cursor mode, A11, key 5) - - - L - - - - (0=Pressed)
DFFE AGF (2nd Joystick, A13, keys Y,U,I,P) - - - D U R - F (0=Pressed)
FBFE AGF (2nd Joystick, A10, key T) - - - L - - - - (0=Pressed)
EFFE Sinclair Port 1 (keys 6,7,8,9,0) - - - L R D U F (0=Pressed)
F7FE Sinclair Port 2 (keys 5,4,3,2,1) - - - F U D R L (0=Pressed)
E7FE Sinclair Garbage or Nothing - - - x x x x x (0=Pressed)
01F6 Timex TS2068/TC2068 PSG Reg 14, Port 1 F ? ? ? R L D U (0=Pressed)
02F6 Timex TS2068/TC2068 PSG Reg 14, Port 2 F ? ? ? R L D U (0=Pressed)
03F6 Timex TS2068/TC2068 PSG Reg 14, Both F ? ? ? R L D U (0=Pressed)
xxBF Timedata ZXM Sound Box, PSG Reg 14 0 F U D L R y x (0=Pressed)
? Rotronics Wafadrive Joystick Adaptor ? ? ? ? ? ? ? ? (?=Select)
</TD></TR></TABLE><BR>
<B>Recommended Controls</B><BR>
When making Spectrum software, best support ALL of the following controls:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 6,7,8,9,0 --&gt; Interprete as Sinclair Joystick Port 1
SHIFT+5,6,7,8,SPACE --&gt; Interprete as Cursor Keys (for use in emulators)
Q,A,O,P,SPACE --&gt; Interprete as Keyboard Keys
Port 1Fh --&gt; Interprete as Kempston Joystick Port
</TD></TR></TABLE><BR>
<B>Kempston Port Notes</B><BR>
This is a quite popular standard, and should be supported by most games.
There are a lot of homebrew clones, including some released in magazines,
many variants are decoding only A5=0, ignoring A6 and A7. Some variants are
using the upper data bits (D5-D7) as centronics busy input, or as floppy
interrupt or data requests.<BR>
<BR>
<B>Sinclair Port Notes</B><BR>
Sinclair ports are supported by the Interface 2 adaptor, by the Disciple disk
interface, and are built-in in Spectrum +2/+3. The Sinclair joysticks are
equivalent to keyboard keys 1,2,3,4,5 (port2) and 6,7,8,9,0 (port1), both
keyboard groups are arranged as L,R,D,U,F (that keyboard arrangement is why
the data bits are in opposite order for port1 and port2) (note: the
arrangement does NOT comply with the cursor keys on keys 5,6,7,8). Reading
both ports at once doesn't work well: Interface 2 doesn't respond to reads
from Port E7FEh, Spectrum +2/+3 does respond to it (but, due to the reversed
data bit arrangement, it returns rather useless garbage, eg. Up1 ANDed with
Fire2).<BR>
<BR>
<B>Protek Port Notes</B><BR>
The original Protek supports only cursor mode, newer variants can be
reportedly switched to three modes (probably cursor, kempston, and sinclair
or so).<BR>
AGF and Thurnall support Cursor+Rubout, too. AGF additionally supports
T-Y-U-I-P as second joystick. Thurnall additionally supports Q-A-Z-X for
whatever usage.<BR>
<BR>
<B>Timex TS2068/TC2068 Port Notes</B><BR>
Timex Ports are using PSG register 14, which must be configured properly:
Clear Bit6 of PSG Register 7 (input direction), write FFh or 8Fh or so to PSG
register 14 (output HIGH levels), and set PSG index to 14. For details see
PSG/sound specs.<BR>
<BR>
<B>Rotronics Wafadrive Joystick Adaptor</B><BR>
According to the Rotronics Wafadrive manual, one can connect a joystick to
the centronics port of the Wafadrive via an adaptor. There's no info on how
to build that adaptor, but the manual says it is sold separately (if that
adaptor was actually ever produced, then it didn't became very popular).
Because the Wafadrive centronics port is one-directonal, it is probably using
the joystick switches in reversed direction (ie. outputting LOW levels to
L,R,U,D,F via some of the Data lines, and reading the result from the common
pin via the Busy input).<BR>
<BR>
<B>Joystick Port Pin-outs</B><BR>
The five switches are connected to Pin8 as a common pin, in the Atari
standard that'd be GND, but in some variants it is a /SELECT signal that goes
low when reading from the joystick port (that method works with joystick that
consists of raw switches; but won't work with sticks that contain autofire
functions or other logic that requires +5V/GND supply at Pin7/Pin8).<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Kempston Homebrew TS2068/TC2068 Interface2 Spectrum+2 Protek
Pin Joy1 Joy1 Joy1 Joy2 Joy1 Joy2 Joy1 Joy2 Joy1
1 Up Up Up Up Up Up N/A? N/A? Up
2 Down Down Down Down Down Down MA3 MA4 Down
3 Left Left Left Left Left Left N/A? N/A? Left
4 Right Right Right Right Right Right Fire Fire Right
5 N/A N/A N/A N/A N/A N/A Up Up ?
6 Fire Fire Fire Fire Fire Fire Right Right Fire
7 +5V (Fire 2) +5V +5V N/A N/A Left Left ?
8 GND +5V /A8 /A9 GND GND MA3 MA4 ?
9 N/A N/A GND GND N/A N/A Down Down ?
</TD></TR></TABLE>Amstrad's Spectrum +2 uses standard DSUB-9 ports, but with nonstandard
pinouts (so it works only when re-wiring the connection on the mainboard,
using an external adaptor, or buying an original "SJS1" joystick from
Amstrad) (the MA3/MA4 lines are DRAM row/column address bits; essentially
same as A11/A12 at time when reading the ports).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrummouseports"></A><FONT SIZE=+2>&nbsp;Spectrum Mouse Ports</FONT></TD></TR></TABLE><BR>
<B>Kempston Mouse (hardware counters)</B><BR>
This is probably the most popular, best working, and most often supported
mouse interface.<BR>
<A HREF="#spectrummousekempstonmouse">Spectrum Mouse - Kempston Mouse</A><BR>
The original package consists of a Kempston Mouse and Kempston Mouse
Interface, there are also compatible interfaces that can be used with Amiga,
PS/2, or USB mice, and maybe also some for RS232, Atari, or even analog mice.<BR>
<BR>
<B>AMX Mouse (IM2 interrupts)</B><BR>
This is almost as powerful as the Kempston Mouse, but conflicts with various
other hardware expansions, the AMX Mouse is rarely supported by any programs.<BR>
<A HREF="#spectrummouseamxmouseadvancedmemorysystems">Spectrum Mouse - AMX Mouse (Advanced Memory Systems)</A><BR>
The I/O addresses conflict with various other expansions like Kempston
Joysticks (Port 1Fh), Beta Disk, Fuller Box, etc.<BR>
<BR>
<B>Amiga/Atari Mice (software counters)</B><BR>
Amiga/Atari mice can be connected directly to Kempston Joystick ports (which
have +5V and GND), without needing any mouse interface. Although it's simple
at hardware side, it's supported only by a dozen of programs.<BR>
<A HREF="#spectrummouseamigamouseoratarimouseinkempstonjoystickport">Spectrum Mouse - Amiga Mouse or Atari Mouse in Kempston Joystick port</A><BR>
The problem is that the mickeys must be counted by software, meaning that the
software must check Port 1Fh more than 500 times per second, ie. much more
often than it could be done via the 50Hz vblank interrupt.<BR>
<BR>
<B>Other Mice</B><BR>
Some other less popular and/or less powerful solutions are:<BR>
<A HREF="#spectrummouseothermice">Spectrum Mouse - Other Mice</A><BR>
<BR>
<B>Double Speed Threshold</B><BR>
Don't forget to implement Threshold in software, ie. if you have received
more than so-and-so-many mickeys per frame, multiply that value by two.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrummousekempstonmouse"></A><FONT SIZE=+2>&nbsp;Spectrum Mouse - Kempston Mouse</FONT></TD></TR></TABLE><BR>
<B>FADFh - Kempston Mouse Buttons (R)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 Right Button (0=Pressed, 1=Released)
1 Left Button (0=Pressed, 1=Released)
2 Middle Button (not supported in original Kempston Mouse interface)
3 Not used
4-7 Mouse Wheel Counter (supported in some russian interfaces only)
</TD></TR></TABLE>The wheel "Counter is 4-bit and its value increases with the movement of
wheels down, decrases the movement up." Whatever that means...? normally the
wheel turns away from, or towards to user (where "away from user" should look
UP-wards in a document; which means the screen scrolls DOWN-wards).<BR>
<BR>
<B>FBDFh - Kempston Mouse X (R)</B><BR>
<B>FFDFh - Kempston Mouse Y (R)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-7 Counter (mickeys)
</TD></TR></TABLE>"8bit reverse counters" whatever that means... increasing or decreasing when
moving towards where? The counters aren't reset after reading, and may wrap
from FFh to 00h, or vice versa, when exceeding the 8bit range. To get mickeys
since last read, subtract old/new value.<BR>
<BR>
<B>Notes</B><BR>
Usually deconds A5, A7, A8, A10, /RD, /IORQ, sometimes also /RD, A9, and/or
A0. Uh, why A0...?<BR>
There is port conflict with incompletely implemented Kempston Joystick ports
that decode only A5 (eg. Timex TC2048).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrummouseamxmouseadvancedmemorysystems"></A><FONT SIZE=+2>&nbsp;Spectrum Mouse - AMX Mouse (Advanced Memory Systems)</FONT></TD></TR></TABLE><BR>
<B>1Fh - AMX Mouse - Z80PIO Data Reg A, Mouse X, Centronics LSBs/Strobe (R/W)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 Mouse X Direction (XB input from mouse) (?=Left, ?=Right)
1-2 Not used
3 Centronics Strobe (should be usually output in Mode 3)
4-7 Centronics Data LSBs (should be usually output in Mode 3)
</TD></TR></TABLE><BR>
<B>3Fh - AMX Mouse - Z80PIO Data Reg B, Mouse Y, Centronics MSBs/Busy (R/W)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 Mouse Y Direction (YB input from mouse) (?=Up, ?=Down)
1-2 Not used
3 Centronics Busy (should be usually input in Mode 3)
4-7 Centronics Data MSBs (should be usually output in Mode 3)
</TD></TR></TABLE><BR>
<B>5Fh - AMX Mouse - Z80PIO Control Register A, Horizontal Control (W)</B><BR>
Used to configure Port A and Interrupt A by writing 1 or 2 byte(s) to this
register, the meaning depends on the LSBs of the 1st byte:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1stByte 2ndByte Function
vvvvvvv0 N/A Set Interrupt Vector
exxx0011 N/A Set Interrupt Enable
eah00111 N/A Set Interrupt Enable/Control (for Mode 3 only)
eah10111 mmmmmmmm Set Interrupt Enable/Control/Mask (for Mode 3 only)
00xx1111 N/A Set Mode 0 (all 8 data bits = Output)
01xx1111 N/A Set Mode 1 (all 8 data bits = Input)
10xx1111 N/A Set Mode 2 (all 8 data bits = Bidirectional) (Port A only)
11xx1111 dddddddd Set Mode 3 and Direction bits (0=Out, 1=In)
</TD></TR></TABLE>Whereas,<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> vvvvvvv Interrupt Vector (Bit0=0, Bit1-7=vvvvvvv, Bit8..15="I"-Register)
e Interrupt Enable (0=Disable, 1=Enable; trigger on each mickey)
a Interrupt AND/OR (for Mode3 only)
h Interrupt HI/LO (for Mode3 only)
mmmmmmmm Interrupt Mask (for Mode3 only) (0=Monitor, 1=Mask)
dddddddd Data Direction bits 0-7 (0=Output, 1=Input)
</TD></TR></TABLE><BR>
<B>7Fh - AMX Mouse - Z80PIO Control Register B, Vertical Control (W)</B><BR>
Same as Control Register A (see there), but for Port B accordingly.<BR>
<BR>
<B>DFh - AMX Mouse - 74LSXX Logic, Mouse Buttons (R)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-4 Not used
5 Right Button
6 Middle Button
7 Left Button
</TD></TR></TABLE>Buttons are handled via separate 74LSxx chips. Although, theoretically, they
could be mapped to bit1-2 of the Z80PIO data ports; maybe the whole 8bit data
ports are latched on interrupts; which would freeze the state of bit1-2.<BR>
<BR>
<B>Interrupts</B><BR>
The AMX mouse triggers an interrupt and outputs an IM2 interrupt vector on
the databus on each mickey, the CPU should be in IM2, and the CPUs I-register
should contain MSB of the interrupt table, the Z80 does then do am indirect
"CALL [I*100h+databus]" on interrupts. Mind that trying to set I=40h..7Fh
results in ULA Snow bug.<BR>
The two Z80PIO interrupt vectors should point to the address of X and Y
motion handler; which should read the X or Y direction bit, and
inrease/decrease the mickey counter accordingly. If both X and Y mickeys
occor simultaneously, then the Z80PIO would first produce vector A, and then
vector B (after vector A was processed).<BR>
The normal Vblank interrupt doesn't output anything on databus, so databus
should be (hopefully) FFh, causing a "CALL [I*100h+FFh]" on vblank. If
mickeys occur simulaneously with vblank, then the vblank interrupt is
probably lost...? which would be bad for general animation synchronizations,
keyboard handling, as well as for mouse specific threshold calculations.<BR>
<BR>
<B>Notes</B><BR>
The Z80PIO is reset on power-up (when raising VCC) only, but NOT on /RESET.<BR>
The AMX Mouse is supported by Minesweeper (new version - EN), and Artist II.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrummouseamigamouseoratarimouseinkempstonjoystickport"></A><FONT SIZE=+2>&nbsp;Spectrum Mouse - Amiga Mouse or Atari Mouse in Kempston Joystick port</FONT></TD></TR></TABLE><BR>
<B>Pinouts</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Pin Amiga Mouse Atari Mouse Kempston Joystick Kempston Mouse
1 YA XB Joystick up +5V
2 XA XA Joystick down XA
3 YB YA Joystick left YB
4 XB YB Joystick right Left Button
5 Middle Button Not connected Not connected Right Button
6 Left Button Left Button Fire button GND
7 +5V +5V +5V Not connected
8 GND GND GND YA
9 Right Button Right Button Not connected XB
</TD></TR></TABLE>As shown in 1st/2nd column, Amiga and Atari have XA/XB/YA/YB arranged
differently. 3rd column shows how the signals are mapped on the joystick
port. The 4th column is just for curiosity, it shows the connection between
Kempston Mouse and Kempston Mouse Interface (aside from the different pinouts
it's much the same as Amiga/Atari mice, the big difference is that the
Kempston Mouse Interface contains hardware counters, without needing to count
mickeys by software).<BR>
<BR>
<B>Motion Signals</B><BR>
The XA/XB indicate horizontal motion (and YA/YB vertical motion), like so:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> One Direction Opposite Direction
XA _______----____ _____----______
XB _____----______ _______----____
</TD></TR></TABLE>The signal timings depend on how fast the mouse is moved (ie. if the mouse is
not moved, then it may stop anywhere in the above diagram, eg. while XA and
XB are both high, both low, or one high and one low).<BR>
The simpliest approach is to wait for raising edge on XA, and then to check
XB (either XB is already high, or XB is still low) and increase/decrease the
software's mickey counter accordingly. In situations where the direction
changes, it may be also recommended to handle "half mickeys" on falling edges
on XA, eg.:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> One Direction Stop Opposite Direction
XA _______---------------------------______
XB _____-------------------------------____
</TD></TR></TABLE>In the above case, checking only raising XA would miss the direction change
on falling XA (if that happens repeatedly, then the mouse would disappear
towards the screen border, eg. if the mouse is in an unstable position,
without actually being moved).<BR>
<BR>
<B>Notes</B><BR>
Mind that the Kempston Joystick port inverts all signals (that is don't care
for XA,XB,YA,XB, but the button bit may be opposite as expected). And, of
course, a Kempston Joystick port does have only one Fire button (so only the
Left mouse button can be read).<BR>
Games that support BOTH Amiga and Atari mouse: Godzilla, Ultra Reflect,
Advanced Patience, Pyramid Patience.<BR>
Games that support ONLY Amiga mouse: Black Raven 1, Hexxagon, Indian
Patience, Magic Field, Mezi Vezemi 128 (cz), Sparrows, and Art Studio.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrummouseothermice"></A><FONT SIZE=+2>&nbsp;Spectrum Mouse - Other Mice</FONT></TD></TR></TABLE><BR>
<B>Datel Genius Mouse</B><BR>
Early Datel mice (April-March 1987) had 3 buttons, all later mice had only 2
buttons. Very late Datel mouse interfaces (1989 or so) additionally included
a kempston joystick port. The interface (at least the latest version)
contains only a single 28pin SMD chip, plus some resistors and capacitors.<BR>
The used I/O addresses are still unknown, however, the interface with the SMD
chip connects to D0-D7, /IORQ, A5, A8-A10, +5V, and GND... so it might be
simply a clone of the Kempston Mouse interface? Although, Kempston Mouse and
Kempston Joystick both use A5=LOW, so, without checking A6/A7, it couldn't
separate between them...?<BR>
<BR>
<B>Joystick Mouse (supports only fixed speed motion)</B><BR>
Some mice (Commodore Mouse 1350, Noris Data Mouse M1, Boeder GEOS-Mouse,
Elite Mouse, Datalux SV-705) emulate a digital joystick. The advantage is
that these mice can be used with any games that support joystick input
(provided that the joystick port outputs +5V and GND pn Pin 7 and 8, ie.
works only with standard Kempston Joystick ports, not with standard Sinclair
Joystick ports). The big disadvantage that these mice can't separate between
slow and fast motion.<BR>
<BR>
<B>RS232 Mouse on RS232 Port</B><BR>
Standard RS232 PC mice can be theoretically connected to Spectrum RS232
ports. In practice it's difficult at both hardware and software side, and so
it's rarely supported. The first problem is that there are at least 16
Spectrum RS232 interfaces from different companies. Next, some Spectrum RS232
ports have non-standard pinouts (eg. Interface 1), simple Spectrum RS232
ports would require to watch the incoming bitstream permanently by software
(eg. Interface 1). So, to execute any other program code, one would need a
RS232 interface with built-in shift register and baudrate timer, and
preferably also an interrupt notification, or, even more preferably a FIFO
that can hold at least 3 characters (so the 1200 baud mouse data would need
to be processed only on vblank interrupts).<BR>
<BR>
<B>AY-Mouse (C) V.M.G. (schematic in russian ZX Power digital magazine)</B><BR>
This is a (rather rarely supported) mouse interface. Similar to the Kempston
Mouse interface it contains two hardware counters and button inputs, intended
to be used with mice that have XA/XB/YA/YB signals (ie. any Amiga, Atari,
AMX, or Kempston mice) (of course, needing to recurse the different pinouts
of that mice).<BR>
The interface connects to PSG register 14, with the PSG being accessed via
Port FFFDh and BFFDh, ie. the Spectrum 128 style PSG addresses, but with PSG
register 14 being used to access the mouse (the real Spectrum 128 uses it as
RS232/Keypad port). The PSG register 14 bits are:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-3 In Horizontal or Vertical 4bit Counter (as selected via bit6)
4 In Button 1 (0=Pressed, 1=Released) (presumably Left)
5 In Button 2 (0=Pressed, 1=Released) (presumably Right)
6 Out Select Counter to be mapped to bit0-3 (?=Horizontal, ?=Vertical)
7 ? Border ("for testing, and computer effects, type multicolor")
</TD></TR></TABLE>Changing bit6 (raising or falling edge?) does additionally reset the two 4bit
counters to a value of 8 each, so, the difference since last access is new-8
(or 8-new), rather than new-old.<BR>
Supported by Art Mouse (Art Studio), ZX Power 1-4, Lemmings (TRDOS version).<BR>
<BR>
<B>Nidd Valley - Digimouse (digital)</B><BR>
<B>Nidd Valley - Anamouse (analog)</B><BR>
<B>Saga Systems - Star Mouse</B><BR>
<B>Individual Software - Keyboard Mouse</B><BR>
<B>Tropic Informatica - TPX Mouse (for brazilian TK90X and TK95)</B><BR>
No idea how these devices work? They don't seem to be very popular.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumlightguns"></A><FONT SIZE=+2>&nbsp;Spectrum Light Guns</FONT></TD></TR></TABLE><BR>
<B>Stack Light Rifle (Stack Computer Services Ltd) (1983)</B><BR>
connects to expansion port, accessed by reading from Port DFh:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> bit1 = Trigger Button (0=Pressed, 1=Released)
bit4 = Light Sensor (0=Light, 1=No Light)
other bits = Must be "1" (the programs use compare FDh to test if bit1=0)
</TD></TR></TABLE>The vertical position is measured by counting time between vblank & light
sensor signal; none of the games seems to attempt to measure the horizontal
position; so there should be only one bright object per scanline).<BR>
The software timings are matched for PAL Spectrum 48K (and probably don't
work on other/newer spectrums due to different BIOS (irq handler), video
(clks per scanline), and cpu speed (waitstate) timings.<BR>
<BR>
<B>Magnum Light Phaser for Spectrum +2/+3 (Sinclair/Amstrad/Trojan) (1989)</B><BR>
<B>Defender Light Gun for Spectrum 128/+2/+3 (Cheetah) (1989)</B><BR>
These two guns seem to be compatible with each other. Both are connected to
AUX/Keypad (aka PSG Register 0Eh):<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> bit4 = light sensor (0=None, 1=Light)
bit5 = trigger button (0=Pressed, 1=Released)
</TD></TR></TABLE>Although the Spectrum 128 does have an AUX/Keypad socket, the Magnum manual
says that one should use the MIC-socket based gun on the Spectrum 128 (dunno
why).<BR>
<BR>
<B>Magnum Light Phaser for Spectrum 48K (Sinclair/Amstrad/Trojan) (1989)</B><BR>
Requires 9V battery, connects to MIC-output socket (which is misused as input
in this case). In the output direction, port FEh should be set to 00h
(accordingly, the 48K games cannot output sound while reading the gun) (mind
that CAS-IN, CAS-OUT, and SOUND-OUT are sharing the same ULA pin).<BR>
The trigger button is sensed as LONG pulse (Jungle Warfare reads 8Ch times,
and accepts trigger only if [FEh].Bit6=ZERO on all 8Ch reads). The light
sensor is sensed as EDGE (ie. 0-to-1 or 1-to-0 transitions on [FEh.Bit6]).
Knowing that, it seems that the trigger button and light sensor signals are
XORed with each other.<BR>
<BR>
<B>Defender Light Gun for Spectrum 48K (Cheetah) (1989)</B><BR>
Connects to Kempston Joystick interface. The Kempston Port 1Fh bits are:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Joystick UP (bit3) = Trigger button
Joystick FIRE (bit4) = Light sensor
Other (bit0-2,5-7) = Must be 0 (Jungle W. compares [1Fh] with 08h,10h,18h)
</TD></TR></TABLE>Works only with Kempston interfaces (other joystick interfaces don't seem to
be supported at software side, and, other interfaces usually don't provide
the required +5V supply voltage at hardware side).<BR>
<BR>
<B>Gunstick for Spectrum 48K/+/128 (MHT Ingenieros)</B><BR>
Connects to joystick interface. Requires four 1.5V batteries (and so, doesn't
require 5V/GND on joystick port).<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Joystick FIRE = Trigger Button (LOW=Pressed, HIGH=Released)
Joystick DOWN = Light Sensor (LOW=?)
</TD></TR></TABLE>Most games seem to support only Sinclair Joystick Interfaces (Port EFFEh or
F7FEh), although the hardware should work with all joystick interfaces.<BR>
<BR>
<B>Gunstick for Spectrum +2/+3 (MHT Ingenieros)</B><BR>
Same as the 48K version, but matched to the (distorted) pin-outs of the
bizarre Spectrum +2/+3 joystick ports.<BR>
<BR>
<B>Note on Defender "sliding autofire/function select switch"</B><BR>
Additionally to the trigger button, the Defender guns have a "sliding
autofire/function select switch", reportedly used to select one-shot or
machine-gun mode in some games, however, unknown how this switch is accessed
by software (there seem to be only two data bits used; the light sensor and
trigger button; so maybe it affects the length of the trigger button signal),
also unknown if that switch acts as a push button, sticky switch, or even as
potentiometer?<BR>
<BR>
<B>Existing Lightgun Games for the Spectrum</B><BR>
Stack Light Rifle Games:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Grouse Shoot Stack Computer Services Ltd (compiled BASIC code)
Shooting Gallery Stack Computer Services Ltd (compiled BASIC code)
High Noon Stack Computer Services Ltd (compiled BASIC code)
Invasion Force Micromania (real Z80 assembler code)
</TD></TR></TABLE>Defender Light Gun Games:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Advanced Pinball Simulator Code Masters Ltd
Billy the Kid Code Masters Ltd
Bronx Street Cop Code Masters Ltd
F-16 Fighting Falcon Code Masters Ltd
Jungle Warfare Code Masters Ltd
Super Car Trans Am Code Masters Ltd
And... theoretically the AUX-based Magnum games should work, too?
</TD></TR></TABLE>Magnum Light Phaser Games:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Billy the Kid Code Masters Ltd
Bronx Street Cop Code Masters Ltd
Bullseye Macsen Software
F-16 Fighting Falcon Code Masters Ltd
Jungle Warfare Code Masters Ltd
Living Daylights Domark Ltd
Lord Bromley's Estate Amstrad
Missile Ground Zero Software Creations
Operation Wolf Ocean Software Ltd
Q's Armoury Amstrad
Robot Attack Mastertronic Ltd
Rookie Mastertronic Ltd
Solar Invasion Mastertronic Ltd
Super Car Trans Am Code Masters Ltd
</TD></TR></TABLE>Gunstick Games:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Acid Killer New Frontier
Bestial Warrior Dinamic Software
Cosmic Sheriff Dinamic Software
El Equipo A (aka A-Team) Zafiro Software Division
Guillermo Tell Opera Soft S.A.
Hunting Mix New Frontier
Mike Gunner Dinamic Software
Shooting Range: Mix I New Frontier
Solo Opera Soft S.A.
Sootland Zafiro Software Division
Space Smugglers MHT Ingenieros S.L.
Target Plus Dinamic Software
Trigger Opera Soft S.A.
</TD></TR></TABLE>Note: In many cases there are two versions of each Magnum game: one hardcoded
to work with MIC port, another one hardcoded to work with AUX port. The Code
Masters titles do auto-detect if the Magnum (or Defender) is connected to
MIC, AUX, or Kempston joystick port.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumprinterports"></A><FONT SIZE=+2>&nbsp;Spectrum Printer Ports</FONT></TD></TR></TABLE><BR>
Sinclair focused on selling their own 32-column printer (see ZX81 chapter),
and (until the Spectrum +2A/+3 were released) didn't support regular
centronics printers. The only official alternative to the 32-column thing was
to use (rather rare) RS232 printers connected to Interface 1 (see Serial port
chapter). Various other companies have released Centronics ports for the
spectrum (often included in disk interfaces), but without using any
standarized I/O addresses...<BR>
<BR>
<B>Centronics Ports</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Type Data Busy Strobe
Interface Bis #1D (#1D).7 auto
M'ody Technik 1986-12 #1F (inv) (#9F).4=0 (#9F).4=1
MB-02 #3F (#5F).7=1 (#5F).1=0
YAMOD.8211 #0n58 (#0n59).7=0 (#0n5A).0=1 ;n=0..1
Unipolbrit 2086 #xx7B (#BB).?=1 (#BB).?=0
AERCo Centronics #7F (#7F).4=1 auto
MultiPrint #BF (#BB).6=1 (#BF)=X,(#BB)=X,(#BF)=X
Informik 1989-II #E3 (#F3).4=0 (#F3).4=1
Sam FDD #E8 (#E9).0 (#E9).0=1
Elwro 800 Jr #DE (#DD).7=1 (#DD).2=0
Scorpion #DD (#FE).7 auto(?)
AERCo FD-68 #E0DF ? (#xx??).? ??
PlusD #F7 (#F7).7 (#EF).6
DISCiPLE #FB (#1F).6 (#1F).6
ZX Lprint 3 & Pentagon #FB (#FB).7=1 auto (?)
Centronics Microface #FB (#FB).7=1 auto
ZX Spectrum +3 #0FFD (#0FFD).0=1 (#1FFD).4=0
GP500A PZ "APINA" #xx?? (#xx??).? ??
Kempston S (Software) #E0BF (#E2BF).0 E3BF.0 ;with SOFTWARE driver
Kempston E (EPROM) #xx?? (#xx??).? ?? ;with EPROM driver
DK'Tronics #xx9B (#xxBB).7 xxBB.1
INES Printerface #xx?? (#xx??).? ??
Opus Discovery (memory mapped PIA6821) ;BiDir.D0-D7,STB,READY,ACK
Rotronics Wafadrive dd0Eh 0002h.5 000Ah/200Ah ;via IN (not OUT)
Indescomp #FB (#FB).0 (#7F).0
Watford ? ? ?
Fuller ? ? ?
VISMO ZP83 parallel interface
VTR Parallel Centronics Interface
Tasman Parallel Printer Interface
ADS Advanced Digital Systems Centronics Interface
Dorsch Centronics Interface
Technology Research S-Print
Cambridge Intelligent Printer Interface
Logitek Floppy/Printer Interface (centronics port and c64 floppy port)
Miracle ZX Printer Interface (rs232-to-centronics converter for Interface 1)
Morex Printer Interface (centronics, rs232, built-in word processor)
Romantic Robot Multiprint
Cambridge Microelectronics Polyprint Interface
Camel Products Print-SP
Ram Electronics RamPrint Interface (centronics, joystick, RamWrite in ROM)
Euroelectronics ZX Lprint (centronics)
Euroelectronics ZX Lprint III (centronics and rs232)
AMX Mouse (with 8bit centronics data split into two 4bit fragments)
Nidd Valley Digimouse Interface (professional version with Centronics port)
</TD></TR></TABLE><BR>
<B>Cloned and/or Re-distributed Centronics interfaces</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Hilderbay Interface (same as the Kempston S thing)
Datel Inter Printer (same as the DK'Tronics thing, distributed by datel)
Datel Ramprint (same as the Ram Electronics thing, distributed by datel)
Pentagon (russian spectrum clone, with built-in ZX Lprint 3)
</TD></TR></TABLE><BR>
<B>Centronics Notes</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Interface Bis 5 input lines for LapLink
M'ody Technik 1986-12 8255 used: #DF=config; PA=data. All signals inverted.
MB-02 8255 used; #7F=config; PB=data, PC2=/ACK,
PC3=/AUTOFEED, PC4=/ERROR, PC5=SELECT, PC6=PAPEROUT
Unipolbrit 2086 8255 used; #FB=config; PA=data; only PA and PC0, PC1,
PC4, PC5 are in DB15 slot
Informik 1989-II 8255 used: #FB=config; PA=data (PB switches memory
banks). All signals inverted.
Elwro 800 Jr 8255, other bits reserved
YAMOD.8211 PC LPT connected as YABUS.ZXISA
AERCo Centronics (#7F).5=0 - printer present
MultiPrint 8kB ROM, 8kB RAM
ZX Lprint 3 Pentagon 2kB ROM
Centronics Microface see files for documentation
</TD></TR></TABLE>ZX Lprint by Euro Electronics: The test for printer ready is IN A,(#E0): AND
#E0: CP #40. The ROM is paged into #0800..#0FFF. Looks like paged
permanently.<BR>
ZX Lprint MK III: The ROM is paged into #0000..#07FF (with out to #FB - on,
out #7B - off). The code for selected printer is copied into printer buffer
(at #5B00).<BR>
Multiprint by Romantic Robot: Is NMI & debug interface with parallel port.<BR>
<BR>
<B>Basic Features</B><BR>
All cards should have STROBE and BUSY lines, and (at least) 7bit
one-directional DATA lines (most or all have probably 8bit?). Some cards
allow/require to control STROBE manually, others do generate it automatically
after writing to DATA.<BR>
<BR>
<B>Extended Features</B><BR>
A few parallel ports may have bi-directional DATA lines (namely those with
8255 chips) (also some, but not all, ISA parallel cards may have
bi-directional ports). Aside from STROBE and BUSY, some cards may have ACK,
INIT, AUTOLF, etc.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumserialport"></A><FONT SIZE=+2>&nbsp;Spectrum Serial Port</FONT></TD></TR></TABLE><BR>
Interface 1 -&gt; RS232/Network: Port F7h and EFh<BR>
Spectrum 128/+2/+2A/+3 -&gt; RS232/Keypad: PSG Register 14<BR>
Rotronics Wafadrive -&gt; RS232: Port ? (uses RX,TX,RTS,CTS)<BR>
Timex RS232 Interface -&gt; RS232: Port ?<BR>
Indescomp -&gt; RS232: Port FBh.R and 7Fh.W<BR>
Cobra RS232 Interface (1983)<BR>
Cole RS232 (100/300 baud RS232 output port) (1983)<BR>
Fuller RS232 Interface aka Fuller FD Printerface (1983)<BR>
Fuller Dual Interface (RS232 and Centronics)<BR>
Kempston RS232 Interface (1984)<BR>
Tasman RS232 Printer Interface (1984)<BR>
U-Microcomputers USP-232D (dual RS232 with Z80DART chip, 75..9600 baud)<BR>
Watford Centronics/RS232 Interface (1985)<BR>
Morex Printer Interface (centronics, rs232, built-in word processor)<BR>
Euroelectronics ZX Lprint III (centronics and rs232)<BR>
YAMOD.8250<BR>
<BR>
"Most of ZX Spectrum + 128K is VERSION 6K (C) 1985. There's a VERSION 9G with
DB9 female slot for the RS232."<BR>
<BR>
<B>Network</B><BR>
Supported by Interface 1 (via Port F7h/EFh) and by Disciple (via Port
3Bh/1Fh). Despite of the different I/O ports, the transmission protocol is
the same, and Interface 1 and Disciple can communicate with each other.<BR>
<A HREF="#spectruminterface1microdrivenetworkrs232">Spectrum Interface 1 (Microdrive, Network, RS232)</A><BR>
<A HREF="#spectrumdiscdiscipleandplusd">Spectrum Disc Disciple and Plus D</A><BR>
The network interfaces have two mono 3.5mm headphone sockets: One for the
next, and one for the previous computer in the network. Reportedly up to 64
computers can be connected. On the first and last computer one socket is to
be left unconnected (no matter which one) (the sockets contain a switch which
connects the end of the data line via a terminator resistor to ground when no
plug is inserted).<BR>
Note: Another (incompatible) network-type is supported by the Opus Discovery
BIOS (which allows to use the Centronics port to transfer files to/from
another computer).<BR>
<BR>
<B>RS232 (Sinclair) (9pin DSUB female)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 Not Connected. ___________
2 In TXD | 5 4 3 2 1 |
3 Out RXD \_9_8_7_6_/
4 In DTR ;should be high when ready
5 Out CTS ;should be high when ready
6 Not Connected.
7 GND
8 Not Connected.
9 +9V - Pull up. (DSR)
</TD></TR></TABLE>Although standard RS232 ports on PCs are using 9pin DSUB connectors too, the
pinouts are NOT compatible (PCs are using male connectors, and, DTR/CTS/GND
are at other locations).<BR>
<BR>
<B>AUX/Keypad and RS232/MIDI (PSG Register 14)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 AUX/Keypad pin 2 (out)
1 AUX/Keypad pin 4 (out)
2 RS232/MIDI pin 5 (RS232: output to remote CTS) (MIDI: DATA OUT)
3 RS232/MIDI pin 3 (RS232: output to remote RXD) (MIDI: Not used)
4 AUX/Keypad pin 3 (in) (Lightgun: light sensor: 0=No Light, 1=Light)
5 AUX/Keypad pin 5 (in) (Lightgun: trigger button: 0=Pressed, 1=Released)
6 RS232/MIDI pin 4 (RS232: input from remote DTR) (MIDI: Not used)
7 RS232/MIDI pin 2 (RS232: input from remote TXD) (MIDI: Not used)
</TD></TR></TABLE>Using software control loops, the I/O lines could be driven as a second RS232
port (in the same way as the RS232/MIDI socket is driven using bits 2, 3, 6
and 7). Alternatively, the I/O lines could be used to drive, for example, a
robot or some other external device.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Pin Function
1 GND ___________________________
2 OUTPUT BIT 0 __| 6 5 4 3 2 1 |
3 INPUT BIT 4 |__ ### ### ### ### ### ### |
4 OUTPUT BIT 1 |___________________________|
5 INPUT BIT 5
6 +12V AUX/Keypad socket
</TD></TR></TABLE><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Pin Function
1 GND (MIDI: RETURN) ____________________
2 input from remote TXD (MIDI: not used) __| |
3 output to remote RXD (MIDI: not used) |__ 6 5 4 3 2 1 |
4 input from remote DTR (MIDI: not used) |____________________|
5 output to remote CTS (MIDI: DATA OUT)
6 +12V (MIDI: not used) RS232/MIDI socket
</TD></TR></TABLE>Rather unconventional "BT 603A" sockets. As far as I understand, the plugs
are similar to RJ/Western plugs, but with the plastic clip at the left-side
(next to pin6), rather than at the top-side (above pin3/4).<BR>
<BR>
<B>Signal Naming</B><BR>
Spectrum RS232 pins are usually named according to the REMOTE side, eg. the
spectrums transmit output is named RXD (not TXD) meaning to be connected to
the remote receive input.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumexpansionports"></A><FONT SIZE=+2>&nbsp;Spectrum Expansion Ports</FONT></TD></TR></TABLE><BR>
<B>Expansion Ports (male cart-edge, 2x23 or 2x28 or 2x32 pins)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> -------TS2068------- ------TC2068------ ----Spectrum---- -ZX80/ZX81/TS1x00-
Top Bottom Top/A Bottom/B
GND 1 GND /BE 1 /EXROM Top Bottom
EAR 2 SPKR/TAPE A15 2 A14 A15 1 A14
A7R 3 +15V A13 3 A12 A13 2 A12 Top Bottom
D7 4 +5V D7 4 +5V D7 3 +5V D7 1 5V
(DZ IN) 5 N.C. N.C. 5 +9V N.C. 4 +9V /RAM CS 2 9V
(SLOT) 6 (SLOT) (SLOT) 6 (SLOT) (SLOT) 5 (SLOT) (SLOT) 3 (SLOT)
D0 7 PWR GND D0 7 0V D0 6 0V D0 4 0V
D1 8 PWR GND D1 8 0V D1 7 0V D1 5 0V
D2 9 CPU CLK D2 9 CPU CLK D2 8 CPU CLK D2 6 CPU CLK
D6 10 A0 D6 10 A0 D6 9 A0 D6 7 A0
D5 11 A1 D5 11 A1 D5 10 A1 D5 8 A1
D3 12 A2 D3 12 A2 D3 11 A2 D3 9 A2
D4 13 A3 D4 13 A3 D4 12 A3 D4 10 A3
/INT 14 A15'B /INT 14 /INT 13 /IORQULA /INT 11 A15
/NMI 15 A14'B /NMI 15 0V /NMI 14 0V /NMI 12 A14
/HALT 16 A13'B /HALT 16 VIDEO /HALT 15 VIDEO /HALT 13 A13
/MREQ'B 17 A12 /MREQ 17 /MREQ 16 /Y /MREQ 14 A12
/IORQ'B 18 A11 /IOREQ 18 /IOREQ 17 V /IORQ 15 A11
/RD'B 19 A10 /RD 19 /RD 18 U /RD 16 A10
/WR'B 20 A9 /WR 20 /BUSREQ /WR 19 /BUSREQ /WR 17 A9
/BUSAK 21 A8 21 /RESET -5V 20 /RESET /BUSAK 18 A8
/WAIT 22 A7 /WAIT 22 A7 /WAIT 21 A7 /WAIT 19 A7
/BUSRQ 23 A6 23 A6 +12V 22 A6 /BUSRQ 20 A6
/RESET 24 A5 24 A5 -12V 23 A5 /RESET 21 A5
/M1 25 A4 /M1 25 A4 /M1 24 A4 /MI 22 A4
/RFSH'B 26 (DZ OUT) /RFSH 26 /ROMCS /RFSH 25 /ROMCS /REFSH 23 /ROM CS
/EXROM 27 RGB-R A8 27 /BUSACK A8 26 /BUSACK
/ROSCS 28 RGB-G A10 28 A9 A10 27 A9
/BE 29 RGB-B N.C. 29 A11 N.C. 28 A11
(IO A5) 30 (BUSISO) RED 30 CSYNC
SOUND 31 VIDEO GREEN 31 BRIGHT
GND 32 GND BLUE 32 GND
</TD></TR></TABLE>The Spectrum/TC20xx port (europe) is compatible only with the signals used by
the ZX81 printer, but not compatible with other ZX80/ZX81 hardware (for some
crazy reason, the /RESET pin is replaced by -12V, giving it a good chance to
vaporize any ZX80/ZX81 hardware). The TS2068 port (usa) is almost fully
backwards compatible with the ZX80/ZX81 and TS1000/TS1500 ports, but
incompatible with Spectrum/TC20xx ports.<BR>
On the Spectrum 48K, the /Y,U,V,VIDEO signals are passed through jumpers on
the mainboard, the Y,U,V jumpers are usually installed, but the VID jumper
isn't (so without adding that jumper, VIDEO isn't actually output on
Pin15/Bottom).<BR>
<BR>
<B>Signal Notes</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> CPU CLK normally 3.5MHz clock, but, PAUSED during waitstates
/ROMCS BIOS chipselect (can be dragged to 5V to disable internal BIOS)
/IORQULA ULA chipselect (can be dragged to 5V to disable ULA mirrors)
</TD></TR></TABLE><BR>
<B>TS2068 Notes</B><BR>
(BUSISO),(IO A5),(DZ IN),(DZ OUT) are "not connected" (but are reserved for
something or so). "IO A5 (Bit5 of PSG Port A) available on edge-slot)" so it
is NOT not-connected...?<BR>
<BR>
<B>TC20xx</B><BR>
Although the TC2048/TC2068 are based on the US TS2068, their expansion port
pin-outs were converted back to the 2x28 pin Spectrum layout to match the
european market. During that backwards-conversion the /IORQULA pin got lost,
the TC devrs apparently didn't understand its purpose, in the first version
of the mainboard they have left it unconnected, in the next version it's
accidently connected to /IOREQ via a jumper, in the third version it's
directly wired to /IOREQ without any jumper.<BR>
<BR>
<B>Later Spectrums</B><BR>
Later Spectrums (eg. +3) don't use a +9V power supply, and thus leave the +9V
pin unconnected; also, later models changed the pin numbering from 1..28 to
1..27 (with the SLOT spacings not being counted as pins). Also, the +3 has
Pin4/comp = /ROM1OE, no -5V, no /BUSACK, no /IORQULA, no /ROMCS,
Pin28/comp=RESET, and VIDEO,/Y,V,U replaced by
/ROM2OE,/DISKRD,/DISKWR,/MOTORON.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumromcartridges"></A><FONT SIZE=+2>&nbsp;Spectrum ROM Cartridges</FONT></TD></TR></TABLE><BR>
<B>Cartridge Slots (female cart-edge, 2x18 or 2x15 pins)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> TS2068/TC2068 Cartridges (2x18 pin) Interface 2 Cartridges (2x15 pin)
Solder Side Component Side Whatever Side Other Side
1 A14'B 2 +5V 1A /ROMCS (+5V) 1B +5V
3..A12...........4..A13'B.....SLOT.. 2A A12 2B A15 (/CS2)
5 D0 6 D7 3A A7 3B A13
7 D1 8 A0 4A A6 4B A8
9 D2 10 A1 5A (SLOT) 5B (SLOT)
11 D6 12 A2 6A A5 6B A9
13 D5 14 A3 7A A4 7B A11
15 D3 16 A15B 8A A3 8B /MREQ (/OE)
17 D4 18 /MREQ'B 9A A2 9B A10
19 /IORQ'B 20 A7R'B 10A A1 10B A14 (/CS1)
21 /RD'B 22 /M1 11A A0 11B D7
23 /WR'B 24 A8 12A D0 12B D6
25 A7 26 A9 13A D1 13B D5
27 A6 28 A10 14A D2 14B D4
29 A5 30 A11 15A GND 15B D3
31 A4 32 /RFSH'B or /ROMCS
33 /BE or ROMDIS 34 /EXROM
35 /ROSCS 36 GND
</TD></TR></TABLE><BR>
<B>Timex TS2068/TC2068 Cartridges</B><BR>
The TS2068/TC2068 (but not the TC2048) contain a built-in cartridge slot.<BR>
The TC2068 cartridges are slightly bigger in height than TS2068 cartridges
(so the bigger TC2068 carts won't fit into the smaller TS2068 slot without
modifying the plastic case), and, the pinouts are slightly different for
TS2068/TC2068 (pin32 and pin33).<BR>
A7R'B=Refresh Address Bit7, /RFSH=Refresh (TS2068 only), /BE=Bank Enable
(TS2068 only), /EXROM (useless), /ROMCS (useless) (TC2068 only),
ROMDIS="disables both internal ROM and also forces high state on both /ROMCS
and /EXROM in the slot" (TC2068 only), /ROSCS=ROS Chip Select (Dock Bank
Enable), xx'B=buffered (not directly connected to corresponding xx pin on
CPU).<BR>
<BR>
<B>Timex Cartridge Types</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> LROS --&gt; Language ROM-Oriented Software at 0000h (Z80 Code)
AROS --&gt; Application ROM-Oriented Software at 8000h (BASIC or Z80 Code)
</TD></TR></TABLE>BASIC code isn't directly executed in ROM, instead, the current BASIC line is
copied to ARSBUF in RAM, and then executed from there. USR function does
address ROM. While PEEK/POKE address RAM?. User-Defined BASIC functions (DEF
FN) aren't supported.<BR>
<BR>
<B>Timex LROS Header</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0000h Not used (should be F4h for Spectrum ROMs, see comment)
0001h Cartridge Type (01h=LROS)
0002h Entrypoint (16bit)
0004h Initial Value Port F4h (XORed by FFh)
0038h IRQ Handler
</TD></TR></TABLE>Note: [0004h].Bit3 should be set (otherwise the Machine Stack and Bank
Switching code gets replaced by ROM). Caution the LROS is started with IRQs
enabled (so the handler at 0038h might be called even before the Entrypoint
handler is executed). Accordingly, [0004h] must enable any ROM locations used
by the Entrypoint, and such used by the IRQ handler.<BR>
Comment: Some Spectrum games have JR FFF4h opcode as IM 2 interrupt handler
at FFFFh, the opcode consists of [FFFFh]=18h (in RAM), and [0000h]=F4h (ie.
initial DI opcode - or 1st byte of the LROS header) in BIOS ROM. Ie. an LROS
cartridge with Spectrum ROM and LROS header should contain the DI opcode at
0000h.<BR>
<BR>
<B>Timex AROS Header</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 8000h Language Type (01h=BASIC, 02h=Machine Code) (other=Error)
8001h Cartridge Type (02h=AROS) (other=no cartridge)
8002h Entrypoint (16bit) (ptr to first BASIC Line, or to first opcode)
8004h Initial Value Port F4h (not XORed) (Bit0-3 must be set for BIOS/VRAM)
8005h Autostart Flag (0=No, 1=Autostart)
8006h Number of bytes of RAM reserved for Machine Code variables (16bit)
</TD></TR></TABLE>Bug: [8006h] must be set to "N+15h" to allocated "N" bytes.<BR>
<BR>
<B>Timex The Spectrum Emulator Cartridge:</B><BR>
"This cartridge made by Timex of Portugal, contains a ROM image of TC2048. I
think that this isn't a ROM cartridge, but a LROS cartridge, because it is
simply plugged to TC2068 and it starts automaticaly. Many American Timex
Sinclair 2068 users made a cartridge with a ROM chip of a ZX Spectrum and
because of this, they have to type the OUT 244,3 command."<BR>
<BR>
<B>Spectrum Interface 2 Cartridges</B><BR>
In the cartridge, /ROMCS is usually wired to +5V, completely disabling the
BIOS, and allowing to map 16K ROM to 0000h..3FFFh. There were only 10
cartridges manufactured, all of them only 16K in size, using ROM chips with
two /CS pins. For normal EPROMs, /CS1 and /CS2 would need to be ORed by
external logic (although /CS2 aka A15 could be left unconnected when not
using the upper 32K of RAM). Bank switching for more than 16K ROM can be
implemented by reading from a specific memory region, and latching LSBs of
the address as bank number; observe that /MREQ gets low on /RD, /WR, and
/RFSH; during refresh, the IR register pair is output to the address bus, so
the I register should be set to a value that doesn't conflict with the bank
switching addresses.<BR>
<BR>
<B>Timex TS1510 Command Cartridge Player (Pinouts unknown?)</B><BR>
An external cartridge adaptor for the TS1500. It can be also used with
TS1000/ZX81 with a 16K RAM upgrade (assuming that most or all cartridges do
require 16K RAM; there were only 4 carts manufactured).<BR>
The TS1500 BIOS starts cartridges automatically; it jumps to 2000h if the
first byte at [2000h] is 01h (ie. a LD BC,nnnn opcode). On a ZX81/TS1000, the
cartridge must be manually started (eg. by typing RAND USR 8192). Aside from
the cartridge connector, the TS1510 includes a RESET button.<BR>
The first 8K of ROM is obviosly mapped to 2000h. Carts with 16K or more ROM
are mapped to unknown (?) memory locations. According to the manual, such
bigger carts won't work on computers expanded to 32K RAM (which have extra
RAM at 8000h..BFFFh) (so the extra ROM is probably mapped to that region).<BR>
The memory mapping logic seems to be built-in in the TS1510 (rather than in
the cartridge), looking at photo found in the internet, it seems to contain a
74LS00 chip, and another chip whose part number is unknown due to bad quality
of the photo.<BR>
The TS1510 was advertised to support up to 24K ROM.<BR>
Only four TS1510 cartridge titles were ever released:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 07-9001 Supermath
07-9002 States and Capitals
07-9003 Chess
07-9004 Flight Simulator
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumchipsetpinouts"></A><FONT SIZE=+2>&nbsp;Spectrum Chipset Pinouts</FONT></TD></TR></TABLE><BR>
<B>Ferranti 6C001 (Spectrum 48K) - Uncommitted Logic Array (ULA):</B><BR>
<B>Ferranti 7C001 (Spectrum 128K) - Uncommitted Logic Array (ULA):</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 /CAS 6 A1 11 A6 16 VIDEO V 21 D1 26 KB4 31 D7 36 A14
2 /WR 7 A2 12 /INT 17 VIDEO /Y 22 D2 27 D4 32 CLOCK 37 A15
3 /RD 8 A3 13 +5V 18 D0 23 KB2 28 SOUND 33 /IO-ULA 38 /MREQ
4 /WE 9 A4 14 +5V' 19 KB0 24 KB3 29 D5 34 /ROM CS 39 OSC
5 A0 10 A5 15 VIDEO U 20 KB1 25 D3 30 D6 35 /RAS 40 GND
</TD></TR></TABLE>SOUND is the analog-I/O-line for beep, save and load.<BR>
CLK is the clock-source to the CPU including the inhibited T-states.<BR>
IO-ULA is "A0(CPU) OR /IORQ" for the I/O-port FEh.<BR>
OSC is the 14MHz-crystal, other side grounded through a capacitor.<BR>
One of the +5V is decoupled through a RC-low-pass.<BR>
<BR>
<B>TS2068 SCLD</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 A0 11 /EXROM 21 MUX 31 MA0 41 /CAS1 51 KB2 61 D4
2 A1 12 /BE 22 MA7 32 /ROSCS 42 CLK CPU 52 KB3 62 D7
3 A2 13 OSC OUT 23 MA3 33 /RAS1 43 +5V 53 KB4 63 /RD
4 A3 14 OSC IN 24 MA4 34 VIDEO U 44 A14 54 /RD' 64 /IORQ
5 A4 15 TAPE IN 25 MA2 35 VIDEO V 45 A15 55 D1 65 /WR
6 A5 16 TAPE OUT 26 GND 36 VIDEO /Y 46 VIDEO B 56 D2 66 /MREQ
7 A6 17 PSG BC1 27 /ROMCS 37 /DRAMWE 47 VIDEO G 57 D0 67 /INT
8 A7 18 PSG BDIR 28 MA6 38 A7R 48 VIDEO R 58 D3 68 /RFSH
9 A13 19 PSG CLK 29 MA1 39 /CAS3 49 KB0 59 D5
10 CLK EXP 20 /TS 30 MA5 40 /CAS2 50 KB1 60 D6
</TD></TR></TABLE><BR>
<B>Gate Array +2A/+3</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 BUSY 14 MA3 27 A15 40 GND2 53 K10 66 GND3 79 /RFS 92 PSG CLK
2 EAR 15 GND1 28 K0 41 VCC1 54 DV7 67 VA3 80 /IRQ 93 PSG BC1
3 A0 16 MA4 29 K1 42 BRIT 55 DV6 68 VA2 81 /MRQ 94 PSG BDIR
4 A1 17 MA5 30 K2 43 /SNC 56 DV5 69 VA1 82 /WR 95 /VWE
5 A2 18 MA6 31 K3 44 FSC2 57 DV4 70 VA0 83 /RD 96 /VCS
6 A3 19 MA7 32 K4 45 /RS 58 DV3 71 D7 84 /ROM2 97 /VRS
7 A4 20 A8 33 /MTR 46 /CS 59 DV2 72 D6 85 /ROM1 98 MIC
8 A5 21 A9 34 PRNT 47 STRB 60 DV1 73 D5 86 RA14 99 /RS
9 A6 22 A10 35 /DRD 48 K5 61 DV0 74 D4 87 /ZCK 100 OSC
10 A7 23 A11 36 /DWR 49 K6 62 VA7 75 D3 88 /INT
11 MA0 24 A12 37 VIDEO B 50 K7 63 VA6 76 D2 89 /WAIT
12 MA1 25 A13 38 VIDEO R 51 K8 64 VA5 77 D1 90 GND4
13 MA2 26 A14 39 VIDEO G 52 K9 65 VA4 78 D0 91 VCC2
</TD></TR></TABLE><BR>
<B>AY-3-8912 Sound Chip (PSG)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 SND C 5 SND A 9 P5 13 P1 17 A8 (+5V) 21 D7 25 D3
2 TEST,NC 6 GND 10 P4 14 P0 18 BDIR 22 D6 26 D2
3 +5V 7 P7 11 P3 15 CLK 19 BC2(+5V) 23 D5 27 D1
4 SND B 8 P6 12 P2 16 /RES 20 BC1 24 D4 28 D0
</TD></TR></TABLE>Timex TS2068 uses CLK=1.76475Mhz, Spectrum +3 uses CLK=1.7734MHz.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrumxboo"></A><FONT SIZE=+2>&nbsp;Spectrum Xboo</FONT></TD></TR></TABLE><BR>
<B>Step 1 - Connect Centronics Port and EPROM</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> GND ------------------- CNTR.24 GND
ULA.Pin28 ------|&gt;o---- CNTR.10 ACK (SPKR)
EAR ------------------- CNTR.2 D0 (EAR)
KB1.Pin1 "0" ---|&gt;|---- CNTR.3 D1 (CLK)
KB1.Pin2 "9" ---|&gt;|---- CNTR.4 D2 (D0)
KB1.Pin3 "8" ---|&gt;|---- CNTR.5 D3 (D1)
KB1.Pin4 "7" ---|&gt;|---- CNTR.6 D4 (D2)
KB1.Pin5 "6" ---|&gt;|---- CNTR.7 D5 (D3)
CPU.Pin26 ----|&gt;|---- CNTR.8 D6 (/RESET)
EPROM.Pin27 ----------- CNTR.9 D7 (ROM.A14)
EPROM.Pin27 ---/cut/--- /RD
EPROM.Pin27 ---[3k3]--- +5V
EPROM.Pin1 ----------- +5V
</TD></TR></TABLE>ACK must be amplified via a TTL inverter (eg. by using an unused NAND gate,
found on Pin1-3 of IC24 (74LS00) on Spectrum 48K Issue 2 mainboards; note
that the unused inputs are wired to 5V). Pass the reset and keyboard lines
through 1N4148 diodes to prevent them to get stuck. Remove the ROM, and
replace it by a 28pin socket for the EPROM, with 1:1 connection, except for
pin1 (usually NC), and pin27 (usually /RD), omitting the /RD line causes the
EPROM to respond also to writes and refresh, but that should be no problem.<BR>
<BR>
<B>Step 2 - Connect Joystick (Sinclair 1)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> KB1.PIN1 "0" ---|&gt;|--- DSUB.Pin6 Fire
KB1.PIN2 "9" ---|&gt;|--- DSUB.Pin1 Up
KB1.PIN3 "8" ---|&gt;|--- DSUB.Pin2 Down
KB1.PIN4 "7" ---|&gt;|--- DSUB.Pin4 Right
KB1.PIN5 "6" ---|&gt;|--- DSUB.Pin3 Left
KB2.PIN4 A12 ---|&lt;|--- DSUB.Pin8 Common
</TD></TR></TABLE>Connect all joystick lines through 1N4148 diodes (the diode in A12 line
facing in opposite direction). The five joystick data diodes are required
because the joystick cable doesn't contain terminator resistors; without
these diodes, the xboo transmission won't work without the diodes when
signals "bounce back" from the end of the long joystick cable). Without the
A12 diode, the Spectrum game "Zynaps" would crash after 1-2 minutes (no idea
why, there is already a diode on the mainboard, so adding another diode
should have little effect, but it does fix the zynaps crash, maybe it just
works as a resistor).<BR>
<BR>
<B>Step 3 - Connect AV-Cable</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> GND ----------------------------------------- Cinch GND
VID ----------------------------------------- Cinch V
MIC ----------------------------------------- Cinch A
</TD></TR></TABLE>Connect the Cinch sockets to the "VID" jumper, and to the "MIC" socket, the
cables don't need to be shielded, but, Cinch GND should be connected
somewhere close to the TV modulator (this gives a better picture).<BR>
<BR>
<B>Step 4 - Connect Supply from PC</B><BR>
There are two simple ways to replace the 9V supply by voltages from a PC
power supply. The straight way would be to use a 7809 to lower 12V to 9V, but
the 7809 produces a lot of heat (and the internal 7805 produces further heat
when it lowers the 9V to 5V). So, my preferred way would be to use 5V:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Spectrum 5V ------------ PC 5V (red floppy cable)
Spectrum 5V -----||----- Spectrum GND
Spectrum 5V ----|&gt;|----- Spectrum 9V
</TD></TR></TABLE>Inject 5V from the PC supply to 5V on the mainboard (there's no need to
inject GND, since that's passed through the centronics cable). Add a 470uF
capacitor between 5V and GND for better video quality. Pass 5V to 9V via a
1N4001 diode (this feeds the internal +12V/-5V voltage generator which is
usually driven at 9V, but it does also work at 5V, with 5V it's reaching only
+10V instead of +12V, but does still work; the voltages are required for DRAM
and video signal generation).<BR>
Basically 5V and 9V could be directly shortcut with each other, however, the
diode has two purposes: First, it prevents 9V being passed to 5V (in case
somebody connects a 9V supply). Second, it reduces noise from the voltage
generator on the 5V line (without the diode one might need a larger 2200uF
capactitor instead of 470uF one).<BR>
Caution - The 5V solution has two disadvantages: The TV modulator does no
longer work (not sure why, maybe it requires full 12V, or maybe the voltage
generator is producing too much noise when driven at 5V) (anyways, the AV
cinch output does work). And, it doesn't output 9V on the expansion port
(which may be required by some expansion hardware).<BR>
<BR>
<B>Step 5 - Connect Keyboard</B><BR>
The keyboard is connected via extremly fragile printed plastic wires, which
tend to break when fiddling with them (or just when they get old). The
membrane with the keyboard matrix consists of the same material, but the
wires are the most fragile part.<BR>
Desolder the keyboard connectors. Connect real metal wires to the connectors.
Cut the original plasitic wires close to the membrane. Carefully slide the
connectors on the remaining ends (best, put the ends on a solid surface, if
there's no good surfaces: put 1-2 layers of board under the ends, then firmly
push the ends onto that surface, and move the connector onto the cable;
rather than trying to move the cable into the connector. If needed, add some
tuner/contact spray, and move the cable end in and out a little. Finally,
glue the connectors to the case.<BR>
<BR>
<B>Software</B><BR>
The transmit function (for uploading .TAP files to the Spectrum) is found in
no$zx's "Utility" menu. The "Utility" menu also contains a function called
Create Patched BIOS Image, which creates a file called XMITSPEC.ROM, which is
to be stored in the EPROM; the ROM-image is 32K in size, containing two
copies (one original, and one patched) of the ZX Spectrum BIOS.<BR>
<BR>
<B>Note</B><BR>
Above Pin-numbers are for Spectrum 48K Issue 2 board (some may vary on other
boards). The transmit software currently works only with ZX Spectrum
16K/48K/Plus (not with Spectrum 128 and up).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="lambda8300"></A><FONT SIZE=+2>&nbsp;Lambda 8300</FONT></TD></TR></TABLE><BR>
The Lambda 8300 is a ZX81 clone (not an exact clone) made in china, and
distributed by various companies, in various countries, under various
different names...<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Name___________Usage_______________
Lambda 8300 (Denmark, Sweden, Norway)
Power 3000 Creon Enterprises (Hongkong) (Denmark, Germany)
Marathon 32K (Denmark)
Futura 8300 Unisonic (USA)
DEF 3000 (France)
Your Computer
IQ8300 (China?)
BASIC 2000
BASIC 3000
PC 2000
PC 8300 Text on mainboard
</TD></TR></TABLE><BR>
<B>PC8300 BASIC</B><BR>
The BASIC syntax is more or less the same as on ZX81, so it accepts ZX81
BASIC type-in listings in most cases, there is also (limited) support for
loading ZX81 cassette files. A few commands/functions are different: LOG
(instead LN), LET (can be optionally omitted), and the quad-quotes token ("")
isn't supported (ie. one cannot define double-quotes in strings). Additional
commands are TEMPO, MUSIC, SOUND, BEEP, NOBEEP (for internal speaker), and
INK, PAPER, BORDER (for external COLOR module).<BR>
<BR>
<B>PC8300 BIOS</B><BR>
The BIOS is apparently based on a disassembled and modified ZX81 BIOS. About
ALL procedures are moved to different addresses, so there's no compatibility
when CALLing BIOS functions. Only the INT and NMI handler are (more or less)
same as in ZX81 (the timings are slightly changed, the INT handler has same
function, but C and B registers are exchanged).<BR>
<BR>
<B>PC8300 RAM</B><BR>
Some entries in system area are modified. D_FILE is hardcoded at 407Dh,
D_FILE is always expanded (full 1+33*24 bytes). BASIC program is located
after D_FILE (ie. always at 4396h since D_FILE has fixed size). The BASIC
program is terminated by an FFh byte (ZX81 has no such end byte). The
remaining memory (VARS and up) is same as on ZX81.<BR>
The RAMTOP detection supports up to 32K RAM (unlike ZX81 which detects max
16K). The Lambda includes 2K RAM built-in (unlike 1K in ZX81). Note: despite
of its name, the Marathon 32K also has only 2K RAM built-in (not 32K).<BR>
<BR>
<B>PC8300 CHARSET</B><BR>
Six characters are different as on ZX81. The charset is located in the ULA
chip without using I register (the ZX81 has it in BIOS ROM, accessed via
I=1Eh). Accordingly, changing the I register doesn't affect video (so neither
True Hires nor Pseudo Hires will work, and any UDG/CHRs hardware expansions
won't work either). The CPU can read the charset via I/O ports (mainly
required for printers).<BR>
The video output is reportedly the inverse of ZX81, ie. white text on black
background with black screen border.<BR>
<BR>
<B>PC8300 PRINTERS</B><BR>
The BIOS supports the Sinclair Printer as well as an external Centronics
interface. The Centronics feature includes two modes: ZX chars converted to
ASCII, or ZX chars converted to bitmaps (via ESC codes, which must be
supported by the printer).<BR>
<BR>
<B>PC8300 KEYBOARD</B><BR>
42 Keys. The left 40 keys are same as on ZX81. The upper right key is wired
to /RESET causing a warmboot (pressing /RESET+ENTER forces a coldboot,
/RESET+L_KEY jumps to 2000h in external memory such like ROM, or COLOR RAM).
The lower right key is same as the left SHIFT key. Punctuation marks and
Cursor, Rubout, Edit, Graphics keys are at different location as than in
ZX81. Commands are entered letter-by-letter (eg. type L-O-A-D, unlike
pressing J on ZX81).<BR>
<BR>
<B>PC8300 SOUND</B><BR>
Contains a built-in speaker. The output level can be toggled HIGH/LOW by
reading from an I/O port. Allows to produce a single square wave at fixed
volume (though using PWM, one could eventually mix multiple channels at
variable volume). Since both sound and video require a lot of CPU load, it's
barely possible to output sound & video together. The BEEP (keyclick) is a
very remarkable feature: each key has a different tone assigned, resulting in
a funny melodic old-school SciFi typing effect.<BR>
<BR>
<B>PC8300 SOFTWARE</B><BR>
A few photos of cassettes do exist. As far as known there aren't any tape
images. Strange RAW &lt;--&gt; A83 conversion programs exists (purpose unknown).<BR>
<BR>
<B>PC8300 JOYSTICK</B><BR>
DSUB 9pin Atari-style joystick port (with only four directions and one fire
button implemented). Wired to keyboard matrix Bit3=Common, and<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> A11 = 2 = Up,
A10 = W = Down,
A12 = 9 = Left,
A9 = S = Right,
A13 = O = Fire
</TD></TR></TABLE>(according to Kai Fischer's schematic).<BR>
<BR>
<B>PC8300 FILES</B><BR>
Cassette files are SAVEd with circa 16000 leading sync pulses (though, this
is a fake, the LOAD function simply ignores them). Followed by a ZX81-style
file: Some silence, followed by the Filename terminated with bit7=1, followed
by memory at [4009h..[4014h]-1]. The memory content isn't ZX81 compatibile
though (different system area, different D_FILE location, different BASIC
tokens). The VERSN byte at 4009h is FFh (unlike 00h on ZX81).<BR>
Bits and bytes are encoded same as on ZX81 (0=four pulses, 1=nine pulses,
with same pulse/silence timings).<BR>
<BR>
<B>PC8300 SUPPORT FOR ZX81 FILES</B><BR>
The Lambda BIOS can load ZX81 files, but with several restrictions: The files
are converted to Lambda format (and cannot be converted back to ZX81 format).
Information in the system area (such like Autostart), and VARS and D_FILE
regions are discarded (only the raw BASIC code is accepted).<BR>
BUG: After loading a ZX81 file, the BIOS accidently jumps to 2000h, normally
this is a mirror of 0000h which produces a warmboot - however, it'll crash if
a Color RAM expansion is installed (workaround: POKE a RST0 opcode to 2000h),
or accidently start any expansion ROM at 2000h.<BR>
<BR>
<B>PC8300 COLOR EXPANSION</B><BR>
Colors are optionally supported via an external color module. The Lambda BIOS
contains built-in commands (INK/PAPER/BORDER) for it. The module connects to
expansion port, and also to the monochrome composite video output, deciphers
the "analogue" signal into TTL black/white and TTL sync/nosync signals.<BR>
Color attribtes are stored in 1K read/write-able RAM at 2000h..23FFh. During
drawing, the module takes the D_FILE address (usually 407Dh..4395h) ANDed
with 3FFh as index in the RAM, and reads the color attribute for the current
character. The attributes associated with the HALT opcodes in D_FILE define
the current section of the screen border color. The attribute bytes are
Bit0-2 = INK, Bit4-6 = PAPER/BORDER, bit3,7 can be used as general purpose
flags, but do not affect the video output. The monochrome luminance level
selects INK/PAPER, but otherwise doesn't affect the outgoing signal (eg.
PEN=3 and PAPER=3 do produce exactly the same color & same brightness).<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> XXX does the border affect the COLOR BURST signal?
XXX and thus alter the colors in the picture region?
XXXXXX the 3bit color values allow to use 8 colors,
XXXXXX but it's unknown WHICH colors?
</TD></TR></TABLE><BR>
<B>PC8300 TIMINGS</B><BR>
The INT handler (0038h) is made 1 cycle slower as than on ZX81, meaning that
the Lambda executes 208 clks/scanline (ZX81 only 207 clks).<BR>
The NMI handler is "improved" (the useless JP opcode removed, but the JR is
replaced by a JP, so there is no speedup gained, to the worst, there's a
bizarre NOP inserted making NMI handling 4 cycles slower than on ZX81, making
the SLOW mode even slower-than-slow.<BR>
<BR>
<B>PC8300 I/O PORTS</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> I/O:xxF5h.W ;select charset line number (00..07) ;\use only in FAST mode,
I/O:xxF6h.W ;select charset char number (00..3F) ;/or after HSYNC (NMI)
I/O:xxFBh.W ;printer control (sinclair pixel-style, or ASCII character)
I/O:xxFDh.W ;disable NMIs
I/O:xxFEh.W ;enable NMIs
I/O:xxFFh.W ;terminate retrace / CAS output
I/O:xxF5h.R ;toggle sound output level
I/O:xxF6h.R ;read selected charset data (8 pixels)
I/O:xxFBh.R ;printer status
I/O:NNFEh.R ;read keyboard (A8..A15=row) (and CAS.IN) (and JOYSTICK)
;(but no PAL/NTSC bit here, unlike ZX81)
I/O:FF7Eh.R ;read PAL/NTSC flag (A7=row) (via diode from A7 to KEYB.0)
MEM:00XXh dummy blink addr in write-protected BIOS ROM
MEM:2000h optional boot entryoint (in COLOR RAM, or TS1510-cartirdges)
MEM:2XXXh COLOR ATTRIBUTES (external color module)
MEM:3000h disable color ram (on any write to 3000-3FFE with A0=0)
MEM:3001h enable color ram (on any write to 3001-3FFF with A0=1)
</TD></TR></TABLE><BR>
<B>PC8300 System Area</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 4000 2 unused (unlike ZX81: ERR_NR, FLAGS) (not used)
4002 2 err_sp (same as ZX81)
4004 2 ramtop (same as ZX81, but, max 32K)
4006 1 prmode (unlike ZX81: MODE, cursor shape) (instead: printer mode)
4007 1 err_nr (unlike ZX81: ppc.lsb)
4008 1 color (unlike ZX81: ppc.msb)
</TD></TR></TABLE>SAVE area... (same as ZX81)<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 4009 1 versn (versn, and other temporary flags) (00h=ZX81, FFh=Lambda)
400A 2 nxtlin (unlike ZX81: e_ppc)
400C 2 program (unlike ZX81: d_file)
400E 2 df_cc (same as ZX81)
4010 2 vars (same as ZX81)
4012 2 dest (same as ZX81)
4014 2 e_line (same as ZX81) (input/workspace buffer, end of SAVE area)
4016 2 ch_add (same as ZX81)
4018 2 x_ptr (same as ZX81) (error/abort address)
401A 2 stkbot (same as ZX81)
401C 2 stkend (same as ZX81) (increases on PUSHes)
401E 1 flags (unlike ZX81: berg) (same as 4001h on ZX81)
401F 2 mem (same as ZX81)
4021 1 munit (unlike ZX81: unused) (tempo for music)
4022 1 df_sz (same as ZX81)
4023 2 s_top (same as ZX81)
4025 2 last_k (same as ZX81)
4027 1 bounce (same as ZX81)
4028 1 margin (same as ZX81) (but, derived from other I/O mechanism)
4029 2 e_ppc (unlike ZX81: nxtlin)
402B 2 oldppc (same as ZX81)
402D 1 flagx (same as ZX81)
402E 2 strlen (same as ZX81)
4030 2 t_addr (same as ZX81)
4032 2 seed (same as ZX81)
4034 2 frames (same as ZX81)
4036 2 ppc (unlike ZX81: coords) (same as 4007h on ZX81)
4038 1 pr_cc (same as ZX81)
4039 2 s_posn (same as ZX81)
403B 1 cdflag (additional bit4=graphics_cursor, bit5=beep_disable)
403C 33 prbuff (same as ZX81)
405D 30 membot (same as ZX81)
407B 2 blink (unlike ZX81: blink address instead unused)
N/A 1 mode (no [K],[L],[F] cursors, only [G] = flag in cdflag.bit4)
N/A 1 berg (none such, memorized somehow elsewhere)
N/A 2 coords (none such,isn't really used on ZX81 either)
</TD></TR></TABLE>4009 VERSN Should be 00h to identify ZX81 cassette files<BR>
BUG: [400Ch] is NOT properly set after loading ZX81 files, so better use 4396h than [400Ch].<BR>
<BR>
<B>PC8300 BIOS-MOD</B><BR>
There is also an alternate Lambda BIOS in the internet. It's source is
unknown, it seems to be an commercial or homebrewn BIOS replacement, intended
to improve ZX81 compatibility (called "replacement" because the BIOS doesn't
match-up with the Lambda keyboard, so it's unlikely that Lambda's were sold
with that BIOS built-in).<BR>
Patched TS1500 BIOS (around 1K modified, remaining 7K same as in original
BIOS). RAMTOP is hardcoded as 16K (won't work with less memory). Frame rate
is hardcoded as 60Hz. Keyboard layout is same as in ZX81 (cursor keys,
punctuation marks, and token-hotkeys don't match up with the Lambda
keyboard). Doesn't include charset in BIOS (uses the Lambda ULA charset, so,
for video and printer output, six chars are still different as on ZX81).<BR>
Fileformat and memory map are exactly same as in ZX81, so it's compatible
with machine code programs with hardcoded ZX81 memory addresses. System area
is same as ZX81, though with some extra bits in 403Bh (bit3=REM n Cursor
Blink Enable, bit4=STEP n Auto-Edit enable, bit5=BEEP n Keyclick Beep
disable) and 407Bh (16bit Cursor address for blink).<BR>
BASIC includes some new/modified commands/functions: BEEP n (n=1 enables
keyclick sounds, n=0 disables it), IN/OUT (executes IN/OUT opcode, the port
address is only 8bit wide, not 16bit), STEP n (usually suffix for FOR, but in
this BIOS it can be also as command to edit line "n" and all
following/existing lines), REM n (n=1 enables cursor blink, n=0 disables it).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="jupiterace"></A><FONT SIZE=+2>&nbsp;Jupiter ACE</FONT></TD></TR></TABLE><BR>
The ACE was manufactured by Jupiter Cantab from England in 1983. It was
designed by two ex-Sinclair Research employees, Steven Vickers and Richard
Altwasser, who earlier worked on the Sinclair ZX-80 and ZX-81, as well as the
Spectrum.<BR>
<BR>
<A HREF="#jupiteraceioports">Jupiter ACE I/O Ports</A><BR>
<A HREF="#jupiteracevideo">Jupiter ACE Video</A><BR>
<A HREF="#jupiteracedimensionsandtimings">Jupiter ACE Dimensions and Timings</A><BR>
<A HREF="#jupiteracememorymapandsystemarea">Jupiter ACE Memory Map and System Area</A><BR>
<A HREF="#jupiteracefiles">Jupiter ACE Files</A><BR>
<BR>
<B>FORTH</B><BR>
<A HREF="#forthoverview">FORTH Overview</A><BR>
<A HREF="#forthstackandmemory">FORTH Stack and Memory</A><BR>
<A HREF="#forthmaths">FORTH Maths</A><BR>
<A HREF="#forthinputoutput">FORTH Input/Output</A><BR>
<A HREF="#forth">FORTH ...</A><BR>
<A HREF="#fortherrorcodes">FORTH Error Codes</A><BR>
<BR>
<B>Links</B><BR>
http://www.jupiter-ace.co.uk/<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="jupiteraceioports"></A><FONT SIZE=+2>&nbsp;Jupiter ACE I/O Ports</FONT></TD></TR></TABLE><BR>
<B>Port FEh Read (or any Read with A0=0)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-4 Keyboard Bits
5 Cassette Input (EAR/LOAD)
6-7 Not used
</TD></TR></TABLE>Any read from this port toggles the speaker "off".<BR>
<BR>
<B>Port FEh Write (or any Write with A0=0)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0-2 Not used
3 Cassette Output (MIC/SAVE)
4-7 Not used
</TD></TR></TABLE>Any write to this port toggles the speaker "on".<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="jupiteracevideo"></A><FONT SIZE=+2>&nbsp;Jupiter ACE Video</FONT></TD></TR></TABLE><BR>
<B>General</B><BR>
For VRAM Addressing & Timings, see:<BR>
<A HREF="#jupiteracememorymapandsystemarea">Jupiter ACE Memory Map and System Area</A><BR>
<A HREF="#jupiteracedimensionsandtimings">Jupiter ACE Dimensions and Timings</A><BR>
<BR>
<B>Colors</B><BR>
The colors are 0=Black, 1=White, Border=Black (opposite of ZX81). Bit7 of the
character number can be used as invert-attribute.<BR>
<BR>
<B>BIOS charset at 1D7Bh..1FFBh</B><BR>
The ROM character set is slightly compressed (of the 8 character rows, blank
upper/lower rows are omitted for some characters):<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Char Rows
20h..3Eh 7 ;1Fh chars (upper row blank) (lower row is used in $,;)
3Fh..5Eh 6 ;20h chars (upper and lower row blank)
5Fh..7Eh 7 ;20h chars (upper row blank) (lower row is used in _gjpqy)
7Fh 8 ;01h char (no blank rows) (copyright symbol)
</TD></TR></TABLE>All character numbers ASCII (except 60h=pounds and 7Fh=copyright).<BR>
<BR>
<B>Video Capabilities</B><BR>
With only 1K Charset RAM, the Jupiter is more restrictive than a ZX Spectrum
(or HiRes ZX81) with 6K Bitmap RAM. On the other hand, there's more CPU load
available than on ZX81, so the Jupiter has some potential.<BR>
Possible would be games with not too detailed graphics (like racing games
which have relative featureless BG graphics, or shoot-em-ups without BG
graphics, etc.)<BR>
Another approach would be a medium-resolution Bitmap with 128x96 pixels
(using 128 characters with 4x4 pixel "block graphics", and their inverses,
giving 256 characters in total).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="jupiteracedimensionsandtimings"></A><FONT SIZE=+2>&nbsp;Jupiter ACE Dimensions and Timings</FONT></TD></TR></TABLE><BR>
The Z80 CPU is clocked at 3.25MHz. Picture size is 256x192 pixels.<BR>
<BR>
<B>Horizontal Timings</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Phase__________Dotclock_______________=_CPU Clock___________
Hsync 32 pixels (320..351) = 16 clks
Left Border 64 pixels (352..415) = 32 clks
Picture 256 pixels (0..255) = 128 clks
Right Border 64 pixels (256..319) = 32 clks
Total 416 pixels (0..415) = 208 clks
</TD></TR></TABLE><BR>
<B>Vertical Timings</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Phase__________50_Hz_version__________60_Hz_Version_______
Vsync 8 lines (248..255) 8 lines (224..231)
Upper Border 56 lines (256..311) 32 lines (232..263)
Picture 192 lines (0..191) 192 lines (0..191)
Lower Border 56 lines (192..247) 32 lines (192..223)
Total 312 lines (0..311) 264 lines (0..311)
</TD></TR></TABLE>Note: There are separate mainboards for 50Hz/60Hz (ie. the framerate isn't
software selectable).<BR>
<BR>
<B>VSYNC Interrupt</B><BR>
The default interrupt handler at 0038h isn't too useful, however, one can put
a custom IM2 interrupt handler in RAM. The Z80's /INT pin is wired directly
to /VSYNC. This implies two problems:<BR>
1) The /VSYNC signal is LOW for 8 scanlines (1664 cycles), so, the IRQ
handler should not re-enable IRQs during that period (otherwise the same
interrupt would be executed another time). If necessary include a 1664-cycle
delay in the IRQ handler, or return without enabling IRQs.<BR>
2) For flicker/waitstate-free drawing, it'd be ideal to access VRAM during
VBLANK, but since /INT is generated on VSYNC rather than VBLANK, one can use
only little more than half of the VBLANK periond.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="jupiteracememorymapandsystemarea"></A><FONT SIZE=+2>&nbsp;Jupiter ACE Memory Map and System Area</FONT></TD></TR></TABLE><BR>
<B>Jupiter ACE Memory Map</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0000h-1FFFh R BIOS ROM (8K) (FORTH Interpreter)
2000h-23FFh R/W VRAM BgMap/Pad with CPU priority (video DMA shows garbage)
2400h-27FFh R/W VRAM BgMap/Pad with DMA priority (CPU gets paused by /WAIT)
2800h-2BFFh W VRAM Charset with CPU priority (video DMA shows garbage)
2C00h-2FFFh W VRAM Charset with DMA priority (CPU gets paused by /WAIT)
3000h R/W Unused (mirrors of 1K Work RAM)
3C00h R/W Work RAM (1K)
4000h-FFFFh R/W Expansion RAM (or open-bus if none such)
</TD></TR></TABLE>The total amount of internal RAM is 3K (the CPU/DMA priority regions mirror
to a single 1K VRAM block).<BR>
Note: BgMap/Pad contains 300h bytes BgMap, followed by 100h bytes Pad (the
Pad is used to HOLD characters during formatted output, and to store
filenames and fileheaders during load/save).<BR>
<BR>
<B>Jupiter ACE System Area</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> FP_WS 3C00h 19 Workspace for floating point arithmetic
LISTWS 3C13h 5 Workspace for 'LIST' and 'EDIT'
RAMTOP 3C18h 2 Work RAM End Address (4000h=1K, 8000h=17K, 0000h=49K)
HLD 3C1Ah 2 VRAM PAD Address of the latest character held in the pad by
formatted output ('#', 'HOLD' and so on)
SCRPOS 3C1Ch 2 VRAM Output Address: location of next char to be printed
INSCRN 3C1Eh 2 VRAM InputBuf Address: start of current logical line
CURSOR 3C20h 2 VRAM InputBuf Address: cursor addresss in input buffer
ENDBUF 3C22h 2 VRAM InputBuf Address: end of current logical line
L_HALF 3C24h 2 VRAM InputBuf Address: input buffer start (ends at 26FFh)
KEYCOD 3C26h 1 Keyboard ASCII code of the last key pressed (00h=none)
KEYCNT 3C27h 1 Keyboard Debounce counter (key accept and repeat delay)
STATIN 3C28h 1 Keyboard Flags (0=newkey,1=caps,2=graph,3=invert,5=enter)
EXWRCH 3C29h 2 Address of print chr(A) routine (or 0000h=print to screen)
FRAMES 3C2Bh 4 Frames counter (number of /VSYNC interrupts since power-on)
XCOORD 3C2Fh 1 PLOT last used x-coordinate
YCOORD 3C30h 1 PLOT last used y-coordinate
CURRENT 3C31h 2 Vocabulary Address of CURRENT vocabulary
CONTEXT 3C33h 2 Vocabulary Address of CONTEXT vocabulary
VOCLNK 3C35h 2 Vocabulary Address of NEWEST vocabulary (plus 3)
STKBOT 3C37h 2 Work RAM Address of End of Dictionary / Start of Stack
DICT 3C39h 2 Work RAM Address of the (still undefined) length field of
the newest word in the dictionary (once when that length
field is correctly filled in then DICT may be 0000h)
SPARE 3C3Bh 2 Work RAM Address of first byte past top of the FORTH stack
ERR_NO 3C3Dh 1 Error code (FFh=no error) (ERROR shown on ABORT if bit7=0)
FLAGS 3C3Eh 1 Flags...
Bit2 incomplete definition at the end of the dictionary
Bit3 output is to be fed into the input buffer
Bit4 the Ace is in invisible mode
Bit6 the Ace is in compile (editing) mode
BASE 3C3Fh 1 The system number base (default is 0Ah=decimal)
3C40h 5 FORTH name string "FORTH"+80h
3C45h 2 FORTH disp to next word (or 0000h if no next)
3C47h 2 FORTH ptr to 1FFFh in ROM (links to ROM words)
3C49h 1 FORTH length of "FORTH" name at 3C40h (ie. =05h)
3C4Ah 2 FORTH ptr to 11B5h in ROM (vocabulary handler)
3C4Ch 2 FORTH ptr to next word in chain (or to 3C49h if none)
3C4Eh 1 FORTH unknown/unused (usually 00h)
3C4Fh 2 FORTH ptr to previous vocabulary (always 0000h=none)
3C51h .. user dictionary
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="jupiteracefiles"></A><FONT SIZE=+2>&nbsp;Jupiter ACE Files</FONT></TD></TR></TABLE><BR>
<B>Forth File Headers</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Pre 1 Blocktype (00h=Header)
00h 1 Filetype (00h=Forth)
01h 10 Filename (ASCII, padded with spaces) (chr 00h = no name)
0Bh 2 Filesize (LEN=STKBOT-3C51h)
0Dh 2 Unused (usually 3C51h, dictionary start address)
0Fh 2 Offset to newest word at end of file (relative to 3C51h)
11h 2 Unused (usually 3C4Ch, CURRENT vocabulary)
13h 2 Unused (usually 3C4Ch, CONTEXT vocabulary)
15h 2 Unused (usually 3C4Fh, NEWEST vocabulary+3)
17h 2 Unused (usually 3C51h+filesize, STKBOT)
Post 1 Chksum [00h..18h] XORed together (unlike Spectrum without Blocktype)
</TD></TR></TABLE>The file body is loaded to the begin of free memory (3C51h when memory is
empty). Addresses inside of the file body are relative to 3C51h (if the file
is loaded to a higher memory location, then the addresses are increased
accordingly).<BR>
<BR>
<B>Binary File Header</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Pre 1 Blocktype (00h=Header)
00h 1 Filetype (20h=Binary)
01h 10 Filename (ASCII, padded with spaces) (chr 00h = no name)
0Bh 2 Filesize (LEN)
0Dh 2 Fileaddr (Default target address, used when desired target=0)
0Fh 10 Unused (filled with spaces)
Post 1 Chksum [00h..18h] XORed together (unlike Spectrum without Blocktype)
</TD></TR></TABLE><BR>
<B>File Body</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Pre 1 Blocktype (FFh=Body)
00h LEN Forth stuff (starting with 1st word name) / Binary Data
Post 1 Chksum [00h..LEN-1] XORed together (unlike Spectrum without Blktyp)
</TD></TR></TABLE><BR>
<B>Cassette Signals</B><BR>
The overall format is nearly identical to ZX Spectrum. On the ACE, the Chksum
doesn't include the Blocktype byte. The bit-encoding and various pilot/data
pulse timings are identical as on spectrum (+/- 5 us or so, which can be
ignored). The number of Pilot pulses is slightly different (8192 for header,
1024 for data) (on Spectrum it's 8063 for Header, and 3223 for Data).<BR>
<BR>
<B>.TAP Images</B><BR>
Jupiter ACE cassette images are stored in .TAP files, using the same
extension, and (almost) the same format as ZX Spectrum .TAP files - the
difference is that Jupiter ACE images do not contain Blocktype bytes
(software must insert the missing byles: toggle between FFh or 00h on each
second block). Most or all .TAP images are starting with a header block, so
the first 2 bytes in the file should be 0019h for Jupiter ACE, and 0013h for
ZX Spectrum.<BR>
<BR>
<B>Forth Word Definitions</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Pos Len Content
-N .. word name in ASCII (terminated by bit7=1 in last char)
-4 2 disp from current addr to NEXT &lt;word name&gt; (RAM words only, not ROM)
-2 2 ptr to PREVIOUS word definition
+0 1 length of word name (up to including the last char with bit7=1)
+1 2 ptr to Z80 machine code handler for this word (usually to ROM)
+3 .. whatever, probably TYPE and definition...
</TD></TR></TABLE><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 3C40h 5 FORTH name string "FORTH"+80h
3C45h 2 FORTH disp to next word (or 0000h if no next)
3C47h 2 FORTH ptr to 1FFFh in ROM (links to ROM words)
3C49h 1 FORTH length of "FORTH" name at 3C40h (ie. =05h)
3C4Ah 2 FORTH ptr to 11B5h in ROM
3C4Ch 2 FORTH ptr to next word in chain (or to 3C49h if none)
</TD></TR></TABLE><BR>
<B>Starting files</B><BR>
There is no (intended) autostart mechanism provided. The normal way to load
and start ACE files is bizarre and usually requires detailed loading
instructions: One must know both the name of the file, and name of its "main"
function, in some cases one must also manually execute initialization
functions. For example Jupiter Cantab's "Worms" is - seriously - meant to be
started like so:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> LOAD worms GET graphics GO
</TD></TR></TABLE>If the names are unknown one can do: To discover file names: Type &lt;LOAD
dummy&gt;, watch the first filename listed on screen, rewind tape, type &lt;LOAD
filename&gt;.<BR>
To discover function names: Type VLIST, watch the function/variable names
(watch quickly - before they get scrolled offscreen). Then try typing some of
the names, hoping that it's the main function (variables will produce errors,
subfunctions may act useless) (to start with: &lt;FILENAME&gt;, GO, RUN, PLAY,
START, MAIN, GAME, etc. would be possible candidates) (some programs may have
multiple main funtions, eg. PLAY/HELP, or PLAY_EASY/PLAY_DIFFICULT).<BR>
<BR>
<B>Empty Filenames</B><BR>
The BIOS doesn't allow to SAVE something without filenames, however, it can
LOAD such files (so, with suitable tools, one can create files with empty,
space-padded filenames). There is no "wildcard" to LOAD the first file on
tape, so - unless it's empty - the user must always type-in the filename.<BR>
<BR>
<B>Autostarting Files</B><BR>
There are two ways to autostart binary files by just typing "0 0 BLOAD" (or
"0. BLOAD"):<BR>
1) Load the entrypoint to EXWRCH in system area (EXWRCH gets executed almost
immediately after loading when the BIOS wants to display "OK"). This method
is best for machine code.<BR>
2) Load a commandline string into the Input Buffer in VRAM (ie. load
&lt;00h,"LOAD filename mainfunction"&gt; to address 22E0h). This method is best for
FORTH programs, and existing (older) files which originally didn't include
autostart.<BR>
The VRAM method is used by Spacefighter (also loads a picture into VRAM
alongside with the commandline). The EXWRCH method is used by Magic Floor.<BR>
Autostarting works only with BLOAD, not with LOAD (the FORTH fileheader
doesn't include any useful entries; the relocation feature could be tweaked
to add an offset to whatever memory locations, but that offset is usually
0000h, so it'd be useless).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="forthoverview"></A><FONT SIZE=+2>&nbsp;FORTH Overview</FONT></TD></TR></TABLE><BR>
<B>Stack</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Stack Notation Cells Description
c 1 Character (high byte ignored)
flag 1 Boolean (0 = False, 1 = True)
n 1 Signed 16bit number
u 1 Unsigned 16bit number
x 1 Non-specific 16bit number
adr 1 Memory address (16bit)
d 2 Signed 32bit double number
ud 2 Unsigned 32bit double number
xd 2 Non-specific 32bit number
f 2 Floating point 32bit number
</TD></TR></TABLE>Each stack cell is 16bit wide, the cells do not contain type information, so
the programmer must take care to use the correct commands on each cell.<BR>
<BR>
<B>Word definitions</B><BR>
Defining a word (a procedure, variable, etc.) doesn't erase old words with
the same name, same applies when LOADing words from tape. So, it can happen
that a word is defined multiple times, of which, fortran will "see" the
newest definition; one can also make "newer" definitions of the predefined
ROM words.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="forthstackandmemory"></A><FONT SIZE=+2>&nbsp;FORTH Stack and Memory</FONT></TD></TR></TABLE><BR>
<B>Stack Manipulation</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> x (--&gt; x) Store 16bit immediate on stack (eg. 1)
f (--&gt; f) Store float immediate on stack (eg. 1.0)
DROP (x --&gt;) Discard TOS (top of stack)
DUP (x --&gt; x x) Copy 1st cell to top (Duplicate TOS)
OVER (x2 x1 --&gt; x2 x1 x2) Copy 2nd cell to top
PICK (xn..x1 n --&gt; xn..x1 xn) Copy nth cell to top
SWAP (x2 x1 --&gt; x1 x2) Rotate 2nd cell to top
ROT (x3 x2 x1 --&gt; x2 x1 x3) Rotate 3rd cell to top
ROLL (xn..x1 n --&gt; xn-1..x1 xn) Rotate nth cell to top
?DUP (x --&gt; x (x)) Conditional DUP, only if x = non-zero
&gt;R (x --&gt;) (R: --&gt; x) Move TOS to Return Stack
R&gt; (R: x --&gt;) (--&gt; x) Retrieve from Return Stack
</TD></TR></TABLE><BR>
<B>Memory</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> @ (adr --&gt; x) Read x (2 bytes) from adr
! (x adr --&gt;) Store x (2 bytes) to adr
C@ (adr --&gt; c) Read c (1 byte) from adr
C! (c adr --&gt;) Store c (1 byte) to adr
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="forthmaths"></A><FONT SIZE=+2>&nbsp;FORTH Maths</FONT></TD></TR></TABLE><BR>
<B>Integer Arithmetic</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> + (n1 n2 --&gt; n3) n3 = n1 + n2
- (n1 n2 --&gt; n3) n3 = n1 - n2
* (n1 n2 --&gt; n3) n3 = n1 * n2
/ (n1 n2 --&gt; n3) n4 = n1 / n2
MOD (n1 n2 --&gt; n3) Remainder of n1 / n2 (sign of n1)
/MOD (n1 n2 --&gt; n3 n4) n3 = remainder of n1/n2, n4=n1/n2
*/ (n1 n2 n3 --&gt; n4) n4 = n1*n2/n3
*/MOD (n1 n2 n3 --&gt; n4 n5) n4 = remainder of n1*n2/n3, n5=n1*n2/n3
1+ (n1 --&gt; n2) n2 = n1 + 1
1- (n1 --&gt; n2) n2 = n1 - 1
2+ (n1 --&gt; n2) n2 = n1 + 2
2- (n1 --&gt; n2) n2 = n1 - 2
ABS (n --&gt; u) u = |n| (absolute value)
NEGATE (n1 --&gt; n2) n2 = -n1 (two's complement)
U* (u1 u2 --&gt; ud) ud = u1 * u2
U/MOD (ud u1 --&gt; u2 u3) u2 = remainder of ud/u1, u3 = ud/u1
D+ (d1 d2 --&gt; d3) d3 = d1 + d2
DNEGATE (d1 --&gt; d2) d2 = -d1 (two's complement)
</TD></TR></TABLE><BR>
<B>Floating Point Arithmetic</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> INT (f --&gt; n) Convert floating number to integer
UFLOAT (u --&gt; f) Convert unsigned integer to float
F+ (f1 f2 --&gt; f3) f3 = f1 + f2
F- (f1 f2 --&gt; f3) f3 = f1 - f2
F* (f1 f2 --&gt; f3) f3 = f1 * f2
F/ (f1 f2 --&gt; f3) f3 = f1 / f2
FNEGATE (f1 --&gt; f2) f2 = -f1
</TD></TR></TABLE><BR>
<B>Comparison</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> &lt; (n1 n2 --&gt; flag) True if n1 &lt; n2
= (n1 n2 --&gt; flag) True if n1 = n2
&gt; (n1 n2 --&gt; flag) True if n1 &gt; n2
0&lt; (n --&gt; flag) True if n &lt; 0
0= (n --&gt; flag) True if n = 0
0&gt; (n --&gt; flag) True if n &gt; 0
U&lt; (u1 u2 --&gt; flag) True if u1 &lt; u2
D&lt; (d1 d2 --&gt; flag) True if d1 &lt; d2
MAX (n1 n2 --&gt; n3) Leave greater of two numbers
MIN (n1 n2 --&gt; n3) Leave lesser of two numbers
</TD></TR></TABLE><BR>
<B>Logical</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> AND (x1 x2 --&gt; x3) Bitwise boolean AND
OR (x1 x2 --&gt; x3) Bitwise boolean OR
XOR (x1 x2 --&gt; x3) Bitwise boolean XOR
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="forthinputoutput"></A><FONT SIZE=+2>&nbsp;FORTH Input/Output</FONT></TD></TR></TABLE><BR>
<B>Character Output</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> CR (--&gt;) Print carriage return and line feed
EMIT (c --&gt;) Print ASCII character c
SPACE (--&gt;) Print one space
SPACES (n --&gt;) Print n spaces, if n &gt; 0
." ..." (--&gt;) Print string terminated by " (." 123 test")
TYPE (adr n --&gt;) Print n characters from adr
</TD></TR></TABLE><BR>
<B>Number Output</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> . (n --&gt;) Print n with one trailing space
U. (u --&gt;) Print unsigned with one trailing space
F. (f --&gt;) Print float with one trailing space
</TD></TR></TABLE><BR>
<B>Formatted Output</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> &lt;# (--&gt;) Initiate formatted output
# (ud1 --&gt; ud2) Convert one digit from ud1 and HOLD it in the PAD
#S (ud --&gt; 0 0) Convert and HOLD all remaining significant digits
HOLD (c --&gt;) Insert character into formatted string
SIGN (n --&gt;) HOLD minus sign if n &lt; 0
#&gt; (ud --&gt; adr n) Finish formatted output leaving address & length
of the resulting string
</TD></TR></TABLE><BR>
<B>Conversion</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> BASE (--&gt; adr) 1-byte variable containing system number base
DECIMAL (--&gt;) Set base to decimal
ASCII text (--&gt; c) ASCII code of first character in text
</TD></TR></TABLE><BR>
<B>Character Input</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> QUERY (--&gt;) Accept entry at the input buffer
WORD (c --&gt; adr) Take text from input buffer using c
as delimiter, leave adr of length byte
RETYPE ( --&gt; ) Allow input buffer editing, turning cursor to "?"
INKEY (--&gt; x) Read keyboard (0 = no key pressed)
</TD></TR></TABLE><BR>
<B>Number Input</B><BR>
<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> CONVERT (d1 adr1 --&gt; d2 adr2) Convert string at adr1 to double number
and add into d1 leaving result d2
NUMBER (--&gt; x (adr)) Get number from input buffer
(--&gt; n 4102) Converted to integer
(--&gt; f 4181) Converted to float
(--&gt; 0) Conversion failed
</TD></TR></TABLE><BR>
<B>Misc Screen Output</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> CLS (--&gt;) Clear screen
AT (n1 n2 --&gt;) Set print position to row n1 and column n2
PLOT (n1 n2 n3 --&gt;) Plot X=n1,Y=n2,Mode=n3 (0=unplot,1=plot,2=move,3=change)
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="forth"></A><FONT SIZE=+2>&nbsp;FORTH ....</FONT></TD></TR></TABLE><BR>
<B>Control Structures</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> IF (flag --&gt;) Conditional structure IF..(ELSE)..THEN
ELSE (--&gt;) False condition of an IF structure
THEN (--&gt;) End of an IF conditional structure
DO (n1 n2 --&gt;) Counted loop structure DO...LOOP, (n2=start, n1=end)
LOOP (--&gt;) Increment loop count, terminate if end
+LOOP (n --&gt;) Add n to loop count, terminate if end
I (--&gt; n) Get current loop count
I' (--&gt; n) Get current loop count limit
J (--&gt; n) Get outer loop count
LEAVE (--&gt;) Force a DO...LOOP count to end
BEGIN (--&gt;) Begin a WHILE or UNTIL loop
UNTIL (flag --&gt;) Loop until flag = true (BEGIN..UNTIL)
WHILE (flag --&gt;) Exit loop when flag = false (BEGIN..WHILE..REPEAT)
REPEAT (--&gt;) Jump back to BEGIN in a WHILE loop
EXIT ( --&gt; ) Exit current word execution
EXECUTE (adr --&gt;) Execute word with compilation adr
CALL (adr --&gt;) Call Z80 code (terminated with JP IY) (not by RET)
ABORT (... --&gt;) Quit program, clearing data stack
QUIT (--&gt;) Quit program, not clearing data stack
</TD></TR></TABLE><BR>
<B>Word Definition</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> : pname ... ; (--&gt;) Define a procedure (terminated by semicolon)
VARIABLE vname (x --&gt;) Define a variable with initial value x
CONSTANT cname (x --&gt;) Define a constant with constant value x
CREATE aname (--&gt;) Define an (empty) array (usually followed by ALLOT)
ALLOT (n --&gt;) Allocate n bytes at end of newest word (see CREATE)
vname (--&gt; adr) Get variable adr (eg. "vname @" to get its value)
aname (--&gt; adr) Get array address
cname (--&gt; x) Get constant value
pname (--&gt;) Call a procedure
IMMEDIATE (--&gt;) Make newest word to execute even in compile mode
DEFINER word (--&gt;) Start a defining word definition
DOES&gt; (--&gt; adr) Define the action routine of a defining word
COMPILER word (n --&gt;) Start a compiling word definition (and ALLOT n)
RUNS&gt; (--&gt; adr) Defines the action routine of a compiling word
FIND word (--&gt; adr) Find word compilation address (0 if not found)
LIST word (--&gt;) List word definition
EDIT word (--&gt;) Edit word definition (doesn't delete old word)
FORGET name (--&gt;) Delete &lt;name&gt; as well as ALL newer words
REDEFINE name (--&gt;) Delete old &lt;name&gt; and replace it by newest word
</TD></TR></TABLE><BR>
<B>Vocabulary</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> VOCABULARY dname (--&gt;) Define a new vocabulary
dname (--&gt;) Set CONTEXT to the &lt;dname&gt; vocabulary
FORTH (--&gt;) Set CONTEXT to the FORTH vocabulary
DEFINITIONS (--&gt;) Set CURRENT vocabulary to CONTEXT
CONTEXT (--&gt; adr) Get current word search vocabulary address ;3C33h
CURRENT (--&gt; adr) Get current word definition vocabulary addr ;3C31h
VLIST (--&gt;) List dictionary to screen (press BREAK to stop it)
</TD></TR></TABLE><BR>
<B>Compiler</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> , (x --&gt;) Compile x into dictionary (ALLOT 2 byte, set to x)
C, (c --&gt;) Compile c into dictionary (ALLOT 1 byte, set to c)
LITERAL (x --&gt;) Compile x into edited procedure (preceed by [ x ])
[ ... ] (... --&gt;) Force ... to be interpreted (even during EDITing)
</TD></TR></TABLE><BR>
<B>Miscellaneous</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> ( ...) (--&gt;) Start a comment, terminated by ")"
HERE (--&gt; adr) Next available dictionary location, ie. [STKBOT]
PAD (--&gt; adr) Scratch pad area address (2701h aka 9985)
SLOW (--&gt;) Normal execution. Enable error checks
FAST (--&gt;) Faster execution. Disable error checks (and BREAK-key ?)
BEEP (u1 u2 --&gt;) Play tone, u1=1000000/(8*freq [Hz]), u2=duration [ms]
IN (adr --&gt; c) Read byte from Z80 input port adr
OUT (c adr --&gt;) Write byte to Z80 output port adr
INVIS (--&gt;) Disable copy-up mechanism and OK
VIS (--&gt;) Enable copy-up mechanism and OK
LINE (--&gt;) Interpret the input buffer as FORTH
</TD></TR></TABLE><BR>
<B>Tape Files</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> LOAD name (--&gt;) Load vocabulary ;\lists all filenames
VERIFY name (--&gt;) Verify vocabulary ;/when no name typed
SAVE name (--&gt;) Save vocabulary
BLOAD name (adr u --&gt;) Load u bytes to adr ;\use file header value(s)
BVERIFY name (adr u --&gt;) Verify u bytes from adr ;/when adr=0 or u=0
BSAVE name (adr u --&gt;) Save u bytes from adr
</TD></TR></TABLE>filenames are case sensitive, length must be 1-10 characters, may not include
space characters.<BR>
CAUTION: The filenames are ALWAYS taken from the input buffer - that means
one cannot specify filenames inside of procedures (unless the procedure
'pokes' the filename into the input buffer in VRAM before executing a
cassette command).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="fortherrorcodes"></A><FONT SIZE=+2>&nbsp;FORTH Error Codes</FONT></TD></TR></TABLE><BR>
<B>Error Codes</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 Not enough memory
2 Data Stack Underflow
3 BREAK pressed
4 Compile only word
5 Structure imbalance
6 Name size &lt; 1 or &gt; 64
7 PICK or ROLL operand = 0
8 Floating point overflow
9 AT or PLOT to the input buffer
10 Tape error
11 REDEFINE or FORGET error
12 Incomplete definition in dictionary
13 Word not found or is ROM or is FORTH
14 Word not Listable
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="z80cpuspecifications"></A><FONT SIZE=+2>&nbsp;Z80 CPU Specifications</FONT></TD></TR></TABLE><BR>
<A HREF="#z80registerset">Z80 Register Set</A><BR>
<A HREF="#z80flags">Z80 Flags</A><BR>
<A HREF="#z80instructionformat">Z80 Instruction Format</A><BR>
<A HREF="#z80loadcommands">Z80 Load Commands</A><BR>
<A HREF="#z80arithmeticlogicalcommands">Z80 Arithmetic/Logical Commands</A><BR>
<A HREF="#z80rotateshiftandsinglebitoperations">Z80 Rotate/Shift and Singlebit Operations</A><BR>
<A HREF="#z80jumpcommandsinterrupts">Z80 Jumpcommands & Interrupts</A><BR>
<A HREF="#z80iocommands">Z80 I/O Commands</A><BR>
<A HREF="#z80interrupts">Z80 Interrupts</A><BR>
<A HREF="#z80meaninglessandduplicatedopcodes">Z80 Meaningless and Duplicated Opcodes</A><BR>
<A HREF="#z80garbageinflagregister">Z80 Garbage in Flag Register</A><BR>
<A HREF="#z80compatibility">Z80 Compatibility</A><BR>
<A HREF="#z80pinouts">Z80 Pin-Outs</A><BR>
<A HREF="#z80localusage">Z80 Local Usage</A><BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="z80registerset"></A><FONT SIZE=+2>&nbsp;Z80 Register Set</FONT></TD></TR></TABLE><BR>
<B>Register Summary</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 16bit Hi Lo Name/Function
---------------------------------------
AF A - Accumulator & Flags
BC B C BC
DE D E DE
HL H L HL
AF' - - Second AF
BC' - - Second BC
DE' - - Second DE
HL' - - Second HL
IX IXH IXL Index register 1
IY IYH IYL Index register 2
SP - - Stack Pointer
PC - - Program Counter/Pointer
- I R Interrupt & Refresh
</TD></TR></TABLE><BR>
<B>Normal 8bit and 16bit Registers</B><BR>
The Accumulator (A) is the allround register for 8bit operations.
Registers B, C, D, E, H, L are normal 8bit registers, which can be also
accessed as 16bit register pairs BC, DE, HL.<BR>
The HL register pair is used as allround register for 16bit operations.
B and BC are sometimes used as counters. DE is used as DEstination
pointer in block transfer commands.<BR>
<BR>
<B>Second Register Set</B><BR>
The Z80 includes a second register set (AF',BC',DE',HL') these
registers cannot be accessed directly, but can be exchanged with the
normal registers by using the EX AF,AF and EXX instructions.<BR>
<BR>
<B>Refresh Register</B><BR>
The lower 7 bits of the Refresh Register (R) are incremented with every
instruction. Instructions with at least one prefix-byte (CB,DD,ED,FD, or
DDCB,FDCB) will increment the register twice. Bit 7 can be used by
programmer to store data. Permanent writing to this register will
suppress memory refresh signals, causing Dynamic RAM to lose data.<BR>
<BR>
<B>Interrupt Register</B><BR>
The Interrupt Register (I) is used in interrupt mode 2 only (see command
"im 2"). In other modes it can be used as simple 8bit data register.<BR>
<BR>
<B>IX and IY Registers</B><BR>
IX and IY are able to manage almost all the things that HL is able to
do. When used as memory pointers they are additionally including a
signed index byte (IX+d). The disadvantage is that the opcodes occupy
more memory bytes, and that they are less fast than HL-instructions.<BR>
<BR>
<B>Undocumented 8bit Registers</B><BR>
IXH, IXL, IYH, IYL are undocumented 8bit registers which can be used to
access high and low bytes of the IX and IY registers (much like H and L
for HL). Even though these registers do not officially exist, they seem
to be available in all Z80 CPUs, and are quite commonly used by various
software.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="z80flags"></A><FONT SIZE=+2>&nbsp;Z80 Flags</FONT></TD></TR></TABLE><BR>
<B>Flag Summary</B><BR>
The Flags are located in the lower eight bits of the AF register pair.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bit Name Set Clr Expl.
0 C C NC Carry Flag
1 N - - Add/Sub-Flag (BCD)
2 P/V PE PO Parity/Overflow-Flag
3 - - - Undocumented
4 H - - Half-Carry Flag (BCD)
5 - - - Undocumented
6 Z Z NZ Zero-Flag
7 S M P Sign-Flag
</TD></TR></TABLE><BR>
<B>Carry Flag (C)</B><BR>
This flag signalizes if the result of an arithmetic operation exceeded
the maximum range of 8 or 16 bits, ie. the flag is set if the result was
less than Zero, or greater than 255 (8bit) or 65535 (16bit). After
rotate/shift operations the bit that has been 'shifted out' is stored in
the carry flag.<BR>
<BR>
<B>Zero Flag (Z)</B><BR>
Signalizes if the result of an operation has been zero (Z) or not zero
(NZ). Note that the flag is set (1) if the result was zero (0).<BR>
<BR>
<B>Sign Flag (S)</B><BR>
Signalizes if the result of an operation is negative (M) or positive
(P), the sign flag is just a copy of the most significant bit of the
result.<BR>
<BR>
<B>Parity/Overflow Flag (P/V)</B><BR>
This flag is used as Parity Flag, or as Overflow Flag, or for other
purposes, depending on the instruction.<BR>
Parity: Bit7 XOR Bit6 XOR Bit5 ... XOR Bit0 XOR 1.<BR>
8bit Overflow: Indicates if the result was greater/less than +127/-128.<BR>
HL Overflow: Indicates if the result was greater/less than +32767/-32768.<BR>
After LD A,I or LD A,R: Contains current state of IFF2.<BR>
After LDI,LDD,CPI,CPD,CPIR,CPDR: Set if BC&lt;&gt;0 at end of operation.<BR>
<BR>
<B>BCD Flags (H,N)</B><BR>
These bits are solely supposed to be used by the DAA instruction. The N
flag signalizes if the previous operation has be an addition or
substraction. The H flag indicates if the lower 4 bits exceeded the
range from 0-0Fh. (For 16bit instructions: H indicates if the lower 12
bits exceeded the range from 0-0FFFh.)<BR>
After adding/subtracting two 8bit BCD values (0-99h) the DAA instruction
can be used to convert the hexadecimal result in the A register (0-FFh)
back to BCD format (0-99h). Note that DAA also requires the carry flag
to be set correctly, and thus should not be used after INC A or DEC A.<BR>
<BR>
<B>Undocumented Flags (Bit 3,5)</B><BR>
The content of these undocumented bits is filled by garbage by all
instructions that affect one or more of the normal flags (for more info
read the chapter Garbage in Flag Register), the only way to read out
these flags would be to copy the flags register onto the stack by using
the PUSH AF instruction.<BR>
However, the existence of these bits makes the AF register a full 16bit
register, so that for example the code sequence PUSH DE, POP AF, PUSH
AF, POP HL would set HL=DE with all 16bits intact.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="z80instructionformat"></A><FONT SIZE=+2>&nbsp;Z80 Instruction Format</FONT></TD></TR></TABLE><BR>
<B>Commands and Parameters</B><BR>
Each instruction consists of a command, and optionally one or two
parameters. Usually the leftmost parameter is modified by the operation
when two parameters are specified.<BR>
<BR>
<B>Parameter Placeholders</B><BR>
The following placeholders are used in the following chapters:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> r 8bit register A,B,C,D,E,H,L
rr 16bit register BC, DE, HL/IX/IY, AF/SP (as described)
i 8bit register A,B,C,D,E,IXH/IYH,IXL/IYL
ii 16bit register IX,IY
n 8bit immediate 00-FFh (unless described else)
nn 16bit immediate 0000-FFFFh
d 8bit signed offset -128..+127
f flag condition nz,z,nc,c AND/OR po,pe,p,m (as described)
(..) 16bit pointer to byte/word in memory
</TD></TR></TABLE><BR>
<B>Opcode Bytes</B><BR>
Each command (including parameters) consists of 1-4 bytes. The
respective bytes are described in the following chapters. In some cases
the register number or other parameters are encoded into some bits of
the opcode, in that case the opcode is specified as "xx". Opcode prefix
bytes "DD" (IX) and "FD" (IY) are abbreviated as "pD".<BR>
<BR>
<B>Clock Cycles</B><BR>
The clock cycle values in the following chapters specify the execution
time of the instruction. For example, an 8-cycle instruction would take
2 microseconds on a CPU which is operated at 4MHz (8/4 ms). For
conditional instructions two values are specified, for example, 17;10
means 17 cycles if condition true, and 10 cycles if false.<BR>
Note that in case that WAIT signals are sent to the CPU by the hardware
then the execution may take longer.<BR>
<BR>
<B>Affected Flags</B><BR>
The instruction tables below are including a six character wide field
for the six flags: Sign, Zero, Halfcarry, Parity/Overflow, N-Flag, and
Carry (in that order). The meaning of the separate characters is:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> s Indicates Signed result
z Indicates Zero
h Indicates Halfcarry
o Indicates Overflow
p Indicates Parity
c Indicates Carry
- Flag is not affected
0 Flag is cleared
1 Flag is set
x Flag is destroyed (unspecified)
i State of IFF2
e Indicates BC&lt;&gt;0 for LDX(R) and CPX(R), or B=0 for INX(R) and OUTX(R)
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="z80loadcommands"></A><FONT SIZE=+2>&nbsp;Z80 Load Commands</FONT></TD></TR></TABLE><BR>
<B>8bit Load Commands</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Instruction Opcode Cycles Flags Notes
ld r,r xx 4 ------ r=r
ld i,i pD xx 8 ------ i=i
ld r,n xx nn 7 ------ r=n
ld i,n pD xx nn 11 ------ i=n
ld r,(HL) xx 7 ------ r=(HL)
ld r,(ii+d) pD xx dd 19 ------ r=(ii+d)
ld (HL),r 7x 7 ------ (HL)=r
ld (ii+d),r pD 7x dd 19 ------
ld (HL),n 36 nn 10 ------
ld (ii+d),n pD 36 dd nn 19 ------
ld A,(BC) 0A 7 ------
ld A,(DE) 1A 7 ------
ld A,(nn) 3A nn nn 13 ------
ld (BC),A 02 7 ------
ld (DE),A 12 7 ------
ld (nn),A 32 nn nn 13 ------
ld A,I ED 57 9 sz0i0- A=I ;Interrupt Register
ld A,R ED 5F 9 sz0i0- A=R ;Refresh Register
ld I,A ED 47 9 ------
ld R,A ED 4F 9 ------
</TD></TR></TABLE><BR>
<B>16bit Load Commands</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Instruction Opcode Cycles Flags Notes
ld rr,nn x1 nn nn 10 ------ rr=nn ;rr may be BC,DE,HL or SP
ld ii,nn pD 21 nn nn 13 ------ ii=nn
ld HL,(nn) 2A nn nn 16 ------ HL=(nn)
ld ii,(nn) pD 2A nn nn 20 ------ ii=(nn)
ld rr,(nn) ED xB nn nn 20 ------ rr=(nn) ;rr may be BC,DE,HL or SP
ld (nn),HL 22 nn nn 16 ------ (nn)=HL
ld (nn),ii pD 22 nn nn 20 ------ (nn)=ii
ld (nn),rr ED x3 nn nn 20 ------ (nn)=rr ;rr may be BC,DE,HL or SP
ld SP,HL F9 6 ------ SP=HL
ld SP,ii pD F9 10 ------ SP=ii
push rr x5 11 ------ SP=SP-2, (SP)=rr ;rr may be BC,DE,HL,AF
push ii pD E5 15 ------ SP=SP-2, (SP)=ii
pop rr x1 10 (-AF-) rr=(SP), SP=SP+2 ;rr may be BC,DE,HL,AF
pop ii pD E1 14 ------ ii=(SP), SP=SP+2
ex DE,HL EB 4 ------ exchange DE &lt;--&gt; HL
ex AF,AF 08 4 xxxxxx exchange AF &lt;--&gt; AF'
exx D9 4 ------ exchange BC,DE,HL &lt;--&gt; BC',DE',HL'
ex (SP),HL E3 19 ------ exchange (SP) &lt;--&gt; HL
ex (SP),ii pD E3 23 ------ exchange (SP) &lt;--&gt; ii
</TD></TR></TABLE><BR>
<B>Blocktransfer</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Instruction Opcode Cycles Flags Notes
ldi ED A0 16 --0e0- (DE)=(HL), HL=HL+1, DE=DE+1, BC=BC-1
ldd ED A8 16 --0e0- (DE)=(HL), HL=HL-1, DE=DE-1, BC=BC-1
ldir ED B0 bc*21-5 --0?0- ldi-repeat until BC=0
lddr ED B8 bc*21-5 --0?0- ldd-repeat until BC=0
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="z80arithmeticlogicalcommands"></A><FONT SIZE=+2>&nbsp;Z80 Arithmetic/Logical Commands</FONT></TD></TR></TABLE><BR>
<B>8bit Arithmetic/Logical Commands</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Instruction Opcode Cycles Flags Notes
daa 27 4 szxp-x decimal adjust akku
cpl 2F 4 --1-1- A = A xor FF
neg ED 44 8 szho1c A = 00-A
&lt;arit&gt; r xx 4 szhonc see below
&lt;arit&gt; i pD xx 8 szhonc see below, UNDOCUMENTED
&lt;arit&gt; n xx nn 7 szhonc see below
&lt;arit&gt; (HL) xx 7 szhonc see below
&lt;arit&gt; (ii+d) pD xx dd 19 szhonc see below
&lt;cnt&gt; r xx 4 szhon- see below
&lt;cnt&gt; i pD xx 8 szhon- see below, UNDOCUMENTED
&lt;cnt&gt; (HL) xx 11 szhon- see below
&lt;cnt&gt; (ii+d) pD xx dd 23 szhon- see below
&lt;logi&gt; r xx 4 szhp00 see below
&lt;logi&gt; i pD xx 8 szhp00 see below, UNDOCUMENTED
&lt;logi&gt; n xx nn 7 szhp00 see below
&lt;logi&gt; (HL) xx 7 szhp00 see below
&lt;logi&gt; (ii+d) pD xx dd 19 szhp00 see below
</TD></TR></TABLE>Arithmetic &lt;arit&gt; commands:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> add A,op see above 4-19 szho0c A=A+op
adc A,op see above 4-19 szho0c A=A+op+cy
sub op see above 4-19 szho1c A=A-op
sbc A,op see above 4-19 szho1c A=A-op-cy
cp op see above 4-19 szho1c compare, ie. VOID=A-op
</TD></TR></TABLE>Increment/Decrement &lt;cnt&gt; commands:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> inc op see above 4-23 szho0- op=op+1
dec op see above 4-23 szho1- op=op-1
</TD></TR></TABLE>Logical &lt;logi&gt; commands:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> and op see above 4-19 sz1p00 A=A & op
xor op see above 4-19 sz0p00 A=A XOR op
or op see above 4-19 sz0p00 A=A | op
</TD></TR></TABLE><BR>
<B>16bit Arithmetic Commands</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Instruction Opcode Cycles Flags Notes
add HL,rr x9 11 --h-0c HL = HL+rr ;rr may be BC,DE,HL,SP
add ii,rr pD x9 15 --h-0c ii = ii+rr ;rr may be BC,DE,ii,SP (!)
adc HL,rr ED xA 15 szho0c HL = HL+rr+cy ;rr may be BC,DE,HL,SP
sbc HL,rr ED x2 15 szho1c HL = HL-rr-cy ;rr may be BC,DE,HL,SP
inc rr x3 6 ------ rr = rr+1 ;rr may be BC,DE,HL,SP
inc ii pD 23 10 ------ ii = ii+1
dec rr xB 6 ------ rr = rr-1 ;rr may be BC,DE,HL,SP
dec ii pD 2B 10 ------ ii = ii-1
</TD></TR></TABLE><BR>
<B>Searchcommands</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Instruction Opcode Cycles Flags Notes
cpi ED A1 16 szhe1- compare A-(HL), HL=HL+1, DE=DE+1, BC=BC-1
cpd ED A9 16 szhe1- compare A-(HL), HL=HL-1, DE=DE-1, BC=BC-1
cpir ED B1 x*21-5 szhe1- cpi-repeat until BC=0 or compare fits
cpdr ED B9 x*21-5 szhe1- cpd-repeat until BC=0 or compare fits
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="z80rotateshiftandsinglebitoperations"></A><FONT SIZE=+2>&nbsp;Z80 Rotate/Shift and Singlebit Operations</FONT></TD></TR></TABLE><BR>
<B>Rotate and Shift Commands</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Instruction Opcode Cycles Flags Notes
rlca 07 4 --0-0c rotate akku left
rla 17 4 --0-0c rotate akku left through carry
rrca 0F 4 --0-0c rotate akku right
rra 1F 4 --0-0c rotate akku right through carry
rld ED 6F 18 sz0p0- rotate left low digit of A through (HL)
rrd ED 67 18 sz0p0- rotate right low digit of A through (HL)
&lt;cmd&gt; r CB xx 8 sz0p0c see below
&lt;cmd&gt; (HL) CB xx 15 sz0p0c see below
&lt;cmd&gt; (ii+d) pD CB dd xx 23 sz0p0c see below
&lt;cmd&gt; r,(ii+d) pD CB dd xx 23 sz0p0c see below, UNDOCUMENTED modify and load
</TD></TR></TABLE>Whereas &lt;cmd&gt; may be:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> rlc rotate left
rl rotate left through carry
rrc rotate right
rr rotate right through carry
sla shift left arithmetic (b0=0)
sll UNDOCUMENTED shift left (b0=1)
sra shift right arithmetic (b7=b7)
srl shift right logical (b7=0)
</TD></TR></TABLE><BR>
<B>Singlebit Operations</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Instruction Opcode Cycles Flags Notes
bit n,r CB xx 8 xz1x0- test bit n ;n=0..7
bit n,(HL) CB xx 12 xz1x0-
bit n,(ii+d) pD CB dd xx 20 xz1x0-
set n,r CB xx 8 ------ set bit n ;n=0..7
set n,(HL) CB xx 15 ------
set n,(ii+d) pD CB dd xx 23 ------
set r,n,(ii+d) pD CB dd xx 23 ------ UNDOCUMENTED set n,(ii+d) and ld r,(ii+d)
res n,r CB xx 8 ------ reset bit n ;n=0..7
res n,(HL) CB xx 15 ------
res n,(ii+d) pD CB dd xx 23 ------
res r,n,(ii+d) pD CB dd xx 23 ------ UNDOCUMENTED res n,(ii+d) and ld r,(ii+d)
ccf 3F 4 --h-0c h=cy, cy=cy xor 1
scf 37 4 --0-01 cy=1
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="z80jumpcommandsinterrupts"></A><FONT SIZE=+2>&nbsp;Z80 Jumpcommands & Interrupts</FONT></TD></TR></TABLE><BR>
<B>General Jump Commands</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Instruction Opcode Cycles Flags Notes
jp nn C3 nn nn 10 ------ jump to nn, ie. PC=nn
jp HL E9 4 ------ jump to HL, ie. PC=HL
jp ii pD E9 8 ------ jump to ii, ie. PC=ii
jp f,nn xx nn nn 10;10 ------ jump to nn if nz,z,nc,c,po,pe,p,m
jr nn 18 dd 12 ------ relative jump to nn, ie. PC=PC+d
jr f,nn xx dd 12;7 ------ relative jump to nn if nz,z,nc,c
djnz nn 10 dd 13;8 ------ B=B-1 and relative jump to nn if B&lt;&gt;0
call nn CD nn nn 17 ------ call nn ie. SP=SP-2, (SP)=PC, PC=nn
call f,nn xx nn nn 17;10 ------ call nn if nz,z,nc,c,po,pe,p,m
ret C9 10 ------ pop PC ie. PC=(SP), SP=SP+2
ret f xx 11;5 ------ pop PC if nz,z,nc,c,po,pe,p,m
rst n xx 11 ------ call n ;n=00,08,10,18,20,28,30,38
nop 00 4 ------ no operation
</TD></TR></TABLE><BR>
<B>Interrupt Related Commands</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Instruction Opcode Cycles Flags Notes
di F3 4 ------ IFF1=0, IFF2=0 ;disable interrupts
ei FB 4 ------ IFF1=1, IFF2=1 ;enable interrupts
im 0 ED 46 8 ------ read opcode from databus on interrupt
im 1 ED 56 8 ------ execute call 0038h on interrupt
im 2 ED 5E 8 ------ execute call (i*100h+databus) on int.
halt 76 N*4 ------ repeat until interrupt occurs
reti ED 4D 14 ------ pop PC, IFF1=IFF2, ACK (ret from INT)
retn ED 45 14 ------ pop PC, IFF1=IFF2 (ret from NMI)
&lt;/INT=LOW,IM=0,IFF1=1&gt; 1+var ------ IFF1=0,IFF2=0, exec opcode from databus
&lt;/INT=LOW,IM=1,IFF1=1&gt; 12 ------ IFF1=0,IFF2=0, CALL 0038h
&lt;/INT=LOW,IM=2,IFF1=1&gt; 18 ------ IFF1=0,IFF2=0, CALL [I*100h+databus]
&lt;/NMI=falling_edge&gt; ? ------ IFF1=0, CALL 0066h
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="z80iocommands"></A><FONT SIZE=+2>&nbsp;Z80 I/O Commands</FONT></TD></TR></TABLE><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Instruction Opcode Cycles Flags Notes
in A,(n) DB nn 11 ------ A=PORT(A*100h+n)
in r,(C) ED xx 12 sz0p0- r=PORT(BC)
in (C) ED 70 12 sz0p0- **undoc/illegal** VOID=PORT(BC)
out (n),A D3 nn 11 ------ PORT(A*100h+n)=A
out (C),r ED xx 12 ------ PORT(BC)=r
out (C),0 ED 71 12 ------ **undoc/illegal** PORT(BC)=00
ini ED A2 16 xexxxx MEM(HL)=PORT(BC), HL=HL+1, B=B-1
ind ED AA 16 xexxxx MEM(HL)=PORT(BC), HL=HL-1, B=B-1
outi ED A3 16 xexxxx B=B-1, PORT(BC)=MEM(HL), HL=HL+1
outd ED AB 16 xexxxx B=B-1, PORT(BC)=MEM(HL), HL=HL-1
inir ED B2 b*21-5 x1xxxx same than ini, repeat until b=0
indr ED BA b*21-5 x1xxxx same than ind, repeat until b=0
otir ED B3 b*21-5 x1xxxx same than outi, repeat until b=0
otdr ED BB b*21-5 x1xxxx same than outd, repeat until b=0
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="z80interrupts"></A><FONT SIZE=+2>&nbsp;Z80 Interrupts</FONT></TD></TR></TABLE><BR>
<B>Interrupt Flip-Flop (IFF1,IFF2)</B><BR>
The IFF1 flag is used to enable/disable INTs (maskable interrupts).<BR>
In a raw INT-based system, IFF2 is always having the same state than
IFF1. However, in a NMI-based system the IFF2 flag is used to backup the
recent IFF1 state prior to NMI execution, and may be used to restore
IFF1 upon NMI completion by RETN opcode.<BR>
Beside for the above 'backup' function, IFF2 itself is having no effect.
Neither IFF1 nor IFF2 affect NMIs which are always enabled.<BR>
The following opcodes/events are modifying IFF1 and/or IFF2:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> EI IFF1=1, IFF2=1
DI IFF1=0, IFF2=0
&lt;INT&gt; IFF1=0, IFF2=0
&lt;NMI&gt; IFF1=0
RETI IFF1=IFF2
RETN IFF1=IFF2
</TD></TR></TABLE>When using the EI instruction, the new IFF state isn't applied until the
next instruction has completed (this ensures that an interrupt handler
which is using the sequence "EI, RET" may return to the main program
before the next interrupt is executed).<BR>
Interrupts can be disabled by the DI instruction (IFF=0), and are
additionally automatically each time when an interrupt is executed.<BR>
<BR>
<B>Interrupt Execution</B><BR>
An interrupt is executed when an interrupt is requested by the hardware,
and IFF is set. Whenever both conditions are true, the interrupt is
executed after the completion of the current opcode.<BR>
Note that repeated block commands (such like LDIR) can be interrupted
also, the interrupt return address on the stack then points to the
interrupted opcode, so that the instruction may continue as normal once
the interrupt handler returns.<BR>
<BR>
<B>Interrupt Modes (IM 0,1,2)</B><BR>
The Z80 supports three interrupt modes which can be selected by IM 0, IM
1, and IM 2 instructions. The table below describes the respective
operation and execution time in each mode.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Mode Cycles Refresh Operation
0 1+var 0+var IFF1=0,IFF2=0, read and execute opcode from databus
1 12 1 IFF1=0,IFF2=0, CALL 0038h
2 18 1 IFF1=0,IFF2=0, CALL [I*100h+databus]
</TD></TR></TABLE>Mode 0 requires an opcode to be output to the databus by external
hardware, in case that no byte is output, and provided that the 'empty'
databus is free of garbage, then the CPU might tend to read a value of
FFh (opcode RST 38h, 11 cycles, 1 refresh) - the clock cycles (11+1),
refresh cycles (1), and executed operation are then fully identical as
in Mode 1.<BR>
Mode 1 interrupts always perform a CALL 0038h operation. The downside is
that many systems may have ROM located at this address, making it
impossible to hook the interrupt handler directly.<BR>
<BR>
Mode 2 calls to a 16bit address which is read from a table in memory,
the table pointer is calculated from the "I" register (initialized by LD
I,A instruction) multiplied by 100h, plus an index byte which is read
from the databus. The following trick may be used to gain stable results
in Mode 2 even if no index byte is supplied on the databus: For example,
set I=40h the origin of the table will be then at 4000h in memory. Now
fill the entire area from 4000h to 4100h (101h bytes, including 4100h)
by the value 41h. The CPU will then perform a CALL 4141h upon interrupt
execution - regardless of whether the randomized index byte is an even
or odd number.<BR>
<BR>
<B>Non-Maskable Interrupts (NMIs)</B><BR>
Unlike INTs, NMIs cannot be disabled by the CPU, ie. DI and EI
instructions and the state of IFF1 and IFF2 do not have effect on NMIs.
The NMI handler address is fixed at 0066h, regardless of the interrupt
mode (IM). Upon NMI execution, IFF1 is cleared (disabeling maskable INTs
- NMIs remain enabled, which may result in nested execution if the
handler does not return before next NMI is requested). IFF2 remains
unchanged, thus containing the most recent state of IFF1, which may be
used to restore IFF1 if the NMI handler returns by RETN instruction.<BR>
Execution time for NMIs is unknown (?).<BR>
<BR>
<B>RETN (return from NMI and restore IFF1)</B><BR>
Intended to return from NMI and to restore the old IFF1 state (assuming the
old state was IFF1/IFF2 both set or both cleared).<BR>
<BR>
<B>RETI (return from INT with external acknowledge)</B><BR>
Intended to return from INT and to notify peripherals about completion of the
INT handler, the Z80 itself doesn't send any such acknowledge signal
(instead, peripherals like Z80-PIO or Z80-SIO must decode the databus during
/M1 cycles, and identify the opcode sequence EDh,4Fh as RETI). Aside from
such external handling, internally, RETI is exactly same as RETN, and, like
RETN it does set IFF1=IFF2 (though in case of RETI this is a dirt effect
without practical use; within INT handlers IFF1 and IFF2 are always both
zero, or when EI was used both set). Recommended methods to return from INT
are: EI+RETI (when needing the external acknowledge), or EI+RET (faster).<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="z80meaninglessandduplicatedopcodes"></A><FONT SIZE=+2>&nbsp;Z80 Meaningless and Duplicated Opcodes</FONT></TD></TR></TABLE><BR>
<B>Mirrored Instructions</B><BR>
NEG (ED44) is mirrored to ED4C,54,5C,64,6C,74,7C.<BR>
RETN (ED45) is mirrored to ED55,65,75.<BR>
RETI (ED4D) is mirrored to ED5D,6D,7D.<BR>
<BR>
<B>Mirrored IM Instructions</B><BR>
IM 0,X,1,2 (ED46,4E,56,5E) are mirrored to ED66,6E,76,7E.<BR>
Whereas IM X is an undocumented mirrored instruction itself which
appears to be identical to either IM 0 or IM 1 instruction (?).<BR>
<BR>
<B>Duplicated LD HL Instructions</B><BR>
LD (nn),HL (opcode 22NNNN) is mirrored to ED63NNNN.<BR>
LD HL,(nn) (opcode 2ANNNN) is mirrored to ED6BNNNN.<BR>
Unlike the other instructions in this chapter, these two opcodes are
officially documented. The clock/refresh cycles for the mirrored
instructions are then 20/2 instead of 16/1 as for the native 8080
instructions.<BR>
<BR>
<B>Mirrored BIT N,(ii+d) Instructions</B><BR>
Unlike as for RES and SET, the BIT instruction does not support a third
operand, ie. DD or FD prefixes cannot be used on a BIT N,r instruction
in order to produce a BIT r,N,(ii+d) instruction. When attempting this,
the 'r' operand is ignored, and the resulting instruction is identical
to BIT N,(ii+d).<BR>
Except that, not tested yet, maybe undocumented flags are then read from
'r' instead of from ii+d(?).<BR>
<BR>
<B>Non-Functional Opcodes</B><BR>
The following opcodes behave much like the NOP instruction.<BR>
ED00-3F, ED77, ED7F, ED80-9F, EDA4-A7, EDAC-AF, EDB4-B7, EDBC-BF, EDC0-FF.<BR>
The execution time for these opcodes is 8 clock cycles, 2 refresh cycles.<BR>
Note that some of these opcodes appear to be used for additional
instructions by the R800 CPU in newer turbo R (MSX) models.<BR>
<BR>
<B>Ignored DD and FD Prefixes</B><BR>
In some cases, DD-prefixes (IX) and FD-prefixes (IY) may be ignored by
the CPU. This happens when using one (or more) of the above prefixes
prior to instructions that already contain an ED, DD, or FD prefix, or
prior to any instructions that do not support IX, IY, IXL, IXH, IYL, IYH
operands. In such cases, 4 clock cycles and 1 refresh cycle are counted
for each ignored prefix byte.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="z80garbageinflagregister"></A><FONT SIZE=+2>&nbsp;Z80 Garbage in Flag Register</FONT></TD></TR></TABLE><BR>
<B>Nocash Z80-flags description</B><BR>
This chapter describes the undocumented Z80 flags (bit 3 and 5 of the
Flags Register), these flags are affected by ALL instructions that
modify one or more of the normal flags - all OTHER instructions do NOT
affect the undocumented flags.<BR>
<BR>
For some instructions, the content of some flags has been officially
documented as 'destroyed', indicating that the flags contain garbage,
the exact garbage calculation for these instructions will be described
here also.<BR>
<BR>
All information below just for curiosity. Keep in mind that Z80
compatible CPUs (or emulators) may not supply identical results, so that
it wouldn't be a good idea to use these flags in any programs (not that
they could be very useful anyways).<BR>
<BR>
<B>Normal Behaviour for Undocumented Flags</B><BR>
In most cases, undocumented flags are copied from the Bit 3 and Bit 5 of
the result byte. That is "A AND 28h" for:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> RLD; CPL; RLCA; RLA; LD A,I; ADD OP; ADC OP; XOR OP; AND OP;
RRD; NEG; RRCA; RRA; LD A,R; SUB OP; SBC OP; OR OP ; DAA.
</TD></TR></TABLE>When other operands than A may be modified, "OP AND 28h" for:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> RLC OP; RL OP; SLA OP; SLL OP; INC OP; IN OP,(C);
RRC OP; RR OP; SRA OP; SRL OP; DEC OP
</TD></TR></TABLE>For 16bit instructions flags are calculated as "RR AND 2800h":<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> ADD RR,XX; ADC RR,XX; SBC RR,XX.
</TD></TR></TABLE><BR>
<B>Slightly Special Undocumented Flags</B><BR>
For 'CP OP' flags are calculated as "OP AND 28h", that is the unmodified
operand, and NOT the internally calculated result of the comparision.<BR>
For 'SCF' and 'CCF' flags are calculated as "(A OR F) AND 28h", ie. the flags
remain set if they have been previously set.<BR>
For 'BIT N,R' flags are calculated as "OP AND 28h", additionally the
P-Flag is set to the same value than the Z-Flag (ie. the Parity of "OP
AND MASK"), and the S-flag is set to "OP AND MASK AND 80h".<BR>
<BR>
<B>Fatal MEMPTR Undocumented Flags</B><BR>
For 'BIT N,(HL)' the P- and S-flags are set as for BIT N,R, but the
undocumented flags are calculated as "MEMPTR AND 2800h", for more info
about MEMPTR read on below.<BR>
The same applies to 'BIT N,(ii+d)', but the result is less unpredictable
because the instruction sets MEMPTR=ii+d, so that undocumented flags are
"&lt;ii+d&gt; AND 2800h".<BR>
<BR>
<B>Memory Block Command Undocumented Flags</B><BR>
For LDI, LDD, LDIR, LDDR, undocumented flags are "((A+DATA) AND 08h) +
((A+DATA) AND 02h)*10h".<BR>
For CPI, CPD, CPIR, CPDR, undocumented flags are "((A-DATA-FLG_H) AND
08h) + ((A-DATA-FLG_H) AND 02h)*10h", whereas the CPU first calculates
A-DATA, and then internally subtracts the resulting H-flag from the
result.<BR>
<BR>
<B>Chaotic I/O Block Command Flags</B><BR>
The INI, IND, INIR, INDR, OUTI, OUTD, OTIR, OTDR instructions are doing
a lot of obscure things, to simplify the description a placeholder
called DUMMY is used in the formulas.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> DUMMY = "REG_C+DATA+1" ;for INI/INIR
DUMMY = "REG_C+DATA-1" ;for IND/INDR
DUMMY = "REG_L+DATA" ;for OUTI,OUTD,OTIR,OTDR
FLG_C = Carry of above "DUMMY" calculation
FLG_H = Carry of above "DUMMY" calculation (same as FLG_C)
FLG_N = Sign of "DATA"
FLG_P = Parity of "REG_B XOR (DUMMY AND 07h)"
FLG_S = Sign of "REG_B"
UNDOC = Bit3,5 of "REG_B AND 28h"
</TD></TR></TABLE>The above registers L and B are meant to contain the new values which
are already incremented/decremented by the instruction.<BR>
Note that the official docs mis-described the N-Flag as set, and the
C-Flag as not affected.<BR>
<BR>
<B>DAA Flags</B><BR>
Addition (if N was 0):<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> FLG_H = (OLD_A AND 0Fh) &gt; 09h
FLG_C = Carry of result
</TD></TR></TABLE>Subtraction (if N was 1):<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> FLG_H = (NEW_A AND 0Fh) &gt; 09h
FLG_C = OLD_CARRY OR (OLD_A&gt;99h)
</TD></TR></TABLE>For both addition and subtraction, N remains unmodified, and S, Z, P
contain "Sign", Zero, and Parity of result (A). Undocumented flags are
set to (A AND 28h) as normal.<BR>
<BR>
<B>Mis-documented Flags</B><BR>
For all XOR/OR: H=N=C=0, and for all AND: H=1, N=C=0, unlike described
else in Z80 docs. Also note C,N flag description bug for I/O block
commands (see above).<BR>
<BR>
<B>Internal MEMPTR Register</B><BR>
This is an internal Z80 register, modified by some instructions, and
usually completely hidden to the user, except that Bit 11 and Bit 13 can
be read out at a later time by BIT N,(HL) instructions.<BR>
The following list specifies the resulting content of the MEMPTR
register caused by the respective instructions.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Content Instruction
A*100h LD (xx),A ;xx=BC,DE,nn
xx+1 LD A,(xx) ;xx=BC,DE,nn
nn+1 LD (nn),rr; LD rr,(nn) ;rr=BC,DE,HL,IX,IY
rr EX (SP),rr ;rr=HL,IX,IY (MEMPTR=new value of rr)
rr+1 ADD/ADC/SBC rr,xx ;rr=HL,IX,IY (MEMPTR=old value of rr+1)
HL+1 RLD and RRD
dest JP nn; CALL nn; JR nn ;dest=nn
dest JP f,nn; CALL f,nn ;regardless of condition true/false
dest RET; RETI; RETN ;dest=value read from (sp)
dest RET f; JR f,nn; DJNZ nn ;only if condition=true
00XX RST n
adr+1 IN A,(n) ;adr=A*100h+n, memptr=A*100h+n+1
bc+1 IN r,(BC); OUT (BC),r ;adr=bc
ii+d All instructions with operand (ii+d)
</TD></TR></TABLE>Also the following might or might not affect MEMPTR, not tested yet:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> OUT (N),A and block commands LDXX, CPXX, INXX, OUTXX
and probably interrupts in IM 0, 1, 2
</TD></TR></TABLE>All other commands do not affect the MEMPTR register - this includes all
instructions with operand (HL), all PUSH and POP instructions, not
executed conditionals JR f,d, DJNZ d, RET f (ie. with condition=false),
and the JP HL/IX/IY jump instructions.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="z80compatibility"></A><FONT SIZE=+2>&nbsp;Z80 Compatibility</FONT></TD></TR></TABLE><BR>
The Z80 CPU is (almost) fully backwards compatible to older 8080 and
8085 CPUs.<BR>
<BR>
<B>Instruction Format</B><BR>
The Z80 syntax simplifies the chaotic 8080/8085 syntax. For example, Z80
uses the command "LD" for all load instructions, 8080/8085 used various
different commands depending on whether the operands are 8bit registers,
16bit registers, memory pointers, and/or an immediates. However, these
changes apply to the source code only - the generated binary code is
identical for both CPUs.<BR>
<BR>
<B>Parity/Overflow Flag</B><BR>
The Z80 CPU uses Bit 2 of the flag register as Overflow flag for
arithmetic instructions, and as Parity flag for other instructions.
8080/8085 CPUs are always using this bit as Parity flag for both
arithmetic and non-arithmetic instructions.<BR>
<BR>
<B>Z80 Specific Instructions</B><BR>
The following instructions are available for Z80 CPUs only, but not for
older 8080/8085 CPUs:<BR>
All CB-prefixed opcodes (most Shift/Rotate, all BIT/SET/RES commands).<BR>
All ED-prefixed opcodes (various instructions, and all block commands).<BR>
All DD/FD-prefixed opcodes (registers IX and IY).<BR>
As well as DJNZ nn; JR nn; JR f,nn; EX AF,AF; and EXX.<BR>
<BR>
<B>8085 Specific Instructions</B><BR>
The 8085 instruction set includes two specific opcodes in addition to
the 8080 instruction set, used to control 8085-specifc interrupts and
SID and SOD input/output signals. These opcodes, RIM (20h) and SIM
(30h), are not supported by Z80/8080 CPUs.<BR>
<BR>
<B>Z80 vs Z80A</B><BR>
Both Z80 and Z80A are including the same instruction set, the only
difference is the supported clock frequency (Z80 = max 2.5MHz, Z80A =
max 4MHz).<BR>
<BR>
<B>NEC-780 vs Zilog-Z80</B><BR>
These CPUs are apparently fully compatible to each other, including for
undocumented flags and undocumented opcodes.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="z80pinouts"></A><FONT SIZE=+2>&nbsp;Z80 Pin-Outs</FONT></TD></TR></TABLE><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> _____ _____
| |_| |
A11 |1 40| A10
A12 |2 39| A9
A13 |3 38| A8
A14 |4 37| A7
A15 |5 36| A6
CLK |6 35| A5
D4 |7 34| A4
D3 |8 33| A3
D5 |9 32| A2
D6 |10 Z80 31| A1
VCC |11 CPU 30| A0
D2 |12 29| GND
D7 |13 28| /RFSH
D0 |14 27| /M1
D1 |15 26| /RST
/INT |16 25| /BUSRQ
/NMI |17 24| /WAIT
/HALT |18 23| /BUSAK
/MREQ |19 22| /WR
/IORQ |20 21| /RD
|_____________|
</TD></TR></TABLE><BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="z80localusage"></A><FONT SIZE=+2>&nbsp;Z80 Local Usage</FONT></TD></TR></TABLE><BR>
<B>CPU and System Clock Overview</B><BR>
The ZX81 is equipped with a NEC D780C-1 CPU (fully compatible to Zilog
Z80 CPUs, including for undocumented opcodes & flags). The CPU is
operated at 3.25 MHz (generated by a 6.5MHz oscillator with very high
tolerance - my ZX81 appears to be rather ticking at 3.33MHz even though
the oscillator DOES have the value 6.5 printed onto it) the available
CPU time is reduced when the display is enabled. The ZX81 produces a
/WAIT signal for the duration while a NMI is requested, otherwise the
CPU runs free of waitstates.<BR>
<BR>
<B>Vectors, Registers and Memory Overview</B><BR>
The INT, NMI, and RST vectors are located in ROM and cannot be changed
by software. The AF' register (ie. EX AF,AF), the IX register, and IR
register (interrupt/refresh) are reserved for video and should be
normally not used, except in FAST mode. Attempting to execute program
code stored at addresses 8000h-FFFFh is interpreted as video data (if
the opcodes Bit 6 was set), if so, a NOP opcode is forwarded to the CPU.<BR>
<BR>
<B>Using Machine Code</B><BR>
A machine code program is called by using the USR function, for example
by using the BASIC expression "LET N=USR &lt;startaddress&gt;", startaddress
must be a decimal number (hex numbers are not supported). If the machine
code program returns to BASIC, the content of the BC register is used as
return value. For info about storing binary data/machine code, see
Memory chapter.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="basicinterpreter"></A><FONT SIZE=+2>&nbsp;BASIC Interpreter</FONT></TD></TR></TABLE><BR>
<B>The BASIC Interpreter</B><BR>
<A HREF="#basiceditor">BASIC Editor</A><BR>
<A HREF="#basiccommands">BASIC Commands</A><BR>
<A HREF="#basicfunctions">BASIC Functions</A><BR>
<A HREF="#basicerrorcodes">BASIC Error Codes</A><BR>
<A HREF="#basicprogramsandvariableszx81spectrum">BASIC Programs and Variables (ZX81/Spectrum)</A><BR>
<A HREF="#basicprogramsandvariableszx80">BASIC Programs and Variables (ZX80)</A><BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="basiceditor"></A><FONT SIZE=+2>&nbsp;BASIC Editor</FONT></TD></TR></TABLE><BR>
This chapter explains ZX81 keyboard modes and key-combinations. The table
with all keywords/characters assigned to each key can be found here:<BR>
<A HREF="#zx80zx81keyboardassignment">ZX80/ZX81 Keyboard Assignment</A><BR>
<A HREF="#spectrumkeyboardassignment">Spectrum Keyboard Assignment</A><BR>
<BR>
<B>Special Keys</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE><B> Key Name Expl. Equivalent/emulated PC Key</B>
Ret NEWLINE Confirm Input Enter
Space BREAK Stops the program! Space
Shift+0 RUBOUT Deletes a character Backspace
Shift+1 EDIT Edits [&gt;] Cursor selected line -
Shift+5/8 &lt;CURSOR&gt; Moves Cursor left/right in input buffer Cursor Keys
Shift+7/6 &lt;CURSOR&gt; Moves [&gt;] Cursor up/down in listing Cursor Keys
Shift+9 GRAPHICS Switches to [G] Graphics Cursor Mode Alt
Shift+Ret FUNCTION Switches to [F] Function Cursor Mode Control
</TD></TR></TABLE>Beside for these general special keys, all ZX81 keys are behaving kinda
special, depending on various input modes as shown below.<BR>
<BR>
<B>[K] Cursor - Keyword Mode (Expecting Keywords and/or Line Numbers)</B><BR>
This mode is automatically used at the beginning of each line (and after THEN).<BR>
At the beginning of line, a line number can be entered by using 0-9 keys.
Character keys are interpreted as command keywords (for example, P=PRINT).
Some commands must be entered as SHIFT combinations (for example,
SHIFT+F=FAST).<BR>
Entering a line number without keyword deletes the specified line.<BR>
<BR>
<B>[L] Cursor - Letter Mode (Expecting Operands or Functions)</B><BR>
This mode is automatically selected after entering a keyword in [K] mode.<BR>
Allows to enter expressions, such like "HELLO" or 1234.5678. When SHIFT is
held down, functions/operators such like +,-,*,&gt;=,OR,AND can be entered (for
example, SHIFT+W=OR), note that typing "OR" as characters by pressing "O",
"R" will result in syntax errors.<BR>
<BR>
<B>[F] Cursor - Function Mode (Expecting Functions) (ZX81 only)</B><BR>
This mode is entered by pressing SHIFT+ENTER from inside of [L] Mode,
allowing to enter functions such like L=USR, U=CHR$ which cannot be
entered in [L] mode directly.<BR>
<BR>
<B>[G] Cursor - Graphics Mode (Inverted Text and Block Graphics) (ZX81 only)</B><BR>
This mode is entered by pressing SHIFT+9 from inside of [L] Mode,
allowing to enter inverted characters (including inverted SPACE).<BR>
When keeping SHIFT held down, all combinations of Block Graphics can be
entered (for example, SHIFT+1=Dot-in-upper-left).<BR>
<BR>
<B>[&gt;] Cursor/Symbol - Currently selected line</B><BR>
This cursor isn't part of the input line. Instead, it is displayed in the
program listing (if any) in the upper screen area. The cursor can be moved by
UP/DOWN key combinations (SHIFT+7/6), causing the listing to be scrolled if
necessary.<BR>
The EDIT key combination (SHIFT+1) copies the line that is currently selected
by the [&gt;] Cursor to the input buffer (overwriting any old input).<BR>
<BR>
<B>[S] Symbol - Syntax Error</B><BR>
This is not actually a cursor, when entering an incorrect line, the [S]
symbol appears, indicating the fault position, and prompting the user to
repair the problem.<BR>
<BR>
<B>Note</B><BR>
The ZX80/ZX81 allows only one command per line. On the Spectrum, multiple
commands can be separated by ":" colons.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="basiccommands"></A><FONT SIZE=+2>&nbsp;BASIC Commands</FONT></TD></TR></TABLE><BR>
<B>BEEP n,n (Spectrum only)</B><BR>
Plays a sound via ULA port FEh. The 1st parameter specifies the duration in
seconds (or fractions thereof, like 0.5), the 2nd parameter specifies the
pitch in semitones above middle C (or below thereof, if negative). The
waveform is software generated, so the program becomes paused during beep.<BR>
<BR>
<B>BORDER n (Spectrum only)</B><BR>
Changes the screen border color (0..7).<BR>
<BR>
<B>CLEAR [n]</B><BR>
Erases all variables and frees up memory. The optional parameter changes
RAMTOP (supported on Spectrum only).<BR>
<BR>
<B>CIRCLE x,y,radius (Spectrum only)</B><BR>
Draws a circle.<BR>
<BR>
<B>CLS</B><BR>
Clears the screen.<BR>
<BR>
<B>CONT (called CONTINUE on ZX80/Spectrum)</B><BR>
Works much like GOTO, continues the program in the current line, or in
the next line if program has been halted by STOP.<BR>
<BR>
<B>COPY (ZX81/Spectrum only)</B><BR>
Sends a screen copy to the printer (if connected). Only topmost 32x22
characters are printed, ie. excluding bottommost 2 lines.<BR>
<BR>
<B>DATA item[,item[,item]] (Spectrum only)</B><BR>
Contains expressions (numbers, variables, or quoted strings) which may be
loaded into variables via READ command. DATA is just a data definition, not
an executable command (trying to execute DATA lines acts as REM lines).<BR>
<BR>
<B>DEF FN v(v1,v2,etc)=expression (Spectrum only)</B><BR>
Creates a user defined function. The function name must be a single letter
expression (like x or a$). For example, "DEF FN s(a)=a*a" would cause "FN
s(n)" to act identical as "n**2".<BR>
<BR>
<B>DELETE [n],[m] (Timex TS2068/TC2068 only)</B><BR>
Deletes BASIC line numbers n..m. Defaults to from 1st/to last line if n/m are
omitted. Note: To delete a single line, simply enter its line number and
press Enter.<BR>
<BR>
<B>DIM b(n1,...,nk) or DIM b$(n1,...,nk)</B><BR>
Defines dimensions for an array. All values (or strings) in the array
are reset to 0, (or SPACE-filled for strings/characters). The lastmost
dimension of a character array indicates the string length. For example,
DIM A$(x,y,z) could be accessed either as three-dimensional character
array A$(x,y,z), or as two-dimensional string array A$(x,y) with
LENGTH=z.<BR>
The ZX80 supports only one-dimensional numeric arrays, ie. no
multi-dimensional arrays, and no string/character arrays.<BR>
<BR>
<B>DRAW x,y[,angle] (Spectrum only)</B><BR>
Draws a line (from most recent DRAW/PLOT/CIRCLE position) to x,y. The 3rd
parameter allows to draw curved lines (angle should be below +/-2*PI).<BR>
<BR>
<B>FAST (ZX81 only)</B><BR>
Switches to FAST mode, the CPU focuses on program execution only (approx. 4
times faster) and the display becomes black until end of program, or until
switching to SLOW mode. Also, the screen becomes temporarily enabled during
PAUSE or INPUT periods.<BR>
The ZX80 is always operating in 'FAST' mode.<BR>
<BR>
<B>FOR b=x TO y [STEP z]</B><BR>
Defines the begin and range of a FOR-NEXT loop, the default STEP is +1. The
ZX80 doesn't support the STEP operand.<BR>
<BR>
<B>GOSUB n (called GO SUB on ZX80/Spectrum)</B><BR>
Saves RETURN address on GOSUB stack, and jumps to the specified line
number, see GOTO for details.<BR>
<BR>
<B>GOTO n (called GO TO on ZX80/Spectrum)</B><BR>
Jumps to the specified line number. An immediate, a variable and/or
other expression may be used as line number, such like "GOTO A*10+230".<BR>
<BR>
<B>IF x THEN command</B><BR>
Executes command if x&lt;&gt;0 (eg. if an expression like "A=0" is true). The ZX
does not understand "THEN n" as alias for "THEN GOTO n".<BR>
<BR>
<B>INK/PAPER/FLASH/BRIGHT n (affects VRAM attributes) (Spectrum only)</B><BR>
<B>INVERSE/OVER n (affects VRAM bitmap) (Spectrum only)</B><BR>
Changes parameters for following printing/drawing operations (like PRINT,
INPUT, PLOT, DRAW, CIRCLE).<BR>
INK/PAPER can be a color number in range 0..7, or 8=transparent, FLASH/BRIGHT
can be 0=off, 1=on, or 8=transparent, transparent means that the old
attribute value in VRAM is left unchanged. INVERSE/OVER can be 0=off, or
1=on. INVERSE inverts the character data when printing, or causes pixels to
become 0 when drawing. OVER causes the new character/pixel data to be XORed
with the old VRAM bitmap content.<BR>
INK/PAPER/FLASH/BRIGHT/INVERSE/OVER can be used as "standalone" commands
(affecting all following printing/drawing commands) (eg. "INVERSE 1"), or as
"temporary" parameters inserted between a printing/drawing command and its
parameters (affecting only that command) (eg. "PLOT INVERSE 1;x,y" is
equivalent to UNPLOT x,y).<BR>
Note: Another way to use colors in printing is to use "hidden" tokens, like
typing PRINT"Hello {INK RED}Test", where {INK RED} is entered as EXT+SHIFT+2.
The {INK RED} token isn't displayed in text form when listing/editing the
program, it just causes the following characters to be drawn in red (this
method was supported only by the original 48K BASIC, and was discontinued in
128 BASIC).<BR>
<BR>
<B>INPUT ["text",] [LINE] v</B><BR>
Prompts the user to enter a value (or string) to be assigned to v. In
FAST mode, the display is temporarily re-enabled. Program is breaked if
user enters STOP as first character.<BR>
Strings must enclosed in quotes (otherwise any text input is treated as a
variable). Adding the LINE keyword allows to enter strings without quotes
(Spectrum only). "text" is an optional message displayed on the screen
(Spectrum only).<BR>
<BR>
<B>LET v=e</B><BR>
Assigns e to the variable v. The ZX does not understand "v=e" as alias for
"LET v=e". In case that v is a string-fragment, ie. A$(..TO..), the TO-length
remains unchanged, and truncated/space padded string is assigned to the
TO-area.<BR>
<BR>
<B>LIST [n]</B><BR>
Lists the program on the screen. The default starting line number is 0.
Use CONT to continue if program does not fit onto screen.<BR>
<BR>
<B>LLIST [n] (ZX81/Spectrum only)</B><BR>
Lists the program to the printer.<BR>
<BR>
<B>LOAD f</B><BR>
Loads a memory image from cassette. When specifying an empty filename,
ie. LOAD "", the first encountered file is loaded. Text display is
suspended during loading, white lines are shown on the screen when
receiving cassette signals. The program and all variables that are
already in memory become overwritten.<BR>
The memory image contains all memory from 4009h up to (4014h), ie. most
of the system area, the actual BASIC program, the video memory, and any
defined variables. The program is automatically started, continuing at
the next line number, if it has been saved from &lt;inside&gt; of a running
program.<BR>
The ZX80 does not support filenames, just type LOAD and hit NEWLINE.<BR>
<BR>
<B>LPRINT (ZX81/Spectrum only)</B><BR>
Works much like PRINT, but outputs to the printer. AT may be used to specify
a horizontal position inside of the currently printed line.<BR>
Bug: Numbers with more than one zero in their fractional portion aren't
displayed properly, for example, LPRINT 0.00001 does output "0.0XYZ1" (this
bug appears only with the ZX81/TS1000 BIOS, it's fixed in the TS1500, Lambda
8300, and Spectrum BIOSes).<BR>
<BR>
<B>NEW</B><BR>
Restarts BASIC. The program, all variables, and all further memory up to
RAMTOP are erased. In the ZX80 this is equivalent to CALL 0.<BR>
<BR>
<B>NEXT b</B><BR>
Adjusts b as specified in the corresponding FOR command, and (if the target
condition has not been reached or exceeded) loops back to the line following
to the FOR command. The ZX does not understand "NEXT" as alias for "NEXT b".<BR>
<BR>
<B>ON ERR command (Timex TS2068/TC2068 only)</B><BR>
Defines error handling. command can be combined GOTO, CONT, or RESET.<BR>
<BR>
<B>OUT n,m (Spectrum only)</B><BR>
Writes a byte (m) to the specified 16bit I/O address (n).<BR>
<BR>
<B>PAUSE n (ZX81/Spectrum only)</B><BR>
Pauses the program for n/50 seconds (assuming 50Hz display refresh rate)
or until the user hits a key, and displays the screen for the duration
of this period (even if display was disabled by FAST mode). The highest
allowed value for n is 32767. Note that hitting the BREAK key (SPACE) stops
the program rather than continuing it. On the Spectrum, PAUSE 0 waits endless
(until a key is pressed).<BR>
<BR>
<B>PLAY string1[,string2[,string3]] (Spectrum 128/+2/+2A/+3 only)</B><BR>
Plays up to three sounds (on the three PSG sound channels). The strings are
composed of following characters:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> c-b Play note within current octave (c,d,e,f,g,a,b)
C-B Play note within next higher octave (C,D,E,F,G,A,B)
$ Flattens note following it (can be more flattened by $$ or $$$ etc.)
# Sharpens note following it (can be more sharpened by ## or ### etc.)
& Play silence (a pause of same length as normal c-b and C-B notes)
_ Tied notes (eg. "5_7c" = crotchet c and a minim c tied together)
On Set current octave (0..8)
Tn Set tempo (60..240)
n Set length of notes (1..12) (use "Nn" if preceeded by other digits)
Nn Separates two numbers (eg. octave=1,length=2 --&gt; O1N2, instead of O12)
Vn Set volume level (0..15) (0=Off, 15=Loudest)
Wn Set volume envelope type (0..7) (bit0=ATTACK, bit1=HOLD, bit2=REPEAT)
Xn Set volume envelope frequency (0..65535) (affects all 3 channels)
U Turn on volume envelope in any string
( Set loop start (if none specified: default is begin of string)
) Jump to loop start (repeat 2x, multiple brackets can repeat 4x,8x,16x..)
)) Jump to loop starts (repeats endless if only ONE loop start was defined)
! ! Enclose a comment
H Stop PLAY command (stops all 3 channels, including endless looping ones)
Mn Configure PSG channels (bit0..2=Tone A..C, bit3..5=Noise A..C)
Yn Turn on MIDI channel (1..16)
Zn Send MIDI programming/configuration code (numbers depend on hardware)
</TD></TR></TABLE>Although the sounds are hardware generated, the program gets paused until the
PLAY command has finished, which is making the feature rather useless.<BR>
<BR>
<B>PLOT x,y (ZX81/Spectrum only)</B><BR>
ZX81: Draws a black dot (of 4x4 pixels, ie. one quarter of a 8x8 pixel
character) at the specified position by using graphics characters. Spectrum:
Draws a single pixel. For both ZX81/Spectrum: The origin (0,0) is at the
lower left of the screen, excluding the bottom-most two character lines.<BR>
<BR>
<B>POKE m,n</B><BR>
Writes the byte n at address m into memory, both must be decimal values (the
ZX does not recognize hexadecimal numbers).<BR>
<BR>
<B>PRINT ...</B><BR>
Displays the operand(s) - if any - on the screen. Possible operands are:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> a) nothing
b) a numeric expression, displayed either as
normal decimal number (if in range 10^-5 .. 10^13)
otherwise as nnEmm indicating nn*10^mm
leading zeroes are displayed only if the first digit after
the "." is not zero, ie. 0.3 and .03 are displayed as such.
c) a string. undefined characters are displayed as question marks.
d) AT y,x; - moves the PRINT position to the specified screen
location, 0,0 is upper left.
e) TAB n; - moves the PRINT position to the specified horizontal
location. If this is to the left of the current location, then
the vertical position is incremented.
</TD></TR></TABLE>Operands may be separate by semicolon ";" (next operand displayed directly at
current position) or comma "," (next operand displayed at next TAB 0 or TAB
16 position).<BR>
Upon completion, the print position is moved to the begin of the next
line (unless expression was terminated by semicolon or comma).<BR>
An error may be generated if memory or screen is full, if so, CONT may
be used to clear the screen and to continue the program.<BR>
<BR>
<B>RAND [n] (called RANDOMISE on ZX80, and RANDOMIZE on Spectrum)</B><BR>
Initializes the random generators seed (n=1..65535). When n is zero (the
default), the current frame counter is used as seed.<BR>
<BR>
<B>READ v1[,v2[,v3]] (Spectrum only)</B><BR>
Loads expressions from DATA lines into the specified variable(s). See also:
RESTORE.<BR>
<BR>
<B>REM ...</B><BR>
Defines a remark, ignored by the program. The comment field may be also
mis-used to define binary machine code inside of a basic program.<BR>
However, the comment may not contain a NEWLINE character (76h) - ie. a
HALT instruction (opcode 76h) may not be used, as well as any other
opcodes with 76h as parameter byte, such like JP 4176h, or LD A,76h,
etc.<BR>
<BR>
<B>RESET (Timex TS2068/TC2068 only)</B><BR>
Intended to reset connected peripherals. No idea if/which/how any peripherals
do actually support this command.<BR>
<BR>
<B>RESTORE [n] (Spectrum only)</B><BR>
Sets the first line number where following READ commands start searching for
DATA statements, the default is the begin of the program.<BR>
<BR>
<B>RETURN</B><BR>
Returns to the line following to the most recently executed GOSUB command.<BR>
<BR>
<B>RUN [n]</B><BR>
Clears all variables and jumps to the specified line number. The default is
the first line of the program. See GOTO for details.<BR>
<BR>
<B>SAVE f</B><BR>
Saves the system area, the program, the video memory, and any defined
variables to cassette. The filename f must be a 1-127 characters string,
which may not include inverted characters. The text display is suspended for
the duration of saving, white lines are displayed indicating the cassette
signals.<BR>
When using SAVE from inside of the program, then the program is automatically
continued at the following line. Note that the GOSUB stack is not saved, so
that SAVE should not be used from inside of a sub-routine.<BR>
The ZX80 does not support filenames, just enter SAVE without parameter.<BR>
<BR>
<B>SCROLL (ZX81 only)</B><BR>
Moves the display upwards, and inserts a blank line at the bottom.<BR>
Note: The blank line is totally empty, in VRAM it is defined as a single HALT
opcode, without any SPACE characters.<BR>
<BR>
<B>SLOW (ZX81 only)</B><BR>
Switches to SLOW mode (approx. 4 times slower than FAST mode). The text
screen is displayed, and the program is executed during vertical blanking
periods only. The ZX81 is initially operating in SLOW mode.<BR>
The ZX80 does not support SLOW and FAST commands, and it is always operating
in FAST mode.<BR>
<BR>
<B>SOUND index,data [;index,data] [...] [;index,data] (Timex TS2068/TC2068 only)</B><BR>
Allows to write one or more values to the PSG sound registers. Unlike the
PLAY/BEEP commands, it does just start (or stop or change) sounds, but
doesn't pause program execution.<BR>
<BR>
<B>SPECTRUM (Spectrum 128/+2/+2A/+3 only)</B><BR>
Switches to Spectrum 48K backwards-compatible mode. Disables the new I/O
ports, disables the Extended System area, re-enables the old color codes like
{INK RED}, re-enables the hotkey mode like R=RUN, etc. The BASIC program (if
any) is kept in memory (eg. allows to load 48K program from Spectrum +3 disk
drive, and then run it in 48K mode).<BR>
<BR>
<B>STOP</B><BR>
Stops the program. User may enter CONT to continue in following line.<BR>
<BR>
<B>UNPLOT x,y (ZX81 only)</B><BR>
Same as PLOT, but drawing a white dot instead of a black dot.<BR>
<BR>
Additional commands...<BR>
<BR>
<B>FORMAT (Spectrum only)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> FORMAT LINE baudrate ;default=9600
FORMAT LPRINT target ;"R"=RS232, "C"=Centronics
FORMAT LPRINT tokenmode ;"E"=Expanded, "U"=Unexpanded tokens
COPY - normal screen copy to printer
COPY EXP - expanded screen copy to printer (recurse BRIGHT attributes)
COPY EXP INVERSE - expanded inverse screen copy to printer
</TD></TR></TABLE><B>CAT (Spectrum only)</B><BR>
<B>MOVE (Spectrum only)</B><BR>
<B>ERASE (Spectrum only)</B><BR>
<B>OPEN # (Spectrum only)</B><BR>
<B>CLOSE # (Spectrum only)</B><BR>
<B>MERGE (Spectrum only)</B><BR>
<B>VERIFY (Spectrum only)</B><BR>
<A HREF="#spectrumdiscandtapecommands">Spectrum Disc and Tape Commands</A><BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="basicfunctions"></A><FONT SIZE=+2>&nbsp;BASIC Functions</FONT></TD></TR></TABLE><BR>
Note that all ZX81 and Spectrum 48K functions must be entered in form of
SHIFT or FUNCTION mode key combinations. For example, type SHIFT+ENTER,B for
the INKEY$ keyword - attempting to enter I,N,K,E,Y,$ would result in a syntax
error. The same applies for multi-character operands such like "&gt;=" and "**".<BR>
For the ZX80 and Spectrum 128/+2/+2A/+3 it is vice-versa, and all functions
must be entered character by character. Also, ZX80 function parameters must
be put into () brackets.<BR>
<BR>
<B>ABS n</B><BR>
Returns the unsigned value of n.<BR>
<BR>
<B>ATTR (y,x) (Spectrum only)</B><BR>
Returns the characters 8bit color attritbute stored in VRAM attribute area.<BR>
<BR>
<B>BIN n (Spectrum only)</B><BR>
Treats the following digits as binary number (max 16bit).<BR>
<BR>
<B>CHR$ n</B><BR>
Returns character n. (Converts a number into a single-character string.)<BR>
<BR>
<B>CODE string</B><BR>
Returns the character number of the first character (or 0 if string is
empty). Opposite of CHR$.<BR>
<BR>
<B>FN name(n,n,etc) (Spectrum only)</B><BR>
Executes a user defined function (which can be defined with DEF FN).<BR>
<BR>
<B>FREE (Timex TS2068/TC2068 only)</B><BR>
Returns amount of free memory in bytes.<BR>
<BR>
<B>IN n (Spectrum only)</B><BR>
Returns a byte read from the specified 16bit I/O address.<BR>
<BR>
<B>INKEY$ (ZX81/Spectrum only)</B><BR>
Returns the character of the currently pressed key, or "" if none pressed.<BR>
<BR>
<B>LEN string (ZX81/Spectrum only)</B><BR>
Returns the length of the string.<BR>
<BR>
<B>PEEK n</B><BR>
Returns a byte read from decimal (!) memory address n. The ZX does not
recognize hexadecimal numbers.<BR>
<BR>
<B>POINT (x,y) (Spectrum only)</B><BR>
Returns the pixel color (0 or 1) stored in VRAM bitmap area.<BR>
<BR>
<B>RND (for ZX80: RND n)</B><BR>
Returns a random number in range 0 to 0.99999... (ZX81/Spectrum), or 1 to n
(ZX80).<BR>
<BR>
<B>SCREEN$ (y,x) (Spectrum only) ;returns character at location x,y</B><BR>
Returns character that matches the 8x8 pixel cell in VRAM bitmap area.<BR>
<BR>
<B>SGN n (ZX81/Spectrum only)</B><BR>
Returns the sign (-1, 0, or +1) of n.<BR>
<BR>
<B>STICK n,m (Timex TS2068/TC2068 only)</B><BR>
Returns joystick status (via PSG register 14). n=1 returns 1bit button
status, n=2 returns 4bit direction status. m selects the joystick port (1 or
2).<BR>
<BR>
<B>STR$ n</B><BR>
Returns n converted into a string.<BR>
<BR>
<B>TL$ string (-ZX80- only)</B><BR>
Returns string with leftmost character truncated. Equivalent to the ZX81
expression 'string(2 TO)'.<BR>
<BR>
<B>USR n</B><BR>
Calls a machine program in memory at address n, and returns the value of
the BC register when (if) the machine code program returns. The ZX does
not recognize hexadecimal addresses.<BR>
<BR>
<B>VAL string (ZX81/Spectrum only)</B><BR>
Converts the string into a value, stops the program if failed.<BR>
<BR>
<B>VAL$ string (Spectrum only)</B><BR>
This is a subfunction of the VAL function, it removes bounding quotes from
the string, but without actually doing a string-to-value conversion. No idea
if it's useful for anything.<BR>
<BR>
<B>Floating Point related functions (ZX81/Spectrum only)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> ACS n Arcus Cosinus.
ASN n Arcus Sinus.
ATN n Arcus Tangens.
COS n Cosinus.
EXP n Exponent e^n.
INT n Returns an integer value (rounded DOWN).
LN n Logarhytmn of n (base e).
PI 3.14159265...
SIN n Sinus.
SQR n Square root.
TAN n Tangens.
</TD></TR></TABLE><BR>
<B>Numeric operations</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Op. Prio. Expl.
a+b 6 Addition
a-b 6 Subtraction
a*b 8 Multiplication
a/b 8 Division
-a 9 Invert sign
a**b 10 a^b
</TD></TR></TABLE><B>Logical operations (Returns 1 if true, 0 if false)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Op. Prio. Expl.
a=b 5 Equal
a&gt;b 5 Greater than
a&lt;b 5 Less than
a&lt;=b 5 Less or equal
a&gt;=b 5 Greater or equal
a&lt;&gt;b 5 Not equal
</TD></TR></TABLE><B>Special Numeric/Logical operations</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Op. Prio. Expl.
a OR b 2 b&lt;&gt;0: Returns 1; b=0: Returns a.
a[$] AND b 3 b&lt;&gt;0: Returns a (or a$); b=0: Returns 0 (or "").
NOT b 4 b&lt;&gt;0: Returns 0; b=0: Returns 1.
</TD></TR></TABLE>Priority for indexing (DIM) and string-fragments (TO) is 12. Priority
for all functions is 12.<BR>
<BR>
<B>String ( [first] TO [last] ) Operand</B><BR>
Used to specify a fragement of a string from first character to last
character. The default values are: first=1, and last=LEN.<BR>
May be used either in source and destination of string operations, eg.:<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> LET A$(5 TO 7) = "***" ;overwrites 5th-7th character of A$
LET A$ = B$(TO 4) ;copies 1st-4th character of B$ to A$
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="basicerrorcodes"></A><FONT SIZE=+2>&nbsp;BASIC Error Codes</FONT></TD></TR></TABLE><BR>
<B>Commandline Errors</B><BR>
When entering a line incorrectly, the [S] symbol (Syntax Error) is
displayed at the fault location, prompting the user to correct the
problem.<BR>
<BR>
<B>ZX81 Execution Errors</B><BR>
Otherwise, when errors occur during program execution, the following
error codes are displayed.<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 No Error, program terminated succesfully.
1 Encountered NEXT without FOR.
2 Undefined Variable.
3 DIM Index out of range. May also return error B if 16bit exceeded.
4 Memory full.
5 Screen full. Type CONT to continue with cleared screen.
6 Arithmetic Overflow, a value is greater than 10^38.
7 Encountered RETURN without GOSUB.
8 Attempted to use INPUT as command (without line number).
9 Program halted by STOP command, may continue by CONT.
A Function with bad argument.
B Integer out of range.
C Failed VAL function.
D Program aborted by BREAK (SPACE KEY), or entered STOP at begin of INPUT.
E Not used.
F Attempted to SAVE a file with empty "" name.
</TD></TR></TABLE>Errors are always displayed as ERR/LINE indicating the line number which
caused the error.<BR>
<BR>
<B>ZX80 Execution Errors</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 0 program completed (or breaked), no error
1 NEXT without FOR
2 variable not defined
3 dimension out of range (DIM)
4 memory or gosub stack full
5 (???)
6 integer overflow (value exceeds -32768..+32767)
7 RETURN without GOSUB
8 attempted INPUT but program isn't running
9 STOP command
</TD></TR></TABLE><BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="basicprogramsandvariableszx81spectrum"></A><FONT SIZE=+2>&nbsp;BASIC Programs and Variables (ZX81/Spectrum)</FONT></TD></TR></TABLE><BR>
<B>BASIC Program Line Structure</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bytes Expl.
2 Line Number (MSB,LSB) (!)
2 Line Length (LSB,MSB)
LEN-1 Text
1 Newline (ZX81=76h) (Spectrum=0Dh)
</TD></TR></TABLE>The following are used in the Text area: 00h-3Fh and 80h-BFh for normal and
inverted characters, C0h-FFh and 40h-42h for keywords, 7Eh for values, and
76h indicates the end of the line. On the Spectrum, characters are in ASCII,
keywords are different, values are 0Eh, and end of line is 0Dh.<BR>
Values are duplicated in program lines: First, as normal text, ie. as
entered by the user (this field is ignored during execution, still it
must exist, but might be always set to "0" if desired). And second, invented
by the code 7Eh, as pre-calculated 5-byte FLOAT number.<BR>
An immediate thus occupies at least 7 bytes. However, there are some grindy
methods to save memory, such like: PI-PI defines 0 in only 3 bytes, VAL "9"
defines 9 in only 4 bytes, etc.<BR>
<BR>
<B>BASIC One-Letter Variables</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bytes Expl.
1 60h + Letter (5bit)
5 Floating point number (exponent/value)
</TD></TR></TABLE><BR>
<B>BASIC Multi-Character Variables</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bytes Expl.
1 A0h + First Letter (5bit)
NN 00h + Further Characters (6bit)
1 80h + Last Character (6bit)
5 Floating point number (exponent/value)
</TD></TR></TABLE><BR>
<B>BASIC Numeric Array</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bytes Expl.
1 80h + Letter (5bit)
2 Total Length of all following data
1 Number of Dimensions
D*2 Range of each of the Dimension(s)
N*5 Values
</TD></TR></TABLE><BR>
<B>BASIC FOR-NEXT Counter</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bytes Expl.
1 E0h + Letter (5bit)
5 Current Value (float)
5 Target Value (float)
5 Step
2 Loop Linenumber (MSB,LSB) (!)
</TD></TR></TABLE><BR>
<B>BASIC String</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bytes Expl.
1 40h + Letter (5bit)
2 String Length (0 if empty)
LEN Character String (none if empty)
</TD></TR></TABLE><BR>
<B>BASIC Character Array</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bytes Expl.
1 C0h + Letter (5bit)
2 Total Length of all following data
1 Number of Dimensions
D*2 Range of each of the Dimension(s)
N*1 Characters
</TD></TR></TABLE><BR>
<B>5-byte FLOAT numbers</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 Exponent 81h +/- location of most significant bit
4 Sign-Bit and Value excluding most significant bit
</TD></TR></TABLE>For example, the value 7FFFh would be defined as such: In this case the
MSB is Bit 14 (ie. 4000h) the exponent byte must be set to 14+81h
(=8Fh). The sign bit is zero (Bit 7 of first byte), and the remaining
bits, in this case Bit 13-0 (3FFFh), are shifted to the left as much as
possible (so that highest bit is located in Bit 6 of first byte) the
four bytes must be: 7F FE 00 00.<BR>
<BR>
<B>5-byte NON-FLOAT numbers with Exponent=00h (Spectrum only / not ZX81)</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 Exponent 00h (indicates that it is a non-float value)
1 Sign (00h=Positive, FFh=Negative)
2 Integer (0000h..FFFFh) (or -0001h..-FFFFh when negative)
1 Unused (00h)
</TD></TR></TABLE>BUG: In some cases (not sure when?), -10000h is also stored as non-float,
and, in some further cases (not sure when?) that causes problems.<BR>
<BR>
<B>5-byte FLOAT bug</B><BR>
There's some inaccuracy when converting text strings (eg. user input) to
float numbers. For example, the correct value for 0.25 would be 7F 00 00 00
00, however, the ZX81/TS1000 BIOSes do convert it to 7E 7F FF FF FF
(accidently rounded down), the TS1500 BIOS does unsuccessfully try to fix
that problem by converting it to 7F 00 00 00 01 (accidently rounded up). This
is resulting in incompatibility, for example,<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 10 FOR I = 0 TO 1 STEP .25
20 PRINT I
30 NEXT I
</TD></TR></TABLE>The ZX81/TS1000 does correctly stop at 1 being displayed as last number,
whilst the "improved" TS1500 does incorrectly stop at 0.75. Mind that
immediates are pre-compiled at time of entering the program code, so a
program SAVEd on a ZX81, may work exactly as on the ZX81 even when LOADing it
on a TS1500 (unless it contains conversions being done at runtime, like VAL
".25" or VAL A$).<BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> 1 IF VAL"0.25" &lt; 1/4 THEN PRINT "TOO SMALL (ZX81 OR TS1000 OR SPECTRUM)"
2 IF VAL"0.25" &gt; 1/4 THEN PRINT "TOO BIG (TS1500 OR LAMBDA)"
3 IF VAL"0.25" = 1/4 THEN PRINT "MATCH (WHOOPS)"
</TD></TR></TABLE>Typing IF VAL"0.25" forces conversion on runtime (typing IF 0.25 would be
converted when entering the program, and stay so even when SAVing it and
LOADing it on another computer). Interestingly, the TOO SMALL variants, do
also (incorrectly) display a MATCH in line 3.<BR>
<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="basicprogramsandvariableszx80"></A><FONT SIZE=+2>&nbsp;BASIC Programs and Variables (ZX80)</FONT></TD></TR></TABLE><BR>
<B>BASIC Program Line Structure</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bytes Expl.
2 Line Number (MSB,LSB) (!)
... Text
1 Newline (76h)
</TD></TR></TABLE>The following are used in the Text area: 00-3F and 80-BF for normal and
inverted characters, D4-FF for keywords, and 76 indicates the end of the
line. A couple of 'special' characters such like ';()*+/-' are stored in
form as keywords rather than as normal character codes.<BR>
Function names and values in program lines are stored as normal text.<BR>
<BR>
<B>BASIC One-Letter Variables</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bytes Expl.
1 60h + Letter (5bit)
2 Signed Integer
</TD></TR></TABLE><BR>
<B>BASIC Multi-Character Variables</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bytes Expl.
1 40h + First Letter (5bit)
NN 00h + Further Characters (6bit)
1 80h + Last Character (6bit)
2 Signed Integer
</TD></TR></TABLE><BR>
<B>BASIC Numeric Array</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bytes Expl.
1 A0h + Letter (5bit)
1 Range (Counted from 0 to N)
(N+1)*2 Signed Integers
</TD></TR></TABLE><BR>
<B>BASIC FOR-NEXT Counter</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bytes Expl.
1 E0h + Letter (5bit)
2 Current Value
2 Target Value
2 Loop Linenumber (normal LSB,MSB for ZX80)
</TD></TR></TABLE><BR>
<B>BASIC String</B><BR>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> Bytes Expl.
1 80h + Letter (5bit)
... Character String (none if empty)
1 Ending Quotes (01h)
</TD></TR></TABLE><BR>
<B>BASIC Character/String Arrays</B><BR>
None such - ZX80 supports numeric arrays only.<BR>
<BR>
<BR>
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="aboutthisdocument"></A><FONT SIZE=+2>&nbsp;About this document</FONT></TD></TR></TABLE><BR>
This document has been extracted from the no$zx emulator/debugger.<BR>
Copyright 2001-2012 by Martin Korth.<BR>
<BR>
<B>Homepage</B><BR>
http://nocash.emubase.de/zx.htm<BR>
<BR>
<B>ZX Specifications</B><BR>
This document in .TXT and .HTML format:<BR>
- http://nocash.emubase.de/zxdocs.txt<BR>
- http://nocash.emubase.de/zxdocs.htm<BR>
<BR>
<B></B><BR>
</BODY></HTML>