;
; Ullrich von Bassewitz, 08.08.1998
;
; Support routines for the debugger
;

        .export         _DbgInit
        .export         _DbgSP, _DbgCS, _DbgHI
        .import         popptr1, return0, _DbgEntry, _set_brk, _end_brk
        .import         _DbgBreaks
        .import         _brk_pc
        .import         __ZP_START__            ; Linker generated

        .include        "zeropage.inc"


; C callable function, will install the debugger

_DbgInit:
        lda     #<DbgBreak
        ldx     #>DbgBreak
        jmp     _set_brk


; Entry for the break vector.

DbgBreak:
        pla
        sta     retsav
        pla
        sta     retsav+1

        cli
        tsx                     ; Stack pointer
        stx     _DbgSP

        jsr     DbgSwapZP       ; Swap stuff
        lda     #<DbgStack      ; Set new stack
        sta     sp
        lda     #>DbgStack
        sta     sp+1
        jsr     ResetDbgBreaks  ; Reset temporary breakpoints
        jsr     _DbgEntry       ; Call C code
        jsr     SetDbgBreaks    ; Set temporary breakpoints
        jsr     DbgSwapZP       ; Swap stuff back

        lda     retsav+1
        pha
        lda     retsav
        pha
        rts



; Stack used when in debugger mode

.bss
        .res    256
DbgStack:

; Swap space for the the C temporaries

CTemp:
_DbgCS: .res    2               ; sp
_DbgHI: .res    2               ; sreg
        .res    (zpsavespace-4) ; Other stuff

_DbgSP: .res    1
retsav: .res    2               ; Save buffer for return address

.code

; Swap the C temporaries

DbgSwapZP:
        ldy     #zpsavespace-1
Swap1:  ldx     CTemp,y
        lda     <__ZP_START__,y
        sta     CTemp,y
        txa
        sta     sp,y
        dey
        bpl     Swap1
        rts

; ----------------------------------------------------------------------------
; Utility functions


; Set/reset the breakpoints. We must do that here since the breakpoints
; may be in the runtime stuff, causing the C part to fail before it has
; reset the breakpoints. See declaration of struct breakpoint in the C
; source

MaxBreaks       = 48            ; 4*12

ResetDbgBreaks:
        ldy     #0
        ldx     #0
L4:     lda     _DbgBreaks+3,x  ; Get bk_use
        beq     L6              ; Jump if not set
        bpl     L5              ; Jump if user breakpoint
        lda     #0
        sta     _DbgBreaks+3,x  ; Clear if temp breakpoint
L5:     lda     _DbgBreaks+1,x  ; PC hi
        sta     ptr1+1
        lda     _DbgBreaks,x    ; PC lo
        sta     ptr1
        lda     _DbgBreaks+2,x  ; Old OPC
        sta     (ptr1),y        ; Reset the breakpoint
L6:     inx
        inx
        inx
        inx
        cpx     #MaxBreaks      ; Done?
        bne     L4
        rts

SetDbgBreaks:
        ldx     #0
        ldy     #0
L7:     lda     _DbgBreaks+3,x  ; Get bk_use
        beq     L8              ; Jump if not set
        lda     _DbgBreaks+1,x  ; PC hi
        sta     ptr1+1
        lda     _DbgBreaks,x    ; PC lo
        sta     ptr1
        lda     (ptr1),y        ; Get the breakpoint OPC...
        sta     _DbgBreaks+2,x  ; ...and save it
        lda     #$00            ; Load BRK opcode
        sta     (ptr1),y
L8:     inx
        inx
        inx
        inx
        cpx     #MaxBreaks      ; Done?
        bne     L7
        rts

; Get a free breakpoint slot or return 0

        .export         _DbgGetBreakSlot

_DbgGetBreakSlot:
        ldx     #0
L10:    lda     _DbgBreaks+3,x  ; Get bk_use
        beq     L11             ; Jump if not set
        inx
        inx
        inx
        inx
        cpx     #MaxBreaks      ; Done?
        bne     L10
        jmp     return0         ; No free slot

L11:    stx     tmp1
        lda     #<_DbgBreaks
        ldx     #>_DbgBreaks
        clc
        adc     tmp1
        bcc     L12
        inx
L12:    ldy     #1              ; Force != 0
        rts


; Check if a given address has a user breakpoint set, if found, return the
; slot, otherwise return 0.

        .export         _DbgIsBreak

_DbgIsBreak:
        jsr     popptr1         ; Get address
        ldx     #0
L20:    lda     _DbgBreaks+3,x  ; Get bk_use
        beq     L21             ; Jump if not set
        bmi     L21             ; Jump if temp breakpoint
        lda     _DbgBreaks,x    ; Low byte of address
        cmp     ptr1
        bne     L21
        lda     _DbgBreaks+1,x  ; High byte of address
        cmp     ptr1+1
        beq     L22
L21:    inx
        inx
        inx
        inx
        cpx     #MaxBreaks      ; Done?
        bne     L20
        jmp     return0         ; Not found

L22:    stx     tmp1
        lda     #<_DbgBreaks
        ldx     #>_DbgBreaks
        clc
        adc     tmp1
        bcc     L23
        inx
L23:    ldy     #1              ; Force != 0
        rts



