nocash ZX81 docs by martin korth -------------------------------- 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 -- 1000 1 NOT 2 2 AND -- 0100 2 AND 3 3 THEN -- 0001 3 THEN 4 4 TO -- 0010 4 TO 5 5 -- 0101 5 6 6 -- 0011 6 7 7 -- 1100 7 8 8 -- 0101 8 9 9 -- -- 9 0 0 -- -- 0 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 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 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 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 Moves Cursor left/right in input buffer Cursor Keys Shift+7/6 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 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 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. 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