Contents

Technical Information
Keyboard Assignment
General Specifications
Display Output
The BASIC Interpreter
Z80 Usage in ZX Models
Z80 CPU Specifications
Data Structures
Hardware, Connectors, Upgrading

Links
Internet Resources


 Keyboard Assignment

Here's the ZX81 keyboard assignment. The Graphics column is meant to be Shift+Graphics (Graphic without Shift just returns inverted 'normal' characters).
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.

  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

Keyboard Translation
When the no$zx81 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:
  ZX81  ZX80  PC
  EDIT  NOT   !
  AND   AND   &
  THEN  THEN  #
  TO    TO    %


 General Specifications

SPECs Machine Code Programs
SPECs I/O Ports
SPECs Memory Map and System Area
SPECs Memory Mirrors and Expansions
SPECs What is...
SPECs Internal Hardware
SPECs ZX80 vs ZX81 Compatibility


 SPECs Machine Code Programs

General Guidelines
A machine code program is called by using the USR function, for example:
  LET N=USR <startaddress>
  Note that only decimal addresses are supported.
The official ZX81 manual guidelines for returning to BASIC are:
  BC may contain returned value, if any (loaded into N in above example).
  IY must be 4000h upon return (pointer to the System Area)
  I must be 1Eh upon return (pointer to the Character set in ROM)
  return by RET opcode
That is nonsense, IY=4000h is restored automatically when returning, but when video is enabled it might be not a good idea to change IY or I at all.
The official ZX81 manual guidelines for machine code execution are:
  In SLOW mode, the AF' and IX' and R registers are used by
  the video interrupt handler and should not be modified.
That's garbage in so far that I've never heard of a IX' register :-)

Depositing Binary Data/Program in Memory
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.
The following are places that can be used as reserved area for binary code.

Using a REM instruction (in the program area)
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.
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".

Using a string (in the variables area)
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.
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.

Using memory above RAMTOP (outside of the known memory)
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.
RESTRICTION: The (standard) SAVE instruction does not save this area to cassette.


 SPECs I/O Ports

Output to Port FFh (or ANY other port)
Writing any data to any port terminates the Vertical Retrace period, and restarts the LINECNTR counter.

Input from Port FEh (or any other port with A0 zero)
Reading from this port also initiates the Vertical Retrace period, 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.
  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)
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).
(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.)

The Keyboard Matrix
  __Line____Bit__0____1____2____3____4__
   0  (A8)     SHIFT  Z    X    C    V
   1  (A9)       A    S    D    F    G
   2  (A10)      Q    W    E    R    T
   3  (A11)      1    2    3    4    5
   4  (A12)      0    9    8    7    6
   5  (A13)      P    O    I    U    Y
   6  (A14)    ENTER  L    K    J    H
   7  (A15)     SPC   .    M    N    B

Port FDh Write (ZX81 only)
Writing any data to this port disables the NMI generator.

Port FEh Write (ZX81 only)
Writing any data to this port enables the NMI generator.
NMIs (Non maskable interrupts) are used during SLOW mode vertical blanking periods to count the number of drawn blank scanlines.

ZX81 Printer
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.
Port FBh Read - Printer Status
  Bit  Expl.
  0    Data Request   (0=Busy, 1=Ready/DRQ)
  1-5  Not used
  6    Printer Detect (0=Okay, 1=None)
  7    Printer Online (0=Nope, 1=Ready/Online)
Port FBh Write - Printer Output
  Bit  Expl.
  0-6  ??? Somewhat one or more bits for linefeed and/or else...
  7    Pixel Output   (0=White, 1=Black)
As you can see, these BIOS functions are using a serial 1-bit / 1-pixel protocol, which isn't compatible with normal character based printers.

Note
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 relevant for video output also. For details refer to chapters about Video.


 SPECs Memory Map and System Area

Overview
  0000-1FFF   BIOS ROM (8KBytes)
  2000-3FFF   not used
  4000-43FF   Internal RAM (1 KByte)
  4000-7FFF   External RAM (16 KBytes)
Internal RAM is disabled (and cannot be accessed) when external RAM is installed.


ZX81 RAM Map
  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)

ZX81 System Area
  Addr.  Name    Expl
  4000   ERR_NR  Errorcode-1
  4001   FLAGS   Various BASIC Control flags
           Bit0=?
           Bit1=Redirect Output to printer
           Bit2-7=?
  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
  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   -       Keyboard - Debounce State
  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
                  Bit 0-7:?
  402E   STRLEN  Length of string during assignment
  4030   T_ADDR  Pointer to next item in Syntax Table
  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)

ZX80 Memory Map
  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
  ...

ZX80 System Area
  4000  byte          error code
  4001  byte (flags)
  4002  word          line number which is to be executed next
                        (bit 15: 1=stopped)
  4004  word          pointer (similiar as 400A ???, probably there is sth
                        that can be inserted between either one..)
  4006  word          line number for LIST
  4008  word          pointer to VARS / end of BASIC PROGRAM
  400A  word          pointer to INPUT BUFFER / end of VARS (-save area end-)
  400C  word  D_FILE  pointer to VRAM / end of INPUT BUFFER
  400E  word          pointer to ???
  4010  word          pointer to ???
  4012  byte
  4013  word
  4015  word
  4017  word          line number for CONTINUE
  4019  byte (flags)
  401A  word
  401C  word  SEED    random generator seed
  401E  word  FRAMES  incrementing frames counter
  4020  word
  ---Active/Basic:
  4022  word
  4024  word   // 4025 byte
  4026  word  CH_ADD  BASIC program pointer
  ---Pause/Input:
  4022  byte          keyboard 'Debounce'
  4023  byte  MARGIN  screen border height
  4024  word   // 4025 byte
  4026  word  LAST_K  last key pressed


 SPECs Memory Mirrors and Expansions

