DISA Z

Developer(s): Algis Gedris
Date: 1983
Type: Program
Platform(s): TS 2068

DISA Z is a Z80 disassembler written in BASIC that decodes machine code bytes stored in memory and prints human-readable assembly mnemonics. The program accepts a decimal start address, then reads and decodes opcodes including all prefixed instruction groups: DD (IX), FD (IY), ED (extended), and CB (bit operations). It handles multi-byte instructions by computing instruction length before fetching operand bytes, and formats 16-bit addresses in big-endian hex by swapping high and low byte pairs. A configurable variable `TS2` at line 160 adjusts the hex character offset (`NCOD`) to accommodate different character code mappings between the TS1000 and TS2068 models. The main loop uses `POKE 23692,255` to suppress the automatic scroll prompt, allowing continuous output without user intervention.


Program Analysis

Program Structure

The program is organized as a collection of BASIC subroutines dispatched from a main loop beginning at line 3560. After prompting for a start address, the loop at lines 3580–3760 repeatedly fetches an instruction, computes its length, formats a hex dump string, decodes the mnemonic, prints the result, and advances to the next instruction. Control never exits this loop during normal operation; line 3770 (STOP) is unreachable in practice.

Line rangePurpose
10–50REM header block
60–140Data string initialization (mnemonic tables)
150–180Platform selection and branch to main loop
190–250Octal digit decoder subroutine
260–380Hex formatting subroutines (byte and address)
390–950Instruction length calculator
960–3220Mnemonic decoder (unprefixed + CB + ED groups)
3230–3470CB-prefixed (bit/rotate/shift) instruction decoder
3480–3550DD/FD (IX/IY) prefix handler
3560–3780Main input/display loop

Platform Adaptation via TS2 Flag

Line 160 sets TS2=1, and line 170 computes NCOD=28+20*TS2, giving 48 for TS2068 (ASCII ‘0’) or 28 for TS1000. This offset is used in line 300 when building the hex string: CHR$(NCOD+Y+7*(Y>9)*TS2). On the TS1000 the character set places digits at code 28; on the TS2068 they follow ASCII. The expression 7*(Y>9)*TS2 adds 7 for A–F only on the TS2068 model, bridging the gap between ‘9’ and ‘A’ in ASCII.

Mnemonic Data Encoding

Rather than storing one string per mnemonic, the program packs related mnemonics into fixed-width substrings within shared data strings, then slices them by computed index. This approach saves significant memory.

  • O$ (line 70): 8 arithmetic/logic ops, 3 characters each — ADD, ADC, SUB, SBC, AND, XOR, OR, CP
  • D$ (line 80): register-pair names, 2 characters each — BC, DE, HL, SP, AF, IX, IY
  • B$ (line 90): BIT, RES, SET — 3 characters each
  • C$ (line 100): rotate/shift direction qualifiers
  • R$ (line 110): single-character register names B, C, D, E, H, L, X (placeholder for (HL)), A
  • E$ (line 120): condition codes, 2 characters each — NZ, Z, NC, C, PO, PE, P, M
  • F$ (line 130): miscellaneous group-0/group-3 single-byte ops (RLCA, RRCA, RLA, RRA, DAA, CPL, SCF, CCF), 4 characters each
  • G$ (line 140): block instruction roots — LD, CP, IN, OT

Instruction Length Calculation

The subroutine at lines 390–950 determines how many bytes the current instruction occupies before any decoding begins. It initializes L=0 and increments it based on opcode class. Prefix bytes (DD=221, FD=253) cause a recursive-style re-entry via the GO TO 410 loop at line 440. The ED prefix (237) triggers a separate path at line 540 that classifies the following byte to decide whether a 2-byte operand follows. CB prefix (203) always yields a 2-byte instruction body (plus any preceding prefix). Unprefixed opcodes in the range 64–191 (LD r,r block) take 1 byte; operand-bearing opcodes in the first and fourth groups are detected by modular arithmetic on the octal decomposition.

Octal Decomposition Idiom

The Z80 instruction set is most naturally described in octal. The subroutine at lines 190–250 decomposes an opcode X0 into three fields: the high octal digit pair K (0–3, the “group”), the middle octal digit C (0–7), and the low octal digit T (0–7). This decomposition is used throughout the decoder, e.g. group 1 (64–127) are LD r,r; group 2 (128–191) are arithmetic/logic on registers; group 3 (192–255) contains calls, jumps, and miscellaneous ops.

