         Title      Interpretive Debugger for 6809 Microprocessor
*        IDB for 6809
*        "DBG09MAIN.ASM"
*
*       The Interpretive Debugger for 6809 is a comprehensive debugging
*       package for 6809 assembly code programs. It includes:
*
*       1)  Full symbolic display/entry of machine instructions/operands
*           using symbol values from the SD Assembler.
*       2)  Multiple display modes: ASCII, byte, word, doubleword and
*           floating point.  Single object or block displays are allowed.
*           The byte format can be used to run an IBM-style dump to either
*           screen or arbitrary file.
*       3)  Multiple real-time breakpoints with arbitrary break conditions
*           specified in an algebraic format (i.e., break when PC=129C and
*           X register > 42 or location 62 contains 'Z ).  Breakpoint action
*           can be any sequence of debugger commands (allowing the operator
*           to specify any arbitrary display automatically at the break).
*       4)  Interpretive execution allowing read/write/execute breakpoints,
*           trace in regions, single-step, or free-run until arbitrary
*           condition.  Interpretive execution (and breakpoints) record the
*           last "n" instruction histories (instruction address and effective
*           address) for post-execution/breakpoint inspection.
*       5)  Memory clear, fill and search for arbitrary pattern under mask.
*       6)  SD Link compatible.
*       7)  Access to symbol table, user space and keyboard-input/display via
*           transfer vectors allow IDB to be customized to operate not only
*           on memory, but also on object files or disk files.  Symbol tables
*           can thus be memory or disk resident.  Console I/O may likewise
*           be controlled by CRT or files.
*       8)  Handles all expressions allowed by SD Assembler, including multiple
*           radices.  Relocation bases may be set so that offsets into modules
*           can be used for display purposes.
*       9)  The Debugger is a process independent of the Debuggee
*           so it can logically start the Debuggee, and watch in real time.
*           This also allows debugging of a process in a computer other than
*           the one in which the debugger is running.
*           This means the Debugger has its own context..
*           and therefore its own Z page
*
         page Defaults
         ifund Code
Code     equ  $C000                    For lack of a better place
         fin

         ifund ZPageAddress
ZPageAddress  equ $f000                address of Z page for debugger
         fin

         ifund IDBStackSize
IDBStackSize equ 40                    for lack of a better value
         fin

         ifund NBreakpoints
NBreakpoints   equ   8                 at least 8 breakpoints
         fin   NBreakpoints
         page  Equates
*        Ascii constants
*
ascii:tab equ $09                      tab character
ascii:lf equ   $0a                     line feed
ascii:cr equ   $0d                     carriage return
ascii:blank equ $20                    blank character
ascii:rubout equ $7F                   rubout character

*
*        Breakpoint table entry offsets
*
          org         0
Break:Type           rmb 1             = -1 for ;R, 0 for ;B and +1 for ;W
Break:SavedOpcode    rmb 1             holds saved opcode when user task running
Break:Counter        rmb 2             holds repeat counter for this breakpoint
Break:LowerBound     rmb 2             is lower bound of region for bkpt
Break:UpperBound     rmb 2             is upper bound of region
*        Note: Break:UpperBound<Break:LowerBound marks this slot as free
Break:Size equ       *                 Size of breakpoint table entries
         page  IDB Z Page Storage
         org   ZPageAddress
         setdp ZPageAddress
CellIsOpenFlag       rmb 1             0 --> No location open, <>0 --> open
OpenCellAddress      rmb 2             contains address of last location opened
DisplayMode          rmb 2             points to routine to display data
EFApresent           rmb 1             <>0 --> EffectiveAddress is valid
EffectiveAddress     rmb 2             contains effective address of instruction
EFABuffer            rmb 2             contains data from EffectiveAddress

FillSource           rmb 2             what to fill with
FillLength           rmb 1             size of byte string to fill with

DisplayedCount       rmb 1             number of bytes displayed last