Memory Overview
RAM is originated at 4000h, for 1K RAM: at 4000h-43FFh; 48K: at 4000h-FFFFh, the area below 4000h is used only when more then 48K are installed.
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.
  address     code  read  write
  0000..1FFF  ROM   ROM   ---
  2000..3FFF  RAM4  RAM4  RAM4
  4000..7FFF  RAM1  RAM1  RAM1
  8000..BFFF  VRAM2 RAM2  RAM2
  C000..FFFF  VRAM1 RAM3  RAM3
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).
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.

1K RAM
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.
The ZX81 mainboard provides space for either two 1K x 4bit SRAM chips, or one 1K x 8bit SRAM chip (with L1 jumper closed).

2K RAM
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.

16K RAM
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.
Timex TS1500 has been delivered with 16K built-in RAM.

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.

32K RAM
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.
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).
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.

48K RAM
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'.
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.
Some 16K expansions can be combined with 32K expansions to gain a total of 48K RAM.

64K RAM
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.
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.


 SPECs What is...

Sinclair ZX81 Personal Computer

Multimedia
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.

Energy
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.

Computers Today
Unfortunately, the rather ineffective new invention of animated pictures has been adapted by newer computers, up to today!
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.


 SPECs Internal Hardware

ZX81
 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.820800 MHz
  For 60Hz Display Refresh:  0.547200 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

ZX80
Memory: 4 KBytes ROM, 1 KByte RAM
Video: Same as ZX81, but without NMI-generator, ie. not supporting SLOW mode, thus cannot display a picture while program is operating.

TS1000
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.

TS1500
Same as above TS1000, but with 16 KBytes of RAM.

TKs
Reportedly brazilian ZX81 clones are called the "TKs".


 SPECs ZX80 vs ZX81 Compatibility

Hardware
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, optionally allowing to execute programs during vertical blanking periods, ie. while display is enabled.

Firmware
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.

Software
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.

Performance
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.
Otherwise ZX81 should be theoretically as fast as the trusty ZX80, unfortunately the new BASIC interpreter uses floating point values rather then integers, and thus ZX81 BASIC programs are ways slower even when using FAST mode.


 Display Output

Display Modes
Video Text and Blockgraphics
Video Pseudo Hi-Res Graphics
Video True Hi-Res Graphics

Display Details
Video Blanking and Retrace
Video Interrupts (INTs and NMIs)
Video Display Timings
Video Character Set


 Video Text and Blockgraphics

Overview
This is the ZX standard video mode. The display area consists of 32x24 characters of 8x8 pixels each. The user cannot set single pixels though, only 64 predefined characters can be used. However, some of these characters are split into 2x2 blocks (4x4 pixel each), allowing to display 64x48 block low resolution graphics.

Video Memory
Video memory is addressed by the D_FILE pointer (400Ch) in ZX80/81 system area. The first byte in VRAM is a HALT opcode (76h), followed by the data (one byte per character) for each of the 24 lines, each line is terminated by a HALT opcode also. In case that a line contains less than 24 characters, the HALT opcode blanks (white) the rest of the line up to the right screen border. (Thus left-aligned text will take up less memory than centered or right-aligned text.)

Character Data, VRAM Size
Character data in range 00h..3Fh displays the 64 characters, normally black on white. Characters may be inverted by setting Bit 7, ie. C0h..FFh represents the same as above displayed white on black.
The fully expanded VRAM size is 793 bytes (32x24 + 25 HALTs, almost occupying the whole 1Kbyte of internal RAM), an empty fully collapsed screen occupies only 25 bytes (HALTs).

Character Set
The character set is addressed by the I register multiplied by 100h. In the ZX81 this is 1Eh for 1E00h..1FFFh, in ZX80 0Eh for 0E00h..0FFFh. Setting I=40h..7Fh in attempt to define a custom charset in RAM rather than ROM does not work.

Display procedure Tech Details
The display data is more or less 'executed' by the CPU. When displaying a line, the BIOS takes the address of the first character, eg. 4123h, sets Bit 15, ie. C123h, and then jumps to that address.

The hardware now senses A15=HIGH and /M1=LOW (signalizing opcode read), upon this condition memory is mirrored from C000-FFFF to 4000-7FFF. The 'opcode' is presented to the databus as usually, the display circuit interpretes it as character data, and (if Bit 6 is zero) forces the databus to zero before the CPU realizes what is going on, causing a NOP opcode (00h) to be executed. Bit 7 of the stolen opcode is used as invert attribute, Bit 0-5 address one of the 64 characters in ROM at (I*100h+char*8+linecntr), the byte at that address is loaded into a shift register, and bits are shifted to the display at a rate of 6.5MHz (ie. 8 pixels within 4 CPU cycles).

However, when encountering an opcode with Bit 6 set, then the video circuit rejects the opcode (displays white, regardless of Bit 7 and 0-5), and the CPU executes the opcode as normal. Usually this would be the HALT opcode - before displaying a line, BIOS enables INTs and initializes the R register, which will produce an interrupt when Bit 6 of R becomes zero.
In this special case R is incremented at a fixed rate of 4 CPU cycles (video data executed as NOPs, followed by repeated HALT), so that line display is suspended at a fixed time, regardless of the collapsed or expanded length of the line.

As mentioned above, an additional register called linecntr is used to address the vertical position (0..7) whithin a character line. This register is reset during vertical retrace, and then incremented once per scanline. The BIOS thus needs to 'execute' each character line eight times, before starting to 'execute' the next character line.


 Video Pseudo Hi-Res Graphics

This method is used to display 256x192 pixels graphics, limited to max 128 combinations within each row of 8 pixels though. Even though not supported by the BIOS, a couple of games are using this video mode: Rock Crush, Dans Revenge, Rocketman, Forty Niner, Madjump II, Bipods, Micromouse, and possibly others.

