--- title: "Zeal Disassembler" id: 55034 type: "computer_media" slug: "zeal-disassembler" url: "http://localhost/computer_media/zeal-disassembler/" markdown_url: "http://localhost/computer_media/zeal-disassembler.md" published_at: "2024-06-10T08:11:29+00:00" modified_at: "2026-04-04T08:18:39+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A full-featured Z80 disassembler with a menu-driven interface, cross-reference listing, printer support, and configurable relocation displacement — all backed by machine code routines." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "J. C. Kilday Associates" slug: "j-c-kilday-associates" taxonomy: "post_tag" url: "http://localhost/tag/j-c-kilday-associates/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "John C. Kilday" slug: "john-c-kilday" taxonomy: "indiv" url: "http://localhost/indiv/john-c-kilday/" genre: - name: "Machine Language" slug: "machine-language" taxonomy: "genre" url: "http://localhost/type/machine-language/" - name: "Programming" slug: "programming" taxonomy: "genre" url: "http://localhost/type/programming/" media_type: "Program" programmers: - name: "John C. Kilday" slug: "john-c-kilday" taxonomy: "indiv" url: "http://localhost/indiv/john-c-kilday/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Zeal%20Disassembler%20%281983%29%28J.%20C.%20Kilday%20Associates%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "1983" producer_company: - id: 10966 title: "J. C. Kilday Associates" type: "company" url: "http://localhost/company/j-c-kilday-associates/" images: - url: "http://localhost/wp-content/uploads/2024/06/zeal-disassembler.png" related_products: - id: 14180 title: "Zeal Disassembler" type: "product" url: "http://localhost/product/t-s-2068-disassembler-and-rom-explorer/" media_type_tags: "Machine Language, Programming" --- 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 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 `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 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. ## 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+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, 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): 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 BUL 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 EUL 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 DUL 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<> ```