CurrentSymbolTable   rmb 2             Pointer to currently open symbol table
TargetPC             rmb 2             Single-step limit address
ExecuteUnconditionalPC rmb 2           holds address of instruction to s/s
DebugIntControl      rmb 1             contains $F0 if debugger uninterruptable

NewUserCC            rmb 1             holds CC after instruction executed
NewUserPC            rmb 2             holds PC after instruction is executed
NewIndexRegister     rmb 2             holds value of index reg when inst done
ModifiedIndexRegister rmb 2            points to index register to be changed

scratch              rmb 2             a trashable place to store into

TraceHistoryBufferStart rmb 2          points to start of trace history buffer
TraceHistoryBufferEnd rmb 2            points to end of trace history buffer
TraceHistoryPtr      rmb 2             points to next place to record trace

CharRejectedFlag     rmb 1             <>0 --> read last character again
RejectedCharacter    rmb 1             contains char if CharRejectedFlag <> 0
InputStreamPointer   rmb 2             points to next byte in input stream
InputStreamEnd       rmb 2             points to last byte of input stream

TokenBufferCount     rmb 1             number of bytes stored in token buffer
TokenBufferFill      rmb 2             Pointer into token buffer
TokenBuffer          rmb 64            to hold next collected token
TokenBufferEnd       rmb 0             end of token buffer

*******************************************************************************
*        The Instruction assembler constructs the complete instruction...
*        in the InstructionBuffer.
*        The InstructionPrefix byte holds 0, $10 or $11 depending on
*        whether the instruction requires a prefix opcode or not.
*        The InstructionOpcode contains the main opcode of an instruction.
*        The Postbyte(s) buffer contains the remaining part of the instruction.
InstructionAddress rmb 2     Holds address of instruction in this buffer
InstructionLength rmb 1      Holds length of assembled instruction
InstructionPrefix rmb 1      Holds instruction prefix byte (not counted!)
InstructionOpcode rmb 1      Holds main opcode byte of instruction
InstructionAddress equ *     Holds instruction address
InstructionPostByte rmb 3    Holds 1 to 3 bytes of postbyte information
*******************************************************************************
InstructionType rmb 1                  holds IAT: instruction type

SetDP    rmb   1                       value set by SETDPR psudo-op
*
*        Register Names for user context block (stored in Pull order)
*
UserContextBlock     equ *             This is start of user context block
UserRegisterCC       rmb 1             User Condition codes
UserRegisterD        rmb 0             User Register D
UserRegisterA        rmb 1             User Register A
UserRegisterB        rmb 1             User Register B
UserRegisterDP       rmb 1             User Register Direct Page
UserRegisterX        rmb 2             User Register X
UserRegisterY        rmb 2             User Register Y
UserRegisterU        rmb 2             User Register U
UserRegisterPC       rmb 2             User Register PC
UserContextBlockSize equ *-UserContextBlock Size of context block
UserRegisterS        rmb 2             User Register S

*   IgnoreBreakTestCount contains the number of opportunities to test for
*   a breakpoint that must be ignored while single-stepping an instruction.
*   This variable is zeroed whenever
*   a register or memory location is changed, or the breakpoint table is
*   modified.  It is incremented everytime a Proceed from break command is
*   given.  This scheme allows ExecuteInstruction to signal a break;
*   a proceed will allow ExecuteInstruction to ignore the test that
*   caused the break on the next pass thru.  If ExecuteInstruction
*   succeeds in stepping thru an instruction without a break, this value
*   is zeroed.
IgnoreBreakTestCount rmb 1             = # break tests to ignore before break
BreakTestsDuringInstruction rmb 1      = # break tests encountered while
*                                        executing an instruction

ReadBreakSetCount rmb 1                = # of Read breakpoints currently set
WriteBreakSetCount rmb 1               = # of Write breakpoints currently set
ExecBreakSetCount rmb 1                = # of Execute breakpoints currently set
LastBreakPoint rmb 2                   Points to last breakpoint encountered

