--- title: "Z80 Disassembler" id: 56450 type: "computer_media" slug: "z80-disassembler" url: "http://localhost/computer_media/z80-disassembler/" markdown_url: "http://localhost/computer_media/z80-disassembler.md" published_at: "2024-08-04T20:44:32+00:00" modified_at: "2026-03-30T21:22:11+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/08/SCR-20240804-oslo.png" excerpt: "A Z80 disassembler written entirely in BASIC. You give a start and end address, choose hexadecimal or decimal output and an offset, and the program lists the code one instruction a line: address, bytes in hex, then the mnemonic. The offset lets you disassemble code held at one address as if it ran at another.…" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Z80%20Disassembler%20%28198x%29%28TS2068%29%28US%29%28Program%29.tap.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/08/SCR-20240804-oslo.png" - url: "http://localhost/wp-content/uploads/2024/08/SCR-20240804-oruz.png" license: false --- # Z80 Disassembler A Z80 disassembler written entirely in BASIC. You give a start and end address, choose hexadecimal or decimal output and an offset, and the program lists the code one instruction a line: address, bytes in hex, then the mnemonic. The offset lets you disassemble code held at one address as if it ran at another. When the screen fills, it can copy the page to the printer (and feeds paper every third page) or ask whether to `COPY` it. No author or date is given in the listing. It is saved as `DISASSY`. ## Program Analysis The program decodes each opcode into its octal fields (the top two bits, the middle three and the bottom three), then uses `RESTORE 3000+100*CL+10*A(1)+A(2)` to jump straight to the `DATA` line for that opcode group. `CL` is 1 after a `CB` prefix and 2 after `ED`, and `IN` records a `DD` or `FD` prefix. Each `DATA` pair is a three-character pattern (with `-` as a wildcard) and the mnemonic template. The templates use punctuation as placeholders: `&`, `'`, `!`, `"`, `#`, `$` and `%` are replaced from tables at lines 3333–3345 (register pairs, registers, conditions, ALU operations, bit numbers), found by `RESTORE 3300+CODE` of the placeholder character. `*` and `-` become `(HL)`, `(IX+d)` or `(IY+d)` and `HL`, `IX` or `IY`. A `.` takes an immediate byte or a two-byte address, and `/` a displacement; `JR` and `DJNZ` targets are worked out and shown in brackets. ## Notable Techniques - Placeholder characters chosen so that `CODE` of the character plus 3300 gives the line number of its substitution table. - `HALT` is caught before the table search, since it sits where `LD (HL),(HL)` would be. - `POKE 23658,8` sets CAPS LOCK so the H/D and y/n answers come in as capitals. ## Potential Issues - The ALU table at line 3336 has `"SUB,"`, so `SUB` instructions print as `SUB,B` and so on. - Opcodes with no entry (undocumented ones such as `SLL`, or unused `ED` codes) make the search read past its `DATA` and stop with an error. - Hex output is chosen only if the answer is exactly `H`; any longer answer gives no address column. - The save line uses `LINE 1`, which does not exist; the program starts at line 70 instead. ## Source Code ``` 70 POKE 23658,8 80 PAPER 0: INK 7: BORDER 0: CLS 100 LET O=0: LET X=O: LET T=O: DIM A$(3): DIM A(4): LET M=O: DIM X$(2): GO TO 420 120 REM CONVERSION 140 LET M=M+1 160 LET X=PEEK M 180 LET X$(1)=CHR$ ((48+INT (X/16) AND INT (X/16)<=9)+(55+INT (X/16) AND INT (X/16)>9)): LET X=X-INT (X/16)*16: LET X$(2)=CHR$ ((48+X AND X<=9)+(55+X AND X>9)): RETURN 200 LET N=M 220 LET X=INT (N/256): GO SUB 180: LET M$=X$: LET X=N-256*INT (N/256): GO SUB 180: LET M$=M$+X$: RETURN 240 REM DISPLACEMENT 250 IF IN<>0 AND CL=1 THEN LET M$=Z$: RETURN 260 GO SUB 120: PRINT ;X$;: LET X=PEEK M 270 LET X=(X AND X<128)+(X-256 AND X>127): LET M$=(X$ AND H$="H")+(STR$ X AND H$="D"): RETURN 280 GO SUB 260: LET N=M+1+X+MX 300 IF H$="D" THEN LET M$=STR$ X+" ("+STR$ N+")" 320 IF H$="H" THEN LET Z$=X$: GO SUB 220: LET M$=Z$+" ("+M$+")" 340 LET D$=D$+M$: PRINT TAB 15;D$: GO TO 440 360 REM V CHANGE 370 IF O+1>LEN D$ THEN GO TO 400 380 IF D$(O+1)="." THEN GO SUB 120: PRINT ;X$;: LET M$=X$: GO SUB 120: PRINT ;X$;: LET M$=(X$+M$ AND H$="H")+(STR$ (256*PEEK M+PEEK (M-1)) AND H$="D"): LET D$=D$( TO O-1)+D$(O+1 TO ): RETURN 400 GO SUB 120: PRINT ;X$;: LET M$=(X$ AND H$="H")+(STR$ PEEK M AND H$="D"): RETURN 420 FLASH 1: PRINT AT 8,8;"Z80 DISASSEMBLER": FLASH 0: INPUT " INPUT START ADDRESS#";M: LET M=M-1: INPUT " INPUT END ADDRESS#";MM: PRINT AT 20,9;"DO YOU WANT": INPUT "EXADECIMAL OR ECIMAL ADDRESS OUTPUT ";H$: INPUT "PRINTER OUTPUT (y/n) ";p$: CLS : INPUT AT 10,8;"OFFSET #";MX: LET PC=3 440 LET CL=0: LET IN=0: IF M+1>MM THEN GO SUB 820: GO TO 420 460 IF PEEK 23689=2 THEN GO SUB 820 480 LET M=M+1: LET N=M+MX: IF H$(1)="D" OR H$(1)="d" THEN LET M$=STR$ N: LET O=5-LEN M$: PRINT TAB O;M$;" "; 500 IF H$(1)="H" THEN GO SUB 220: PRINT M$;" "; 520 GO SUB 160 530 PRINT ;X$; 540 LET X=PEEK M: IF CL>0 THEN GO TO 580 550 IF X=203 OR X=237 THEN LET CL=(1 AND X=203)+(2 AND X=237): GO SUB 140: GO TO 530 560 IF X=221 OR X=253 THEN LET IN=(1 AND X=221)+(2 AND X=253): GO SUB 140: GO TO 530 570 IF X=118 THEN PRINT TAB 15;"HALT": GO TO 480 580 IF IN>0 AND CL>0 THEN GO SUB 270: LET Z$=M$: GO SUB 140: PRINT ;X$;: LET X=PEEK M 590 REM BINARY 600 LET D$="00000000": FOR O=1 TO 8: LET X=(X/2): LET D$(O)=STR$ (X+.5-INT X): NEXT O 620 LET A(1)=VAL D$(8)*2+VAL D$(7): LET A(2)=VAL D$(3)*4+VAL D$(2)*2+VAL D$(1): LET A(3)=VAL D$(6)*4+VAL D$(5)*2+VAL D$(4): LET A(4)=VAL D$(6)*2+VAL D$(5): LET A$(1)=STR$ A(3): LET A$(2)=D$(4): LET A$(3)=STR$ A(4) 640 REM SEARCH 660 RESTORE 3000+(100*CL+10*A(1)+A(2)) 670 READ D$: FOR X=1 TO 3: IF D$(X)="-" THEN GO TO 700 680 IF A$(X)<>D$(X) THEN READ D$: GO TO 670 700 NEXT X: READ D$ 720 REM VAR CHANGE 730 IF D$(1 TO 2)="JR" OR D$(1 TO 2)="DJ" THEN GO TO 280 740 FOR O=1 TO 14 750 IF O>LEN D$ THEN GO TO 810 760 LET B$=D$(O): IF B$>="!" AND B$<="'" THEN RESTORE 3300+CODE B$: LET T=(A(3) AND B$<"%")+(A(2) AND B$="%")+(A(4) AND B$>"%"): FOR N=0 TO T: READ M$: NEXT N: LET D$=D$( TO O-1)+M$+D$(O+1 TO ): LET B$=D$(O) 770 IF B$="*" OR B$="-" THEN RESTORE 3300+CODE B$: FOR N=0 TO IN: READ M$: NEXT N: LET D$=D$( TO O-1)+M$+D$(O+1 TO ): LET B$=D$(O) 780 IF B$="." OR B$="/" THEN GO SUB (360 AND B$=".")+(240 AND B$="/"): LET D$=D$( TO O-1)+M$+D$(O+1 TO ) 800 NEXT O 810 PRINT TAB 15;D$: GO TO 440 820 REM OUTPUT 840 IF P$="N" OR P$="n" THEN BEEP .1,20: INPUT "COPY(y/n)?";M$: IF M$="N" OR M$="n" THEN CLS : RETURN 850 COPY : CLS 860 LET PC=PC-1: IF PC=0 THEN LET PC=3: FOR X=1 TO 8: LPRINT : NEXT X 880 RETURN 3000 DATA "0--","NOP","1--","EX AF,AF","2--","DJNZ ","3--","JR ","4--","JR NZ,","5--","JR Z,","6--","JR NC,","7--","JR C," 3001 DATA "-0-","LD &,..","-1-","ADD -,&" 3002 DATA "0--","LD (BC),A","1--","LD A,(BC)","2--","LD (DE),A","3--","LD A,(DE)","4--","LD (..),-","5--","LD -,(..)","6--","LD (..),A","7--","LD A,(..)" 3003 DATA "-0-","INC &","-1-","DEC &" 3004 DATA "---","INC """ 3005 DATA "---","DEC """ 3006 DATA "---","LD "",." 3007 DATA "0--","RLCA","1--","RRCA","2--","RLA","3--","RRA","4--","DAA","5--","CPL","6--","SCF","7--","CCF" 3017 DATA "---","LD "",%" 3027 DATA "---","$%" 3030 DATA "---","RET #" 3031 DATA "-0-","POP '","-10","RET","-11","EXX","-12","JP (-)","-13","LD SP,-" 3032 DATA "---","JP #,.." 3033 DATA "0--","JP ..","2--","OUT (.),A","3--","IN A,(.)","4--","EX (SP),-","5--","EX DE,HL","6--","DI","7--","EI" 3034 DATA "---","CALL #,.." 3035 DATA "-0-","PUSH '","-1-","CALL .." 3036 DATA "---","$." 3037 DATA "0--","RST 00H (0)","1--","RST 08H (8)","2--","RST 10H (16)","3--","RST 18H (24)","4--","RST 20H (32)","5--","RST 28H (40)","6--","RST 30H (48)","7--","RST 38H (56)" 3107 DATA "0--","RLC %","1--","RRC %","2--","RL %","3--","RR %","4--","SLA %","5--","SRA %","7--","SRL %" 3117 DATA "---","BIT !,%" 3127 DATA "---","RES !,%" 3137 DATA "---","SET !,%" 3210 DATA "---","IN "",(C)" 3211 DATA "---","OUT (C),""" 3212 DATA "-0-","SBC HL,&","-1-","ADC HL,&" 3213 DATA "-0-","LD (..),&","-1-","LD &,(..)" 3214 DATA "---","NEG" 3215 DATA "-0-","RETN","-1-","RETI" 3216 DATA "0--","IM 0","2--","IM 1","3--","IM 2" 3217 DATA "0--","LD I,A","1--","LD R,A","2--","LD A,I","3--","LD A,R","4--","RRD","5--","RLD" 3220 DATA "4--","LDI","5--","LDD","6--","LDIR","7--","LDDR" 3221 DATA "4--","CPI","5--","CPD","6--","CPIR","7--","CPDR" 3222 DATA "4--","INI","5--","IND","6--","INIR","7--","INDR" 3223 DATA "4--","OUTI","5--","OUTD","6--","OTIR","7--","OTDR" 3333 DATA "0","1","2","3","4","5","6","7" 3334 DATA "B","C","D","E","H","L","*","A" 3335 DATA "NZ","Z","NC","C","PO","PE","P","M" 3336 DATA "ADD A,","ADC A,","SUB,","SBC A,","AND ","XOR ","OR ","CP " 3337 DATA "B","C","D","E","H","L","*","A" 3338 DATA "BC","DE","-","SP" 3339 DATA "BC","DE","-","AF" 3342 DATA "(HL)","(IX+/)","(IY+/)" 3345 DATA "HL","IX","IY" 4000 SAVE "DISASSY" LINE 1 ```