mcdis

Developer(s): Dick Scoville
Type: Program
Platform(s): TS 2068

This program is a Z80 machine code disassembler and development toolkit designed to be merged into an existing BASIC program, with all line numbers starting at 7999. It relies on a companion machine code block (“mcdiscode”) loaded at address 62720 that handles the actual Z80 instruction decoding, with the BASIC layer providing a menu-driven interface for disassembly, hex/decimal conversion, memory peeking, and a simple address dictionary for labeling. The disassembler reads decoded instruction text from address 65216, uses PEEK 64973 to determine operand type, and dispatches to subroutines for relative jumps (including proper signed-offset calculation for JR and DJNZ) and address lookups. A custom hex-input function, defined via DEF FN, converts both digit and lowercase-letter hex characters to numeric values. The dictionary feature stores 8-byte records (2-byte address plus 6-character label) growing downward from address 63080, and a machine code search routine at 62720 performs label lookups during disassembly output.


Program Analysis

Program Structure

The program is organized as a menu-driven toolkit with line numbers starting at 7999, explicitly designed to be merged with a user’s existing BASIC program. The entry point at line 7999 branches to 8183 (initialization), and the menu at line 8000 lists eight functional areas by their starting line numbers.

Line RangeFunction
7999–8029Entry point, initialization branch, menu display
8102Hex-digit conversion function (DEF FN)
8110–8128Hex loader (POKE bytes into memory) and address input subroutine
8130–8174Disassembler main loop
8180–8188Machine code loader and variable initialization
8190–8196Decimal-to-hex conversion subroutine
8210–8214Decimal-to-hex display utility
8220–8229Operand dispatcher (reads PEEK 64973 type flag)
8230–8252Dictionary entry (label assignment to an address)
8260–8288Dictionary lookup and display during disassembly
8290–8293Hex-to-decimal converter (interactive)
8300–8329Instruction display with color coding and JR offset resolution
8350–8385Memory peek utility with hex, decimal, and CHR$ display
8990–8996Save routine (BASIC + machine code block)
8999REM credits line
9000–9006Extended help text (intended for deletion after familiarization)

Machine Code Integration

The core disassembly engine resides in a 2560-byte machine code block loaded at address 62720 via LOAD "mcdiscode" CODE. The BASIC program communicates with it through a shared memory interface:

  • POKE 64044/64045/64046 — pass the address to disassemble (low and high bytes)
  • POKE 64973,0 — clear the operand-type flag before calling the routine
  • RANDOMIZE USR 65040 — invoke the disassembler; decoded mnemonic text is written to 65216
  • PEEK 64973 — read back operand type: 0 = none, 1 = byte/offset operand, 2 = word/address operand
  • PEEK 64974 / PEEK 64975 — retrieve the operand byte(s)
  • PEEK 64045 / PEEK 64046 — read back the updated program counter after disassembly

A second machine code routine at 62720 (invoked via USR 62720 after poking a target address into 62728/62734) performs the dictionary label search, returning either a pointer to a matching 6-character label or 0 if not found.

Key BASIC Idioms and Techniques

The hex-digit conversion at line 8102 uses DEF FN v(v$)=CODE v$-48-39*(CODE v$>96). Subtracting 48 converts ASCII digits 0–9 to 0–9; the additional -39*(CODE v$>96) handles lowercase a–f, where CODE "a"=97, so 97-48-39=10 as required. This is a compact single-expression function avoiding any branching.

The decimal-to-hex conversion subroutine at lines 8192–8196 builds the hex string right-to-left using repeated modulo-16 extraction and indexing into h$="0123456789ABCDEF", terminating when the result is exactly 4 characters. The result is placed in n$ for use by the caller.

The address input subroutine (lines 8121–8128) supports toggling between decimal and hex entry: entering "0" flips the h flag with LET h=NOT h and loops back to re-prompt. Four-nibble hex input is parsed using four successive calls to FN v() with positional weights 4096, 256 (tfs), 16 (sx), and 1.

Disassembly Loop

The main disassembly loop (lines 8131–8174) operates as follows:

  1. Call address input subroutine (GO SUB 8120) to get starting address n
  2. Print address (decimal or hex depending on h)
  3. Decompose n into high/low bytes and POKE into 64045/64046
  4. Call machine code disassembler via RANDOMIZE USR 65040
  5. Read mnemonic text from 65216 into i$ by scanning for a zero terminator
  6. Display mnemonic with optional INK 2 coloring for jump instructions
  7. Dispatch operand display via GO SUB 8220 based on PEEK 64973
  8. Advance n from updated PC in 64045/64046 and loop

Jump Target Resolution

Lines 8310–8329 handle relative jump operands for JR and DJNZ instructions. The signed offset is read from PEEK 64974 and the resolved absolute address is computed as n+2+oo-tfs*(oo>=128), where subtracting 256 when the offset byte is ≥ 128 correctly implements two’s-complement sign extension. The result is then displayed as either hex or decimal according to the h flag.

