Disassymbl

Developer(s): Ben H. Jackson
Date: 1985
Type: Program
Platform(s): TS 2068

This program is a Z80 machine code disassembler written in BASIC that decodes opcode bytes at user-specified memory addresses and prints both to the screen and to a printer via LPRINT. It reads the byte at each address, looks it up against DATA statements listing multi-byte instruction prefixes (such as ED/&ED=237, CB/&CB=203), and dispatches to subroutine-like branches at lines 200, 300, 400, and 700 to handle one-byte, two-byte, and prefixed instructions. The program uses string arrays A$, B$, and C$ (presumably DIMmed and populated elsewhere, consistent with the GOTO 100 start warning) to hold mnemonic text indexed by opcode value. POKE 23692,255 at line 171 resets the BASIC scroll counter to prevent “scroll?” prompts interrupting long disassembly runs. Lines 5000–5040 form an independent memory dump utility that prints each byte’s numeric value and its CHR$ representation.


Program Analysis

Program Structure

The program is organised into several distinct functional blocks rather than true subroutines (no GOSUB/RETURN pairs are used; all branching is via GO TO):

  1. Initialisation guard (lines 5–21): A REM header and a deliberate STOP prevent accidental RUN from line 1, since the mnemonic string arrays must be set up before the disassembler loop begins.
  2. Main decode loop (lines 100–180): Reads the byte at ADDRESS, checks for special prefix opcodes, searches two DATA tables for multi-byte instructions, then advances the address pointer.
  3. One-byte operand handler (lines 200–230): Handles opcodes with an immediate 8-bit operand, including sign-extension for relative jumps and offsets (line 210).
  4. ED-prefix handler (lines 305–390): Processes ED-prefixed two-byte instructions using the B$ mnemonic array and a secondary DATA search.
  5. Two-byte operand handler (lines 400–430): Reconstructs a 16-bit address or immediate from two successive bytes using PEEK (ADDRESS+1)+256*PEEK (ADDRESS+2).
  6. CB-prefix handler (line 700): Handles CB-prefixed bit-manipulation instructions via the C$ array.
  7. Standalone memory dumper (lines 5000–5040): An independent utility loop that prints each byte’s decimal value and its CHR$ equivalent, entirely separate from the disassembler.

Opcode Dispatch Mechanism

The main loop uses a three-level dispatch strategy:

  • Zero byte: Line 115 catches opcode 0 (NOP) as a special case, printing the mnemonic directly without an array lookup.
  • ED prefix (237): Detected at line 120, branching to line 300/305 for the extended instruction set.
  • CB prefix (203): Detected at line 125, branching to line 700 for bit, rotate, and shift instructions.
  • Two-byte operand opcodes: Line 130–150 searches a DATA list at line 2000 for opcodes requiring a 16-bit operand (e.g. LD rr,nn, JP cc,nn).
  • One-byte operand opcodes: Lines 160–165 search a secondary DATA list at line 4000 for opcodes requiring an 8-bit operand (e.g. LD r,n, ADD A,n).
  • All other opcodes: Fall through to line 170, treated as single-byte instructions looked up via A$.

Mnemonic Storage

Mnemonics are stored in string arrays A$, B$, and C$, indexed directly by opcode byte value (or byte+1 in the CB case at line 700). These arrays are not initialised within this listing — they must be populated by a companion program or setup block, which is why the header warns never to RUN the program and instead to GO TO 100 after setup.

Notable Techniques

  • Scroll suppression: POKE 23692,255 at line 171 writes to the FRAMES/scroll counter system variable to prevent the “scroll?” prompt interrupting a long disassembly run — a standard BASIC idiom for continuous output.
  • Sign extension: Line 210 applies ONEBIT=ONEBIT-256 when the byte is ≥128 and the opcode is one of the relative-jump or indexed-offset instructions (opcodes 16, 24, 32, 40, 48, 56), correctly converting the unsigned byte to a signed 8-bit offset.
  • 16-bit reconstruction: Line 400 uses the standard little-endian formula PEEK(ADDRESS+1)+256*PEEK(ADDRESS+2) to reconstruct a 16-bit word from two successive memory bytes.
  • Dual output: Every decoded line is sent to both the display (PRINT) and the printer (LPRINT), making the tool useful for producing hardcopy disassembly listings.
  • DATA table searching: RESTORE followed by a FOR/READ loop is used instead of arrays for the opcode classification tables, conserving variable space at the cost of repeated sequential scanning.

DATA Tables

LinePurposeCountSample values
2000Opcodes with 16-bit operand (nn)34 entries (loop reads 26)1 (LD BC,nn), 17 (LD DE,nn), 195 (JP nn), 205 (CALL nn)
3000ED-prefixed opcodes with 16-bit operand867 (LD (nn),BC), 75, 83, 91…
4000Opcodes with 8-bit operand (n)246 (LD B,n), 14 (LD C,n), 198 (ADD A,n), 254 (CP n)

