cc65/libsrc/dbg/dbgdasm.s

297 lines
7.7 KiB
ArmAsm

;
; Ullrich von Bassewitz, 07.08.1998
;
; unsigned DbgDisAsm (char* buf, unsigned addr);
; unsigned DbgDisAsm (unsigned addr);
;
;
; Part of this code is taken from the Plus/4 machine language monitor
; (TEDMon).
;
.import popax
.import __hextab, OffsetTab, AdrFlagTab
.import SymbolTab1, SymbolTab2, MnemoTab1, MnemoTab2
; -------------------------------------------------------------------------
; Equates for better readability
.importzp sreg, tmp1, tmp2, tmp3, tmp4, ptr1, ptr2, ptr3
BufIndex = tmp1 ; Index into output buffer
OperandLen = tmp2 ; Length of operand
BufLen = tmp3 ; Length of output buffer
AdrFlagBuf = tmp4 ; Flag for addressing mode
YSave = sreg ; Temp storage
XSave = sreg+1 ; Dito
BufPtr = ptr1 ; Pointer to output buffer
MemPtr = ptr2 ; Pointer to memory to disassemble
MnemoBuf = ptr3 ; Buffer for decoding mnemonic
; -------------------------------------------------------------------------
; Main entries
.export _DbgDisAsm, _DbgDisAsmLen
.proc _DbgDisAsm
sta BufLen ; Save the buffer length
jsr popax ; Get the buffer pointer
sta BufPtr
stx BufPtr+1
jsr popax ; Get the address
sta MemPtr
stx MemPtr+1
lda #0
sta BufIndex ; Initialize index into buffer
jsr DisAssLine ; Disassemble one line into the buffer
lda BufLen ; Get requested length
sec
sbc BufIndex
beq L2
tax ; Count into X
ldy BufIndex
lda #$20 ; Get a space
L1: sta (BufPtr),y
iny
dex
bne L1
L2: lda #0 ; Add C string terminator
sta (BufPtr),y
beq disassret
.endproc
_DbgDisAsmLen:
sta MemPtr ; Save address
stx MemPtr+1
ldy #$00
lda (MemPtr),y ; Get the opcode from memory...
jsr AnalyzeOPCode ; ...and analyze it
disassret:
ldx OperandLen ; Get length of operand
inx ; Adjust for opcode byte
txa
ldx #$00 ; Clear high byte
rts
; -------------------------------------------------------------------------
; Helper functions
Put3Spaces:
jsr PutSpace
Put2Spaces:
jsr PutSpace
PutSpace:
lda #$20
PutChar:
sty YSave ; Save Y
ldy BufIndex ; Get current line pointer
cpy BufLen ; Be sure not to overflow the buffer
bcs PC9
sta (BufPtr),y ; store character
iny ; bump index
sty BufIndex
PC9: ldy YSave ; get old value
rts
; Print the 16 bit hex value in X/Y
PutHex16:
txa
jsr PutHex8
tya
; Print 8 bit value in A, save X and Y
PutHex8:
stx XSave
sty YSave
ldy BufIndex
pha
lsr a
lsr a
lsr a
lsr a
tax
lda __hextab,x
sta (BufPtr),y
iny
pla
and #$0F
tax
lda __hextab,x
sta (BufPtr),y
iny
sty BufIndex
ldy YSave
ldx XSave
rts
; -------------------------------------------------------------------------
; Disassemble one line
DisAssLine:
ldy MemPtr
ldx MemPtr+1
jsr PutHex16 ; Print the address
jsr Put2Spaces ; Add some space
ldy #$00
lda (MemPtr),y ; Get the opcode from memory...
jsr AnalyzeOPCode ; ...and analyze it
pha ; Save mnemonic
ldx OperandLen ; Number of bytes
; Print the bytes that make up the instruction
inx
L2083: dex
bpl L208C ; Print the instruction bytes
jsr Put3Spaces ; If none left, print spaces instead
jmp L2094
L208C: lda (MemPtr),y ; Get a byte from memory
jsr PutHex8 ; ...and print it
jsr PutSpace ; Add some space
L2094: iny ; Next one...
cpy #$03 ; Maximum is three
bcc L2083 ;
jsr Put2Spaces ; Add some space after bytes
; Print the assembler mnemonic
pla ; Get mnemonic code
ldx #$03
jsr PutMnemo ; Print the mnemonic
ldx #$06
; Print the operand
L20A4: cpx #$03
bne L20BA
ldy OperandLen
beq L20BA
L20AC: lda AdrFlagBuf
cmp #$E8 ; Branch?
lda (MemPtr),y ; Get branch offset
bcs GetBranchAdr ; If branch: Calculate address
jsr PutHex8 ; Otherwise print 8bit value
dey
bne L20AC
L20BA: asl AdrFlagBuf
bcc L20CC
lda SymbolTab1-1,x
jsr PutChar
lda SymbolTab2-1,x
beq L20CC
jsr PutChar
L20CC: dex
bne L20A4
rts
; If the instruction is a branch, calculate the absolute address of the
; branch target and print it.
GetBranchAdr:
jsr L20DD
clc
adc #$01
bne L20D9
inx ; Bump high byte
L20D9: tay
jmp PutHex16 ; Output address
L20DD: ldx MemPtr+1
tay
bpl L20E3
dex
L20E3: adc MemPtr
bcc L20E8
inx ; Bump high byte
L20E8: rts
; -------------------------------------------------------------------------
; Subroutine to analyze an opcode byte in A. Will return a byte that
; encodes the mnemonic, and will set the number of bytes needed for this
; instruction in OperandLen
AnalyzeOPCode:
tay
lsr a
bcc L20F8
lsr a
bcs L2107
cmp #$22
beq L2107
and #$07
ora #$80
L20F8: lsr a
tax
lda OffsetTab,x
bcs L2103
lsr a
lsr a
lsr a
lsr a
L2103: and #$0F
bne L210B
L2107: ldy #$80
lda #$00
L210B: tax
lda AdrFlagTab,x
sta AdrFlagBuf
and #$03
sta OperandLen
tya
and #$8F
tax
tya
ldy #$03
cpx #$8A
beq L212B
L2120: lsr a
bcc L212B
lsr a
L2124: lsr a
ora #$20
dey
bne L2124
iny
L212B: dey
bne L2120
rts
; -------------------------------------------------------------------------
; Print the mnemonic with code in A (that code was returned by
; AnalyzeOpcode).
PutMnemo:
tay
lda MnemoTab1,y
sta MnemoBuf
lda MnemoTab2,y
sta MnemoBuf+1
L213A: lda #$00
ldy #$05 ; 3*5 bits in two bytes
L213E: asl MnemoBuf+1
rol MnemoBuf
rol a
dey
bne L213E
adc #$3F
jsr PutChar
dex
bne L213A
jmp PutSpace