Zeal Disassembler

Developer(s): John C. Kilday
Date: 1983
Type: Program
Platform(s): TS 2068

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 98609930. Cross-reference output is handled by lines 99719983, error recovery by 99909998, and a key-flush subroutine lives at 99609970.

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 line 9815 via LET B=USR 61586.
  • USR 61855 — a sort routine for the cross-reference array, called at line 9971 via RANDOMIZE USR 61855.
  • USR 30165 — a loader routine invoked at line 9998 to 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 99769981 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 99609970 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 99909993 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 and x-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, enabling LPRINT output from within the cross-reference loop.
  • Line 9999 contains a REM with 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

Appears On

Related Products

Uses machine code routines for fast listings to screen or printer decimal addresses. Zilog mnemonics, labeling of system variables, DEFB/DEFW...

Related Articles

Related Content

Image Gallery

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.

Scroll to Top