BreakpointTable ; Holds all breakpoint information
         rmb   Break:Size*NBreakpoints reserve space for breakpoint table slots

         rmb   IDBStackSize            = space reserved for IDB's working stack
IDBStack rmb   0                       = logical location of IDB's working stk
         if    *>/$FF
         ?IDB Scratch page overflow?
         fin
         page

         page Interface Vector
*
         Org  Code
IDB:Runaway   ; Entry point for Runaway programs
         Nop                  Force PC into sync
         Nop                  Worst case is LDY [$7fff,x] = 5 byte instruction
         Nop                  so 4 nops will resynchronize the PC
         Nop
         Jmp  IDBRunaway      Go handle this case
IDB:Init ; Entry point to subroutine to initialize debugger after power-up
; Note: one can merely Init IDB for operation without starting it up
; So it can be available after invoking the operating system
         JMP  IDBInit
IDB:Start     ; Entry point to start debugger after calling IDB:Init
         Jmp  IDBStart
IDB:OpenConsole ; Place pointer here to routine to open user console
         #DefaultOpenConsole
IDB:GetChar   ; Place pointer here to routine to get a character from console
         #DefaultGetChar               Returns character in (A), bit 7 = 0
IDB:EchoChar  ; Place pointer here to routine to echo a character to console
         #DefaultEchoChar              Outputs character in (A).
IDB:PutChar   ; Place pointer here to routine to put a character to console
         #DefaultPutChar               Outputs character in (A), appends LF to CR
????? the following lines are in the wrong place!
???? They should be placed just after IDB:RunAway to make them easy to patch
IDB:ACIAStatus ; Place pointer here to ACIA status register
         #$FCF4       ; Default is Exorciser ACIA address

IDB:ACIAData ; Place pointer here to ACIA data register
         #$FCF5       ; Default is Exorciser ACIA address

???????
IDB:AttentionCheck ; Place pointer here to routine for operator attention check
         #DefaultAttentionCheck        Returns C=0 --> no attention
IDB:CloseConsole ; Place pointer here to routine to close link to console
         #DefaultCloseConsole
IDB:Extension ; Place pointer here to routine that extends IDB
         page
IDB:OpenLoad ; Place pointer here to routine to open Load device
; (X) points to load file name string, (D)=Count
; Note: this routine can actually load the contents, too,
; if GetLoadByte is simply fed an End of File signal when called
; An Open error is signalled if C is set on return, (X) is error code
IDB:GetLoadByte ; Place pointer here to routine to read byte from load device
; An end of file code is signalled when C is set on return
IDB:CloseLoad ; Place pointer here to routine to close Load device
; Close error signalled by C set, (D)= error code
; File MUST be closed even if error is returned

IDB:CreateDump ; Place pointer here to routine to Create Dump file
; (X) points to Dump file name string, (D)=Count
; C set on return --> Create failed, (X) is error code
IDB:DumpByte ; Place pointer here to routine to output ascii byte (A) to Dump file
; C set on return --> Dump failed, (X) is error code
IDB:DumpClose ; Place pointer here to routine to Close Dump device
; Close error signalled by C set, (D)= error code
; File MUST be closed even if error is returned

IDB:CreateSave ; Place pointer here to routine to Create a Save file
; (X) points to Save file name string, (D)=Count
; (Y) = file start address
; C set on return --> Create failed, (X) is error code
IDB:SaveRegion ; Place pointer here to routine to place code in specified
; region in object file
; Region starts at (X) and goes for (D) bytes; (D)>0
; C set on return --> Save failed, (X)=error code
; This routine is normally aimed at IDB:SDOSsave,
; which generates load records for the save file in SDOS load record format
IDB:SaveByte ; Place pointer here to routine to save SDOS object byte
; C set on return --> Save failed, (X) is error code
IDB:CloseSave ; Place pointer here to routine to close Save file
; (y) contains file start address
; Close error signalled by C set, (D)= error code
; File MUST be closed even if error is returned
         page
IDB:Fetchbyte ; Place pointer here to routine to fetch byte @X in user space
; (D) = 16 bit task id
         #DefaultFetchByte