Basically it is working much like Text video mode, the character height is reduced to a single scanline, so each tile consists of 8x1 pixels rather than 8x8 pixels. And the screen consists of 32x192 of these 'flat' characters, each line usually terminated by a RET opcode (C9h), thus occupying 6176 bytes of memory.

A special display procedure is required which forces the linecntr register to zero by issuing a very short 'vertical retrace' signal each scanline (preferably simultaneously to the hardware generated horizontal retrace signal). In result, only the topmost row of each character will be displayed, as the topmost row of most of the normal characters is just blank, it'd be recommended to change the characterset pointer in the I register to another address in ROM.

For example, setting I=0Ch would select the area 0C00h..0DFFh (in steps of eight: topmost rows of chars #0, #1, #2 at C00h, C08h, C10h, etc). The machine code bytes in this memory region are then used as 'randomly' predefined pixel rows, which may or may not match the programmers requirements. Each of the 64 rows may be inverted as normal text characters, so theoretical a total of 128 different 8-pixel rows can be used, practically less because most likely a couple of rows will be duplicated.

As the interrupt based BIOS display procedre at 0038h does not support above, a raw software based handler is used in most cases, that's why each line is terminated by a RET rather than HALT opcode.


 Video True Hi-Res Graphics

This mode produces a 256x192 pix graphics screen, and, unlike Pseudo Hi-Res, it allows to set each pixel separately. The downside is that it does not work with most external RAM Paks (memory expansions can be quite easily upgraded by using two diodes and a resistor though, see chapter Hardware Modifications for details).

However, it does work with internal RAM and with modified RAM Paks.
When using internal RAM, take care about these two limitiations: Only a small picture will fit into 1K memory (so the display procedure must increase horizontal and/or vertical blanking times), and external RAM must be disconnected (as it'd otherwise disable internal RAM).

The true hi-res technique is used by the games Guus Flater, Starfight, and by some demos such like WRX1K.

The general idea is to move the character set into RAM at 4000h..7FFFh by setting I to 40..7Fh. Now this does NOT work as expected, ie. as
(I*100h+char*8+linecntr) as for text mode. Both the executed opcode (character number) and the linecntr value are ignored. Instead, pixels are directly read from memory at (IR). Each eight bits of each byte represent eight pixels. The picture is defined in form of a common monochrome bitmap.

The bitmap data can be located anywhere in RAM, and as it is not 'executed' as in other display modes, only raw data is required (ie. and no HALT or RET opcodes need to be attached to each line). Note that only the lower seven bits of the R register are incremented by the CPU; care should be taken that it does not overflow within a line. For example, a bitmap of 256 pixels width (32 bytes) should be aligned to 32 in memory.

The main display procedure should load the MSB of the current bitmap line into the I register, and the LSB into the A register, then jump to a dummy D_FILE display procedure in memory with A15=HIGH. This dummy procedure should copy the LSB from A into R register, and then execute a stream of 32 NOP opcodes (00h: Bit 7 indicates not inverted output, Bit 6 disables blanking, data is directly read from (IR), so that the character number in Bit 0-5 is ignored), and return to the main procedure - which'd then issue some delays, prepare new address in I and A and start over with the next line (using the same dummy procedure again), until the whole screen has been displayed.


 Video Blanking and Retrace

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.

Vertical Blanking
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 ;-)

ZX80 Vertical Blanking ("PAUSE")
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).

ZX81 Vertical Blanking ("SLOW")
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.

Horizontal Blanking
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.

Retrace
The cathode ray is moved back to the begin of the scanline / top of display during horizontal / vertical retrace periods.
Horizontal retrace is generated by the video hardware, so care should be taken to keep the display procedure synchronized to retrace signals.
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.


 Video Interrupts (INTs and NMIs)

INTs
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.
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.
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.
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).

NMIs (ZX81 only)
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).
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.
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).


 Video Display Timings

Horizontal Scanline Timings
  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
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.

Vertical Timings (50Hz)
  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

Vertical Timings (60Hz)
  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

User Available Blank Lines
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.

User Available Blanking Time
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).
  Total scanline time       207 cycles
  NMI WAITs/CALL 66h    ca.  23 cycles
  NMI handler                32 cycles
  Remaining user time   ca. 152 cycles
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.

Resulting User Available CPU Time
  SLOW, 50Hz Effective Speed   0.820800 MHz  (54*2*152 cycles, 50 frames)
  SLOW, 60Hz Effective Speed   0.547200 MHz  (30*2*152 cycles, 60 frames)
  FAST, Total CPU Speed        3.250000 MHz  (display disabled)
  ZX80/PAUSE/INPUT             0.0 MHz


 Video Character Set

First, here's the ZX81 character set (64 characters)
  ____0___1___2___3___4___5___6___7___8___9___A___B___C___D___E___F____
  00 SPC GRA GRA GRA GRA GRA GRA GRA GRA GRA GRA  "  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
For the ZX80, some characters are located at other positions:
  ____0___1___2___3___4___5___6___7___8___9___A___B___C___D___E___F____
  00 SPC  "  GRA GRA GRA GRA GRA GRA GRA GRA GRA GRA 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
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.

For ZX81, above SPC and GRA characters can be used for Block Graphics
  00__01__02__03__04__05__06__07__08__09__0A__0B   ;"."=blank
  ..  #.  .#  ##  ..  #.  .#  ##  %%  ..  %%  ,,   ;"#"=solid
  ..  ..  ..  ..  #.  #.  #.  #.  %%  %%  ..       ;"%"=dithered
