--- title: "DISM" id: 50608 type: "computer_media" slug: "dism" url: "http://localhost/computer_media/dism/" markdown_url: "http://localhost/computer_media/dism.md" published_at: "2023-06-23T11:26:00+00:00" modified_at: "2026-03-31T07:41:59+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A two-part Z80 disassembler decodes memory addresses into mnemonics using a tape-loaded 1792-entry instruction table, covering all major opcode prefix groups." 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: "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/" 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" download_url: "https://archive.org/download/timex-sinclair-software-archive/DISM%20%281984-10-8%29%28Cultice%2C%20Dick%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "1984-10-8" images: - url: "http://localhost/wp-content/uploads/2023/06/SCR-20260329-psqv.png" media_type_tags: "Machine Language, Programming" --- 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, incrementing `B`. - `"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 incrementing `B` by 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 `ED` opcodes 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 `B` serves 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. ## 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," 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 ```