Bugs and Anomalies

  • Overlong DATA at line 2000: The FOR loop at line 130 reads only 26 items, but the DATA statement at line 2000 contains 34 values. The extra 8 values (67, 75, 83, 91, 99, 107, 115, 123) are never read by the 26-iteration loop and appear to be the ED-prefix 16-bit operand opcodes accidentally duplicated from line 3000.
  • Missing line 300: The main loop at line 120 branches to GO TO 300 for the ED prefix, but line 300 does not exist in the listing. Execution would fall through to line 305, which is the intended target — this works correctly in practice because BASIC finds the next available line.
  • Variable shadowing: The variable PEEK at line 110 stores PEEK ADDRESS into a numeric variable also named PEEK, shadowing the built-in function name. Subsequent use of PEEK ADDRESS in lines 120–125 calls the function, while IF PEEK=0 and IF PEEK=237 reference the variable — this is consistent but potentially confusing.
  • CB operand index off-by-one: Line 700 indexes C$ with PEEK ADDRESS+1 rather than PEEK ADDRESS. This appears intentional to convert the 0-based opcode to a 1-based array index, but assumes C$ is dimensioned and loaded accordingly.

Content

Appears On

One of the largest single-tape collections anywhere, with over 40 programs spanning flight planning, satellite tracking, hydrology, Forth programming, a 17-game mega-pack, and a complete calligraphic font renderer. A snapshot of a thriving Texas user group at its peak.

Related Products

Related Articles

Related Content

Image Gallery

Source Code

    5 REM "DISASSYMBL" © by Ben H. Jackson, 1985; ALL RIGHTS RESERVED
   10 REM SAVE "DISASSYMBL" LINE 1
   20 PRINT "Never RUN this program ! Always GOTO 100 to RUN or re-start"
   21 STOP 
  100 CLS : INPUT "ENTER BEGINNING ADDRESS ";ADDRESS
  110 LET PEEK=PEEK ADDRESS
  115 IF PEEK=0 THEN PRINT ADDRESS;"   0","NOP": LPRINT ADDRESS;"   0","NOP": GO TO 170
  120 PRINT ADDRESS;"   ";PEEK ADDRESS,A$(PEEK): LPRINT ADDRESS;"   ";PEEK ADDRESS,A$(PEEK): IF PEEK=237 THEN GO TO 300
  125 IF PEEK=203 THEN GO TO 700
  130 RESTORE 2000: FOR I=1 TO 26
  140 READ TWOBIT: IF PEEK=TWOBIT THEN GO TO 400
  150 NEXT I
  160 RESTORE 4000: FOR I=1 TO 24: READ OB: IF PEEK=OB THEN GO TO 200
  165 NEXT I
  170 LET ADDRESS=ADDRESS+1
  171 POKE 23692,255
  180 GO TO 110
  200 LET BIT=PEEK ADDRESS: LET ADDRESS=ADDRESS+1: LET ONEBIT=PEEK ADDRESS
  210 IF (BIT=16 OR BIT=24 OR BIT=32 OR BIT=40 OR BIT=48 OR BIT=56) AND ONEBIT>=128 THEN LET ONEBIT=ONEBIT-256
  220 PRINT ADDRESS;"   ";PEEK ADDRESS,ONEBIT: LPRINT ADDRESS;"   ";PEEK ADDRESS,ONEBIT
  230 GO TO 170
  305 LET ADDRESS=ADDRESS+1: PRINT ADDRESS;"   ";PEEK ADDRESS,B$(PEEK ADDRESS): LPRINT ADDRESS;"   ";PEEK ADDRESS,B$(PEEK ADDRESS)
  310 RESTORE 3000
  320 FOR I=1 TO 8
  330 READ TWOBIT: IF PEEK ADDRESS=TWOBIT THEN GO TO 400
  340 NEXT I
  390 GO TO 170
  400 LET NUMBER=PEEK (ADDRESS+1)+256*PEEK (ADDRESS+2)
  410 LET ADDRESS=ADDRESS+1: PRINT ADDRESS;"   ";PEEK ADDRESS,NUMBER: LPRINT ADDRESS;"   ";PEEK ADDRESS,NUMBER: LET ADDRESS=ADDRESS+1
  420 PRINT ADDRESS;"   ";PEEK ADDRESS: LPRINT ADDRESS;"   ";PEEK ADDRESS
  430 GO TO 170
  700 LET ADDRESS=ADDRESS+1: PRINT ADDRESS,C$(PEEK ADDRESS+1): LPRINT ADDRESS,C$(PEEK ADDRESS+1)
  710 GO TO 170
 2000 DATA 1,17,33,34,42,49,50,58,194,195,196,202,204,205,210,212,218,220,226,228,234,236,242,244,250,252,67,75,83,91,99,107,115,123
 3000 DATA 67,75,83,91,99,107,115,123
 4000 DATA 6,14,16,22,24,30,32,38,40,46,48,54,56,62,198,206,211,214,219,222,230,238,246,254
 5000 INPUT "ADDRESS? ";ADDRESS
 5010 PRINT ADDRESS;"  ";PEEK ADDRESS,CHR$ PEEK ADDRESS
 5020 LET ADDRESS=ADDRESS+1
 5040 GO TO 5010

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

Scroll to Top