Skip to content

Instantly share code, notes, and snippets.

@ruyrybeyro
Forked from jblang/disz80.asm
Last active September 29, 2019 20:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ruyrybeyro/e4af49aa29086b3a5b61a0d52c5d0d8f to your computer and use it in GitHub Desktop.
Save ruyrybeyro/e4af49aa29086b3a5b61a0d52c5d0d8f to your computer and use it in GitHub Desktop.
John Kerr's DIS-Z80 with Comments - adapted for the ZX Spectrum
; Adapted for Z80 Spectrum syntax, assembled with pasmo
; Z80 disassembly routine in Z80
ORG 50000
LD A,2 ; upper screen
CALL 5633 ; open channel
LD DE,0 ; first address to disassembly
LD BC,30 ; number of lines
CALL _disz80
; need to return to lower screen
LD A,1 ; lower screen
CALL 5633 ; open channel
CALL $15DE ; WAIT-KEY1
RET
; This code is been found in a ZX Spectrum tool called UTILITY3 v1.3
_disz80:
push ix
dizloop:
push bc
call DISASM
pop bc
ld a,13
call CHROP
dec bc
ld a,b
or c
jr nz,dizloop
ld h,d
ld l,e
pop ix
ret
; ====================
; DIS-Z80 was published in the SUBSET column of Personal Computer World 1987.
; The routine disassembles a single Z80 instruction at address DE.
; It is required to be followed by a routine called CHROP that outputs a
; single ASCII character.
; It was originally developed for CP/M on an Amstrad CPC128.
; The original ORG was $0100. I have added $5000 to all addresses.
; The stated aim was to write a Z80 disassembly routine in as short a space
; as possible and, at just over 1K (1090 bytes), it is a rather incredible
; program.
; The SUBSET editor David Barrow was able to trim only one byte from John
; Kerr's compact code. I've forgotten where so there's a challenge.
; ====================
; STRUCTURAL CONCEPTS
; DATA
;
; Disassembled line:
; field 1: instruction 1st byte location (5 cols).
; field 2: instruction bytes (12 cols).
; field 3: mnemonic (5 cols).
; field 4: operand(s) (13 cols).
;
; Location address : ASCII hex (4 digits).
; Instruction bytes : ASCII hex (2 digits sequence).
; Operand data & : ASCII hex with appended "H" if >9,
; addresses : and preceeding "0" if 1st digit >9.
; Operand offsets : signed decimal, linked "+" or "-".
; PROGRAM DETAILS
;
; INPUT DE addresses 1st byte of instruction to disassemble.
; OUTPUT 35 character disassembled line to uotput device.
; STATE CHANGES DE updated to address 1st byte of next instruction.
; AF BC HL changed.
; I/O ERRORS None.
; OPTIMISATION Not given.
; INTERRUPT EFFECT May be interrupted and re-entered.
; LOCATION NEEDS Not specific. Not relocatable. PROMable.
; (Listing in this datasheet is assembled at 0100H)
; PROGRAM BYTES 695: code 206 + referenced tables:-
; GROUP2 (27), GROUP1 (168), GROUP3 (86),
; MONICS (208).
; STACK BYTES 46 maximum.
; CLOCK CYCLES Not given.
DISASM: CALL ADRSP ; Output the source pointer.
LD BC,$0900 ; Create an 18-byte output
LD HL,$2020 ; buffer in the stack area.
BUFFER: PUSH HL ; Buffer initially contains
DJNZ BUFFER ; 18 ASCII spaces (20H).
LD H,B ; Copy SP into HL, so the
LD L,C ; first byte of the output
ADD HL,SP ; buffer is addressed by HL.
PUSH BC ; Save original IX and
EX (SP),IX ; initialize to zero.
PUSH BC ; Initialize temp storage
PUSH BC ; (workspace) to all zeros.
ADD IX,SP ; Point IX to workspace.
PUSH HL ; Save buffer pointer; point
LD HL,GROUP3 ; to "ED" instruction group.
TRYNDX: CALL FETCH ; Fetch a byte of code.
LD B,C ; First check whether this
CP $ED ; is an "ED" instruction.
JR Z,CONFLG ; Yes; clear the index flag.
INC B ; Ready to set flag to "1"
CP $DD ; if the byte is 0DDH (an
JR Z,CONFLG ; instruction using IX).
INC B ; Ready to set flag to "2"
CP $FD ; if the byte is 0FDH (an
JR NZ,NOTNDX ; instruction using IY).
CONFLG: LD (IX+1),B ; Condition the index flag.
INC B ; Repeat index tests if the
DJNZ TRYNDX ; pre-byte was 0DDH or 0FDH.
JR NXBYTE ; Otherwise continue.
NOTNDX: LD C,A ; Save byte; check if index
LD A,(IX+1) ; flag was set (Allows any
OR A ; series of 0DDH and/or OFDH
JR Z,NODISP ; bytes, as per Zilog spec).
LD A,C ; If so, check for presence
CP $CB ; of any displacement.
JR Z,GETDIS ; 0CBH needs a displacement.
AND $44 ; A displacement is required
CP 4 ; if opcode has bit 2 set
JR Z,GETDIS ; and bit 6 reset.
LD A,C ; A displacemnet is required
AND $C0 ; if opcode has bit 6 set
CP $40 ; and bit 7 reset.
JR NZ,NODISP
GETDIS: CALL FETCH ; Get displacement if needed
LD (IX+2),A ; and save it in workspace.
NODISP: LD HL,GROUP1 ; "Main" instruction gorup.
LD A,C ; Recover opcode & check
CP $CB ; for OCBH ("bit" group).
JR NZ,NEWMSK ; No; start the search.
LD HL,GROUP2 ; Yes; point to "CB" group.
NXBYTE: CALL FETCH ; Fetch the last non-data
LD C,A ; byte and store it in C.
NEWMSK: LD A,(HL) ; Fetch a mask from table.
OR A ; Mask value of 0 indicates
JR Z,TABEND ; end of table; quit search.
AND C ; Otherwise mask the opcode
INC HL ; and address the mode byte.
NEWMOD: LD B,(HL) ; Fetch the mode byte in B.
INC HL ; Point to the match byte.
INC B ; Test if the mode is 0FFH
JR Z,NEWMSK ; and if so, get a new mak.
TRYMAT: CP (HL) ; Is the masked opcode
INC HL ; equal to the match byte?
JR Z,GETNDX ; Stop searching if it is.
BIT 7,(HL) ; index byte bit 7 is set if
INC HL ; address mode changes.
JR Z,TRYMAT ; No change; try next match.
JR NEWMOD ; Change; get a new mode.
GETNDX: LD A,(HL) ; Matched: fetch mnemonic
AND $7F ; index, mask bit 7, and
DEC B ; restore the mode byte.
TABEND: POP HL ; Save the source pointer
PUSH DE ; below the output buffer
PUSH HL ; pointer on stack.
EX DE,HL ; Point HL to start of the
LD HL,MONICS ; mnemonics table.
CALL XTRACT ; Copy mnemonic to buffer.
POP HL ; Restore output pointer
LD DE,5 ; and adjust to align
ADD HL,DE ; any operands present.
POP DE ; Restore source pointer.
LD A,B ; Test high-order B to see
AND $F0 ; if any "first" operand
JR Z,SECOND ; is present.
RRA ; Yes; move the operand
RRA ; index into the lower
RRA ; half of A.
RRA ; Then save
PUSH BC ; operand and opcode.
LD B,A ; Operand index in B.
LD A,C ; Restore opcode to A.
CALL OPRND1 ; Process the operand.
POP BC ; Restore the operand byte
LD A,B ; and opcode; test
AND $0F ; low-order B for any
JR Z,OPDONE ; "second" operand.
LD (HL),44 ; Opearnd index in B.
INC HL ; Restore opcode to A.
SECOND: LD A,B ; Check for the presence
AND $0F ; of a "second" operand.
LD B,A ; Operand index in B.
LD A,C ; Restore opcode to A.
CALL NZ,OPRND2 ; Process any operand.
OPDONE: LD A,3 ; Check how many bytes
SUB (IX+0) ; have been fetched.
POP HL ; Discard workspace.
POP HL
POP IX ; Restore index register.
JR C,OUTEXT ; 4 or more bytes fetched.
INC A ; Less than four bytes
LD B,A ; fetched; so output
ADD A,B ; enough spaces to
ADD A,B ; align the mnemonics.
LD B,A
SPACES: LD A,$20 ; Output spaces
CALL CHROP ; to start of
DJNZ SPACES ; mnemonic field.
OUTEXT: LD B,18 ; Set buffer byte count.
PUTOUT: DEC SP ; Copy stored text, byte
POP HL ; at a time, from output
LD A,H ; buffer on stack to
CALL CHROP ; the output channel.
DJNZ PUTOUT
RET ; Instruction disassembled.
;***********************
GROUP2: defb $C0,$36,$40
defb $04,$80,$2D,$C0,$BE
defb $FF,$F8,$06,$00,$33
defb $08,$38,$10,$35,$18
defb $3A,$20,$3F,$28,$40
defb $30,$00,$38,$C1
GROUP1: defb $FF,$00,$00
defb $24,$07,$32,$0F,$37
defb $17,$31,$1F,$36,$27
defb $0D,$2F,$0B,$37,$3D
defb $3F,$06,$76,$14,$C9
defb $30,$D9,$12,$F3,$0F
defb $FB,$91,$72,$C6,$02
defb $CE,$01,$DE,$BC,$02
defb $D6,$42,$E6,$03,$EE
defb $43,$F6,$25,$FE,$8C
defb $04,$08,$93,$01,$10
defb $10,$18,$9D,$AF,$22
defb $A2,$FA,$2A,$A2,$A7
defb $32,$A2,$7A,$3A,$A2
defb $03,$C3,$1C,$CD,$85
defb $97,$D3,$AA,$79,$DB
defb $9B,$5F,$E3,$93,$0E
defb $E9,$9C,$05,$EB,$93
defb $DF,$F9,$A2,$FF,$C0
defb $B6,$40,$A2,$FF,$F8
defb $76,$80,$02,$88,$01
defb $98,$BC,$06,$90,$42
defb $A0,$03,$A8,$43,$B0
defb $25,$B8,$8C,$FF,$C7
defb $0B,$04,$16,$05,$8E
defb $B2,$06,$A2,$20,$C0
defb $B0,$23,$C2,$1C,$C4
defb $85,$10,$C7,$BB,$FF
defb $CF,$D3,$01,$A2,$0D
defb $03,$16,$0B,$8E,$FD
defb $09,$82,$60,$C1,$2B
defb $C5,$AC,$FF,$E7,$21
defb $20,$9D,$FF,$EF,$E7
defb $02,$A2,$7E,$0A,$A2
GROUP3: defb $FF,$00,$44
defb $23,$45,$2F,$4D,$2E
defb $4E,$00,$67,$39,$6F
defb $34,$70,$00,$71,$00
defb $A0,$21,$A1,$0A,$A2
defb $1A,$A3,$29,$A8,$1F
defb $A9,$08,$AA,$18,$AB
defb $28,$B0,$20,$B1,$09
defb $B2,$19,$B3,$27,$B8
defb $1E,$B9,$07,$BA,$17
defb $BB,$A6,$FF,$C7,$B8
defb $40,$9B,$8B,$41,$AA
defb $FF,$CF,$FD,$42,$3C
defb $4A,$81,$AD,$43,$A2
defb $DA,$4B,$A2,$FF,$E7
defb $40,$46,$95,$FF,$F7
defb $C7,$47,$A2,$7C,$57
defb $A2,$FF,$00
;_______________
MONICS: defb $BF
defb 'A','D','C'+$80 ; ADC
defb 'A','D','D'+$80 ; ADD
defb 'A','N','D'+$80 ; AND
defb 'B','I','T'+$80 ; BIT
defb 'C','A','L','L'+$80 ; CALL
defb 'C','C','F'+$80 ; CCF
defb 'C','P','D','R'+$80 ; CPDR
defb 'C','P','D'+$80 ; CPD
defb 'C','P','I','R'+$80 ; CPIR
defb 'C','P','I'+$80 ; CPI
defb 'C','P','L'+$80 ; CPL
defb 'C','P'+$80 ; CP
defb 'D','A','A'+$80 ; DAA
defb 'D','E','C'+$80 ; DEC
defb 'D','I'+$80 ; DI
defb 'D','J','N','Z'+$80 ; DJNZ
defb 'E','I'+$80 ; EI
defb 'E','X','X'+$80 ; EXX
defb 'E','X'+$80 ; EX
defb 'H','A','L','T'+$80 ; HALT
defb 'I','M'+$80 ; IM
defb 'I','N','C'+$80 ; INC
defb 'I','N','D','R'+$80 ; INDR
defb 'I','N','D'+$80 ; IND
defb 'I','N','I','R'+$80 ; INIR
defb 'I','N','I'+$80 ; INI
defb 'I','N'+$80 ; IN
defb 'J','P'+$80 ; JP
defb 'J','R'+$80 ; JR
defb 'L','D','D','R'+$80 ; LDDR
defb 'L','D','D'+$80 ; LDD
defb 'L','D','I','R'+$80 ; LDIR
defb 'L','D','I'+$80 ; LDI
defb 'L','D'+$80 ; LD
defb 'N','E','G'+$80 ; NEG
defb 'N','O','P'+$80 ; NOP
defb 'O','R'+$80 ; OR
defb 'O','T','D','R'+$80 ; OTDR
defb 'O','T','I','R'+$80 ; OTIR
defb 'O','U','T','D'+$80 ; OUTD
defb 'O','U','T','I'+$80 ; OUTI
defb 'O','U','T'+$80 ; OUT
defb 'P','O','P'+$80 ; POP
defb 'P','U','S','H'+$80 ; PUSH
defb 'R','E','S'+$80 ; RES
defb 'R','E','T','I'+$80 ; RETI
defb 'R','E','T','N'+$80 ; RETN
defb 'R','E','T'+$80 ; RET
defb 'R','L','A'+$80 ; RLA
defb 'R','L','C','A'+$80 ; RLCA
defb 'R','L','C'+$80 ; RLC
defb 'R','L','D'+$80 ; RLD
defb 'R','L'+$80 ; RL
defb 'R','R','A'+$80 ; RRA
defb 'R','R','C','A'+$80 ; RA
defb 'R','R','C'+$80 ; RRC
defb 'R','R','D'+$80 ; RRD
defb 'R','R'+$80 ; RR
defb 'R','S','T'+$80 ; RST
defb 'S','B','C'+$80 ; SBC
defb 'S','C','F'+$80 ; SCF
defb 'S','E','T'+$80 ; SET
defb 'S','L','A'+$80 ; SLA
defb 'S','R','A'+$80 ; SRA
defb 'S','R','L'+$80 ; SRL
defb 'S','U','B'+$80 ; SUB
defb 'X','O','R'+$80 ; XOR
; OPRNDZ Operand Disassembler. To disassembler and output a valid
; Z80 machine code operand.
; OPRND1 Entry point for certain modes (see DATA)
; OPRND2 Entry point for certain modes (see DATA)
; STRUCTURAL CONCEPTS
; DATA
;
; Operand: Standard Z80 assembler format.
; The operand mode is determined by an input
; index (1 - 15) and by point of entry:-
;
; Index OPRND1 OPRND2
; ------------------------------------------------------
; 1 RST address Relative address
; 2 Condition Immediate byte
; 3 Bit number Immediate word
; 4 Interrupt mode AF,AF'
; 5 (SP) DE,HL
; 6 Register pair 8-bit source
; ------------------------------------------------------
; 7 A
; 8 (C)
; 9 (port number)
; A (Absolute address)
; B 8-bit destination
; C I or R
; D 16-bit register
; E Address in 16-bit register
; F Index register
;
; PROGRAM DETAILS
; INPUT
; A = opcode.
; B = operand index.
; DE addresses next instruction byte.
; HL addresses next free byte in output buffer.
; (IX+0) = no. of instruction bytes fetched.
; (IX+1) = index register flag (1=IX, 2=IY, else 0).
; (IX+2) = displacement for any indexed instruction.
;
; OUTPUT Operand is in output buffer.
; DE and HL are updated.
; STATE CHANGES AF BC are changed.
; IX IY (IX+0,1,2) are unchanged.
;*****************
OPRND1: DJNZ CONDIT ; First entry point; is mode
RSTADR: AND $38 ; a restart address? If so,
JR DA ; isolate opcode bits 5-3.
OPRND2: DJNZ DAT8 ; 2nd entry point; is mode
RELADR: CALL FETCH ; PC relative? If so, fetch
LD C,A ; displacement & extend
RLA ; sign; put full 16-bit
SBC A,A ; signed displacemnet into
LD B,A ; BC.
EX DE,HL ; Move source pointer to HL,
PUSH HL ; save it on stack, compute
ADD HL,BC ; destination address & send
JR DHL ; to the output buffer.
CONDIT: RRA ; Opcode bits 2-0 are not
RRA ; needed for any of the
RRA ; following modes (OPRND1).
DJNZ BITNUM ; Is operand a condition?
BIT 4,A ; If so, check whether the
JR NZ,ABS ; address mode is relative
AND 3 ; or absolute. If relative,
ABS: AND 7 ; adjust condition index.
ADD A,$14 ; Index condition in table.
JR PS1 ; Copy it to the output buffer.
DAT8: DJNZ DAT16 ; Is operand immediate byte?
D8: CALL FETCH ; Fetch a byte.
JR DA ; Send to output buffer.
BITNUM: DJNZ INTMOD ; Is operand a bit number?
AND 7 ; Yes; isolate the index.
DA: LD C,A ; Move 8-bit data for output
SUB A ; from A into AC (so A=0)
JR DAC ; and send to output buffer.
DAT16: DJNZ EXAF ; Is operand an address?
D16: CALL FETCH ; Fetch low-order byte.
LD C,A ; Save it in C.
CALL FETCH ; Fetch high order byte.
DAC: EX DE,HL ; Exchange source & output
PUSH HL ; pointers. Save the source
LD H,A ; pointer & copy output data
LD L,C ; from AC into HL.
DHL: LD C,$F8 ; Specify hex conversion.
PUSH HL ; Save output for checking.
CALL CONVHL ; Perform ASCII conversion.
POP HL ; retrieve output value.
LD BC,$000A ; Check whether the value
OR A ; output was greater than 9.
SBC HL,BC ; Result of test in Cy.
POP HL ; Restore source & output
EX DE,HL ; pointers to their originall
RET C ; registers. Exit if output
LD (HL),'H' ; value was 9 or less; else
INC HL ; put "H" (denoting hex)
RET ; after the output & exit.
INTMOD: DJNZ STKTOP ; Is operand interrupt mode?
AND 3 ; Index the list of
ADD A,$1C ; interrupt modes (0,1,2)
PS1: JR PS3 ; Copy to output buffer.
STKTOP: LD C,$13 ; The constant operand (SP)
DEC B ; is entry number 19 in the
JR Z,PS2 ; RGSTRS table.
REG16P: DJNZ COMMON2 ; Is the operand register pair?
RRA ; Isolate the two bits of the
AND 3 ; opcode which determine the
CP 3 ; pair. Is it AF?
JR NZ,RX ; No; go to double register.
DEC A ; Yes, adjust pointer.
JR RNX ; Copy out register name.
EXAF: LD C,$0A ; The constant operand
DEC B ; AF,AF' is entry number 10
JR Z,PS2 ; in the RGSTRS table.
EXDE: INC C ; The constant operand DE,HL
DEC B ; is entry number 11 in the
JR Z,PS2 ; RGSTRS table.
REG8S: DJNZ ACCUM ; Is operand 8-bit source?
R8: AND 7 ; Get register number.
CP 6 ; Is it a memory location?
JR NZ,PS3 ; No; so it's B/C/D/E/H/L/A.
LD (HL),'(' ; Yes; put the left parenthesis
INC HL ; into the output buffer.
CALL REGX ; Copy register HL/IX/IY.
LD A,(IX+2) ; Retrieve offset; check if
OR A ; it is zero. If so, don't
JR Z,RP ; bother to print it.
LD (HL),43 ; Otherwise, put a "+" sign
RLCA ; into the output buffer, but
RRCA ; now test the offset sign.
JR NC,POS ; If negative, change the
LD (HL),45 ; sign to "-" and negate
NEG ; the offset.
POS: INC HL ; Update the output pointer.
EX DE,HL ; Exchange pointers, saving
PUSH HL ; source pointer on stack.
LD H,B ; Put the absolute value
LD L,A ; of the offset into HL.
LD C,$FB ; Specify decimal and
CALL CONVHL ; perform ASCII convesion.
POP HL ; Restore pointers to their
EX DE,HL ; original registers.
JR RP ; Go put right parenthesis.
ACCUM: RRA ; Opcode bits 2-0 can now
RRA ; be discarded by OPRND2.
RRA
COMMON2:
LD C,7 ; OPRND1 and OPRND2 merge.
DEC B ; Accumulator addressing;
JR Z,PS2 ; put "A" to output buffer.
PORTC: DEC C ; Constant operand "(C)" is
DJNZ IDAT8 ; entry number 6 in RGSTRS.
PS2: LD A,C ; Copy string number into A.
PS3: JR PS4 ; Go copy out the string.
IDAT8: DJNZ IDAT16 ; Is operand a constant port
LD (HL),'(' ; number? If so, that's just
INC HL ; like an immediate byte but
CALL D8 ; inside brackets.
JR RP ; Close the brackets.
IDAT16: DJNZ REG8 ; Is operand an address for
LD (HL),'(' ; data? That's just like a
INC HL ; CALL or JP address but
CALL D16 ; inside brackets.
JR RP ; Close the brackets.
REG8: DEC B ; Use 8-bit source routine
JR Z,R8 ; for an 8-bit destination.
IPAREF: DJNZ REG16 ; Is operand I or R?
AND 9 ; Yes, then copy the correct
JR PS4 ; string from RGSTRS.
REG16: RRA ; Is operand a
DJNZ IREG16 ; 16-bit register?
R16: AND 3 ; Check for index register.
RX: CP 2 ; If it's an index register,
JR Z,REGX ; go use separate routine.
RNX: ADD A,$0C ; Not an index register;
JR PS4 ; point ot BC/DE/AF/SP.
IREG16: DJNZ REGX ; Is the operand an address
LD (HL),'(' ; contained in a register?
INC HL ; Then just put brackets
CALL R16 ; round the result from R16.
RP: LD (HL),')' ; Put right parenthesis in
INC HL ; output buffer, update
RET ; pointer, then exit.
REGX: LD A,(IX+1) ; Use the index flag to
ADD A,$10 ; select an index register.
PS4: EX DE,HL ; Copy a string from RGSTRS.
PUSH HL ; Exchange pointers; save
LD HL,RGSTRS ; source pointer; point HL
CALL XTRACT ; to start of table and
POP HL ; copy out the string. Then
EX DE,HL ; restore pointers to their
RET ; original registers, exit.
;*************
RGSTRS: defb 'B' +$80
defb 'C' +$80
defb 'D' +$80
defb 'E' +$80
defb 'H' +$80
defb 'L' +$80
defb '(','C',')' +$80
defb 'A' +$80
defb 'I' +$80
defb 'R' +$80
defb 'A','F',',','A','F','\' +$80
defb 'D','E',',','H','L' +$80
defb 'B','C' +$80
defb 'D','E' +$80
defb 'A','F' +$80
defb 'S','P' +$80
defb 'H','L' +$80
defb 'I','X' +$80
defb 'I','Y' +$80
defb '(','S','P',')' +$80
defb 'N','Z' +$80
defb 'Z' +$80
defb 'N','C' +$80
defb 'C' +$80
defb 'P','O' +$80
defb 'P','E' +$80
defb 'P' +$80
defb 'M' +$80
defb '0' +$80
defb '?' +$80
defb '1' +$80
defb '2' +$80
;********************
CONVHL: SUB A
CVHL1: PUSH AF
SUB A
LD B,16
CVHL2: ADD A,C
JR C,CVHL3
SUB C
CVHL3: ADC HL,HL
RLA
DJNZ CVHL2
JR NZ,CVHL1
CP 10
INC B
JR NC,CVHL1
CVHL4: CP 10
SBC A,$69
DAA
LD (DE),A
INC DE
POP AF
JR NZ,CVHL4
RET
;****************
XTRACT: OR A
JR Z,COPY
SKIP: BIT 7,(HL)
INC HL
JR Z,SKIP
DEC A
JR NZ,SKIP
COPY: LD A,(HL)
RLCA
SRL A
LD (DE),A
INC DE
INC HL
JR NC,COPY
RET
;*******************
FETCH: LD A,(DE)
INC DE
INC (IX+0)
PUSH AF
CALL BYTSP
POP AF
RET
ADRSP: LD A,D
CALL BYTOP
LD A,E
BYTSP: CALL BYTOP
LD A,$20
JR CHROP
BYTOP: PUSH AF
RRA
RRA
RRA
RRA
CALL HEXOP
POP AF
HEXOP: AND $0F
CP 10
SBC A,$69
DAA
; -----------------------------------
;
; End of John Kerr's DIS-Z80 routine.
;
; The next routine outputs a character.
;
; -------------------------------------
CHROP: PUSH HL
PUSH DE
PUSH BC
push AF ; parameter passing
RST 16
pop AF
POP BC
POP DE
POP HL
RET
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment