This program is a Z80 machine code disassembler that decodes memory contents into human-readable mnemonics. It loads a pre-built mnemonic table from tape as a string array `D$` dimensioned to 1792 by 12 characters, covering all Z80 instruction prefix groups: unprefixed (256 entries), CB (256), DD (256), DDCB (256), ED (254), FD (256), and FDCB (256). Instruction bytes are decoded by mapping prefix bytes (CBH, DDH, EDH, FDH) to index offsets into the table, then formatting the opcode bytes as hexadecimal using a manual nibble-splitting technique. A companion section starting at line 500 (in the second program block) prints the full mnemonic table to the printer along with opcode byte sequences, paginating output every 78 lines.
Program Analysis
Program Structure
The listing contains two distinct programs. The first (lines 10–530) is the interactive disassembler itself. The second (lines 10–690, with its own line 10 REM) is a utility that prints the mnemonic table to a line printer. Both share the D$() array, which must be loaded from tape before use. The REM at line 25 instructs users to enter at line 80 to skip the tape-loading preamble once the data is already resident.
Mnemonic Table Layout
The array D$ is dimensioned (1792, 12), giving 1792 rows of 12 characters each. The rows are partitioned into seven prefix groups, each mapped to an index range:
| Index Range | Prefix | Entry Count |
|---|---|---|
| 1–256 | (none) | 256 |
| 257–512 | CB | 256 |
| 513–768 | DD | 256 |
| 769–1024 | DD CB | 256 |
| 1025–1278 | ED | 254 |
| 1271–1526 | FD | 256 |
| 1527–1782 | FD CB | 256 |
The instruction index I is computed in lines 110–170 by adding the opcode byte to the appropriate base offset for its prefix group.
Prefix Detection and Dispatch
Lines 110–170 perform a cascade of PEEK comparisons to identify instruction prefixes. The double-byte prefixes DD CB and FD CB (lines 120 and 150) are detected first within their respective groups, since they require reading the opcode from byte offset +3 (the displacement byte precedes the opcode in these encodings). The flag variable C is set to 0 for these cases to adjust operand addressing: the expression A+B-(NOT C) at line 220 compensates for the displacement byte position.
Operand Substitution
The mnemonic strings in D$ use embedded placeholder characters. During formatting (lines 210–260), each character of D$(I) is examined:
"n"(line 220) — replaced with a decimal byte operand from memory, incrementingB."n"(line 230) — a duplicate check for"n"; in context this appears intended to handle a second distinct placeholder character but is textually identical, suggesting a character encoding artifact where two visually similar but distinct characters were intended (possibly a signed displacement variant)."m"(line 240) — replaced with a 16-bit word operand (little-endian), consuming two bytes and incrementingBby 2.
Hexadecimal Conversion
Lines 330 and 570 implement manual hex byte formatting without lookup tables. Each byte value I1 is split into high and low nibbles. The expression CHR$ (H+48+(7 AND H>9)) converts a nibble to its ASCII hex digit: adding 48 gives the digit characters ‘0’–’9′, and the additional offset of 7 (added when the nibble exceeds 9) bridges the gap between ‘9’ (57) and ‘A’ (65) in ASCII.
Output Formatting
Line 360 prints the disassembly line with address, hex bytes tabbed to column 6, and the mnemonic tabbed to column 16. Line 370 adds a blank line after any instruction whose mnemonic begins with "RET", visually separating subroutines in the output. The byte count B is used both to accumulate the hex dump and to advance the address pointer A at line 380.
Printer Utility (Second Program)
The second program block iterates over all 1792 D$ entries, skipping blank ones (line 510 checks for a leading space). For each valid entry it reconstructs the opcode byte sequence using the same index arithmetic, outputs it with LPRINT, and paginates every 78 lines by printing several blank lines (line 670). The operand placeholder substitution uses string concatenation with "XX" and "XXXX" as stand-in byte and word operand markers.
Notable Anomalies
- Lines 220 and 230 appear identical in the listing (both test
D$(I,J)="n"). This is almost certainly a character-set artifact where two distinct placeholder characters (e.g., for unsigned versus signed byte operands) have been collapsed to the same glyph during transcription. - The ED prefix group is allocated only 254 entries (indices 1025–1278) rather than 256, matching the fact that
EDopcodes do not define all 256 values. - The overlap between the FD base offset (1271) and the end of the ED range (1025+254=1279) means the index ranges for ED and FD overlap by several entries, which could produce incorrect decoding for ED opcodes near the top of their range if not carefully managed by the table data.
- Variable
Bserves dual purpose as both the byte-count accumulator for hex display and the operand-byte offset counter, which is reset to 1 at line 100 each iteration.
Content
Source Code
10 REM DISASSEMBLER BY
20 REM RESET 1984 R.D.CULTICE
25 REM *** Use GOTO 80 ***
30 DIM D$(1792,12)
40 CLS : PRINT "START TAPE,<ENTER>"
50 IF INKEY$="" THEN GO TO 50
60 LOAD "MNOM" DATA D$()
70 BEEP .25,10: BEEP .25,10: BEEP .4,14
80 INPUT "ENTER STARTING ADDRESS OR 0 ";A
90 CLS : PRINT "ADD. CODE MNOMONICS": PRINT
100 LET B=1: LET C=1
110 IF PEEK A=203 THEN LET I=PEEK (A+1)+257: LET B=B+1: GO TO 200
120 IF PEEK A=221 AND PEEK (A+1)=203 THEN LET I=PEEK (A+3)+769: LET B=B+2: LET C=0: GO TO 200
130 IF PEEK A=221 THEN LET I=PEEK (A+1)+513: LET B=B+1: GO TO 200
140 IF PEEK A=237 THEN LET I=PEEK (A+1)+1025: LET B=B+1: GO TO 200
150 IF PEEK A=253 AND PEEK (A+1)=203 THEN LET I=PEEK (A+3)+1527: LET B=B+2: LET C=0: GO TO 200
160 IF PEEK A=253 THEN LET I=PEEK (A+1)+1271: LET B=B+1: GO TO 200
170 LET I=PEEK A+1
200 LET N$=""
210 FOR J=1 TO LEN D$(I)
220 IF D$(I,J)="n" THEN LET N$=N$+STR$ PEEK (A+B-(NOT C)): LET B=B+1: GO TO 260
230 IF D$(I,J)="n" THEN LET N$=N$+STR$ PEEK (A+B-(NOT C)): LET B=B+1: GO TO 260
240 IF D$(I,J)="m" THEN LET N$=N$+STR$ (PEEK (A+B)+256*PEEK (A+B+1)): LET B=B+2: GO TO 260
250 LET N$=N$+D$(I,J)
260 NEXT J
300 LET H$=""
310 FOR J=0 TO B-1
320 LET I1=PEEK (A+J)
330 LET H=INT (I1/16): LET L=I1-H*16: LET O$=CHR$ (H+48+(7 AND H>9))+CHR$ (L+48+(7 AND L>9))
340 LET H$=H$+O$
350 NEXT J
360 PRINT A;TAB 6;H$;TAB 16;N$
370 IF D$(I,1 TO 3)="RET" THEN PRINT
380 LET A=A+B: GO TO 100
400 STOP
500 LET I=1
510 PRINT I-1;TAB 10;D$(I)
520 LET I=I+1
530 GO TO 510
10 REM RESET 1984 R.D.CULTICE
500 LET Q=0: FOR I=1 TO 1792
510 IF D$(I,1)=" " THEN GO TO 680
520 LET X$=""
530 FOR J=1 TO LEN D$(I)
540 LET X$=X$+("XX" AND D$(I,J)="n")+("XXXX" AND D$(I,J)="m")
550 NEXT J
560 LET I1=(I-1 AND I<257)+(I-257 AND (I-257<257 AND I-257>=0))+(I-513 AND (I-513<257 AND I-513>=0))+(I-769 AND (I-769<257 AND I-769>=0))+(I-1025 AND (I-1025<255 AND I-1025>=0))+(I-1271 AND (I-1271<257 AND I-1271>=0))+(I-1527 AND (I-1527<257 AND I-1527>=0))
570 LET H=INT (I1/16): LET L=I1-H*16: LET O$=CHR$ (H+48+(7 AND H>9))+CHR$ (L+48+(7 AND L>9))
580 IF I<257 THEN LPRINT O$+X$;: GO TO 660
590 IF I-257<257 THEN LPRINT "CB"+O$;: GO TO 660
600 IF I-513<257 THEN LPRINT "DD"+O$+X$;: GO TO 660
610 IF I-769<257 THEN LPRINT "DDCB"+X$+O$;: GO TO 660
620 IF I-1025<255 THEN LPRINT "ED"+O$+X$;: GO TO 660
630 IF I-1271<257 THEN LPRINT "FD"+O$+X$;: GO TO 660
640 IF I-1527<257 THEN LPRINT "FDCB"+X$+O$;
660 LPRINT TAB 10;D$(I): LET Q=Q+1
670 IF Q>=78 THEN LET Q=0: LPRINT '''''''
680 NEXT I
690 GO TO 80
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
