--- title: "DIS-ED" id: 70773 type: "computer_media" slug: "dis-ed" url: "http://localhost/computer_media/dis-ed/" markdown_url: "http://localhost/computer_media/dis-ed.md" published_at: "2026-08-23T15:08:14+00:00" modified_at: "2026-08-23T17:26:26+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2026/08/dis-ed.png" alt: "DIS-ED screen" excerpt: "A Z80 disassembler and hex editor driven by a self-relocating 2KB machine code module tucked inside a string variable — browse, edit, and execute RAM one keystroke at a time." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Campbell Systems" slug: "campbell-systems" taxonomy: "post_tag" url: "http://localhost/tag/campbell-systems/" - 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/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/DIS-ED%20%281982%29%28Campbell%20Systems%29%28TS2068%29%28UK%29%28Program%29.zip" mediadate: "1982" producer_company: - id: 10719 title: "Campbell Systems" type: "company" url: "http://localhost/company/campbell-systems/" images: - url: "http://localhost/wp-content/uploads/2026/08/dis-ed.png" alt: "DIS-ED screen" media_type_tags: "Machine Language" --- # DIS-ED DIS-ED is a Z80 disassembler and memory editor that displays memory either as plain hexadecimal with ASCII characters or as fully decoded Z80 assembly language mnemonics. A 2KB self-relocating machine code module stored in the string variable `M$` (from position 36 onward) is invoked via `RANDOMIZE USR` to build each 32-character display line, with `M$(1 TO 32)` returned ready to print, `M$(33–34)` passing the target address in binary, and `M$(35)` acting as a flag to select between full disassembly and plain hex/char editing modes. The program supports hex and character data entry into RAM, a block memory move routine, and instant decimal-to-hex and hex-to-decimal conversion. Navigation is handled by single-keypress commands — uppercase or lowercase — with the menu accessible at any time via the Q key. *** ### Program Structure The program is organized around a central keypress dispatch loop and a collection of subroutines handling display, input, and memory manipulation. The main flow is: 1. Line 10: Safety trap — warns the user not to RUN directly and halts. 2. Lines 20–180: Key dispatch loop. `INKEY$` is read into `d$`, case-folded to uppercase, and routed via a series of `IF`/`GO TO` branches. 3. Lines 190–290: Display loop — iterates from address `o` to `d`, calling the machine code module via `RANDOMIZE USR e` and printing `m$(TO n32)` for each line. 4. Lines 300–640: Functional subroutines — execute, flip display mode, set address, store hex, store character, and hex validation. 5. Lines 650–820: Built-in instructions/help text (deletable to save space). 6. Lines 840–1050: Block memory move (handles overlapping regions correctly). 7. Lines 1060–1200: Decimal-to-hex conversion. 8. Lines 1210–1270: Hex-to-decimal conversion. 9. Lines 1280–1470: Menu display. 10. Lines 1480–1530: Character string store. 11. Lines 1540–1630: Hex address input subroutine (`ha`). 12. Lines 1640–1660: SAVE with auto-resume. 13. Lines 1670–1680: Initialization — computes machine code entry address `e` and jumps to menu. ### Machine Code Integration The 2KB self-relocating machine code module is stored in `m$` starting at position 36. Its entry address `e` is computed at line 1670 using the BASIC variable area pointer from system variable addresses 23627–23628: `LET e = 41 + PEEK 23627 + 256 * PEEK 23628` This makes the code position-independent relative to the BASIC program size, explaining why `RUN` and `CLEAR` must not be used — either would destroy or relocate `m$` and invalidate `e`. The machine code is invoked via `RANDOMIZE USR e`, which calls it without crashing on a non-zero return value. The interface contract is: - `m$(1 TO 32)` — 32-character display line returned ready to print. - `m$(33–34)` — current target address passed in binary (low byte, high byte). - `m$(35)` — flag: `CHR$ (CODE "F")` selects full Z80 disassembly; anything else selects plain hex/char edit mode. ### Variable Naming Conventions and Symbolic Constants The program relies on a set of pre-initialized numeric variables used as named constants, avoiding repeated literal values and saving memory. These include: | Variable | Purpose | | --- | --- | | `n32` | 32 (display line length / string slice) | | `n33`, `n34` | Address byte positions in `m$` | | `n35` | Display mode flag position in `m$` | | `n7` | 7 (used in hex digit conversion offset) | | `n5`, `n6` | PAPER color codes | | `nb` | 256 (byte modulus for address splitting) | | `o` | 1 (loop step / offset constant) | | `z` | 0 (zero sentinel) | | `e` | Entry address of machine code module | | `ha` | Line number of hex address input subroutine | | `l27` | Line number of main display loop entry | | `l39` | Line number of address update/display restart | | `l54` | Line number of address pack subroutine | The subroutine targets `ha`, `l27`, `l39`, `l54` are stored as numeric variables pointing to line numbers, functioning as symbolic labels and saving memory compared to literal `GO SUB` targets. Several `GO TO VAL "number"` constructs also appear, which is a standard memory-saving idiom storing the line number as a string constant. ### Hex Conversion Function Line 20 defines a function `FN n(l$)` that converts a single hex digit character to its numeric value 0–15: `DEF FN n(l$) = CODE l$ - 48 - n7*(l$>"9") - n32*(l$>"Z")` This handles all three ranges: `0–9` (subtract 48), `A–F` (subtract 48+7=55), and `a–f` (subtract 48+7+32=87). The boolean expressions `(l$>"9")` and `(l$>"Z")` each evaluate to 1 when true, providing conditional subtraction without branching. ### Key Dispatch and Case Folding Line 50 folds lowercase input to uppercase by subtracting 32 from the character code if the character is above `"Z"`, using `CODE d$ - n32`. The dispatch at lines 60–180 is a linear chain of `IF` comparisons. The final catch-all at line 170 treats any digit `1–9` as a “forward N lines” command, and any other unrecognized key triggers a forward-page action. ### Memory Move Routine Lines 840–1050 implement a safe overlapping block move. Line 940 branches on whether the source address `f` is less than the destination `t`: if moving to a higher address, the copy proceeds from the end of the block backward (lines 1000–1030) to avoid clobbering source bytes before they are copied; if moving to a lower address, it proceeds forward (lines 950–980). This is correct behavior for overlapping memory regions. ### Decimal-to-Hex Conversion Display Lines 1120–1160 implement a digit-by-digit decimal-to-hex conversion loop, dividing successively by powers of 16 (4096, 256, 16, 1) and printing each hex digit using `CHR$ (48 + x + 7*(x>9))` to select the correct ASCII character from `0–9` or `A–F`. ### Display Mode Toggle Lines 350–360 implement the flip between plain hex/char and full disassembly modes by XOR-ing against `CODE "F"`: `LET m = CODE "F" - m`, then storing `CHR$ m` into `m$(35)`. This toggles between `CODE "F"` (full disassembly) and `0` (plain edit), cleanly alternating on successive F keypresses. ### Address Packing Subroutine Lines 540–570 (the subroutine at `l54`) clamp the address to zero if negative, then pack it into the two-byte interface positions of `m$`: low byte at `m$(n33)`, high byte at `m$(n34)`, using `CHR$ (a MOD 256)` and `CHR$ INT (a/256)` respectively. ### Hex Data Validation Lines 580–630 validate user-entered hex data strings. Each character is tested with `FN n`; any value outside 0–15 causes the input to be rejected as “Bad hex data”. Line 620 additionally checks that the string has an even number of characters (since each byte requires two hex digits) before proceeding to the POKE loop at lines 430–450. ### Notable Anomalies - Line 10’s `STOP` is intentional — the program must be loaded and resumed at line 1670 rather than run from the start, because initialization of the symbolic constant variables (not visible in this listing) and the machine code in `m$` must be preserved. - Lines 300 and 1060 are absent from the listing but referenced by dispatch (lines 80 and 100). These presumably exist in the full saved file as the Execute and Decimal-to-Hex entry points; the visible code for those functions begins at lines 310 and 1070 respectively. - The `SAVE` at line 1650 uses `LINE 1670` to auto-resume at the initialization line after loading, bypassing the line 10 trap. ## Source Code ``` 10 CLS : PRINT "Should not RUN. Now you must re-LOAD to restore the m/c of the Disassembler.": STOP 20 DEF FN n(l$)=CODE l$-48-n7*(l$>"9")-n32*(l$>"Z") 30 LET d$=INKEY$ 40 BEEP VAL ".03",n30 50 IF d$>"Z" THEN LET d$=CHR$ (CODE d$-n32) 60 IF d$="B" THEN GO TO VAL "470" 70 IF d$="F" THEN GO TO VAL "350" 80 IF d$="E" THEN GO TO VAL "300" 90 IF d$="M" THEN GO TO VAL "840" 100 IF d$="D" THEN GO TO VAL "1060" 110 IF d$="H" THEN GO TO VAL "1210" 120 IF d$="I" THEN GO TO VAL "650" 130 IF d$="Q" THEN GO TO VAL "1280" 140 IF d$="V" THEN GO TO VAL "1640" 150 IF d$="A" THEN GO TO VAL "380" 160 IF d$="C" THEN GO TO VAL "1480" 170 IF d$>"0" AND d$<="9" THEN GO TO VAL "490" 180 IF d$="S" THEN GO TO VAL "410" 190 LET a=CODE m$(n33)+nb*CODE m$(n34) 210 CLS : PRINT PAPER n5;"Addr"; 220 IF m=z THEN PRINT TAB VAL "6"; PAPER n5;" Hex Data "; PAPER n7;TAB VAL "20"; PAPER n5;"Char" 230 IF m<>z THEN PRINT " "; PAPER n5;"HexData "; PAPER n7;" "; PAPER n5;"Op "; PAPER n7;" "; PAPER n5;"Operands " 240 FOR i=o TO d: RANDOMIZE USR e 250 PRINT m$( TO n32) 260 IF INKEY$="" THEN NEXT i 270 IF INKEY$="" THEN GO TO l27 280 PAUSE n30 290 GO TO VAL "30" 310 LET y=a: LET p$="USR address": GO SUB ha 320 RANDOMIZE USR a: LET a=y 330 PAUSE n30 340 GO TO l27 350 LET m=CODE "F"-m 360 LET m$(35)=CHR$ m 370 GO TO l39 380 LET p$="Address": GO SUB ha 390 GO SUB l54 400 GO TO VAL "200" 410 INPUT "Hex Data = "; LINE d$ 420 LET y=a: GO TO VAL "580" 430 FOR i=o TO LEN d$ STEP o+o 440 POKE y-o+i/2,16*FN n(d$(i))+FN n(d$(i+o)) 450 NEXT i 460 GO TO l39 470 LET a=a-4*d 480 GO TO l39 490 GO SUB l54 500 FOR i=o TO VAL d$ 510 RANDOMIZE USR e 520 NEXT i 530 GO TO VAL "190" 540 IF a15 THEN GO TO VAL "630" 610 NEXT i 620 LET x=LEN d$: IF x=2*INT (x/2) THEN GO TO VAL "430" 630 PRINT PAPER n5;d$: PRINT PAPER n5;"Bad hex data, ignored": GO TO VAL "410" 640 RETURN 650 CLS : PRINT TAB VAL "8"; PAPER n5;"INSTRUCTIONS": PRINT 660 PRINT ,,"The program will display memory in one of two formats - plain hexadecimal and character, or full Z80 dis-Assembly." 670 PRINT ,,"It will also let you enter data in hex or character strings intoRAM, and is therefore a valuableaid in developing machine code." 680 PRINT ,,"A 2K module of machine code is invoked to build each line of the display. The module is selfrelocating and we have placed itin M$(36 TO )." 690 PRINT ,,,,"The 2K module interfaces with Basic via M$ which is the 1st variable. M$(1 TO 32) is returned ready toprint, (33 TO 34) pass target address in binary, and (35) is Ffor full disassembly else plain edit is assumed." 700 PRINT ,,"The use of preset variables means that RUN and CLEAR must not be used." 710 PRINT ,,"The Menu options are quite easy to understand and memorise, and the Q key summons the menu." 720 PRINT ,,"Most of the time we work with hex notation, but also we need decimal - so we have instant conversion either way via keys H and D. Try them." 730 PRINT ,,"Data can be stored into RAM via Hex string (S) or via Character string (C). The start target address is as the top left of the edited display." 740 PRINT ,,"Upper or lower case are equally valid, as they are for the menu keys generally." 750 PRINT ,,"Move (M) is non-destructive no matter which way the addresses may overlap. It is in Basic, so be patient!" 760 PRINT ,,"Forward 1-9 lines or forward page are simple. So is back page(B) when in plain display mode. But back page in full disassem- bler overshoots deliberately so as to find correct Z80 instruct-ion alignment by coming forwardsagain." 770 PRINT ,,"Line 1670 calculates e which is entry address to the 2K machine code. So if you make any change to the Basic, resume execution via GOTO 1670." 780 PRINT "Also GOTO 1670 after any accid- ental drop into Command mode." 790 PRINT ,,"Delete lines 650 to 820 and 120 to remove these instructions andsave a bit a space, if needed." 800 PRINT ,, PAPER n6;"Any key to return to the menu. " 810 IF INKEY$="" THEN GO TO VAL "810" 820 GO TO VAL "1280" 840 LET p$="Move FROM addr" 850 GO SUB ha 860 LET f=a 870 PRINT a$;" to "; 880 LET p$="TO addr" 890 GO SUB ha 900 LET t=a 910 PRINT a$;" for "; 920 INPUT "Dec length ";l 930 PRINT l 940 IF fVAL "65535" THEN GO TO VAL "1090" 1110 PRINT "Dec ";a;TAB VAL "10";"= Hex "; 1120 LET f=VAL "4096": LET t=a 1130 LET x=INT (t/f) 1140 PRINT CHR$ (VAL "48"+x+VAL "7"*(x>VAL "9")); 1150 LET t=t-f*x: LET f=f/VAL "16" 1160 IF f>=o THEN GO TO VAL "1130" 1170 PRINT 1180 PAUSE VAL "10": PAPER n7 1190 LET a=y 1200 GO TO l27 1220 PAPER n6 1230 LET y=a 1240 LET p$="" 1250 GO SUB ha 1260 PRINT "Hex ";a$;TAB VAL "10";"= Dec ";a 1270 GO TO VAL "1180" 1280 CLS 1290 PRINT PAPER n6;" DISASSEMBLER & EDITOR " 1300 PRINT ,,,," "; PAPER n6;"MENU"; 1310 PRINT ,,," A......Show from Hex Address" 1320 PRINT " B......Back Page" 1330 PRINT " C......Store Character Data" 1340 PRINT " D......Decimal to Hex Calc" 1350 PRINT " E......Execute USR Code" 1360 PRINT " F......Flip Display Style" 1370 PRINT " H......Hex to Decimal Calc" 1380 PRINT " I......"; PAPER 6;"Instructions" 1390 PRINT " M......Move Data" 1400 PRINT " Q......This Menu" 1410 PRINT " S......Store Hex Data" 1420 PRINT " V......SAVE the Program" 1430 PRINT " 1-9....Forward 1-9 Lines" 1440 PRINT " Other..Forward Page" 1450 PRINT ,,,, PAPER n6;" © 1982 CAMPBELL SYSTEMS (UK) " 1460 GO SUB l54 1470 GO TO l27 1480 LET y=a 1490 INPUT "Character String...", LINE d$ 1500 FOR i=o TO LEN d$ 1510 POKE y-o+i,CODE d$(i) 1520 NEXT i 1530 GO TO l39 1540 INPUT (p$);" Hex "; LINE a$ 1550 IF LEN a$>VAL "3" THEN GO TO VAL "1570" 1560 LET a$="0"+a$: GO TO VAL "1550" 1570 LET g=VAL "4096": LET a=z 1580 FOR i=o TO VAL "4" 1590 IF FN n(a$(i))15 THEN GO TO ha 1610 LET a=a+g*FN n(a$(i)): LET g=g/16 1620 NEXT i 1630 RETURN 1640 INPUT "Give SAVE name "; LINE n$ 1650 SAVE n$ LINE VAL "1670" 1660 GO TO VAL "1280" 1670 LET a=z: LET e=VAL "41"+PEEK VAL "23627"+VAL "256"*PEEK VAL "23628" 1680 GO TO VAL "1280" ```