Zeal Disassembler is a Z80 machine code disassembler that operates through a BASIC control menu, with the heavy lifting performed by a machine code routine loaded via `RANDOMIZE USR 30165` and invoked through `USR 61586`. The program offers configurable parameters including begin and end addresses, disassembly mode (instruction, DEFB byte, or DEFW word), printer output, relocation displacement, ROM switching, and optional cross-reference listing generation. Cross-reference data is stored in a dimensioned string array `X$` whose capacity is read from a two-byte value POKEd into addresses 61995–61996, with a maximum of 1000 entries. The cross-reference sort is performed by a separate machine code routine at address 61855, and the results can be sent to either screen or printer via LPRINT. Error handling uses `ON ERR` with `RESET` and `CONTINUE` to manage crash recovery and re-initialization.
Program Analysis
Program Structure
The program is organized into distinct functional blocks, all residing in the 9800–9999 line range. The entry point at line 9850 initializes all variables and dimensions arrays, then falls through to the main control menu loop at 9860–9930. Cross-reference output is handled by lines 9971–9983, error recovery by 9990–9998, and a key-flush subroutine lives at 9960–9970.
Initialization and Variable Conventions
Line 9850 establishes several idioms used throughout. Boolean false is represented by B=PI-PI (i.e., 0) and true by U=PI/PI (i.e., 1), avoiding the use of literal numeric constants that would consume extra memory. The constants W=32, V=256, E=65535, and Z=0 (aliased from B) are all set via VAL "...", a memory-saving technique that stores a short string rather than a full floating-point number in the tokenized line.
Machine Code Integration
The disassembler core is not written in BASIC. Two machine code entry points are used:
USR 61586— the main disassembly routine, called at line9815viaLET B=USR 61586.USR 61855— a sort routine for the cross-reference array, called at line9971viaRANDOMIZE USR 61855.USR 30165— a loader routine invoked at line9998to install the machine code into high memory before the main program runs.
Parameters are communicated to the machine code via POKEs into fixed addresses (e.g., begin address at A=64641, end address at 61727–61728, relocation at R=64639, printer flag at 61726, ROM-switch flag at 61725). The cross-reference capacity is stored at addresses 61995–61996 as a 16-bit little-endian value, read back with PEEK 61995+256*PEEK 61996 to dimension X$(XM,4).
Control Menu and Status Display
The menu at line 9860 uses compound PRINT statements with AT, TAB, and the AND operator for conditional string display. Expressions such as "Inst" AND NOT M and "Prtr" AND O exploit the fact that a string multiplied by zero yields an empty string, producing a compact inline conditional without IF statements. The OVER U attribute is used to underline the “Status” column heading by overprinting underscores.
Labeling and Cross-Reference Mode Flags
The byte at address C=65328 is a packed flag byte shared between the machine code and BASIC. Its bits encode the disassembly mode (M: 0=instruction, 1=DEFB, 2=DEFW), the label flag (l=32 when enabled), and the cross-reference flag (64 when enabled). The BASIC manipulates this byte with arithmetic rather than bitwise operations, carefully adding and subtracting field values while checking boundary conditions to avoid corruption of other bits. The DEF FN C() function at line 9850 tests whether the label bit is currently set.
Cross-Reference Listing
Cross-reference data is accumulated in the string array X$(XM,4), where each entry uses four one-character “cells” to store two 16-bit addresses in packed form. Lines 9976–9981 iterate over the sorted array, grouping entries by their first two bytes (the referenced address) and printing up to four references per output line in a formatted table. The loop variable J counts columns, resetting when a new group starts or when four columns are filled. If the array was filled to capacity, the warning string W$ is printed at line 9982.
Key Input Subroutine
The subroutine at lines 9960–9970 implements a clean keypress wait: line 9960 loops while a key is currently held (flushing any buffered press), then line 9965 loops until a new keypress is detected. This is the standard PAUSE 0 / INKEY$ idiom expressed as explicit loops, used before reading INKEY$ immediately after returning, so the caller can inspect the key without it being consumed.
Error Recovery
Lines 9990–9993 implement a three-stage error handler using ON ERR. On the first error, ON ERR RESET resets the error state; after a brief PAUSE 30, ON ERR GO TO 9990 reinstalls the handler, and then ON ERR CONTINUE attempts to resume execution. This pattern is designed to survive transient errors (such as those that might occur during machine code execution) without crashing to a BASIC error prompt. Line 9850 arms the handler with ON ERR GO TO 9990.
Initialization and Reset Path
Line 9998 is the cold-start path, reached after an error-triggered CLEAR 61585. It displays the title and copyright screen, then calls RANDOMIZE USR 30165 to reload the machine code, and finally RUN (with no line number) restarts from the first program line, which is line 9800‘s REM, effectively jumping to 9810‘s GO TO 9850.
Notable Techniques
- 16-bit values split across two bytes using
INT(x/256)for the high byte andx-256*INT(x/256)for the low byte, POKEd into consecutive addresses. VAL "number"used for all numeric constants to reduce tokenized program size.- Boolean arithmetic on strings (
"text" AND condition) used extensively for conditional display. - The printer channel is activated by POKEing the system channel table address
SC=23692 with 32, enablingLPRINToutput from within the cross-reference loop. - Line
9999contains aREMwith what appear to be encoded or token-escaped characters, likely used to embed machine code data or loader bytes within the BASIC program itself.
Content
Source Code
9800 REM ** ZEAL DISASSEMBLER **
9810 GO TO 9850
9815 LET B=USR 61586
9820 BEEP .1,10: IF X THEN GO TO 9830
9825 PRINT #U;"End of run. Press any key for menu.": PAUSE Z: GO TO T
9830 PRINT #U;"End of run. Produce cross-ref listing now? (Y or N) ": PAUSE Z: LET Q=INKEY$<>"Y" AND INKEY$<>"y": INPUT "": IF NOT Q THEN GO TO 9971
9835 GO TO 9825
9850 DIM D$(32): LET XM=PEEK 61995+256*PEEK 61996: DIM X$(XM,4): DIM S$(32): LET W$="WARNING: Cross-reference maximumcapacity exceeded.": LET B=PI-PI: LET U=PI/PI: LET SC=VAL "23692": LET W=VAL "32": LET Z=B: LET Q=B: LET X=B: LET E=VAL "65535": POKE 61725,Z: POKE 61726,Z: LET UL=E: LET V=VAL "256": LET M=B: LET O=B: LET D=B: LET C=VAL "65328": POKE C,B: DEF FN C()=PEEK C<W OR PEEK C>=W+W AND PEEK C<67: LET A=VAL "64641": LET R=VAL "64639": LET T=VAL "9860": LET S=B: LET l=B: CLS : LET T$="*** ZEAL DISASSEMBLER ***": ON ERR GO TO 9990
9860 LET B=PEEK A+V*PEEK (A+U): CLS : PRINT " ";T$;AT 2,8;"Control Menu";AT 3,26;"Status";AT 3,26; OVER U;"______"'"B- Begin Address";TAB 27;B''"E- End Address";TAB 27;E''"M- Mode Select";TAB 28;"Inst" AND NOT M;"DEFB" AND M=U;"DEFW" AND M=U+U''"P- Printer Output Select";TAB 28;"Prtr" AND O;"Scrn" AND NOT O''"R- Relocation Select";TAB 27;D''"L- Labeling Select";TAB 28;"Lbls" AND l>PI;"None" AND NOT l''"S- Switch 3rd ROM to 0-8191";TAB 29;"Yes" AND S;"No" AND NOT S''"C- Cross-Ref. List Select";TAB 29;"Yes" AND X;"No" AND NOT X''"Press letter of run parameter to be changed.": BEEP .05,-10: PRINT #U;"If no changes, <ENTER> to RUN."
9865 IF NOT Q THEN LET XT=PEEK 23627+V*PEEK 23628+53: POKE 62058,INT (XT/V): POKE 62057,XT-V*INT (XT/V): POKE 63156,Z: POKE 63157,Z
9870 GO SUB 9960
9875 LET Y$=INKEY$: IF LEN Y$>U THEN GO TO 9865
9880 IF CODE Y$=13 THEN CLS : GO TO 9815
9885 IF Y$="P" OR Y$="p" THEN LET O=NOT O: POKE 61726,O: GO TO T
9890 IF Y$="L" OR Y$="l" THEN LET l=W AND NOT l: POKE C,PEEK C+(l AND l=W AND FN C())-(W AND NOT l AND NOT FN C()): GO TO T
9895 IF Y$="S" OR Y$="s" THEN LET S=NOT S: POKE 61725,S: GO TO T
9900 IF Y$="C" OR Y$="c" THEN LET X=NOT X: POKE C,PEEK C+(W+W AND X AND PEEK C<W+W)-(W+W AND NOT X AND PEEK C>=W+W): GO TO T
9903 IF Y$="X" OR Y$="x" THEN PRINT AT 20,Z;"Maximum cross-reference capacityis ";XM;" entries. Change?(Y or N)": INPUT "": GO SUB 9960: IF INKEY$="Y" OR INKEY$="y" THEN GO TO 9935
9905 PRINT AT 20,Z;S$'S$: IF Y$="B" OR Y$="b" THEN INPUT "Enter begin address. ";B: IF B<Z OR B>UL THEN GO TO 9905
9910 POKE A+U,INT (B/V): POKE A,B-V*INT (B/V)
9915 IF Y$="E" OR Y$="e" THEN INPUT "Enter end address. ";E: IF E<Z OR E>UL THEN GO TO 9915
9918 POKE 61728,INT (E/V): POKE 61727,E-V*INT (E/V)
9920 IF Y$="M" OR Y$="m" THEN PRINT AT 20,Z;"Press letter of desired mode: I-Inst., B-Byte, or W-Word.": INPUT "": GO SUB 9960: LET M=(INKEY$="B" OR INKEY$="b")+(U+U AND (INKEY$="W" OR INKEY$="w")): POKE C,M+l+(W+W AND X)
9925 IF Y$="R" OR Y$="r" THEN INPUT "Enter relocation displacement. ";D: IF D<Z OR D>UL THEN GO TO 9925
9930 POKE R+U,INT (D/V): POKE R,D-V*INT (D/V): GO TO T
9935 INPUT "Enter new capacity (10-1000)";XM: IF XM<10 OR XM>1000 THEN GO TO 9935
9940 POKE 61996,INT (XM/V): POKE 61995,XM-V*INT (XM/V): RUN 9850
9960 IF INKEY$<>"" THEN GO TO 9960
9965 IF INKEY$="" THEN GO TO 9965
9970 RETURN
9971 LET N=PEEK 63156+V*PEEK 63157: IF N>Z THEN PRINT #U; FLASH U;"Sorting "; FLASH Z;N;" records.": RANDOMIZE USR 61855: INPUT ""
9972 PRINT #U;"List to printer? (Y or N)": PAUSE Z: INPUT "": LET P=INKEY$="Y" OR INKEY$="y": IF P THEN POKE SC,W
9973 LET D$="CROSS-REFERENCE LISTING ": PRINT ''D$: IF P THEN LPRINT ''D$
9974 LET D$="LOC. * REFERENCED BY JP/CALL AT:": PRINT 'D$: IF P THEN LPRINT 'D$
9976 LET J=U: LET Y=Z: FOR I=U TO N: IF J=U THEN LET D$=S$
9977 IF NOT Y THEN LET D$( TO 5)=STR$ (CODE X$(I,2)*V+CODE X$(I,U))
9978 LET D$(10+6*(J-U) TO 14+6*(J-U))=STR$ (CODE X$(I,4)*V+CODE X$(I,3)): IF I<>N THEN LET Y=X$(I, TO 2)=X$(I+U, TO 2)
9980 IF I=N OR NOT Y OR J=4 THEN PRINT D$: IF P THEN LPRINT D$: POKE SC,W
9981 LET J=((J+U) AND Y AND J<4)+(J=4 OR NOT Y): NEXT I: LET Q=Z
9982 IF N=XM THEN PRINT 'W$: IF P THEN LPRINT 'W$
9983 GO TO 9825
9990 ON ERR RESET
9991 PAUSE 30
9992 ON ERR GO TO 9990
9993 ON ERR CONTINUE
9998 CLEAR 61585: PRINT AT 5,2;"*** ZEAL DISASSEMBLER ***"''" \* 1983 J. KILDAY"''''" J.C. Kilday Associates"'" Central Avenue"'" Peaks Island, ME 04108"''''"Machine code portion "; FLASH 1;"now loading": RANDOMIZE USR 30165: RUN
9999 REM INVERSE !\c LIST RETURN STEP \jd STEP DRAW COPY STEP \jd<>
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
