I am unsure of the copyright on the ZX81 ROM. The original copyright was with Sinclair Research Ltd. I believe that the copyright for the Sinclair Spectrum ROMs was transferred to Amstrad PLC. It is debatable if the ZX81 copyright was transferred at this time. I am assuming that the ROMs are able to be released into the public domain (It's been 20 years!). If anyone knows differently, please let me know and I will withdraw the ROMs from this site.
Having bought one of the first ZX81 on the market, I am blessed with a ZX81 with an "unimproved" ROM. As far as I know, the unimproved ROM has not been published on the Web, until now! My unimproved ROM was read using a PROM programmer. The ROM is of device type 2364, but was read using the device type set to Motorola MCM 68764, which is pin-compatible. The unimproved ROM had a couple of problems, the most serious being a floating point bug (it seemed to think that the SQR of 0.25 was 1.3591409). The exact differences between the unimproved and improved ROM are described further below. The label names have been taken from Part A & Part B of the ROM Disassembly by Dr. Ian Logan & Dr. Frank O'Hara (good work guys, wherever you are now!).
"Unimproved" Address Range |
"Improved" Address Range |
Description of Change |
0000-0EEE | 0000-0EEE | No change (other than offsets) |
N/A | 0EEF-0EF1 | A new CALL instruction added to clear the workspace during the INPUT routine |
0EEF-0F39 | 0EF2-0F3C | No change (other than offsets) |
0F3A-0F40 | 0F3D-0F43 | Rewritten PAUSE routine to ensure bit 15 of FRAMES set. |
0F41-102E | 0F44-1031 | No change (other than offsets) |
102F-1034 | 1032-1038 | Rewritten numeric processing routine to cater for syntax checking |
1035-1732 | 1039-1736 | No change (other than offsets) |
1733-1735 | N/A | Deleted spurious instructions causing floating point bug |
1736-1DFD | 1737-1DFE | No change (other than offsets) |
1DFE-1DFF | IDFF-1DFF | One spare location removed |
1E00-1FFF | 1E00-1FFF | No change to character map |
Unimproved:
0EE9 | FD CB 08 7E | INPUT: | BIT | 7,(IY+08) | ; Test high byte of PPC for line number |
0EED | 20 2F | JR | NZ,0F1E | ; REPORT-8 (Input must have line number) | |
0EEF | 21 2D 40 | LD | HL,402D | ; FLAGX | |
0EF2 | CB EE | SET | 5,(HL) | ; Set INPUT mode | |
0EF4 | CB B6 | RES | 6,(HL) | ; to string |
Improved:
0EE9 | FD CB 08 7E | INPUT: | BIT | 7,(IY+08) | ; Test high byte of PPC for line number |
0EED | 20 2F | JR | NZ,0F21 | ; REPORT-8 (Input must have line number) | |
0EEF | CD A3 14 | CALL | 14A3 | ; Call X-TEMP to clears the workspace | |
0EF2 | 21 2D 40 | LD | HL,402D | ; FLAGX | |
0EF5 | CB EE | SET | 5,(HL) | ; Set INPUT mode | |
0EF7 | CB B6 | RES | 6,(HL) | ; to string |
Unimproved:
0F2F | CD A7 0E | PAUSE: | CALL | 0EA7 | ; Call FIND-INT to get the PAUSE parameter |
0F32 | CD E7 02 | CALL | 02E7 | ; Call SET-FAST to go into fast mode (but keep CDFLAG bit 6 set, indicating SLOW mode) | |
0F35 | 60 | LD | H,B | ; Move PAUSE parameter into HL | |
0F36 | 69 | LD | L,C | ; NB: This will be saved to FRAMES | |
0F37 | CD 2D 02 | CALL | 022D | ; Call DISPLAY-P to generate display until FRAMES zero or a key is pressed | |
0F3A | CD 07 02 | CALL | 0207 | ; Call SLOW/FAST to re-enter "normal" slow mode | |
0F3D | FD CB 35 FE | SET | (IY+35),7 | ; Sets the top bit (bit 15) of FRAMES to indicate not in PAUSE | |
0F41 | 18 05 | JR | 0F4B | ; Jump to D-BOUNCE |
Improved:
0F32 | CD A7 0E | PAUSE: | CALL | 0EA7 | ; Call FIND-INT to get the PAUSE parameter |
0F35 | CD E7 02 | CALL | 02E7 | ; Call SET-FAST to go into fast mode (but keep CDFLAG bit 6 set, indicating SLOW mode) | |
0F38 | 60 | LD | H,B | ; Move PAUSE parameter into HL | |
0F39 | 69 | LD | L,C | ; NB: This will be saved to FRAMES | |
0F3A | CD 2D 02 | CALL | 022D | ; Call DISPLAY-P to generate display until FRAMES zero or a key is pressed | |
0F3D | FD 36 35 FF | LD | (IY+35),FF | ; Set high byte of FRAMES | |
0F41 | CD 07 02 | CALL | 0207 | ; Call SLOW/FAST to re-enter "normal" slow mode | |
0F44 | 18 05 | JR | 0F4B | ; Jump to D-BOUNCE |
Unimproved:
1022 | FE 26 | S-LET-NUM: | CP | 26 | ; Jump if dealing with a digit 'A'=26H |
1024 | 38 1D | JR | C,1043 | ; to the S-DECIMAL routine | |
1026 | CD 18 11 | CALL | 1118 | ; We have a variable name. See if it exists by calling LOOK-VARS | |
1029 | DA 4B 0D | JP | C,0D4B | ; REPORT-2 (Undefined variable) | |
102C | CC A3 11 | CALL | Z,11A3 | ; Call STK-VAR to stack parameters for a string or string array | |
102F | FD CB 01 76 | BIT | 6,(IY+01) | ; IY=4000H | |
1033 | 28 4E | JZ | 1083 | ; Jump to S-CONT-2 to continue processing if not a number | |
1035 | 23 | INC | HL | ; A numeric value is to be stacked | |
1036 | ED 5B 1C 40 | LD | DE,(401C) | ; so fetch the old STKEND |
Improved:
1025 | FE 26 | S-LET-NUM: | CP | 26 | ; Jump if dealing with a digit 'A'=26H |
1027 | 38 1E | JR | C,1047 | ; to the S-DECIMAL routine | |
1029 | CD 1C 11 | CALL | 111C | ; We have a variable name. See if it exists by calling LOOK-VARS | |
102C | DA 4B 0D | JP | C,0D4B | ; REPORT-2 (Undefined variable) | |
102F | CC A7 11 | CALL | Z,11A7 | ; Call STK-VAR to stack parameters for a string or string array | |
1032 | 3A 01 40 | LD | A,(4001) | ; Fetch the value of FLAGS | |
1035 | FE C0 | CP | C0 | ; Test bit 6 & 7 together | |
1037 | 38 4E | JR | C,1087 | ; Jump to S-CONT-2 to continue processing if not a number and/or are syntax checking | |
1039 | 23 | INC | HL | ; A numeric value is to be stacked during line execution | |
103A | ED 5B 1C 40 | LD | DE,(401C) | ; so fetch the old STKEND |
Unimproved:
1732 | D9 | ADDEND-0: | EXX | ; Fetch L', D' & E' | |
1733 | 7C | LD | A,H | ||
1734 | 95 | SUB | L | ||
1735 | 67 | LD | H,A | ||
1736 | AF | XOR | A | ; Clear the A register | |
1737 | 2E 00 | ZEROS-4/5: | LD | L,0 | ; Sign indicator |
Improved:
1736 | D9 | ADDEND-0: | EXX | ; Fetch L', D' & E' | |
1737 | AF | XOR | A | ; Clear the A register | |
1738 | 2E 00 | ZEROS-4/5: | LD | L,0 | ; Sign indicator |
The ROM contents also differs at various locations where the target of an address reference has changed. For example, the first of these differences is at 0029. This is part of a call to the floating point CALCULATE routine.
Unimproved:
0028 | C3 9C 19 | JP | 199C | ; CALCULATE |
Improved:
0028 | C3 9D 19 | JP | 199D | ; CALCULATE |
Finally, at the end of the ROM (just prior to the character bitmaps) the unimproved ROM has two spare locations (1DFE & 1DFF) whereas the improved ROM only has one (1DFF). These locations contain FF.
(C) Copyright Mr. S. C. Agate, BSc (Hons.)
Last revised: 11 December 2001.
http://www.agate.f9.co.uk