For ZX80, above SPC and GRA characters can be used for Block Graphics
  00__01__02__03__04__05__06__07__08__09__0A__0B   ;"."=blank
  ..  ,,  #.  ..  #.  .#  ..  ..  .#  %%  ..  %%   ;"#"=solid
  ..      #.  ##  ..  ..  #.  .#  #.  %%  %%  ..   ;"%"=dithered
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.

ZX81 charset is defined at 1E00h-1FFFh in BIOS ROM (I register I=1Eh), ZX80 charset at 0E00h-0FFFh (I=0Eh).

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), so that RAM cannot be used to store character data.


 The BASIC Interpreter

BASIC Editor
BASIC Commands
BASIC Functions
BASIC Error Codes


 BASIC Editor

This chapter explains ZX81 keyboard modes and key-combinations. The table with all keywords/characters assigned to each key can be found here:
Keyboard Assignment

Special Keys
  Key        Name      Expl.                      Equivalent/emulated PC Key
  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
Beside for these general special keys, all ZX81 keys are behaving kinda special, depending on various input modes as shown below.

[K] Cursor - Keyword Mode (Expecting Keywords and/or Line Numbers)
This mode is automatically used at the beginning of each line (and after THEN).
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).
Entering a line number without keyword deletes the specified line.

[L] Cursor - Letter Mode (Expecting Operands or Functions)
This mode is automatically selected after entering a keyword in [K] mode.
Allows to enter expressions, such like "HELLO" or 1234.5678. When SHIFT is held down, functions/operations 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.

[F] Cursor - Function Mode (Expecting Functions) (ZX81 only)
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.

[G] Cursor - Graphics Mode (Inverted Text and Block Graphics) (ZX81 only)
This mode is entered by pressing SHIFT+9 from inside of [L] Mode, allowing to enter inverted characters (including inverted SPACE).
When keeping SHIFT held down, all combinations of Block Graphics can be entered (for example, SHIFT+1=Dot-in-upper-left).

[>] Cursor/Symbol - Currently selected line
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.
The EDIT key combination (SHIFT+1) copies the line that is currently selected by the [>] Cursor to the input buffer (overwriting any old input).

[S] Symbol - Syntax Error
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.


 BASIC Commands

CLEAR
Erases all variables and frees up memory.

CLS
Clears the screen.

CONT (called CONTINUE in ZX80)
Works much like GOTO, continues the program in the current line, or in the next line if program has been halted by STOP.

COPY (ZX81 only)
Sends a screen copy to the printer (if connected). Only topmost 32x22 characters are printed, ie. excluding bottommost 2 lines.

DIM b(n1,...,nk) or DIM b$(n1,...,nk)
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.
The ZX80 supports only one-dimensional numeric arrays, ie. no multi-dimensional arrays, and no string/character arrays.

FAST (ZX81 only)
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.
The ZX80 is always operating in 'FAST' mode.

FOR b=x TO y [STEP z]
Defines the begin and range of a FOR-NEXT loop, the default STEP is +1.
The ZX80 doesn't support the STEP operand.

GOSUB n (called GO SUB in ZX80)
Saves RETURN address on GOSUB stack, and jumps to the specified line number, see GOTO for details.

GOTO n (called GO TO in ZX80)
Jumps to the specified line number. Am immediate, a variable and/or other expression may be used as line number, such like "GOTO A*10+230".

IF x THEN s
Executes s if x<>0. The ZX81 does not understand "THEN n" as alias for "THEN GOTO n".

INPUT v
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.

LET v=e
Assigns e to the variable v. The ZX81 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.

LIST [n]
Lists the program on the screen. The default starting line number is 0. Use CONT to continue if program does not fit onto screen.

LLIST [n] (ZX81 only)
Lists the program to the printer.

LOAD f
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.
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.
The ZX80 does not support filenames, just type LOAD and hit NEWLINE.

LPRINT (ZX81 only)
Works much like PRINT, but outputs to the printer. AT may be used to specify a horizontal position inside of the currently printed line.

NEW
Restarts BASIC. The program, all variables, and all further memory up to RAMTOP are erased. In the ZX80 this is equivalent to CALL 0.

NEXT b
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 ZX81 does not understand "NEXT" as alias for "NEXT b".

PAUSE n (ZX81 only)
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.

PLOT m,n (ZX81 only)
Draws a black dot (of 4x4 pixels, ie. one quarter of a 8x8 pixel character) at the specified position by using graphics characters. The origin (0,0) is at the lower left of the screen, excluding the bottommost two character lines.

POKE m,n
Writes the byte n at address m into memory, both must be decimal values. Note that the ZX81 does not recognize hexadecimal numbers.

PRINT ...
Displays the operand(s) - if any - on the screen. Possible operands are:
  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 charcters are displayed as question marks.
  d) AT m,n - 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.
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).
Upon completion, the print position is moved to the begin of the next line (unless expression was terminated by semicolon or comma).
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.

RAND [n] (called RANDOMISE in the ZX80)
Initializes the random generators seed (n=1..65535). When n is zero (the default), the current frame counter is used as seed.

REM ...
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.
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.

RETURN
Returns to the line following to the most recently executed GOSUB command.

RUN [n]
Clears all variables and jumps to the specified line number. The default is the first line of the program. See GOTO for details.

SAVE f
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.
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.
The ZX80 does not support filenames, just enter SAVE without parameter.

SCROLL (ZX81 only)
Moves the display upwards, and inserts a blank line at the bottom.
Note: The blank line is totally empty, in VRAM it is defined as a single HALT opcode, without any SPACE characters.

SLOW (ZX81 only)
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.
The ZX80 does not support SLOW and FAST commands, and it is always operating in FAST mode.

STOP
Stops the program. User may enter CONT to continue in following line.

UNPLOT m,n (ZX81 only)
Same as PLOT, but drawing a white dot instead of a black dot.


 BASIC Functions