The modulo-8 test used in many conditional branches is expressed as NOT (W - INT(W/8)*8), which is true when W is a multiple of 8, equivalent to W MOD 8 = 0.

Hex String Construction and Address Formatting

The program builds a fixed-width display string H$ that holds the address, hex bytes, and mnemonic in a single concatenated string. The address hexer (lines 320–380) calls the byte hexer (lines 260–310) twice — first for the high byte, then for the low byte — placing them in big-endian print order. For 16-bit address operands embedded in instructions, the decoder retrieves them as H$(10 TO 11)+H$(8 TO 9), swapping the two hex-byte pairs back to little-endian Z80 format.

Line 3670 strips the last two characters of H$ after the initial address hex call, removing the byte that was PEEKed purely to test for prefix status but should not appear in the opcode dump at that position.

Index Register Substitution

When an IX or IY prefix is active (DD or FD flags set), the placeholder register "X" in P$ or Q$ is replaced by an indexed address string such as "(IX+nn)" at lines 1240–1280. The displacement byte nn is read directly from the pre-built hex string at positions 10–11. Without a prefix, "X" becomes "(HL)" (lines 1200–1210).

Scroll Suppression

Line 3750 executes POKE 23692,255 each iteration. Address 23692 is the system variable SCRCT (scroll counter), which normally halts output and prompts “scroll?” after a screenful of lines. Poking 255 resets the counter to its maximum, effectively disabling the pause and allowing the disassembly to scroll continuously.

Notable Bugs and Anomalies

  • Line 3080 contains IF T<>7 THEN GO TO 3180, but the ED-prefix decoder at lines 2760–3220 never routes execution to line 3080 — the T=7 case is not reachable from the preceding branch structure, so LD A,I / LD A,R / LD I,A / LD R,A / RRD / RLD decode is dead code in practice (only lines 3090–3170 are ever reached via line 3080 if it were called). The correct dispatcher for T=7 would need an explicit check after line 3070.
  • The EX AF,AF' mnemonic at line 2180 is rendered as EX AF,AF" due to BASIC string quoting — the closing single-quote of the alternate register notation cannot be represented inside a BASIC string literal and is approximated with a double-quote. This is a display inaccuracy rather than a functional bug.
  • Lines 2540–2570 handle certain LD (rr),A and LD A,(rr) forms. The branch for C=4 at line 2560 falls through to GO TO 1100, which appends a pointer register name but does not add the surrounding parentheses or comma, potentially producing malformed output for the LD (nn),HL class of instructions when no IX/IY prefix is active.

Image Gallery