IDB:Storebyte ; Place pointer here to routine to store byte @X in user space
; (D) = 16 bit task id
         #DefaultStoreByte
IDB:Fetchword ; Place pointer here to routine to fetch word @X in user space
; (D) = 16 bit task id
         #DefaultFetchWord
IDB:Storeword ; Place pointer here to routine to store word @X in user space
; (D) = 16 bit task id
         #DefaultStoreWord

IDB:OpenSymbol ; Place pointer here to routine to open symbol table file
; (X) points to symbol table name, (D) is count>0
; Init implicitly assumes that the "default" symbol table is open
IDB:FindSymbol ; Place pointer here to routine to search symbol table
; (X) points to symbol name, (D) is count >0
; C set on return --> failed to find
IDB:SetSymbol ; Place pointer here to routine to modify/add to symbol table
; (X) points to symbol name, (D) is count > 0
; (y) is new symbol value
; C set on return --> failed to update
IDB:CloseSymbol ; Place pointer here to routine to close symbol table file
; Close error signalled by C set, (D)= error code
; File MUST be closed even if error is returned

IDB:StepSWI ; Single-step thru SWI routine, adjust context block accordingly
; This allows the debugger to single-step through OS-dependent calls
; (X) = context block address in user space
; Returned (X) is used as context block address in user space

IDB:SetWriteBkpt ; Set up hardware write breakpoint
; (X) = address of break
; (C) set on return --> cannot
IDB:ClearWriteBkpt ; Clear hardware write breakpoint
; Must never return an error
IDB:SetFetchBkpt ; Set up hardware fetch breakpoint
; (X) = address of break
; (C) set on return --> cannot
IDB:ClearFetchBkpt ; Clear hardware fetch breakpoint
; Must never return an error

IDB:StartUserProcess ; Start user process running
; (D) = user process id
; (X) = new user process sp, assuming a context block on top of stack
; A breakpoint can stop it
; [This code is logically just: TFR X,S\RTI]