Note that all ZX81 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 "**".
For the ZX80 it is vice-versa, and all functions must be entered character by character.

ABS n
Returns the unsigned value of n.

CHR$ n
Returns character n. (Converts a number into a single-character string.)

CODE string
Returns the character number of the first charcter (or 0 if string is empty). Opposite of CHR$.

INKEY$ (ZX81 only)
Returns the character of the currently pressed key, or "" if none pressed.

LEN string (ZX81 only)
Returns the length of the string.

PEEK n
Returns a byte read from decimal (!) memory address n. The ZX does not recognize hexadecimal numbers.

RND (for ZX80: RND n)
Returns a random number in range 0 to 0.99999... (ZX81), or 1 to n (ZX80).

SGN n (ZX81 only)
Returns the sign (-1, 0, or +1) of n.

STR$ n
Returns n converted into a string.

TL$ string (-ZX80- only)
Returns string with leftmost character truncated. Equivalent to the ZX81 expression 'string(2 TO)'.

USR n
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.

VAL string (ZX81 only)
Converts the string into a value, stops the program if failed.

Floating Point related functions (ZX81 only)
  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.

Numeric operations
  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
Logical operations (Returns 1 if true, 0 if false)
  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
Special Numeric/Logical operations
  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.
Priority for indexing (DIM) and string-fragments (TO) is 12. Priority for all functions is 12.

String ( [first] TO [last] ) Operand
Used to specify a fragemnt of a string from first charcter to last character. The default values are: first=1, and last=LEN.
May be used either in source and destination of string operations, eg.:
  LET A$(5 TO 7) = "***"    ;overwrites 5th-7th character of A$
  LET A$ = B$(TO 4)         ;copies 1st-4th character of B$ to A$


 BASIC Error Codes

Commandline Errors
When entering a line incorrectly, the [S] symbol (Syntax Error) is displayed at the fault location, prompting the user to correct the problem.

ZX81 Execution Errors
Otherwise, when errors occur during program execution, the following error codes are displayed.
  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.
Errors are always displayed as ERR/LINE indicating the line number which caused the error.

ZX80 Execution Errors
  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


 Z80 Usage in ZX Models

CPU and System Clock Overview
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.

Vectors, Registers and Memory Overview
The INT, NMI, and RST vectors are located in ROM and cannot be changed by software. The AF' register (ie. EX AF,AF) and IX register, 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.


 Z80 CPU Specifications

Z80 Register Set
Z80 Flags
Z80 Instruction Format
Z80 8bit Load Commands
Z80 16bit Load Commands
Z80 Blocktransfer- and Searchcommands
Z80 8bit Arithmetic/Logical Commands
Z80 16bit Arithmetic Commands
Z80 Rotate and Shift Commands
Z80 Singlebit Operations and CPU-Control Commands
Z80 Jumpcommands
Z80 I/O Commands
Z80 Interrupts
Z80 Meaningless and Duplicated Opcodes
Z80 Garbage in Flag Register
Z80 Compatibility


 Z80 Register Set

Register Summary
  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

Normal 8bit and 16bit Registers
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.
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.

Second Register Set
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.

Refresh Register
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.

Interrupt Register
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.

IX and IY Registers
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.

Undocumented 8bit Registers
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.


 Z80 Flags

Flag Summary
The Flags are located in the lower eight bits of the AF register pair.
  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

Carry Flag (C)
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.

Zero Flag (Z)
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).

Sign Flag (S)
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.

Parity/Overflow Flag (P/V)
This flag is used as Parity Flag, or as Overflow Flag, or for other purposes, depending on the instruction.
Parity: Bit7 XOR Bit6 XOR Bit5 ... XOR Bit0 XOR 1.
8bit Overflow: Indicates if the result was greater/less than +127/-128.
HL Overflow: Indicates if the result was greater/less than +32767/-32768.
After LD A,I or LD A,R: Contains current state of IFF2.
After LDI,LDD,CPI,CPD,CPIR,CPDR: Set if BC<>0 at end of operation.

BCD Flags (H,N)
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.)
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.

Undocumented Flags (Bit 3,5)
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.
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.


 Z80 Instruction Format

Commands and Parameters
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.

Parameter Placeholders
The following placeholders are used in the following chapters:
  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

Opcode Bytes
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".

Clock Cycles
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.
Note that in case that WAIT signals are sent to the CPU by the hardware then the execution may take longer.

Affected Flags
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:
  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)


 Z80 8bit Load Commands
 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 ------


 Z80 16bit Load Commands
 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


 Z80 Blocktransfer- and Searchcommands
 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
 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
 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
 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


 Z80 8bit Arithmetic/Logical Commands
 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
Arithmetic <arit> commands:
 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
Increment/Decrement <cnt> commands:
 inc   op       see above 4-23 szho0- op=op+1
 dec   op       see above 4-23 szho1- op=op-1
Logical <logi> commands:
 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


 Z80 16bit Arithmetic Commands
 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


 Z80 Rotate and Shift Commands
 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
Whereas <cmd> may be:
 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)


 Z80 Singlebit Operations and CPU-Control Commands
 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
 nop            00           4 ------ no operation
 halt           76           4 ------ repeat until interrupt occurs
 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.


 Z80 Jumpcommands
 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
 reti           ED 4D       14 ------ pop PC, IFF1=IFF2, ACK (ret from INT)
 retn           ED 45       14 ------ pop PC, IFF1=IFF2 (ret from NMI)
 rst  n         xx          11 ------ call n  ;n=00,08,10,18,20,28,30,38


 Z80 I/O Commands
 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


 Z80 Interrupts