Dictionary System

The dictionary stores 8-byte records growing downward from end=63080. Each record consists of a 2-byte little-endian address followed by a 6-character label. Adding an entry (lines 8230–8252) prompts for an address and a label, POKEs the data, then decrements end by 8. The machine code search routine at 62720 receives the target address in 62728/62734 and scans the dictionary, returning either the address of the matching label string or 0 for no match.

Memory Peek Utility

Lines 8350–8385 implement a memory browser displaying each byte as a 4-digit hex address, 5-digit decimal value, 2-digit hex byte, decimal byte value, and the CHR$ character (suppressed for values below 32). The hex address display reuses the n$/8190 subroutine, and decimal values are right-justified to 5 characters using a string-padding loop at lines 8357–8357 (a GO TO-based loop prepending spaces until LEN v$=5).

Variable Conventions

VariablePurpose
tfs256 — used as the high-byte multiplier (“two fifty-six”)
sx16 — used as the nibble multiplier (“sixteen”)
hFlag: 1=hex display/input mode, 0=decimal
h$“0123456789ABCDEF” — hex digit lookup string
nCurrent memory address being processed
n$Hex string result from conversion subroutine
endCurrent top of dictionary storage (grows downward from 63080)
d$Label string retrieved from dictionary
i$Decoded mnemonic string from disassembler output buffer

Notable Anomalies

Line 8120 is the target of GO SUB 8120 calls but does not appear in the listing — execution falls through to line 8121, which is the actual start of the address input subroutine. This is a standard technique where the GO SUB target line simply doesn’t exist and execution continues at the next available line.

Line 8183 is the target of the initial GO TO 8183 at line 7999, but it does not appear as an explicit line in the listing; line 8184 contains the variable initialization. After saving and reloading, execution resumes at 8184 via SAVE "mcdis" LINE 8180, which causes the loader to run first.

The CLEAR 62719 at line 8180 sets RAMTOP just below the machine code block, protecting it from BASIC memory management before the LOAD "mcdiscode" CODE at 8182 places the code at 62720.

Content

Appears On

Related Products

Related Articles

Related Content

Image Gallery

