mirror of
https://github.com/problemkaputt/problemkaputt.github.io.git
synced 2024-05-13 02:04:53 -04:00
9390 lines
529 KiB
HTML
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> 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> 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> 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> 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> <-key-> <------------- ZX81 -----------> <------ZX80------>
|
|
NORMAL COMMAND SHIFT FUNCTION GRAPHICS ZX80/CMD ZX80/SHFT
|
|
1 1 <edit> -- 1000 1 NOT
|
|
2 2 AND -- 0100 2 AND
|
|
3 3 THEN -- 0001 3 THEN
|
|
4 4 TO -- 0010 4 TO
|
|
5 5 <left> -- 0101 5 <left>
|
|
6 6 <down> -- 0011 6 <down>
|
|
7 7 <up> -- 1100 7 <up>
|
|
8 8 <right> -- 0101 8 <right>
|
|
9 9 <graphics> -- -- 9 <hide???>
|
|
0 0 <rubout> -- -- 0 <rubout>
|
|
Q PLOT "" SIN 0111 NEW 1010
|
|
W UNPLOT OR COS 1011 LOAD 0011
|
|
E REM STEP TAN 1110 SAVE 1000
|
|
R RUN <= INT 1101 RUN 0100
|
|
T RAND <> RND 0110 " " 0022
|
|
Y RETURN >= 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 <edit>
|
|
SHIFT -- -- -- -- -- --
|
|
Z COPY : LN -- "?" :
|
|
X CLEAR ; EXP -- CLEAR ;
|
|
C CONT ? AT -- CLS ?
|
|
V CLS / -- -- GO SUB /
|
|
B SCROLL * INKEY$ -- RETURN OR
|
|
N NEXT < NOT -- NEXT <
|
|
M PAUSE > PI -- "?" >
|
|
. , -- -- "." ,
|
|
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> 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> 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 <nn> 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> 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> 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> 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> 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> 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> 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> 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 ( ) > < = + - * / ; , . 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 ( ) - + * / = > < ; , . 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> 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 <different> 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> 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> 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> 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> 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 --> 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> 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) ;/ <--- 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> 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 [>] 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 >=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 [>] 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> 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> 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> 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> 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> 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> 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> 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> 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> 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> 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> 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> 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> <---- Original NMI Handler ----> <----- Tuned NMI Handler ----->
|
|
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> 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 ----|<|---+--[4K7]--+ +---- RAMPACK./RFSH ;ALWAYS HIGH
|
|
|
|
|
ZX81./RD ----|<|---+-------------------- 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> 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> 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> 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) -----|>|----- Centr.Pin3 (D1)
|
|
Keyb Col1/Pin10 (D0) -----|>|----- Centr.Pin4 (D2)
|
|
Keyb Col2/Pin11 (D1) -----|>|----- Centr.Pin5 (D3)
|
|
Keyb Col3/Pin12 (D2) -----|>|----- Centr.Pin6 (D4)
|
|
Keyb Col4/Pin13 (D3) -----|>|----- Centr.Pin7 (D5)
|
|
Expansion 21A (RESET) -----|>|----- 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> 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> 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> 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 <enable> functions mapped to memory
|
|
(whilst <disable> is done via I/O ports).<BR>
|
|
<BR>
|
|
<BR>
|
|
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="spectrummemorymaps"></A><FONT SIZE=+2> 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> 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 <undocumented/unused byte> ?
|
|
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> 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> 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> 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> 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.. ;<--- U=Blocked by ULA, c=Free for CPU access
|
|
654321006543210065432100.. ;<--- 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.. ;<--- U=Blocked by ULA, c=Free for CPU access
|
|
107654321076543210765432.. ;<--- 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> 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> 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 --> 3.7V
|
|
Port FEh = 10h --> 3.6V
|
|
Port FEh = 08h --> 0.7V
|
|
Port FEh = 00h --> 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> 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> 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 --> max/1, 14 --> max/1.414, 13 --> 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> 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> 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> 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 --> F0 --> F1 --> F2 --> F3 --> F4 --> F5 --> PWM --> 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> <-Pitch-> __ Amplitude level (-)
|
|
<--------repeat=3--------->
|
|
</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
|
|
| | || | || | ||| | |
|
|
<-64->| || | || | ||| | | __ Amplitude level (-)
|
|
<----------repeat=5---------->
|
|
</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> <-64-> __ Amplitude level (-)
|
|
<----------repeat=5---------->
|
|
</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> _____ _____
|
|
------------------>| |------------------->| |-----+----->
|
|
_____ | SUB | ______ | SUB | |
|
|
+--->| *B |--->|_____| +--->| *2*F |-->|_____| |
|
|
| |_____| _____ | |______| _____ |
|
|
+---------------|OLDER|<---+---------------| OLD |<----+
|
|
|_____| |_____|
|
|
</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> 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 ;\ <---- 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> 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> <--------------- Currah Codes --------------->
|
|
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> 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> 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 --> 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> 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--> Spectrum Disc I/O Ports<BR>
|
|
x--> 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 ->
|
|
2 R/W 27 DRQ ->
|
|
3 A0 26 /DDEN <- Double Density Enable
|
|
4 A1 25 /WRPT <-
|
|
5 D0 24 /IP <- Index Hole
|
|
6 D1 23 /TR00 <-
|
|
7 D2 22 WD Write Data ->
|
|
8 D3 21 WG Write Gate ->
|
|
9 D4 20 MO Motor On ->
|
|
10 D5 19 /RD Read Data <-
|
|
11 D6 18 CLK 8MHz <-
|
|
12 D7 17 SD Step-Direction ->
|
|
13 /RES 16 STEP Step ->
|
|
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> 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> 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 <filename> ;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 <filename> DATA a () ;load numeric array
|
|
LOAD <filename> DATA a$ () ;load character array
|
|
SAVE <filename> ;save basic program
|
|
SAVE <filename> LINE <linenumber> ;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 <filename> DATA a () ;save numeric array
|
|
SAVE <filename> DATA a$ () ;save character array
|
|
VERIFY <filename> ;compare file with program in in RAM
|
|
MERGE <filename> ;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! --> 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 ;<B>=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> 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> 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 < 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> 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> 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>0) ;\pilot
|
|
.. .. Pilot/Sync RLE-compressed stream (PRLE) (only if TOTP>0) ;/stream
|
|
.. .. Data symbols definition table (only if TOTD>0) ;\data
|
|
.. .. Data stream (as in .TAP files) (only if TOTD>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> 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> 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> 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> 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 <R> 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 <W> S0 S1 S2 TR HD LS SZ write sector(s)
|
|
06+MT+MF+SK HU TR HD SC SZ LS GP SL <R> 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 <W> 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 <R> S0 S1 S2 TR HD LS SZ rd deleted sec(s)
|
|
0D+MF HU SZ NM GP FB <W> 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 <W> S0 S1 S2 TR HD LS SZ scan equal
|
|
19+MT+MF+SK HU TR HD SC SZ LS GP SL <W> S0 S1 S2 TR HD LS SZ scan low or equal
|
|
1D+MT+MF+SK HU TR HD SC SZ LS GP SL <W> 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->FDC, 1=FDC->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> 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> 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 --> Built-in in Disciple
|
|
G+DOS --> Built-in in PlusD
|
|
Beta DOS --> Third-party DOS Replacement for PlusD
|
|
UniDOS --> 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> 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 --> switch from BASIC to TRDOS ;3C00h/3D00h
|
|
RETURN (aka Y-key) --> 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> 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 <current> position
|
|
of the head, and that the Data Register contains the <desired> 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> 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> 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]<>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> 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> 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 <= SIN ASN ASN USR.Q USR.Q
|
|
w W DRAW <> COS ACS ACS INKEY$ INKEY$
|
|
e E REM >= TAN ATN ATN USR.E USR.E
|
|
r R RUN < INT VERIFY VERIFY USR.R USR.R
|
|
t T RAND > 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> 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 --> Interprete as Sinclair Joystick Port 1
|
|
SHIFT+5,6,7,8,SPACE --> Interprete as Cursor Keys (for use in emulators)
|
|
Q,A,O,P,SPACE --> Interprete as Keyboard Keys
|
|
Port 1Fh --> 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> 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> 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> 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> 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> 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> 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> 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> Spectrum Serial Port</FONT></TD></TR></TABLE><BR>
|
|
Interface 1 -> RS232/Network: Port F7h and EFh<BR>
|
|
Spectrum 128/+2/+2A/+3 -> RS232/Keypad: PSG Register 14<BR>
|
|
Rotronics Wafadrive -> RS232: Port ? (uses RX,TX,RTS,CTS)<BR>
|
|
Timex RS232 Interface -> RS232: Port ?<BR>
|
|
Indescomp -> 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> 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> 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 --> Language ROM-Oriented Software at 0000h (Z80 Code)
|
|
AROS --> 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> 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> 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 ------|>o---- CNTR.10 ACK (SPKR)
|
|
EAR ------------------- CNTR.2 D0 (EAR)
|
|
KB1.Pin1 "0" ---|>|---- CNTR.3 D1 (CLK)
|
|
KB1.Pin2 "9" ---|>|---- CNTR.4 D2 (D0)
|
|
KB1.Pin3 "8" ---|>|---- CNTR.5 D3 (D1)
|
|
KB1.Pin4 "7" ---|>|---- CNTR.6 D4 (D2)
|
|
KB1.Pin5 "6" ---|>|---- CNTR.7 D5 (D3)
|
|
CPU.Pin26 ----|>|---- 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" ---|>|--- DSUB.Pin6 Fire
|
|
KB1.PIN2 "9" ---|>|--- DSUB.Pin1 Up
|
|
KB1.PIN3 "8" ---|>|--- DSUB.Pin2 Down
|
|
KB1.PIN4 "7" ---|>|--- DSUB.Pin4 Right
|
|
KB1.PIN5 "6" ---|>|--- DSUB.Pin3 Left
|
|
KB2.PIN4 A12 ---|<|--- 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 ----|>|----- 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> 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 <--> 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> 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> 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> 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> 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> 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> 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 <word name> (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 <LOAD
|
|
dummy>, watch the first filename listed on screen, rewind tape, type <LOAD
|
|
filename>.<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: <FILENAME>, 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
|
|
<00h,"LOAD filename mainfunction"> 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> 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> 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 (--> x) Store 16bit immediate on stack (eg. 1)
|
|
f (--> f) Store float immediate on stack (eg. 1.0)
|
|
DROP (x -->) Discard TOS (top of stack)
|
|
DUP (x --> x x) Copy 1st cell to top (Duplicate TOS)
|
|
OVER (x2 x1 --> x2 x1 x2) Copy 2nd cell to top
|
|
PICK (xn..x1 n --> xn..x1 xn) Copy nth cell to top
|
|
SWAP (x2 x1 --> x1 x2) Rotate 2nd cell to top
|
|
ROT (x3 x2 x1 --> x2 x1 x3) Rotate 3rd cell to top
|
|
ROLL (xn..x1 n --> xn-1..x1 xn) Rotate nth cell to top
|
|
?DUP (x --> x (x)) Conditional DUP, only if x = non-zero
|
|
>R (x -->) (R: --> x) Move TOS to Return Stack
|
|
R> (R: x -->) (--> x) Retrieve from Return Stack
|
|
</TD></TR></TABLE><BR>
|
|
<B>Memory</B><BR>
|
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> @ (adr --> x) Read x (2 bytes) from adr
|
|
! (x adr -->) Store x (2 bytes) to adr
|
|
C@ (adr --> c) Read c (1 byte) from adr
|
|
C! (c adr -->) 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> FORTH Maths</FONT></TD></TR></TABLE><BR>
|
|
<B>Integer Arithmetic</B><BR>
|
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> + (n1 n2 --> n3) n3 = n1 + n2
|
|
- (n1 n2 --> n3) n3 = n1 - n2
|
|
* (n1 n2 --> n3) n3 = n1 * n2
|
|
/ (n1 n2 --> n3) n4 = n1 / n2
|
|
MOD (n1 n2 --> n3) Remainder of n1 / n2 (sign of n1)
|
|
/MOD (n1 n2 --> n3 n4) n3 = remainder of n1/n2, n4=n1/n2
|
|
*/ (n1 n2 n3 --> n4) n4 = n1*n2/n3
|
|
*/MOD (n1 n2 n3 --> n4 n5) n4 = remainder of n1*n2/n3, n5=n1*n2/n3
|
|
1+ (n1 --> n2) n2 = n1 + 1
|
|
1- (n1 --> n2) n2 = n1 - 1
|
|
2+ (n1 --> n2) n2 = n1 + 2
|
|
2- (n1 --> n2) n2 = n1 - 2
|
|
ABS (n --> u) u = |n| (absolute value)
|
|
NEGATE (n1 --> n2) n2 = -n1 (two's complement)
|
|
U* (u1 u2 --> ud) ud = u1 * u2
|
|
U/MOD (ud u1 --> u2 u3) u2 = remainder of ud/u1, u3 = ud/u1
|
|
D+ (d1 d2 --> d3) d3 = d1 + d2
|
|
DNEGATE (d1 --> 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 --> n) Convert floating number to integer
|
|
UFLOAT (u --> f) Convert unsigned integer to float
|
|
F+ (f1 f2 --> f3) f3 = f1 + f2
|
|
F- (f1 f2 --> f3) f3 = f1 - f2
|
|
F* (f1 f2 --> f3) f3 = f1 * f2
|
|
F/ (f1 f2 --> f3) f3 = f1 / f2
|
|
FNEGATE (f1 --> f2) f2 = -f1
|
|
</TD></TR></TABLE><BR>
|
|
<B>Comparison</B><BR>
|
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> < (n1 n2 --> flag) True if n1 < n2
|
|
= (n1 n2 --> flag) True if n1 = n2
|
|
> (n1 n2 --> flag) True if n1 > n2
|
|
0< (n --> flag) True if n < 0
|
|
0= (n --> flag) True if n = 0
|
|
0> (n --> flag) True if n > 0
|
|
U< (u1 u2 --> flag) True if u1 < u2
|
|
D< (d1 d2 --> flag) True if d1 < d2
|
|
MAX (n1 n2 --> n3) Leave greater of two numbers
|
|
MIN (n1 n2 --> 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 --> x3) Bitwise boolean AND
|
|
OR (x1 x2 --> x3) Bitwise boolean OR
|
|
XOR (x1 x2 --> x3) Bitwise boolean XOR
|
|
</TD></TR></TABLE><BR>
|
|
<BR>
|
|
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="forthinputoutput"></A><FONT SIZE=+2> FORTH Input/Output</FONT></TD></TR></TABLE><BR>
|
|
<B>Character Output</B><BR>
|
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> CR (-->) Print carriage return and line feed
|
|
EMIT (c -->) Print ASCII character c
|
|
SPACE (-->) Print one space
|
|
SPACES (n -->) Print n spaces, if n > 0
|
|
." ..." (-->) Print string terminated by " (." 123 test")
|
|
TYPE (adr n -->) 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 -->) Print n with one trailing space
|
|
U. (u -->) Print unsigned with one trailing space
|
|
F. (f -->) 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> <# (-->) Initiate formatted output
|
|
# (ud1 --> ud2) Convert one digit from ud1 and HOLD it in the PAD
|
|
#S (ud --> 0 0) Convert and HOLD all remaining significant digits
|
|
HOLD (c -->) Insert character into formatted string
|
|
SIGN (n -->) HOLD minus sign if n < 0
|
|
#> (ud --> 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 (--> adr) 1-byte variable containing system number base
|
|
DECIMAL (-->) Set base to decimal
|
|
ASCII text (--> 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 (-->) Accept entry at the input buffer
|
|
WORD (c --> adr) Take text from input buffer using c
|
|
as delimiter, leave adr of length byte
|
|
RETYPE ( --> ) Allow input buffer editing, turning cursor to "?"
|
|
INKEY (--> 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 --> d2 adr2) Convert string at adr1 to double number
|
|
and add into d1 leaving result d2
|
|
NUMBER (--> x (adr)) Get number from input buffer
|
|
(--> n 4102) Converted to integer
|
|
(--> f 4181) Converted to float
|
|
(--> 0) Conversion failed
|
|
</TD></TR></TABLE><BR>
|
|
<B>Misc Screen Output</B><BR>
|
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> CLS (-->) Clear screen
|
|
AT (n1 n2 -->) Set print position to row n1 and column n2
|
|
PLOT (n1 n2 n3 -->) 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> FORTH ....</FONT></TD></TR></TABLE><BR>
|
|
<B>Control Structures</B><BR>
|
|
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><PRE> IF (flag -->) Conditional structure IF..(ELSE)..THEN
|
|
ELSE (-->) False condition of an IF structure
|
|
THEN (-->) End of an IF conditional structure
|
|
DO (n1 n2 -->) Counted loop structure DO...LOOP, (n2=start, n1=end)
|
|
LOOP (-->) Increment loop count, terminate if end
|
|
+LOOP (n -->) Add n to loop count, terminate if end
|
|
I (--> n) Get current loop count
|
|
I' (--> n) Get current loop count limit
|
|
J (--> n) Get outer loop count
|
|
LEAVE (-->) Force a DO...LOOP count to end
|
|
BEGIN (-->) Begin a WHILE or UNTIL loop
|
|
UNTIL (flag -->) Loop until flag = true (BEGIN..UNTIL)
|
|
WHILE (flag -->) Exit loop when flag = false (BEGIN..WHILE..REPEAT)
|
|
REPEAT (-->) Jump back to BEGIN in a WHILE loop
|
|
EXIT ( --> ) Exit current word execution
|
|
EXECUTE (adr -->) Execute word with compilation adr
|
|
CALL (adr -->) Call Z80 code (terminated with JP IY) (not by RET)
|
|
ABORT (... -->) Quit program, clearing data stack
|
|
QUIT (-->) 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 ... ; (-->) Define a procedure (terminated by semicolon)
|
|
VARIABLE vname (x -->) Define a variable with initial value x
|
|
CONSTANT cname (x -->) Define a constant with constant value x
|
|
CREATE aname (-->) Define an (empty) array (usually followed by ALLOT)
|
|
ALLOT (n -->) Allocate n bytes at end of newest word (see CREATE)
|
|
vname (--> adr) Get variable adr (eg. "vname @" to get its value)
|
|
aname (--> adr) Get array address
|
|
cname (--> x) Get constant value
|
|
pname (-->) Call a procedure
|
|
IMMEDIATE (-->) Make newest word to execute even in compile mode
|
|
DEFINER word (-->) Start a defining word definition
|
|
DOES> (--> adr) Define the action routine of a defining word
|
|
COMPILER word (n -->) Start a compiling word definition (and ALLOT n)
|
|
RUNS> (--> adr) Defines the action routine of a compiling word
|
|
FIND word (--> adr) Find word compilation address (0 if not found)
|
|
LIST word (-->) List word definition
|
|
EDIT word (-->) Edit word definition (doesn't delete old word)
|
|
FORGET name (-->) Delete <name> as well as ALL newer words
|
|
REDEFINE name (-->) Delete old <name> 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 (-->) Define a new vocabulary
|
|
dname (-->) Set CONTEXT to the <dname> vocabulary
|
|
FORTH (-->) Set CONTEXT to the FORTH vocabulary
|
|
DEFINITIONS (-->) Set CURRENT vocabulary to CONTEXT
|
|
CONTEXT (--> adr) Get current word search vocabulary address ;3C33h
|
|
CURRENT (--> adr) Get current word definition vocabulary addr ;3C31h
|
|
VLIST (-->) 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 -->) Compile x into dictionary (ALLOT 2 byte, set to x)
|
|
C, (c -->) Compile c into dictionary (ALLOT 1 byte, set to c)
|
|
LITERAL (x -->) Compile x into edited procedure (preceed by [ x ])
|
|
[ ... ] (... -->) 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> ( ...) (-->) Start a comment, terminated by ")"
|
|
HERE (--> adr) Next available dictionary location, ie. [STKBOT]
|
|
PAD (--> adr) Scratch pad area address (2701h aka 9985)
|
|
SLOW (-->) Normal execution. Enable error checks
|
|
FAST (-->) Faster execution. Disable error checks (and BREAK-key ?)
|
|
BEEP (u1 u2 -->) Play tone, u1=1000000/(8*freq [Hz]), u2=duration [ms]
|
|
IN (adr --> c) Read byte from Z80 input port adr
|
|
OUT (c adr -->) Write byte to Z80 output port adr
|
|
INVIS (-->) Disable copy-up mechanism and OK
|
|
VIS (-->) Enable copy-up mechanism and OK
|
|
LINE (-->) 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 (-->) Load vocabulary ;\lists all filenames
|
|
VERIFY name (-->) Verify vocabulary ;/when no name typed
|
|
SAVE name (-->) Save vocabulary
|
|
BLOAD name (adr u -->) Load u bytes to adr ;\use file header value(s)
|
|
BVERIFY name (adr u -->) Verify u bytes from adr ;/when adr=0 or u=0
|
|
BSAVE name (adr u -->) 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> 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 < 1 or > 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> 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> 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> 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<>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> 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<>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> 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 <--> HL
|
|
ex AF,AF 08 4 xxxxxx exchange AF <--> AF'
|
|
exx D9 4 ------ exchange BC,DE,HL <--> BC',DE',HL'
|
|
ex (SP),HL E3 19 ------ exchange (SP) <--> HL
|
|
ex (SP),ii pD E3 23 ------ exchange (SP) <--> 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> 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
|
|
<arit> r xx 4 szhonc see below
|
|
<arit> i pD xx 8 szhonc see below, UNDOCUMENTED
|
|
<arit> n xx nn 7 szhonc see below
|
|
<arit> (HL) xx 7 szhonc see below
|
|
<arit> (ii+d) pD xx dd 19 szhonc see below
|
|
<cnt> r xx 4 szhon- see below
|
|
<cnt> i pD xx 8 szhon- see below, UNDOCUMENTED
|
|
<cnt> (HL) xx 11 szhon- see below
|
|
<cnt> (ii+d) pD xx dd 23 szhon- see below
|
|
<logi> r xx 4 szhp00 see below
|
|
<logi> i pD xx 8 szhp00 see below, UNDOCUMENTED
|
|
<logi> n xx nn 7 szhp00 see below
|
|
<logi> (HL) xx 7 szhp00 see below
|
|
<logi> (ii+d) pD xx dd 19 szhp00 see below
|
|
</TD></TR></TABLE>Arithmetic <arit> 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 <cnt> 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 <logi> 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> 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)
|
|
<cmd> r CB xx 8 sz0p0c see below
|
|
<cmd> (HL) CB xx 15 sz0p0c see below
|
|
<cmd> (ii+d) pD CB dd xx 23 sz0p0c see below
|
|
<cmd> r,(ii+d) pD CB dd xx 23 sz0p0c see below, UNDOCUMENTED modify and load
|
|
</TD></TR></TABLE>Whereas <cmd> 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> 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<>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)
|
|
</INT=LOW,IM=0,IFF1=1> 1+var ------ IFF1=0,IFF2=0, exec opcode from databus
|
|
</INT=LOW,IM=1,IFF1=1> 12 ------ IFF1=0,IFF2=0, CALL 0038h
|
|
</INT=LOW,IM=2,IFF1=1> 18 ------ IFF1=0,IFF2=0, CALL [I*100h+databus]
|
|
</NMI=falling_edge> ? ------ IFF1=0, CALL 0066h
|
|
</TD></TR></TABLE><BR>
|
|
<BR>
|
|
<TABLE WIDTH=100%><TR bgcolor="#cccccc"><TD><A NAME="z80iocommands"></A><FONT SIZE=+2> 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> 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
|
|
<INT> IFF1=0, IFF2=0
|
|
<NMI> 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> 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> 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
|
|
"<ii+d> 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) > 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) > 09h
|
|
FLG_C = OLD_CARRY OR (OLD_A>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> 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> 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> 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 <startaddress>", 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> 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> 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 [>] Cursor selected line -
|
|
Shift+5/8 <CURSOR> Moves Cursor left/right in input buffer Cursor Keys
|
|
Shift+7/6 <CURSOR> Moves [>] 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 +,-,*,>=,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>[>] 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 [>] 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> 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<>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 <inside> 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 --> 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> 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 ">=" 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>b 5 Greater than
|
|
a<b 5 Less than
|
|
a<=b 5 Less or equal
|
|
a>=b 5 Greater or equal
|
|
a<>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<>0: Returns 1; b=0: Returns a.
|
|
a[$] AND b 3 b<>0: Returns a (or a$); b=0: Returns 0 (or "").
|
|
NOT b 4 b<>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> 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> 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" < 1/4 THEN PRINT "TOO SMALL (ZX81 OR TS1000 OR SPECTRUM)"
|
|
2 IF VAL"0.25" > 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> 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> 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>
|