Lack of Information
Z80 interrupts are a mysterium, the official Z80 documentation basically denied the existence of interrupts in general. However, when describing opcodes such like IM 0, EI, and RETI the author couldn't fully avoid to mention the possibility that such a thing like interrupts might eventually exist by suggesting to refer to somewhat called an "application script about interrupt behaviour of Z80 systems".

In case that this document really exists, then it is probably been horribly expensive, made available to authorized developers only, and not available nowadays anymore. The content of this document might or might not confirm the existence of interrupts, and/or explain other details?

Judging from the fragments of information the leaked out in the Z80 docs, the CPU supports non-maskable interrupts (NMI) and maskable interrupts (INT). MSX and CPC homecomputers aren't using NMIs, so information below is reverse engineered guesswork for systems that use maskable interrupts only.

Interrupt Flip-Flop (IFF1,IFF2)
The IFF1 flag is used to enable/disable INTs (maskable interrupts).
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.
Beside for the above 'backup' function, IFF2 itself is having no effect. Neither IFF1 nor IFF2 affect NMIs which are always enabled.
The following opcodes/events are modifying IFF1 and/or IFF2:
  EI     IFF1=1, IFF2=1
  DI     IFF1=0, IFF2=0
  <INT>  IFF1=0, IFF2=0
  <NMI>  IFF1=0
  RETI   IFF1=IFF2
  RETN   IFF1=IFF2
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).
Interrupts can be disabled by the DI instruction (IFF=0), and are additionally automatically each time when an interrupt is executed.

Interrupt Execution
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.
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.

Interrupt Modes (IM 0,1,2)
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.
  Mode  Cycles  Refresh  Operation
  0     1+var   0+var    IFF=0, read and execute opcode from databus
  1     12      1        IFF=0, CALL 0038h
  2     18      1        IFF=0, CALL (I*100h+databus)
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.
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.

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.

Non-Maskable Interrupts (NMIs)
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.
Execution time for NMIs is unknown (?).

RETI and RETN
These instructions are somewhat supposed to return from maskable and non-maskable interrupts. In a raw INT based system which isn't using NMIs they appear to behave 100% identical to normal RET instructions.


 Z80 Meaningless and Duplicated Opcodes

Mirrored Instructions
NEG (ED44) is mirrored to ED4C,54,5C,64,6C,74,7C.
RETN (ED45) is mirrored to ED55,65,75.
RETI (ED4D) is mirrored to ED5D,6D,7D.

Mirrored IM Instructions
IM 0,X,1,2 (ED46,4E,56,5E) are mirrored to ED66,6E,76,7E.
Whereas IM X is an undocumented mirrored instruction itself which appears to be identical to either IM 0 or IM 1 instruction (?).

Duplicated LD HL Instructions
LD (nn),HL (opcode 22NNNN) is mirrored to ED63NNNN.
LD HL,(nn) (opcode 2ANNNN) is mirrored to ED6BNNNN.
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.

Mirrored BIT N,(ii+d) Instructions
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).
Except that, not tested yet, maybe undocumented flags are then read from 'r' instead of from ii+d(?).

Non-Functional Opcodes
The following opcodes behave much like the NOP instruction.
ED00-3F, ED77, ED7F, ED80-9F, EDA4-A7, EDAC-AF, EDB4-B7, EDBC-BF, EDC0-FF.
The execution time for these opcodes is 8 clock cycles, 2 refresh cycles.
Note that some of these opcodes appear to be used for additional instructions by the R800 CPU in newer turbo R (MSX) models.

Ignored DD and FD Prefixes
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.


 Z80 Garbage in Flag Register

Nocash Z80-flags description
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.

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.

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).

Normal Behaviour for Undocumented Flags
In most cases, undocumented flags are copied from the Bit 3 and Bit 5 of the result byte. That is "A AND 28h" for:
  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.
When other operands than A may be modified, "OP AND 28h" for:
  RLC OP; RL OP; SLA OP; SLL OP; INC OP; IN OP,(C);
  RRC OP; RR OP; SRA OP; SRL OP; DEC OP
For 16bit instructions flags are calculated as "RR AND 2800h":
  ADD RR,XX; ADC RR,XX; SBC RR,XX.

Slightly Special Undocumented Flags
For 'CP OP' flags are calculated as "OP AND 28h", that is the unmodified operand, and NOT the internally calculated result of the comparision.
For 'SCF' and 'CCF' flags are calculated as "(A OR F) AND 28h", ie. the flags remain set if they have been set before.
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".

Fatal MEMPTR Undocumented Flags
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.
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".

Memory Block Command Undocumented Flags
For LDI, LDD, LDIR, LDDR, undocumented flags are "((A+DATA) AND 08h) + ((A+DATA) AND 02h)*10h".
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.

Chaotic I/O Block Command Flags
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.
  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"
The above registers L and B are meant to contain the new values which are already incremented/decremented by the instruction.
Note that the official docs mis-described the N-Flag as set, and the C-Flag as not affected.

DAA Flags
Addition (if N was 0):
  FLG_H = (OLD_A AND 0Fh) > 09h
  FLG_C = Carry of result
Subtraction (if N was 1):
  FLG_H = (NEW_A AND 0Fh) > 09h
  FLG_C = OLD_CARRY OR (OLD_A>99h)
For both addition and subtraction, N remains unmodified, and S, Z, P contain "Sign", Zero, and Parity of result (A). Undocumented flags are set as (A AND 28h) as normal.

Mis-documented Flags
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).

Internal MEMPTR Register
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.
The following list specifies the resulting content of the MEMPTR register caused by the respective instructions.
  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)
Also the following might or might not affect MEMPTR, not tested yet:
  OUT (N),A and block commands LDXX, CPXX, INXX, OUTXX
  and probably interrupts in IM 0, 1, 2
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 with condition=false), and the JP HL/IX/IY jump instructions.


 Z80 Compatibility