IDB:StopUserProcess ; Stop user process from running
; (D) = user process id
; returns (X) = user process sp after process has been stopped
;               with Full context block on top of stack
; [This is logically ...SWI (trap to -->) TFR S,X

IDB:FocusonProcess ; Select process (D) for further operations

IDB:InitialUserSP ; Value for initial user stack pointer
         #????                         value used for user sp on startup

; ??? set of entry points to load/save breakpoint lists, data structure defs?
; debug command to show data structure at a location?
; datastructurename.component gives value of component for easy tracing...
*************
         page         Default IDB interface routines
DefaultOpenConsole ; Opens console for debugger to acia
         ldx   #0                      wait for ACIA not busy
DefaultOpenWait
         dex
         bne   DefaultOpenWait
         ldaa  #$3                     get "reset" code
         staa  [IDB:ACIAStatus]
         ldaa  #$15                    set up RTS, divide by 16
         staa  [IDB:ACIAStatus]
         rts

DefaultGetChar ; Get character from console device
         ldaa  [IDB:ACIAStatus]        see if character has arrived yet
         bita  #1
         beq   DefaultGetChar          b/ no
         ldaa  [IDB:ACIAData]          yes
         anda  #$7F                    mask off parity bit
         rts

DefaultEchoChar ; Echo character recieved by Get to console device
*        bra   DefaultPutChar
DefaultPutChar ; Put character to console device
         ldb   #2                      see if ACIA is ready for more
         bitb  [IDB:ACIAStatus]        ...?
         beq   DefaultPutChar
         sta   [IDB:ACIAData]          yes, give it the output character
         tab                           so we can still compare character
         ldaa  #$0A                    assume <CR>, follow by <LF>
         cmpb  #$D                     carriage return ?
         beq   DefaultPutChar          b/ yes, output <LF>
         rts

DefaultAttentionCheck ; Check for operator wants debugger's attention
         clc                           assume operator doesn't want attention
         ldaa  [IDB:ACIAStatus]        see if character has arrived yet
         bita  #1
         beq   DefaultNoAttention      b/ no
         bsr   DefaultGetChar          yes, go get it!
         cmpa  #$1B                    escape ?
         bne   DefaultNoAttention      b/ nope
         sec                           signal "operator wants attention"
DefaultNoAttention
         rts

DefaultCloseConsole ; Close console for debugger
         Rts

DefaultFetchByte ; get byte @(X) from memory space to (A)
         lda  ,x
         rts

DefaultStoreByte ; store byte (A) to memory space @(X)
         sta  ,x
         rts

DefaultFetchWord ; get word @(X) from memory space to (D)
         ldd  ,x
         rts

DefaultStoreWord ; store word (D) to memory space @(X)
         std  ,x
         rts
         page
ListTextatX ; (X) points to CountByte followed by text string
         ldb   ,x+                     fetch length of string to print
ListBCharactersatX ; List the B characters at (X) onto console
         pshb                          save count
         bsr   ListCharacteratX        list a single character at X
         pulb                          decrement remaining count
         decb                          ...
         bne   ListBCharactersatX      b/ more to list
         rts

ResetBreakTable ; Reset all breakpoint table entries to "unused"
         ldb   #NBreakpoints           = number of slots to initialize
         ldu   #$FFFF                  = new lower bound value
         std   Break:UpperBound,x      make Break:UpperBound<Break:LowerBound
         stu   Break:LowerBound,x      ditto
         decb                          one slot processed
         bne   ResetBreakTable         b/ more to reset
         clr   ReadBreakSetCount       remember that no Read breaks are set
         clr   WriteBreakSetCount      remember that no Write breaks are set
         clr   ExecBreakSetCount       remember that no Execute breaks are set
*** if we remembered that some breakpoint has a range restriction, we
*** could automatically decide if single-step or real-time execution
*** was appropriate when a ;P or ;g command was given
         rts

IDBHelloMessage ; Text printed when IDB wakes up after RESET
         fcb   IDBHelloMessageEnd-*
         fcc   "IDB09 here..."
IDBHelloMessageEnd equ *

CopyRightString ; This string is checksummed to verify it is not damaged
         fcc   "Copyright (C) 1982 Software Dynamics"
CopyRightStringEnd

CopyRightSum equ $FF                   = funny sum of copyright string

IDBInit ; Initialize IDB for operation
         lda   idb:scratchpage,pcr     fetch scratch page address
         tfr   a,c                     make dpr point to base of scratch page
         ldb   #$FF                    set debugger's sp to top of scratch page
         tfr   d,s                     set debugger's sp to top of scratch page
         lbsr  IDB:OpenConsole         set up console for correct operation
         lbsr  IDB:StopUserProcess     waking the debugger stops debugee task
         stx   UserRegisterS           save user Stack pointer
         ldy   #UserContextBlock       get register values from user
         ldd   #UserContextBlockSize   = number of bytes to fetch from context
         lbsr  IDB:FetchMultiple       get user context from user space
         lbsr  ResetBreakTable         Reset all breakpoint table entries         ldx   #Breakpointtable        process all the breakpoint table entries
         ldx   #IDBHelloMessage        Tell user we are alive and well!
         bsr   ListTextatX             go list indefinitely long text
         bsr   ListCRLF                output new line mark
         lbra  lrparser                go run parser on keyboard entries

***** the following code should be someplace obscure, like in "GO" routine
***** or the instruction lister
         ldx   #CopyrightString        make sure Copyright isn't fucked up
         clra                          compute checksum over it
         ldb   #CopyRightStringEnd-CopyRightString
CheckCopyRightLoop
         adda  ,x+                     add a byte to checksum
         lsra
         decb                          down count bytes in checksum string
         bne   CheckCopyRightLoop      b/ more to sum
         cmpa  #CopyRightSum           check that total sum is correct
         beq   CopyRightisOk
         ...do something awful...
**** end of copyright check code
