;
; 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