The Z80 CPU is (almost) fully backwards compatible to older 8080 and 8085 CPUs.

Instruction Format
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.

Parity/Overflow Flag
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.

Z80 Specific Instructions
The following instructions are available for Z80 CPUs only, but not for older 8080/8085 CPUs:
All CB-prefixed opcodes (most Shift/Rotate, all BIT/SET/RES commands).
All ED-prefixed opcodes (various instructions, and all block commands).
All DD/FD-prefixed opcodes (registers IX and IY).
As well as DJNZ nn; JR nn; JR f,nn; EX AF,AF; and EXX.

8085 Specific Instructions
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.

Z80 vs Z80A
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).

NEC-780 vs Zilog-Z80
These CPUs are apparently fully compatible to each other, including for undocumented flags and undocumented opcodes.



 Data Structures

ZX81 BASIC Programs and Variables
ZX80 BASIC Programs and Variables
Cassette File Images
Cassette File Content
Cassette Signals


 ZX81 BASIC Programs and Variables

BASIC Program Line Structure
  Bytes  Expl.
  2      Line Number  (MSB,LSB) (!)
  2      Line Length  (LSB,MSB)
  LEN-1  Text
  1      Newline      (76h)
The following are used in the Text area: 00-3F and 80-BF for normal and inverted characters, C0-FF and 40-42 for keywords, 7E for values, and 76 indicates the end of the line.
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 7E, as pre-calculated 5 byte exponent/value.
An immediate thus occupies at least 7 bytes. However, there are some grindy methods to save memory, such like: PI-PI defines 0 in three bytes, VAL "9" defines 9 in four bytes, etc.

BASIC One-Letter Variables
  Bytes  Expl.
  1      60h + Letter (5bit)
  1      Exponent
  4      Sign-Bit and Value
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.

BASIC Multi-Character Variables
  Bytes  Expl.
  1      A0h + First Letter       (5bit)
  NN     00h + Further Characters (6bit)
  1      80h + Last Character     (6bit)
  1      Exponent
  4      Sign-Bit and Value

BASIC Numeric Array
  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

BASIC FOR-NEXT Counter
  Bytes  Expl.
  1      E0h + Letter  (5bit)
  5      Current Value
  5      Target Value
  5      Step
  2      Loop Linenumber (MSB,LSB) (!)

BASIC String
  Bytes  Expl.
  1      40h + Letter     (5bit)
  2      String Length    (0 if empty)
  LEN    Character String (none if empty)

BASIC Character Array
  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


 ZX80 BASIC Programs and Variables

BASIC Program Line Structure
  Bytes  Expl.
  2      Line Number  (MSB,LSB) (!)
  ...    Text
  1      Newline      (76h)
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.
Function names and values in program lines are stored as normal text.

BASIC One-Letter Variables
  Bytes  Expl.
  1      60h + Letter (5bit)
  2      Signed Integer

BASIC Multi-Character Variables
  Bytes  Expl.
  1      40h + First Letter       (5bit)
  NN     00h + Further Characters (6bit)
  1      80h + Last Character     (6bit)
  2      Signed Integer

BASIC Numeric Array
  Bytes    Expl.
  1        A0h + Letter (5bit)
  1        Range (Counted from 0 to N)
  (N+1)*2  Signed Integers

BASIC FOR-NEXT Counter
  Bytes  Expl.
  1      E0h + Letter  (5bit)
  2      Current Value
  2      Target Value
  2      Loop Linenumber (normal LSB,MSB for ZX80)

BASIC String
  Bytes  Expl.
  1      80h + Letter     (5bit)
  ...    Character String (none if empty)
  1      Ending Quotes    (01h)

BASIC Character/String Arrays
None such - ZX80 supports numeric arrays only.


 Cassette File Images

.81 and .80 Files
These are 1:1 copies of the content of real ZX81 and ZX80 cassette files.
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.
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.

.P and .O Files
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.
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.
Programs that deal with these files should determine the correct length (by examining the header/system area), and truncate the extra bytes.

.C and .S and .V and .B or else
These are not actually real ZX files, programs that include such files won't work on real ZX81 or ZX80, nor in no$zx81. 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.


 Cassette File Content

ZX81 Data Field (excluding filename)
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.
The system area should contain proper data. Some entries are of special interest:
  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)
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.

ZX80 Data Field
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.
The system area should contain proper data. The entry at 400Ah defines the end address (used to calculate the file length). ZX80 files cannot be autostarted. Memory at 4028h and up may be misused for whatever purpose.

Maximum File Length
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).
However, most ZXes don't have more than 16K RAM, so bigger files won't work on most computers anyways.


 Cassette Signals

ZX81 Cassette File Structure
  x seconds    your voice, saying "filename" (optional)
  x seconds    video noise
  5 seconds    silence
  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
The data field contains the system area, the basic program, the video memory, and VARS area.

ZX80 Cassette File Structure
  x seconds    your voice, saying "filename" (optional)
  x seconds    video noise
  5 seconds    silence
  LEN bytes    data, loaded to address 4000h, LEN=(400Ah)-4000h.
  x seconds    silence / video noise
ZX80 files do not have filenames, and video memory is not included in the file.

File End
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.

Bits and Bytes
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.
  0:  /\/\/\/\________
  1:  /\/\/\/\/\/\/\/\/\________
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.


 Hardware, Connectors, Upgrading

Hardware - External Connectors
Hardware - Internal Pins
Hardware - Modifications


 Hardware - External Connectors

TV - Video Output - UHF Channel 36 (Cinch, female)
  Ring: Shield
  Tip:  TV Signal
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.

EAR - Cassette Input (from recorder earphone socket to ZX81)
  Ring: Ground
  Tip: Cassette Input