Source Code

   10 REM ***********************             DISA Z
   20 REM ***********************         A Z80 DISASSEMBLER              FOR TS COMPUTERS
   30 REM ***********************         COPYRIGHT,1983                  ALGIS GEDRIS
   40 REM ***********************         RUN AND ENTER START             ADDRESS IN DECIMAL
   50 REM ***********************
   60 REM DATA STRINGS
   70 LET O$="ADDADCSUBSBCANDXOROR CP "
   80 LET D$="BCDEHLSPAFIXIY"
   90 LET B$="BITRESSET"
  100 LET C$="RSLRC AL"
  110 LET R$="BCDEHLXA"
  120 LET E$="NZZ NCC POPEP M "
  130 LET F$="RLCARRCARLA RRA DAA CPL SCF CCF "
  140 LET G$="LDCPINOT"
  150 REM FOR TS2000 SET TS2=1 
  160 LET TS2=1
  170 LET NCOD=28+20*TS2
  180 GO TO 3560
  190 REM OCTAL DIGITS
  200 FOR K=0 TO 3
  210 IF X0 >=K*64 AND X0<(K+1)*64 THEN LET X=X0-K*64
  220 NEXT K
  230 LET C= INT (X/8)
  240 LET T=X-C*8
  250 RETURN 
  260 REM BYTE HEXER
  270 LET X= PEEK J
  280 LET Y= INT (X/16)
  290 LET Z=X-Y*16
  300 LET H$=H$+ CHR$ (NCOD+Y+7*(Y>9)*TS2)+ CHR$ (NCOD+Z+7*(Z>9)*TS2)
  310 RETURN 
  320 REM ADDRESS HEXER
  330 LET X= INT (J/256)
  340 GO SUB 280
  350 LET X=J-256*X
  360 GO SUB 280
  370 LET H$=H$+" "
  380 RETURN 
  390 REM GET INSTRUCTION LENGTH
  400 LET L=0
  410 IF X <>221 AND X <>253 THEN GO TO 520
  420 IF L THEN RETURN 
  430 GO SUB 450
  440 GO TO 410
  450 LET L=1
  460 LET J=J+1
  470 GO SUB 270
  480 LET J=J-1
  490 LET H$=H$( TO LEN H$-2)
  500 RETURN 
  510 REM I-LENGTH FOR PREFIXES
  520 IF L THEN LET L=L+((X>51) AND (X<55) OR X=203)
  530 IF X=203 THEN GO TO 930
  540 IF X <>237 THEN GO TO 700
  550 GO SUB 450
  560 IF X<64 OR X>188 THEN RETURN 
  570 IF X<160 AND X>123 THEN RETURN 
  580 IF X<124 THEN GO TO 610
  590 IF X- INT (X/8)*8<5 THEN GO TO 940
  600 RETURN 
  610 IF X=78 OR X=102 OR X=110 OR X=112 OR X=113 OR X=118 OR X=119 THEN RETURN 
  620 LET W=X-67
  630 IF NOT (W- INT (W/8)*8) THEN GO TO 910
  640 LET W=X-76
  650 IF W >=0 AND NOT (W- INT (W/8)*8) THEN RETURN 
  660 LET W=X-85
  670 IF W >=0 AND NOT (W- INT (W/8)*8) THEN RETURN 
  680 GO TO 940
  690 REM WITHOUT PREFIXES
  700 IF X<64 OR X>191 THEN GO TO 730
  710 IF L THEN LET L=L+(X-8* INT (X/8)=6)
  720 GO TO 940
  730 IF X>191 THEN GO TO 820
  740 IF Z=1 THEN GO TO 910
  750 LET W=X-34
  760 IF W >=0 AND NOT (W- INT (W/8)*8) THEN GO TO 910
  770 LET W=X-6
  780 IF W >=0 AND NOT (W- INT (W/8)*8) THEN GO TO 930
  790 LET W=X-16
  800 IF W >=0 AND NOT (W- INT (W/8)*8) THEN GO TO 930
  810 GO TO 940
  820 IF X=195 OR X=205 THEN GO TO 910
  830 IF X=211 OR X=219 THEN GO TO 930
  840 LET W=X-194
  850 IF NOT (W- INT (W/8)*8) THEN GO TO 910
  860 LET W=W-2
  870 IF NOT (W- INT (W/8)*8) THEN GO TO 910
  880 LET W=W-2
  890 IF NOT (W- INT (W/8)*8) THEN GO TO 930
  900 GO TO 940
  910 IF L=2 THEN GO TO 930
  920 LET L=L+1
  930 LET L=L+1
  940 LET L=L+1
  950 RETURN 
  960 REM MNEMONICS
  970 LET H$=H$+" "
  980 IF LEN H$<14 THEN GO TO 970
  990 IF X0=118 THEN GO TO 1320
 1000 GO SUB 190
 1010 IF X0<64 OR X0>191 THEN GO TO 1440
 1020 IF X0>127 THEN GO TO 1340
 1030 REM EIGHT-BIT REG LDS
 1040 LET P$=R$(C+1)
 1050 LET Q$=R$(T+1)
 1060 IF P$="X" OR Q$="X" THEN GO SUB 1190
 1070 LET H$=H$+"LD "+P$+","+Q$
 1080 RETURN 
 1090 REM ADD POINTER REGS TO H$
 1100 IF NOT DD THEN GO TO 1130
 1110 LET H$=H$+"IX"
 1120 RETURN 
 1130 IF NOT FD THEN GO TO 1160
 1140 LET H$=H$+"IY"
 1150 RETURN 
 1160 LET H$=H$+"HL"
 1170 RETURN 
 1180 REM CHECK FOR FD OR DD
 1190 IF FD OR DD THEN GO TO 1240
 1200 IF P$="X" THEN LET P$="(HL)"
 1210 IF Q$="X" THEN LET Q$="(HL)"
 1220 RETURN 
 1230 REM ADD INDEX REGS TO H$
 1240 IF FD THEN LET W$="(IY+"
 1250 IF DD THEN LET W$="(IX+"
 1260 IF P$="X" THEN LET P$=W$+H$(10 TO 11)+")"
 1270 IF Q$="X" THEN LET Q$=W$+H$(10 TO 11)+")"
 1280 RETURN 
 1290 GO SUB 1190
 1300 LET H$=H$+P$+","+R$(1+T)
 1310 RETURN 
 1320 LET H$=H$+"HLT"
 1330 RETURN 
 1340 REM ARITH/LOGIC OPS
 1350 LET I=C*3+1
 1360 LET Q$=R$(T+1)
 1370 GO SUB 1190
 1380 LET I$=" "
 1390 IF I<7 OR I=10 THEN LET I$=" A,"
 1400 IF I>18 THEN LET I$=""
 1410 LET H$=H$+O$(1 TO I+2)+I$+Q$
 1420 RETURN 
 1430 REM 1ST AND 4TH GROUPS
 1440 IF X0=203 THEN GO TO 3230
 1450 IF X0=253 OR X0=221 THEN GO TO 3480
 1460 IF X0>191 THEN GO TO 1620
 1470 REM 1ST GROUP
 1480 IF T=1 THEN GO TO 2100
 1490 IF T=3 THEN GO TO 2320
 1500 IF T=4 OR T=5 THEN GO TO 2380
 1510 IF T=2 THEN GO TO 2450
 1520 IF NOT T THEN GO TO 2160
 1530 IF T <>6 THEN GO TO 1590
 1540 LET Q$=R$(C+1)
 1550 GO SUB 1190
 1560 LET W=4*(FD OR DD)
 1570 LET H$=H$+"LD "+Q$+","+H$(8+W TO 9+W)
 1580 RETURN 
 1590 LET W=4*C+1
 1600 LET H$=H$+F$(W TO W+3)
 1610 RETURN 
 1620 REM DIRECT ARITHMETIC
 1630 IF T <>6 THEN GO TO 1710
 1640 LET I=3*C+1
 1650 LET I$=" "
 1660 IF I<7 OR I=10 THEN LET I$=" A,"
 1670 IF I>18 THEN LET I$=""
 1680 LET H$=H$+O$(I TO I+2)+I$
 1690 LET H$=H$+H$(8 TO 9)
 1700 RETURN 
 1710 REM 4TH GROUP
 1720 IF X0=237 THEN GO TO 2760
 1730 IF T=1 AND NOT (C- INT (C/2)*2) THEN GO TO 1990
 1740 IF T=7 THEN GO TO 2070
 1750 IF T=5 AND NOT (C- INT (C/2)*2) THEN GO TO 2010
 1760 LET FL=0
 1770 IF X0=205 OR T=4 THEN GO SUB 1890
 1780 IF X0=195 OR T=2 THEN GO SUB 1860
 1790 IF X0=201 OR NOT T THEN GO SUB 1930
 1800 IF NOT T OR T=2 OR T=4 THEN GO SUB 1950
 1810 IF T=3 AND NOT FL THEN GO TO 2590
 1820 IF T=1 AND NOT FL THEN GO TO 2670
 1830 IF FL THEN GO SUB 1910
 1840 RETURN 
 1850 REM MAIN CONDITIONALS
 1860 LET H$=H$+"JP "
 1870 LET FL=1
 1880 RETURN 
 1890 LET H$=H$+"CALL "
 1900 GO TO 1870
 1910 LET H$=H$+H$(10 TO 11)+H$(8 TO 9)
 1920 RETURN 
 1930 LET H$=H$+"RET "
 1940 GO TO 1870
 1950 LET H$=H$+E$(2*C+1 TO 2*(C+1))
 1960 IF NOT (C=1 OR C=3 OR C>5) THEN LET H$=H$+" "
 1970 RETURN 
 1980 REM GROUP 4/C EVEN,T=1 OR 5
 1990 LET H$=H$+"POP "
 2000 GO TO 2020
 2010 LET H$=H$+"PUSH "
 2020 IF C=6 THEN LET C=8
 2030 IF C=4 THEN LET C=C+6*(FD OR DD)
 2040 LET H$=H$+D$(1+C TO 2+C)
 2050 RETURN 
 2060 REM GROUP 4/T=7
 2070 LET W= INT (C/2)
 2080 LET H$=H$+"RST "+ STR$ (W)+ STR$ (8*(C-2*W))
 2090 RETURN 
 2100 REM GROUP 1/T=1
 2110 IF C-2* INT (C/2) THEN GO TO 2140
 2120 LET H$=H$+"LD "+D$(C+1 TO C+2)+","
 2130 GO TO 1910
 2140 LET H$=H$+"ADD HL,"+D$(C TO C+1)
 2150 RETURN 
 2160 REM GROUP 1/T=0 (JRS)
 2170 IF C=0 THEN LET H$=H$+"NOP"
 2180 IF C=1 THEN LET H$=H$+"EX AF,AF"""
 2190 IF C=2 THEN LET H$=H$+"DJNZ"
 2200 IF C>1 THEN GO TO 2220
 2210 RETURN 
 2220 IF C>2 THEN LET H$=H$+"JR "
 2230 LET W=C*2-7
 2240 IF C>3 THEN LET H$=H$+E$(W TO W+1)
 2250 IF NOT (C-2* INT (C/2)) THEN LET H$=H$+" "
 2260 LET W=(PEEK (J-1) AND (PEEK (J-1)<128))+((PEEK (J-1)-256) AND (PEEK (J-1)>127))
 2270 LET J0=J
 2280 LET J=J+W
 2290 GO SUB 320
 2300 LET J=J0
 2310 RETURN 
 2320 REM GROUP 1/T=3
 2330 LET Q$="INC "
 2340 IF C-2* INT (C/2) THEN LET Q$="DEC "
 2350 LET W=2* INT (C/2)+1
 2360 LET H$=H$+Q$+D$(W TO W+1)
 2370 RETURN 
 2380 REM GROUP 1/T=4 OR 5
 2390 LET Q$=R$(C+1)
 2400 GO SUB 1190
 2410 LET P$="INC "
 2420 IF T-2* INT (T/2) THEN LET P$="DEC "
 2430 LET H$=H$+P$+Q$
 2440 RETURN 
 2450 REM GROUP 1/T=2
 2460 LET H$=H$+"LD "
 2470 IF NOT (C-2* INT (C/2)) THEN GO TO 2540
 2480 IF C=5 THEN GO SUB 1100
 2490 IF C=5 THEN GO TO 2510
 2500 LET H$=H$+"A"
 2510 IF C>3 THEN LET H$=H$+",("+H$(10 TO 11)+H$(8 TO 9)+")"
 2520 IF C<4 THEN LET H$=H$+",("+D$(C TO C+1)+")"
 2530 RETURN 
 2540 IF C>4 THEN LET H$=H$+"("+D$(C+1 TO C+2)+"),"
 2550 IF C>3 THEN LET H$=H$+"("+H$(10 TO 11)+H$(8 TO 9)+"),"
 2560 IF C=4 THEN GO TO 1100
 2570 LET H$=H$+"A"
 2580 RETURN 
 2590 REM GROUP 4/T=3
 2600 IF C=2 THEN LET H$=H$+"OUT"+H$(8 TO 9)+",A"
 2610 IF C=3 THEN LET H$=H$+"IN A,"+H$(8 TO 9)
 2620 IF C=4 THEN LET H$=H$+"EX(SP),HL"
 2630 IF C=5 THEN LET H$=H$+"EX DE,HL"
 2640 IF C=6 THEN LET H$=H$+"DI"
 2650 IF C=7 THEN LET H$=H$+"EI"
 2660 RETURN 
 2670 REM GROUP 4/T=1
 2680 IF C=3 THEN LET H$=H$+"EXX"
 2690 IF C=5 THEN LET H$=H$+"JP("
 2700 IF C=7 THEN LET H$=H$+"LD SP,"
 2710 IF C<5 THEN RETURN 
 2720 GO SUB 1100
 2730 IF C=7 THEN RETURN 
 2740 LET H$=H$+")"
 2750 RETURN 
 2760 REM ED PREFIXES TO 3610
 2770 IF L=1 THEN GO TO 3520
 2780 LET X0= PEEK (J-L+1)
 2790 GO SUB 190
 2800 IF X0<160 OR X0>187 THEN GO TO 2910
 2810 IF T>3 THEN RETURN 
 2820 IF T=3 AND C<6 THEN LET Q$="OUT"
 2830 IF T=3 AND C<6 THEN GO TO 2860
 2840 LET W=2*T+1
 2850 LET Q$=G$(W TO W+1)
 2860 IF (C-2* INT (C/2)) THEN LET Q$=Q$+"D"
 2870 IF NOT (C-2* INT (C/2)) THEN LET Q$=Q$+"I"
 2880 IF C>5 THEN LET Q$=Q$+"R"
 2890 LET H$=H$+Q$
 2900 RETURN 
 2910 IF X0<64 OR X0>123 THEN RETURN 
 2920 IF T>1 THEN GO TO 2970
 2930 LET Q$=R$(C+1)
 2940 IF T THEN LET H$=H$+"OUT(C),"+Q$
 2950 IF NOT T THEN LET H$=H$+"IN "+Q$+",(C)"
 2960 RETURN 
 2970 LET W= INT (C/2)
 2980 IF T <>2 THEN GO TO 3020
 2990 IF C-2*W THEN LET H$=H$+"ADC HL,"+D$(2*W+1 TO 2*W+2)
 3000 IF NOT (C-2*W) THEN LET H$=H$+"SBC HL,"+D$(2*W+1 TO 2*W+2)
 3010 RETURN 
 3020 IF T <>3 THEN GO TO 3180
 3030 IF C-2*W THEN GO TO 3060
 3040 LET H$=H$+"LD("+H$(12 TO 13)+H$(10 TO 11)+"),"+D$(2*W+1 TO 2*W+2)
 3050 RETURN 
 3060 LET H$=H$+"LD "+D$(2*W+1 TO 2*W+2)+",("+H$(12 TO 13)+H$(10 TO 11)+")"
 3070 RETURN 
 3080 IF T <>7 THEN GO TO 3180
 3090 IF C>3 THEN GO TO 3150
 3100 IF C=2*W THEN LET Q$="I"
 3110 IF C <>2*W THEN LET Q$="R"
 3120 IF C>1 THEN LET H$=H$+"LD A,"+Q$
 3130 IF C<2 THEN LET H$=H$+"LD "+Q$+",A"
 3140 RETURN 
 3150 IF C=4 THEN LET H$=H$+"RRD"
 3160 IF C=5 THEN LET H$=H$+"RLD"
 3170 RETURN 
 3180 IF T=6 AND C<4 AND C <>1 THEN LET H$=H$+"IM "+ STR$ ((C>0)*(C-1))
 3190 IF X0=68 THEN LET H$=H$+"NEG"
 3200 IF X0=69 THEN LET H$=H$+"RETN"
 3210 IF X0=77 THEN LET H$=H$+"RETI"
 3220 RETURN 
 3230 REM BIT OPS
 3240 LET CB=1
 3250 LET X0= PEEK (J-1)
 3260 LET W= INT (X0/64)
 3270 LET X0=X0-W*64
 3280 IF W THEN GO TO 3410
 3290 LET B1=1+ INT (X0/32)
 3300 LET B2= INT (X0/16)
 3310 LET X0=X0-B2*16
 3320 LET B3= INT (X0/8)+3
 3330 LET B2=B2+5
 3340 LET X0=1+X0-(B3-3)*8
 3350 LET Q$=R$(X0)
 3360 GO SUB 1190
 3370 LET H$=H$+C$(B1)+C$(B3)+C$(B2)
 3380 IF B2 <>6 THEN LET H$=H$+" "
 3390 LET H$=H$+Q$
 3400 RETURN 
 3410 LET W=3*W-2
 3420 LET D= INT (X0/8)
 3430 LET X0=X0-D*8+1
 3440 LET Q$=R$(X0)
 3450 GO SUB 1190
 3460 LET H$=H$+B$(W TO W+2)+" "+ STR$ (D)+","+Q$
 3470 RETURN 
 3480 REM FD,DD PREFIXES
 3490 LET DD=X0=221
 3500 LET FD=X0=253
 3510 IF L>1 THEN GO TO 3540
 3520 LET H$=H$+"DATA"
 3530 RETURN 
 3540 LET X0= PEEK (J-L+1)
 3550 GO TO 990
 3560 REM MAIN LOOP
 3570 INPUT "START LINE NUMBER ";J
 3580 LET H$=""
 3590 LET P$=H$
 3600 LET Q$=H$
 3610 LET DD=0
 3620 LET FD=DD
 3630 LET CB=DD
 3640 GO SUB 320
 3650 GO SUB 270
 3660 GO SUB 390
 3670 LET H$=H$( TO LEN H$-2)
 3680 LET X0= PEEK J
 3690 FOR K=1 TO L
 3700 GO SUB 270
 3710 LET J=J+1
 3720 NEXT K
 3730 GO SUB 960
 3740 PRINT H$
 3750 POKE 23692,255
 3760 GO TO 3580
 3770 STOP 
 3780 SAVE "DISA Z" LINE 10

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