This program is a Z80 disassembler and machine code monitor for the Timex Sinclair 2068, written by Robert Gilder in 1984. It decodes all standard Z80 opcodes including the DD, FD, CB, and ED prefix groups, printing each instruction’s address, hex bytes, mnemonic, and operands to either the screen or a printer via the stream variable `hc`. The monitor section (lines 7500–7890) provides three utilities: a hex memory display, a hex machine code entry tool, and a byte-by-byte memory alteration tool. Symbols (user-defined labels with associated addresses) can be entered manually or loaded from tape, sorted via a bubble sort routine at line 8300, and substituted for raw addresses in the disassembly output. Relative branch offsets are displayed in signed decimal while absolute addresses are shown in four-digit hex, with optional symbol name substitution.
Program Analysis
Program Structure
The program is organized into clearly delineated functional blocks, each beginning with a REM label. Execution starts at line 20 with a GO TO 7500, which launches the Monitor Menu. From there the user can invoke the disassembler (option 4), which is handled starting at line 100. The overall flow is:
- Lines 0–30: Header, symbol array initialization, and
DEF FN s() - Lines 100–910: Disassembler main loop and output formatting
- Lines 1000–6320: Opcode decode routines, grouped by Z80 opcode group
- Lines 7000–7295: Initialization, instructions display, symbol entry/sort/save
- Lines 7500–7930: Machine Code Monitor (display, enter, alter memory)
- Lines 8000–8730: Utility subroutines (defaults, opcode splitting, address resolution, hex formatting)
- Lines 9000–9140: Input and hex conversion routines
- Lines 9900–9980:
DATAtables for mnemonics, condition codes, and ED-group block instructions
Opcode Decoding Architecture
The disassembler splits each opcode byte into three fields at line 8200 using integer arithmetic: g = INT(c/64) (bits 7–6), t1 = INT(c/8) - g*8 (bits 5–3), and t2 = c - t1*8 - g*64 (bits 2–0). The variable rp = INT(t1/2) extracts the register-pair index, and t3 = (rp*2 <> t1) is a parity flag used to distinguish e.g. INC from DEC. Dispatch to the four main opcode groups (00, 01, 10, 11) is done by GO TO 1000+g*1000 at line 460, giving a clean computed jump. Within group 00 and group 11, a further computed GO TO using a packed string of line numbers dispatches to sub-handlers (lines 1010 and 4010).
Prefix Handling
DD and FD prefixes (IX and IY) are detected before the main dispatch at line 420. Subroutine 8100 sets e$ to "IX" or "IY", sets the displacement flag e=1, advances the opcode pointer, and increments the byte count b. Throughout the decoder, e$ substitutes for "HL" in register names, and e offsets memory reads and byte counts to account for the displacement byte. The CB prefix (line 5000) and ED prefix (line 6000) each have their own subroutines, and the CB handler correctly handles the DDCB/FDCB two-prefix case by reading the opcode at a+1+e*2.
Symbol Table
Symbols are stored in the string array s$(), dimensioned with ns+1 rows of 8 characters each. Each row uses columns 1–6 for the label name and columns 7–8 for the 16-bit address stored as two raw bytes (low byte first). The first row (s$(1)) stores the count of valid symbols in CHR$ s. The helper DEF FN s(x) at line 30 reconstructs a 16-bit integer from the two address bytes. At line 8300 a bubble sort orders symbols by address value, enabling the disassembly loop at line 340–415 to efficiently annotate label boundaries. Symbol lookup during address resolution occurs in subroutines 8400 and 8450.
DATA Table Technique
Mnemonic strings for the more regular opcode groups are stored in DATA statements at lines 9900–9980. The RESTORE i: READ n pattern at line 7310 positions the DATA pointer to a specific table, then iterates t1+1 times to select the correct row. The format flag n (read first) is either 1 (mnemonic only) or 3 (mnemonic + two operand fields). Notably, some DATA values embed live BASIC expressions such as FN b$(a+1) and "("+H$+")" — these are read as string values and used verbatim or via VAL$ at lines 1230–1240 to perform deferred evaluation, which is a sophisticated technique for embedding computed operands inside static data.
Input and Address Parsing
The general-purpose input routine at line 9000 uppercases all input by subtracting 32 from lowercase ASCII codes and sets the flag end = NOT LEN a$ on empty (Enter-only) input, which propagates as a cancel/back signal throughout the program. Address parsing at line 8500 handles three formats:
- Hexadecimal: trailing
Htriggers digit-by-digit conversion in a loop (line 8510) - Symbol name: matched against the symbol table (line 8520)
- Decimal: validated character-by-character before using
VAL(line 8540)
Note a subtle bug at line 8530: if neither hex nor symbol matches, execution falls through to line 8540 for decimal conversion, but line 8530’s bare RETURN will be reached before line 8540 when the symbol loop exhausts without matching, causing a to remain unset (value -1 is never assigned in that path). Line 8540 appears to be unreachable after a failed symbol search.
Hex Output Formatter
Two hex formatting routines share a common core at line 9130. Line 9110 initializes h$ to 4 spaces (for 16-bit output) and line 9120 initializes it to 2 spaces (for 8-bit output), then both fall through to the shared digit-extraction loop which fills h$ right-to-left using CHR$(x1 + CODE "0" + 7*(x1>9)) — the +7 bridges the ASCII gap between '9' and 'A'.
Output Stream Selection
The variable hc is set at line 200 to either 2 (screen) or 3 (printer), controlled by the Y/N prompt. All disassembly output uses PRINT #hc;, making the hard-copy option completely transparent to the formatting code. The monitor section always prints to the screen.
Monitor Menu Dispatch
At line 7570, the monitor dispatches to one of four routines using another packed-string computed GO TO:
| Selection | Target | Function |
|---|---|---|
| 1 | 7600 | Display memory in hex |
| 2 | 7700 | Enter hex machine code |
| 3 | 7800 | Alter memory byte-by-byte |
| 4 | 0100 | Disassembler (only if present) |
Disassembler Self-Detection
Lines 7505–7507 implement a clever self-detection mechanism: the program runs GO SUB 8000 and checks whether e$ has been set. Line 8090 (RETURN : REM no disassembler present) would be the return point if the disassembler block were absent; since it is present, the full 8000 subroutine executes normally and sets e$="HL", making LEN e$ <> 0 true. The flag d is then used to conditionally show option 4 in the menu and to enable the disassembler dispatch.
Notable Idioms
VAL "number"inGO TOand constant assignments (e.g.,LET DD=VAL "221") saves token storage compared to storing the integer literal directly.("STRING" AND condition)is the standard Sinclair conditional string idiom, returning the string or""depending on the boolean value of the condition.- Bubble sort at lines 8320–8360 includes an early-exit flag
zthat triggersRETURNimmediately when a pass completes with no swaps. - The
DEF FN r$(x)at line 7005 is redefined in the initialization routine after the index register prefix is known, transparently substitutinge$for"HL"when decoding(HL)references.
Content
Source Code
0 REM RESET ROBERT GILDER 1984
5 REM 2068 DISASSEMBLER & MONITOR
10 LET ns=0: DIM s$(ns+1,8): LET s$(1)=CHR$ 0
20 GO TO 7500
30 DEF FN s(x)=CODE s$(x,7)+256*CODE s$(x,8)
100 GO SUB 7000
110 LET a$="ENTER to continue": GO SUB 9000
120 IF CODE s$(1) THEN GO TO 200
130 LET a$="Enter symbols?(Y/N)": GO SUB 9000: IF FN y() THEN GO SUB 7200: GO SUB 8300
200 LET a$="Hard copy (Y/N)?": GO SUB 9000: LET hc=2+FN y()
210 CLS
300 IF LEN INKEY$ THEN GO TO 300
305 LET a$="Enter start address:": GO SUB 9000: IF end THEN GO TO 20
310 GO SUB 8500: IF a<0 THEN GO TO 305
320 IF LEN INKEY$ THEN GO TO 320
330 PRINT #hc;"Addr Hex OP Operand/Notes"''
340 FOR x=2 TO CODE s$(1)+1: LET xa=FN s(x): IF x>xa THEN NEXT x: LET xa=1e31
350 LET xs=x
400 REM Main loop
405 GO SUB 8000
410 IF LEN INKEY$ THEN GO TO 300
415 IF a>=xa THEN PRINT #hc;TAB 13;s$(xs TO 6);":": LET xs=xs+1: LET xa=1e31: IF xs<=CODE s$(1)+1 THEN LET xa=FN s(xs): GO TO 415
420 LET c=PEEK a: IF c=DD OR c=FD THEN GO SUB 8100
425 LET p$="BCDE"+e$+"AF": LET q$="BCDE"+e$+"SP": LET r$="BCDEHLMA"
430 IF c=CB THEN GO SUB 5000: GO TO 500
440 IF c=ED THEN GO SUB 6000: GO TO 500
450 GO SUB 8200
460 GO SUB 1000+g*1000
500 REM Print
510 LET h=a: GO SUB 9100: PRINT #hc;h$;" ";
520 FOR n=1 TO b: LET h=PEEK (a+n-1): GO SUB 9120: PRINT #hc;h$;: NEXT n
530 PRINT #hc;TAB 14;j$;TAB 19;k$;"," AND L$<>"";L$;" ";">" AND n$<>"";n$
900 LET a=a+b
910 GO TO 400
1000 REM Group 00
1010 GO TO VAL "10201100120013001400140016001700"(t2*4+1 TO t2*4+4)
1020 LET i=9900: GO SUB 7300: IF t1<2 THEN RETURN
1050 LET b=b+1: LET h=a+2+FN p(a+1): GO SUB 9100: GO SUB 8450: LET n$=h$
1060 RETURN
1100 IF t3 THEN LET j$="ADD": LET k$=e$: LET L$=FN p$(q$): RETURN
1120 LET j$="LD": LET k$=FN p$(q$): LET h=a+1+e: GO SUB 8400: LET L$=h$: RETURN
1200 LET i=9905: GO SUB 7300: IF t1<4 THEN RETURN
1220 LET h=a+1+e: GO SUB 8400
1230 IF t3 THEN LET L$=VAL$ L$: RETURN
1240 LET k$=VAL$ k$
1250 RETURN
1300 LET j$=("DEC" AND t3)+("INC" AND (NOT t3)): LET k$=FN p$(q$): RETURN
1400 LET j$=("DEC" AND t2=5)+("INC" AND t2=4)
1420 LET k$=FN r$(t1): LET b=b+e
1430 RETURN
1600 LET j$="LD": LET k$=FN r$(t1): LET h=a+1+e*2: GO SUB 8600: LET b=b+e: LET L$=h$: RETURN
1700 LET i=9910: GO SUB 7300
1710 RETURN
2000 REM Group 01
2010 IF t1=6 AND t2=6 THEN LET j$="HALT": RETURN
2020 LET j$="LD"
2030 LET k$=FN r$(t1): LET L$=FN r$(t2)
2040 LET b=b+e
2050 RETURN
3000 REM Group 10
3010 LET k$=FN r$(t2): LET b=b+e
3100 LET i=9915: GO SUB 7300
3105 IF t1<4 AND t1<>2 THEN LET L$=k$: LET k$="A"
3110 RETURN
4000 REM Group 11
4010 GO TO 4100+t2*100
4020 LET j$="??": RETURN
4100 LET j$="RET": GO SUB 7400: RETURN
4200 IF t3 THEN LET i=9920: GO SUB 7300: RETURN
4210 LET j$="POP": LET k$=FN p$(p$): RETURN
4300 LET j$="JP": GO SUB 7400: LET h=a+1: GO SUB 8400: LET L$=h$: RETURN
4400 IF NOT t1 THEN LET h=a+1: GO SUB 8400
4410 IF t1=2 OR t1=3 THEN LET h=PEEK (a+1): GO SUB 9120: LET b=b+1
4420 LET i=9925: GO SUB 7300: RETURN
4500 LET j$="CALL": GO SUB 7400: LET h=a+1: GO SUB 8400: LET L$=h$: RETURN
4600 IF NOT t3 THEN LET j$="PUSH": LET k$=FN p$(p$): RETURN
4610 IF t1<>1 THEN GO TO 4020
4620 LET j$="CALL": LET h=a+1: GO SUB 8400: LET k$=h$: RETURN
4700 LET h=PEEK (a+1): GO SUB 9120: LET k$=h$: LET b=b+1: GO TO 3100
4800 LET j$="RST": LET h=t1*8: GO SUB 9120: LET k$=h$
4810 RETURN
5000 REM CB Group
5010 LET b=b+1+e: LET c=PEEK (a+1+e*2): GO SUB 8200
5100 IF NOT g THEN LET i=9930: GO SUB 7300: LET k$=FN r$(t2): RETURN
5110 LET j$="BITRESSET"((g-1)*3+1 TO (g-1)*3+3)
5120 LET k$=CHR$ (t1+CODE "0")
5130 LET L$=FN r$(t2)
5140 RETURN
6000 REM ED group
6010 LET b=b+1: LET c=PEEK (a+1): GO SUB 8200
6020 IF g=2 THEN GO TO 6300
6030 IF g<>1 THEN LET j$="??": RETURN
6040 GO TO VAL "60506060607061006200621062206230"(t2*4+1 TO t2*4+4)
6050 LET j$="IN": LET L$="(C)": LET k$=FN r$(t1): RETURN
6060 LET j$="OUT": LET k$="(C)": LET L$=FN r$(t1): RETURN
6070 LET j$=("ADC" AND t3)+("SBC" AND (NOT t3)): LET k$=e$: LET L$=FN p$(q$): RETURN
6100 LET j$="LD": LET h=a+2: GO SUB 8400: LET h$="("+h$+")"
6120 LET k$=FN p$(q$): LET L$=h$
6130 IF NOT t3 THEN LET L$=k$: LET k$=h$
6140 RETURN
6200 LET j$="NEG": RETURN
6210 LET j$=("RETI" AND t1)+("RETN" AND (NOT t1)): RETURN
6220 LET j$="IM": LET k$=CHR$ (t1+CODE "0"): RETURN
6230 LET i=9935: GO SUB 7300
6240 RETURN
6300 RESTORE 9940+t2*10
6310 FOR x=1 TO t1-3: READ j$: NEXT x
6320 RETURN
7000 REM Initialize
7005 DEF FN r$(x)=(r$(x+1) AND r$(x+1)<>"M")+(FN i$(a+1+e) AND r$(x+1)="M")
7010 DEF FN p(x)=PEEK x-(256*(PEEK x>127))
7015 DEF FN b$(x)=("+" AND FN p(x)>=0)+STR$ FN p(x)
7020 DEF FN i$(x)="("+e$+(FN b$(x) AND e)+")"
7025 DEF FN p$(x$)=x$(rp*2+1 TO rp*2+2)
7030 DEF FN y()=CHR$ CODE a$="Y"
7035 DEF FN n(x$)=(x$>="0" AND x$<="9")
7040 LET p$="BCDEHLAF": LET q$="BCDEHLSP": LET r$="BCDEHLMA"
7045 LET DD=VAL "221": LET FD=VAL "253"
7050 LET ED=VAL "237": LET CB=VAL "203"
7070 LET ramtop=1+PEEK 23730+256*PEEK 23731
7100 REM Instructions
7110 CLS : PRINT " *** 2068 DISASSEMBLER ***"
7130 PRINT '"All the values are shown in hex with the exception of relative offset value, which are shown indecimal(e.g. JR +19 or LD (IY-8),FF)."
7140 PRINT '"Addresses may be entered in hex (e.g. 43a2h) or decimal, or evencertain System Variable names, like RAMTOP."
7190 RETURN
7200 REM Enter symbol name
7210 LET a$="Load symbols from tape?": GO SUB 9000: IF FN y() THEN INPUT "Name:"; LINE a$: LOAD a$ DATA s$(): RETURN
7220 FOR s=2 TO ns+1
7230 LET a$="Enter symbol name:": GO SUB 9000: IF end THEN LET s=s-2: GO TO 7280
7240 LET s$(s, TO 6)=a$
7250 LET a$="Enter address:": GO SUB 9000: IF end THEN GO TO 7250
7255 GO SUB 8500: IF a<0 THEN GO TO 7250
7260 LET s$(s,7 TO )=CHR$ (a-INT (a/256)*256)+CHR$ (INT (a/256))
7270 PRINT s$(s, TO 6),a
7275 NEXT s: LET s=ns
7280 LET s$(1)=CHR$ s
7290 LET a$="Save symbols on tape?": GO SUB 9000: IF FN y() THEN INPUT "Name:"; LINE a$: SAVE a$ DATA s$()
7295 RETURN
7300 REM Create operand
7310 RESTORE i: READ n
7320 FOR x=1 TO t1+1
7330 READ j$: IF n=3 THEN READ k$,L$
7340 NEXT x
7390 RETURN
7400 REM Condition codes
7410 RESTORE 9980: FOR x=1 TO t1+1: READ k$: NEXT x
7420 RETURN
7500 REM Machine Code Monitor-ZXMCOM
7501 REM ROBERT GILDER 1984
7505 LET e$="": GO SUB 8000: LET d=(LEN e$<>0): REM DISASM check
7510 LET ramtop=PEEK 23730+256*PEEK 23731+1: IF NOT d THEN LET s$=CHR$ 0: REM set ramtopvalue
7520 CLS : PRINT TAB 10;"MONITOR MENU"''" (1) Display memory in hex"'" (2) Enter hex machine code"'" (3) Alter memory"
7530 IF d THEN PRINT " (4) Disassemble memory"
7540 PRINT ''"Null Finish Program"
7550 LET a$="Enter your selection:": GO SUB 9000: IF end THEN STOP : GO TO 7520
7560 IF VAL a$<1 OR VAL a$>3+d THEN GO TO 7550
7570 CLS : GO TO VAL "7600770078000100"((VAL a$-1)*4+1 TO (VAL a$-1)*4+4)
7600 REM display memory
7610 IF LEN INKEY$ THEN GO TO 7610
7620 GO SUB 8700: IF end THEN GO TO 7500
7630 FOR a=a TO a+65535 STEP 8: LET h=a: GO SUB 9100: PRINT h$;" ";
7640 FOR b=a TO a+7: LET h=PEEK b: GO SUB 9120: PRINT h$;" ";: NEXT b
7650 PRINT : IF LEN INKEY$ THEN GO TO 7600
7660 NEXT a: GO TO 7500
7700 REM Enter machine code
7705 IF LEN INKEY$ THEN GO TO 7705
7710 GO SUB 8700: IF end THEN GO TO 7500
7715 PRINT AT 10,0;"Current address: ";a;"(";: LET h=a: GO SUB 9100: PRINT h$;")"
7720 LET a$="Enter hex: ": GO SUB 9000: IF end THEN GO TO 7500
7725 PRINT AT 21,0,,
7730 IF LEN a$<>INT (LEN a$/2)*2 THEN PRINT AT 21,0; FLASH 1;"LENGTH ERROR"; FLASH 0;" - re-enter": GO TO 7720
7735 FOR X=1 TO LEN a$-1 STEP 2: GO SUB 7900
7740 IF x1*16+x2>255 THEN PRINT AT 21,0; FLASH 1;"RANGE ERROR"; FLASH 0;" - re-enter remainder": GO TO 7715
7745 POKE a,x1*16+x2
7750 LET a=a+1
7755 NEXT x
7760 GO TO 7715
7800 REM Alter memory
7810 IF LEN INKEY$ THEN GO TO 7810
7820 GO SUB 8700: IF end THEN GO TO 7500
7830 LET h=a: GO SUB 9100: LET x$=h$: LET h=PEEK a: GO SUB 9120
7840 LET a$=x$+" "+h$+"-": GO SUB 9000: IF end THEN GO TO 7880
7850 IF a$="." THEN GO TO 7500
7860 IF LEN a$>2 THEN LET a$=a$( TO 2)
7870 LET x=1: GO SUB 7900: POKE a,x1*16+x2
7880 PRINT x$;" ";h$;"-";a$
7890 LET a=a+1: GO TO 7830
7900 REM convert a$(x) to binary
7910 LET x1=CODE a$(x)-CODE "0"-7*(a$(x)>"9")
7920 LET x2=CODE a$(x+1)-CODE "0"-7*(a$(x+1)>"9")
7930 RETURN
8000 REM Reset defaults
8010 LET e$="HL"
8020 LET e=0: LET b=1
8030 LET j$="": LET k$="": LET L$="": LET h$="": LET n$=""
8040 RETURN
8090 RETURN : REM no disassembler present
8100 REM DD/FD opcode
8110 LET e$=("IX" AND c=DD)+("IY" AND c=FD)
8120 LET e=1: LET b=b+1
8130 LET c=PEEK (a+1)
8140 RETURN
8200 REM Split opcode
8210 LET g=INT (c/64): LET t1=INT (c/8)-g*8: LET t2=c-t1*8-g*64
8220 LET rp=INT (t1/2): LET t3=(rp*2<>t1)
8230 RETURN
8300 REM Sort symbols
8310 PRINT AT 21,0;"Sorting...."
8320 FOR x=2 TO CODE s$(1)+1: LET z=1: FOR y=2 TO CODE s$(1)-x+2
8330 IF FN s(y)>FN s(y+1) THEN LET x$=s$(y): LET s$(y)=s$(y+1): LET s$(y+1)=x$: LET z=0
8340 NEXT y: IF z THEN RETURN
8350 NEXT x
8360 RETURN
8400 REM Get address in h$
8410 LET h=PEEK h+256*PEEK (h+1): GO SUB 9100
8420 LET b=b+2
8450 IF NOT CODE s$(1) THEN RETURN
8460 FOR x=2 TO CODE s$(1)+1
8470 IF h>FN s(x) THEN NEXT x: RETURN
8480 IF h=FN s(x) THEN LET h$=s$(x, TO 6)
8490 RETURN
8500 REM Create true address
8510 IF a$(LEN a$)="H" THEN LET a=0: FOR x=1 TO LEN a$-1: LET a=a*16+CODE a$(x)-CODE "0"-7*(a$(x)>"9"): NEXT x: RETURN
8520 FOR x=2 TO CODE s$(1)+1: IF a$=s$(x, TO LEN a$*(LEN a$<7)) THEN LET a=CODE s$(x,7)+256*CODE s$(x,8): RETURN
8530 RETURN
8540 LET a=-1: FOR x=1 TO LEN a$: IF a$(x)>="0" AND a$(x)<="9" THEN NEXT x: LET a=VAL a$
8550 RETURN
8600 REM Byte value
8610 LET h=PEEK h: GO SUB 9120: LET b=b+1
8620 RETURN
8700 REM Start address
8710 LET a$="Enter start address:": GO SUB 9000: IF end THEN RETURN
8720 GO SUB 8500: IF a<0 THEN GO TO 8710
8730 RETURN
9000 REM Line input
9010 INPUT (a$+" "); LINE a$: LET end=NOT LEN a$
9020 FOR x=1 TO LEN a$: LET a$(x)=CHR$ (CODE a$(x)-32*(a$(x)>="a")): NEXT x
9030 RETURN
9100 REM h$=hex$(h)
9110 LET h$=" ": GO TO 9130
9120 LET h$=" "
9130 LET h1=h: FOR x=LEN h$ TO 1 STEP -1: LET x1=h1-INT (h1/16)*16: LET h$(x)=CHR$ (x1+CODE "0"+7*(x1>9)): LET h1=INT (h1/16): NEXT x
9140 RETURN
9900 DATA 3,"NOP","","","EX","AF","AF","DJNZ",FN b$(a+1),"","JR",FN B$(a+1),"","JR","NZ",FN B$(a+1),"JR","Z",FN B$(a+1),"JR","NC",FN B$(a+1),"JR","C",FN B$(a+1)
9905 DATA 3,"LD","(BC)","A","LD","A","(BC)","LD","(DE)","A","LD","A","(DE)","LD","""(""+H$+"")""","HL","LD","HL","""(""+H$+"")""","LD","""(""+h$+"")""","A","LD","A","""(""+h$+"")"""
9910 DATA 1,"RLCA","RRCA","RLA","RRA","DAA","CPL","SCF","CCF"
9915 DATA 1,"ADD","ADC","SUB","SBC","AND","XOR","OR","CP"
9920 DATA 3,"??","","","RET","","","??","","","EXX","","","??","","","JP","("+E$+")","","??","","","LD","SP",E$
9925 DATA 3,"JP",H$,"","??","","","OUT","("+H$+")","A","IN","A","("+H$+")","EX",E$,"(SP)","EX","DE",E$,"DI","","","EI","",""
9930 DATA 1,"RLC","RRC","RL","RR","SLA","SRA","??","SRL"
9935 DATA 3,"LD","I","A","LD","R","A","LD","A","I","LD","A","R","RRD","","","RLD","",""
9940 DATA "LDI","LDD","LDIR","LDDR"
9950 DATA "CPI","CPD","CPIR","CPDR"
9960 DATA "INI","IND","INIR","INDR"
9970 DATA "OUTI","OUTD","OTIR","OTDR"
9980 DATA "NZ","Z","NC","C","PO","PE","P","M"
9999 STOP
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