MIC - Cassette Output (from ZX81 to recorder microphone socket)
  Ring: Ground
  Tip: Cassette Output
This is in fact the video signal, output through resistor and capaciator, causing black and white stripes to be displayed during cassette output.

9V DC - Power Supply
  Ring: Ground
  Tip: 9V DC
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.

Power Consumption
Internal 5V, 0.31A, ie. 1.55W, without 16K RAM
Internal 5V, 0.39A, ie. 1.95W, with Memotech Mempak 16KB

Expansion Port (46 Pin Cartridge Slot, male)
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.
  Upper Side         Lower Side
   1A  D7             1B  5V
   2A  /RAM CS        2B  9V
   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  /NAY  ??? 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  /MI           22B  A4
  23A  /REFSH        23B  /ROM CS
Expansion cartridges should have a male connector one at the rear side - allowing to connect further cartridge(s) - one to each other.


 Hardware - Internal Pins

ZX81 Keyboard Connector
  Pin  1-8:  A15, A14, A8, A13, A9, A12, A10, A11.
  Pin 9-13:  KBD0, KBD1, KBD2, KBD3, KBD4.

Video Signal
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.
  0V   sync
  2.5V black
  5V   white

50Hz/60Hz Refresh Rate Jumper
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.
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.


 Hardware - Modifications

Here 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.

MODs Replacing the ZX81 ROM by an EPROM
MODs Connecting a Joystick
MODs Upgrading RamPaks for True Hi-Res Graphics
MODs Connecting a Monitor
MODs Getting rid of the 9V DC Power Supply
MODs Uploading Programs from the PC to the ZX81


 MODs Replacing the ZX81 ROM by an EPROM

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:
- Disconnect A11 from Pin 20.
- Disconnect A12 from Pin 23.
- Connect /OE Pin 22 to /CE Pin 20.
- Connect A11 to Pin 23.
(Each counted in 28 pin device units, ie. Pin 14 is lower right.)
Caution:
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.


 MODs Connecting a Joystick

As far as I know, there is no 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.

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.

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).


 MODs Upgrading RamPaks for True Hi-Res Graphics

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.

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:
                                +5V
                                 |
                       1N34A   [4.7K]
  connector   RD _______|/|______|_____________ RD of RAMPACK
                        |\|      |
                                 |
  connector RFSH _______|/|______|     +5V_____ RFSH of RAMPACK
                        |\|
                       1N34A

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. Modify at your own risk!

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.


 MODs Connecting a Monitor

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.

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.

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.


 MODs Getting rid of the 9V DC Power Supply

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:

Using 12V DC (Yellow cable in PCs)
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.

Using 5V DC (Red cable in PCs)
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.

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.


 MODs Uploading Programs from the PC to the ZX81

The Transmit function in no$zx81 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):

1) Nocash Highspeed (transmission time 100-1300ms)
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.
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.

2) Mixed (transmission time 3-4 seconds)
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).

3) ZXTAPE (transmission time up to 7 minutes)
This protocol is transferring data at original cassette speed (38 bytes per second), similiar 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.
Note that this method won't work very well with multi-tasking operating systems.

You need:
  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

Step 1 - The Diodes
Connect the diodes to Pin 4-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.)

Step 2 - Connecting the Data Lines.
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.

Step 3 - Connecting Ground, Reset and Cassette.
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).

Patching the ZX81 BIOS
The patch overwrites the original LOAD and SAVE procedures, so both won't work any more. Change the byte at address 0006h to 00, then change the bytes at 0300h and up to:
  F3 ED 56 3E 1E ED 47 21 00 40 E5 FD E1 11 01 40
  75 01 FF 3F ED B0 21 02 40 75 24 F2 19 03 26 40
  35 28 07 35 20 04 24 F2 20 03 2E 00 F9 22 04 40
  21 FF 80 22 00 40 21 00 3E E5 21 76 06 E5 ED 73
  02 40 DB FE E6 1F FE 13 C2 E5 03 01 01 00 CD 59
  03 ED 4B 09 40 21 07 02 E5 21 08 40 DB FE 0F 38
  FB D3 FF 23 0B 77 DB FE 0F 30 FB ED 6F A8 FA 5C
  03 C9
Keep in mind that some pins of the ROM socket must be reconnected for EPROM use (see chapter about replacing BIOS ROM by EPROM).

Joystick Compatibility
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).
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.

Remote Keyboard-Control Side-Effect
As the LPT port is connected to the ZX keyboard input, the PC may be also used to remote-control the ZX keyboard. Even though all keyboard lines are accessed simultaneously, it may be used to pass up to five keys such like Cursor+Space to ZX81 programs (which must recognize this kind of input).




 Internet Resources

ZX81 Software / Games
About 800 games (most are in the packs directory):
- ftp://ftp.nvg.unit.no/pub/sinclair/zx81/snaps/
- ftp://ftp.nvg.unit.no/pub/sinclair/zx81/snaps/packs/
About 100 games:
- http://www.hh.schule.de/hhs/mjaap/zx81.htm
About 20 games that I've treated as interesting, funny, and/or exciting:
- http://www.work.de/nocash/zxprogs.htm

ZX Specifications
This document in .TXT and .HTML format:
- http://www.work.de/nocash/zxdocs.txt
- http://www.work.de/nocash/zxdocs.htm
How to build your own ZX80, includes ZX80 schematic, etc:
- http://www.home-micros.freeserve.co.uk/zx80/zx80.html
Kevin's ZX81 Page [hardware/ram upgrades, zxtape, zx81 schematic,zx81vid]:
- http://edge.edge.net/~krbaker/zx81.html
Wilf Rigter's ZX81 video specs, Hi-Res, sample code:
- http://edge.edge.net/~krbaker/zx81vid.txt

And, my email address
- http://www.work.de/nocash/email.htm