Source Code

 7999 GO TO 8183
 8016 REM 
 8017 LET r=PEEK 23730+tfs*PEEK 23731
 8018 CLS 
 8019 PRINT : PRINT 
 8020 PRINT "menu  8000","dis   8130","load  8110","dc-hx 8210","dict  8230","hx-dc 8290","peek  8350","save  8990"
 8025 PRINT : PRINT "help  9000": PRINT : PRINT "FREE "; FREE ,"RAMTOP ";r: PRINT 
 8026 PRINT "(Enter ""GOTO ...."")": PRINT 
 8029 STOP 
 8102 DEF FN v(v$)=CODE v$-48-39*(CODE v$>96)
 8110 GO SUB 8120
 8111 PRINT : PRINT "input hex (lower case)"
 8112 LET v$=""
 8113 IF v$="" THEN INPUT v$
 8114 IF v$="s" THEN STOP 
 8116 POKE n,sx*FN v(v$(1))+FN v(v$(2))
 8117 LET n=n+1
 8118 LET v$=v$(3 TO )
 8119 GO TO 8113
 8121 PRINT "start addr"
 8122 IF h THEN PRINT "(hex hi-lo)"
 8123 IF NOT h THEN PRINT "(dec)"
 8124 INPUT v$
 8125 IF v$="0" THEN LET h=NOT h: GO TO 8122
 8126 IF NOT h THEN LET n=VAL v$
 8127 IF h THEN LET n=4096*FN v(v$(1))+tfs*FN v(v$(2))+sx*FN v(v$(3))+FN v(v$(4))
 8128 RETURN 
 8130 REM 
 8131 GO SUB 8120
 8136 IF NOT h THEN PRINT n;" ";: GO TO 8140
 8137 GO SUB 8190
 8138 PRINT n$;" ";
 8140 LET y=INT (n/tfs)
 8142 LET x=n-tfs*y
 8143 POKE 65216,0
 8144 POKE 64045,x: POKE 64046,y
 8145 POKE 64973,0
 8148 RANDOMIZE USR 65040
 8150 LET i=0: LET i$=""
 8155 IF PEEK (65216+i)=0 THEN GO TO 8170
 8158 LET i$=i$+CHR$ PEEK (65216+i)
 8160 LET i=i+1: GO TO 8155
 8165 PRINT i$;
 8170 GO SUB 8300
 8171 GO SUB 8220
 8172 LET n=1+PEEK 64045+tfs*PEEK 64046
 8174 GO TO 8136
 8180 CLEAR 62719
 8181 PRINT : PRINT "Continue loading..."
 8182 LOAD "mcdiscode"CODE 
 8184 LET sx=16: LET tfs=256: LET h$="0123456789ABCDEF": LET h=1: LET d$="": LET end=63080
 8188 CLS : GO TO 8000
 8190 REM 
 8192 LET n$="": LET n1=n
 8193 LET k1=INT (n1/sx)
 8194 LET n$=h$(n1-sx*k1+1)+n$
 8195 IF LEN n$=4 THEN RETURN 
 8196 LET n1=k1: GO TO 8193
 8210 PRINT "(dec)"
 8211 INPUT n1
 8212 PRINT n1;" ";
 8213 LET n$="": GO SUB 8193
 8214 PRINT n$: STOP 
 8220 IF PEEK 64973=0 THEN GO TO 8229
 8222 PRINT TAB 19;
 8224 IF PEEK 64973=1 THEN GO SUB 8310
 8225 IF PEEK 64973=2 THEN GO SUB 8260
 8229 PRINT : RETURN 
 8230 REM 
 8231 PRINT "enter addr"
 8234 GO SUB 8122
 8236 LET y=INT (n/tfs): LET x=n-tfs*y
 8237 POKE end,x: POKE (end+1),y
 8238 PRINT "label (6 chars)"
 8240 INPUT l$
 8242 IF LEN l$<>6 THEN GO TO 8238
 8244 FOR i=1 TO 6
 8245 POKE (end+1+i),CODE l$(i)
 8246 NEXT i
 8250 LET end=end-8
 8252 STOP 
 8260 LET x=PEEK 64974: LET y=PEEK 64975: LET n1=x+tfs*y
 8261 POKE 62728,x: POKE 62734,y
 8262 LET k=USR 62720
 8263 IF k=0 THEN GO TO 8287
 8264 LET d$=""
 8265 FOR i=0 TO 5
 8266 LET d$=d$+CHR$ PEEK (k+i)
 8267 NEXT i
 8268 PRINT d$;: RETURN 
 8287 IF h THEN LET n$="": GO SUB 8193: PRINT n$;: RETURN 
 8288 PRINT n1;: RETURN 
 8290 LET h=1: GO SUB 8122
 8292 PRINT v$;"  ";n
 8293 STOP 
 8300 IF i$(1)="J" OR i$( TO 2)="DJ" OR i$( TO 2)="CA" THEN PRINT INK 2;i$;: RETURN 
 8305 PRINT i$;: RETURN 
 8310 LET oo=PEEK 64974
 8315 IF i$( TO 2)<>"JR" AND i$( TO 2)<>"DJ" THEN PRINT oo;: RETURN 
 8320 LET n1=n+2+oo-tfs*(oo>=128)
 8324 IF NOT h THEN PRINT n1;: RETURN 
 8328 LET n$="": GO SUB 8193
 8329 PRINT n$;: RETURN 
 8350 GO SUB 8120
 8351 GO TO 8381
 8353 PRINT v$;
 8355 LET v$=STR$ n
 8357 IF LEN v$<5 THEN LET v$=" "+v$: GO TO 8357
 8360 PRINT " ";v$;" ";
 8362 LET t=PEEK n: LET s=INT (t/sx)
 8364 PRINT h$(1+s);h$(1+t-sx*s);" ";
 8365 PRINT t;TAB 18;
 8367 IF t<32 THEN PRINT : GO TO 8380
 8369 PRINT CHR$ t
 8380 LET n=n+1
 8381 GO SUB 8190
 8385 LET v$=n$: GO TO 8353
 8990 CLEAR 62719
 8992 SAVE "mcdis" LINE 8180
 8994 SAVE "mcdiscode"CODE 62720,2560
 8996 GO TO 8183
 8999 REM "mcdis" R Scoville 1984
 9000 CLS : PRINT "You will still need paper and   pencil to write machine code,   but the routines in this programwill help.  You can always GOTO 8000 for the menu.  All hex num-bers must be  entered with four digits (lower case only).  To   switch between  hex and decimal entry, enter a  single ""0""."
 9001 PRINT "To write code, use ""load."" You  may ENTER as often or as seldom as you wish.  To stop entering, simply add ""s"" to the end of    your code.  You can then check  for proper entry by using ""dis.""You can label any addresses you please by using ""dict."""
 9002 PRINT "The routines ""hex-dec"" and      ""dec-hex"" simply translate from one to the other.  The code for the program is 2560 bytes long  (including the dictionary) and  begins at 62720."
 9003 PRINT "The routine ""peek"" will show theCHR$ values that are entered at each address.  The program is   purposely short and plain, so   you may wish to ""save"" copies   on all of your work tapes.      Note that in the middle of the  ""save,"" you will be prompted    twice to press a key--once for  the BASIC part and once for the machine code part."
 9005 PRINT "These help notes (9000 to 9006) should be deleted after you     become familiar with the pro-   gram.  Now GOTO 8000 and try it." 
 9006 PRINT ''''''

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

Scroll to Top