FetchMultiple ; Fetch block of bytes from user space to debugger space
*        (X) contains source address in user space
*        (Y) contains target address in Debugger space
*        (D) contains count of number of bytes to fetch from user space
*        ??? what to do if can't fetch???
         jsr         ???
         rts
*
FetchBlockof16 ; Fetch block of 16 bytes at (D) for IBM style dump
*        Fetches 16 bytes at a time to minimize accesses over a network
         andb        #%11110000        force to multiple of 16 boundary
         tdx                           move to source address arg register
         ldy         #TokenBuffer      where to read results
         ldd         #16               = number of bytes to transfer
         bsr         FetchMultiple     go get the bytes!
         rts
         page
FetchInstruction ; Fetch instuction specified by (X)
*        Fetches 5 bytes to minimize accesses over a network
*        Note: this may cause unusual interactions if I/O device registers
*        exist less than 5 locations from where single-stepping occurs!
*        Caveat Emptor.
*        The instruction is read in the Instruction Assembly area,
*        with the Opcode byte in InstructionOpcode, etc.
*        If the instruction is prefixed (i.e., by $10 or $11),
*        then it is automatically correctly positioned once fetched.
*        If not, it is "shifted right" one place, so that the true
*        opcode byte actually does end up in InstructionOpcode.
*        Un-prefixed instructions end up with InstructionPrefix being zero.
         ldy         #InstructionPrefix = where to put response
         ldd         #5                = number of bytes to fetch
         jsr         FetchMultiple     fetch the 5 data bytes
         lda         InstructionPrefix is this a prefixed instruction ?
         anda        #%11111110        (ignore LSB when check for $10 or $11)
         cmpa        #$10              ...?
         beq         FetchInstructionDone b/ yes, leave it alone
         ldd         InstructionAddress no, shift instruction right 1 byte
         std         InstructionAddress+1
         ldd         InstructionPrefix
         std         InstructionPrefix+1
         clr         InstructionPrefix set prefix byte to "zero"
FetchInstructionDone
         ldd         InstructionPrefix grab instruction prefix and opcode
         rts
         page        Instruction Execution routines
FetchEFAbyte ; fetch byte from EFA of instruction
*        Check against ;R breakpoints in table, break if match
         ldx         EffectiveAddress  = beginning of region
         ldb         #1                = number of bytes instruction will read
         bsr         SearchforRefBkpt  go look for read-reference breakpoint
         ldy         #EFABuffer        = where to read the value
         bsr         FetchMultiple     go fetch the data
         ldb         EFABuffer         get result
         rts

FetchEFAword ; fetch word from EFA of instruction
*        Check against ;R breakpoints in table, break if match
         ldx         EffectiveAddress  = beginning of region
         ldb         #2                = number of bytes instruction will read
         bsr         SearchforRefBkpt  go look for read-reference breakpoint
         ldy         #EFABuffer        = where to read the value
         bsr         FetchMultiple     go fetch the data
         ldd         EFABuffer         get result
         rts

StoreEFAByte ; Store byte (A) to EFA of instruction
*        Check against ;W breakpoint in table, break if match
         sta         EFABuffer         save byte to store
         ldx         EffectiveAddress  = beginning of region
         ldb         #2                = number of bytes instruction will write
         bsr         SearchforWrtBkpt  go look for write-reference breakpoint
         ldx         #EFABuffer        where to write from in debugger space
         ldy         EffectiveAddress  where to write to in user space
         ldd         #1                = number of bytes to write
         bra         StoreMultiple     copy to user space

StoreEFAWord ; Store word (D) to EFA of instruction
*        Check agains ;W breakpoint in table, break if match
         std         EFABuffer         save word to store
         ldx         EffectiveAddress  = beginning of region
         ldb         #2                = number of bytes instruction will write
         bsr         SearchforWrtBkpt  go look for write-reference breakpoint
         ldx         #EFABuffer        where to write from in debugger space
         ldy         EffectiveAddress  where to write to in user space
         ldd         #2                = number of bytes to write
         bra         StoreMultiple     copy to user space

CheckPCforBreak ; Check User PC for ;R or ;B breakpoint in table, break if match
         ldx         UserRegisterPC    = beginning of region
         ldb         InstructionLength = number of bytes instruction will read
         bsr         SearchforRefBkpt  go look for read-reference breakpoint
         ldx         UserRegisterPC    = beginning of region
         ldb         InstructionLength = number of bytes instruction will read
         bsr         SearchforExecBkpt see if execution breakpoint is set
         rts                           no breakpoints set on instruction!
         page

SearchforRefBkpt ; Search for ;R breakpoint covering (X) for (B) bytes
         tst         ReadBreakSetCount any read breakpoints set?
         beq         SearchforRefBkptNone b/ no, don't search breakpoint table
         ldy         UserRegisterPC    get user pc
         cmpy        ExecuteUnconditionalPC do this one unconditionally?
         beq         SearchforRefBkptNone b/ yes, don't search breakpoint table
         tfr         x,u               compute pointer to end of region
         leau        b,u               = x+b
         ldy         #BreakTable       = 1st breakpoint to check
         lda         #NumberBreakTableEntries
SearchforRefloop ; examine next break table entry
         tst         Break:type,x      a ;R breakpoint ?
         bpl         SearchforRefNext  b/ no
         cmpx        Break:LowerBound,y does breakpoint cover region ?
         blo         SearchforRefNext  b/ no
         cmpu        Break:UpperBound,y ...?
         blo         BREAKPOINT        b/ yes, cause breakpoint display!
SearchforRefNext ; advance to next break table entry
         leay        Break:Size,y
         decb                          down count remaining slots to inspect
         bne         SearchforRefloop  b/ more to search for
SearchforRefBkptNone ; didn't find match for EFA in ;R breakpoints
         ldy         #EFABuffer        where to put results
         clra                          now (D) = number of bytes to fetch
         rts

SearchforWrtBkpt ; Search for ;W breakpoint covering (X) for (B) bytes
         tst         WriteBreakSetCount any write breakpoints set?
         beq         SearchforWrtBkptNone b/ no, don't search breakpoint table
         ldy         UserRegisterPC    get user pc
         cmpy        ExecuteUnconditionalPC do this one unconditionally?
         beq         SearchforWrtBkptNone b/ yes, don't search breakpoint table
         tfr         x,u               compute pointer to end of region
         leau        b,u               = x+b
         ldy         #BreakTable       = 1st breakpoint to check
         lda         #NumberBreakTableEntries
SearchforWrtloop ; examine next break table entry
         tst         Break:type,x      a ;W breakpoint ?
         ble         SearchforWrtNext  b/ no
         cmpx        Break:LowerBound,y does breakpoint cover region ?
         blo         SearchforWrtNext  b/ no
         cmpu        Break:UpperBound,y ...?
         blo         BREAKPOINT        b/ yes, cause breakpoint display!
SearchforWrtNext ; advance to next break table entry
         leay        Break:Size,y
         decb                          down count remaining slots to inspect
         bne         SearchforWrtloop  b/ more to search for
SearchforWrtBkptNone ; didn't find match for EFA in ;W breakpoints
         ldx         #EFABuffer        where to get data to store
         clra                          now (D) = number of bytes to fetch
         rts

SearchforXecBkpt ; Search for ;B breakpoint covering (X) for (B) bytes
         tst         ExecBreakSetCount any execution breakpoints set?
         beq         SearchforRefBkptNone b/ no, don't search breakpoint table
         ldy         UserRegisterPC    get user pc
         cmpy        ExecuteUnconditionalPC do this one unconditionally?
         beq         SearchforXecBkptNone b/ yes, don't search breakpoint table
         tfr         x,u               compute pointer to end of region
         leau        b,u               = x+b
         ldy         #BreakTable       = 1st breakpoint to check
         lda         #NumberBreakTableEntries
SearchforWrtloop ; examine next break table entry
         tst         Break:type,x      a ;B breakpoint ?
         bne         SearchforXecNext  b/ no
         cmpx        Break:LowerBound,y does breakpoint cover region ?
         blo         SearchforWrtNext  b/ no
         cmpu        Break:UpperBound,y ...?
         blo         BREAKPOINT        b/ yes, cause breakpoint display!
SearchforXecNext ; advance to next break table entry
         leay        Break:Size,y
         decb                          down count remaining slots to inspect
         bne         SearchforXecloop  b/ more to search for
SearchforXecBkptNone ; didn't find match for EFA in ;R breakpoints
         rts
         page
LoadUserCC ; Loads User CC into debugger's CC
         pshb                          in case (B) is busy...
         ldb         UserRegisterCC    get user status bits
         orb         DebugIntControl   set debugger interrupt control
         tfr         b,ccr
         pulb                          restore (B) to original value
         rts

StoreUserCC ; Stores debugger's CC bits into User CC
         pshd                          in case it is busy
         tfr         ccr,b             grab CC bits
         lda         UserRegisterCC    get old user CC bits
         anda        #%11010000        extract interrupt control bits
         andb        #%00101111        retain only arithmetic flags
         aba                           combine to form new user CC bits
         sta         NewUserCC         store as new user CC (if no ;W bkpt)
         puld                          restore (D)
         rts

         page
*
*        Executes the instruction specified by the PC in the context block
*
ExecuteInstruction ; Execute a single instruction
         ldx         UserRegisterPC    Get program counter
         jsr         FetchInstruction  Fetch the instruction (all 5 bytes!)
         jsr         LegalInstructionQ Is instruction legal ? (computes EFA)
*note: LegalInstructionQ should compute the effective address, and the length of the operand
*also, it should compute a pointer to an index register to be modified,
*and the value to place in that index register when the instruction is
*complete. This includes ALL instructions, even PSH, etc.
         beq         ExecuteInstructionCant b/ no, just exit
         bsr         CheckPCforBreak   are we sposd to stop executing here?
         ldd         UserRegisterPC    advance PC past instruction
         addb        InstructionLength (set up by LegalInstructionQ)
         adca        #0
         std         NewUserPC         default user PC if no branch occurs
         lda         UserRegisterCC    set up default condition code result
         sta         NewUserCC
         bsr         Execute1          No, so do the instruction step
***** we got back, update trace history and UserPc, User CC!!!
         ldd         UserRegisterPC    record old user PC in trace history
         ldx         TraceHistoryPtr   = next place to store trace history
         std         ,x++              update trace history pointer
         cmpx        TraceHistoryBufferEnd at end of buffer ?
         blo         ExecuteInstruction1 b/ no
         ldx         TraceHistoryBufferStart yes, move pointer back to front
ExecuteInstruction1
         stx         TraceHistoryPtr   save updated trace history pointer
         ldd         NewUserPC         Instruction successfully executed...
         std         UserRegisterPC    Update user context block
         ldb         NewUserCC         Update user CC bits
         stb         UserRegisterCC
         ldx         UpdatedIndexRegister finish up auto-inc/auto-dec modes
         stx         [ModifiedIndexRegister]
         rts

Execute1 ; Subroutine to execute one instruction after it has been fetched
         lda         InstructionOpcode decide what instruction we have
         ldb         InstructionPrefix is this a Prefixed instruction ?
         bne         ExecutePrefixed   b/ yes, go handle
         tsta                          no, inspect opcode...
         bmi         ExecuteOpcode$1xxxxxxx b/ msb set, must be arithmetic op
         bita        #%01000000        monadic opcode (any address mode)?
         bne         ExecuteMonadicFormat b/ yes, go handle
         bita        #%00100000        relative branch or stack management?
         bne         ExecuteRBorSM     b/ yep
         bita        #%00010000        miscellaneous opcode?
         bne         ExecuteMiscellaneous b/ yep
         bra         ExecuteMonadicMemory is monadic to memory opcode

ExecuteMonadicformat ; monadic format opcode
         bita        #%00100000        Monadic reference to memory ?
         bne         ExecuteMonadicMemory b/ is monadic to memory instruction
         ldy         #ExecuteMonadicTable Monadic to register, we'll need this
         ldx         #UserRegisterA    assume monadic to (A) register
         bita        #%00010000        Monadic reference to A register ?
         beq         ExecuteMonadictoAccumulator b/ yes, just do it!
         inx                           is monadic on (B); make (X) point to (B)
ExecuteMonadictoAccumulator ; Execute Monadic operator on Accumulator
         anda        #%00001111        mask to get opcode
         asla                          convert to 2 byte displacement
         ldy         a,y               fetch address of execution routine
         lda         ,x                fetch contents of desired accumulator
         bsr         LoadUserCC        get condition code bits
         jsr         0,y               invoke execution routine
         bsr         StoreUserCC       update user condition code bits
         sta         ,x                save result in proper Accumulator
         rts

ExecuteJMP ; Execute JMP opcode
         ldx         EffectiveAddress  boy, this one is easy!
         stx         NewUserPC
         rts

ExecuteMonadicMemory ; Execute Monadic operator to memory, EFA pre-computed
         anda        #%00001111        mask to get monadic opcode
         cmpa        #$0E              JMP ?
         beq         ExecuteJMP        b/ yes, go handle
         asla                          convert to word displacement in table
         ldy         #ExecuteMonadicTable
         ldy         a,y               fetch address of execution routine
         ldx         Effectiveaddress
         jsr         fetchEFAbyte      get byte to perform monadic function on
         bsr         LoadUserCC        set up condition code bits
         jsr         0,y               Execute the instruction
ExecuteMonadicStoreResult ; (A) has result of Monadic operator
         bsr         StoreUserCC       save new value of User CC bits
         bsr         storeEFAbyte      and check for ;W breakpoints
         rts
         page
ExecuteMonadicTable ; Table of monadic instruction kernal executer routines
* Each monadic instruction has 2 bytes in this table, an opcode and a RTS
* 16 consecutive entries in the table make indexed branch to kernal easy
* Note: the following routines are part of a table, and may NOT be moved!
         nega                          Execute NEG(x0): (C) = CC bits
         rts
         bra         *                 dummy filler
         bra         *                 dummy filler
         coma                          Execute COM(x3): (C) = CC bits
         rts
         lsra                          Execute LSR(x4): (C) = CC bits
         rts
         bra         *                 dummy filler
         rora                          Execute ROR(x6): (C) = CC bits
         rts
         asra                          Execute ASR(x7): (C) = CC bits
         rts
         asla                          Execute ASL(x8): (C) = CC bits
         rts
         rola                          Execute ROL(x9): (C) = CC bits
         rts
         deca                          Execute DEC(xA): (C) = CC bits
         rts
         bra         *                 dummy filler
         inca                          Execute INC(xC): (C) = CC bits
         rts
         tsta                          Execute TST(xD): (C) = CC bits
         bra         *                 dummy filler
         rts
         clra                          Execute CLR(xF): (C) = CC bits
         rts
         page
ExecuteMiscellaneous ; Execute opcode of form %0001xxxx
         leax        ExecuteMiscTable-$12,pcr   the $12 is 'cuz NOP is $12 op
         ldb         a,x               = displacement to routine to jump to
         leax        ExecuteNOP,pcr
         jmp         a,x               go to the desired routine

ExecuteMiscTable ; pointers to routines to execute Miscellaneous opcodes
         ExecuteNOP-ExecuteNOP        $12 NOP
         ExecuteSYNC-ExecuteNOP       $13 SYNC
         -1                           $14 Illegal Instruction
         -1                           $15 Illegal Instruction
         ExecuteLBRA-ExecuteNOP       $16 LBRA
         ExecuteLBSR-ExecuteNOP       $17 LBSR
         -1                           $18 Illegal Instruction
         ExecuteDAA-ExecuteNOP        $19 DAA
         ExecuteORCC-ExecuteNOP       $1A ORCC
         -1                           $1B Illegal Instruction
         ExecuteANDCC-ExecuteNOP      $1C ANDC
         ExecuteSEX-ExecuteNOP        $1D SEX
         ExecuteTFR-ExecuteNOP        $1E TFR
         ExecuteEXG-ExecuteNOP        $1F EXG

ExecuteNOP ; Execute NOP opcode
         rts                           pc already advanced past instruction

ExecuteSYNC ; Execute SYNC opcode
         rts                           do NOP instead of real-time simulation

ExecuteLBSR ; Execute LBSR opcode
         ldd         NewUserPC         fetch return address
         bsr         StoreEFAWord      store in stack at proper place
         ldx         EffectiveAddress  now adjust (S) properly
         stx         UserRegisterS
ExecuteLBRA ; Execute LBRA opcode
         ldd         NewUserPC         = PC following the instruction
         addd        InstructionAddress add offset
         std         NewUserPC         = final value of PC
         rts
         page
ExecuteDAA ; Execute DAA opcode
         lda         UserRegisterA     get user's A register
         bsr         LoadUserCC        and Condition code bits
         daa                           do what the user wanted done
         bsr         StoreUserCC       update CC bits
         sta         UserRegisterA     and user register
         rts

ExecuteORCC ; Execute ORCC opcode
         lda         UserRegisterCC    do what instruction specifies
         ora         InstructionAddress = immediate bits
         sta         NewUserCC
         rts

ExecuteANDCC ; Execute ANDCC opcode
         lda         UserRegisterCC    do what instruction specifies
         anda        InstructionAddress = immediate bits
         sta         NewUserCC
         rts

ExecuteSEX ; Execute SEX opcode
         ldb         UserRegisterB     get register to sign extend
         bsr         LoadUserCC        get condition code bits
         sex                           do what the instruction specifies
         bra         ExecuteArithtoADone go save results
         page
ExecuteEXG ; Execute EXG opcode
         lda         InstructionPostByte Fetch Source register spec
         bsr         ExecuteDecodeTFREXGSource get source address
         tfr         x,y               save source address
         lda         InstructionPostByte Fetch Destination register spec
         bsr         ExecuteDecodeTFREXGDestination
         bita        #8                single byte EXG?
         bne         ExecuteEXGbyte    b/ yes
         ldu         0,y               fetch source
         ldd         0,x               and destination values
         stu         0,x               exchange the values
         std         0,y
         rts

ExecuteEXGbyte ; Exchange 8 bit registers
         lda         0,y               fetch source
         ldb         0,x               and destination values
         sta         0,x               exchange the values
         stb         0,y
         rts

ExecuteTFR ; Execute TFR opcode
         lda         InstructionPostByte Fetch Source register spec
         bsr         ExecuteDecodeTFREXGSource get source address
         tfr         x,y               save source address
         lda         InstructionPostByte Fetch Destination register spec
         bsr         ExecuteDecodeTFREXGDestination
         bita        #8                single byte EXG?
         bne         ExecuteTFRbyte    b/ yes
         ldd         0,y               fetch source
         std         0,x               and transfer to destination
         rts

ExecuteTFRbyte ; Transfer an 8 bit register
         lda         0,y               fetch source
         sta         0,x               and transfer to destination
         rts
         page
ExecuteDecodeTFREXGSource ; generate pointer to context block copy of register
         lsra                          get source bits
         lsra
         lsra
         lsra
ExecuteDecodeTFREXGDestination ; (A) contains lower 4 bits of TFR/EXG postbyte
         anda        #%00001111        mask off upper bits
         asla                          convert to word index
         ldx         #TFREXGpostbytetranslate
         ldx         a,x               get pointer to value
         rts

TFREXGpostbytetranslate ; converts TFREXG postbyte nibble to context blk ptr
         fdb         UserRegisterD     0
         fdb         UserRegisterX     1
         fdb         UserRegisterY     2
         fdb         UserRegisterU     3
         fdb         UserRegisterS     4
         fdb         NewUserPC         5
         fdb         0                 6 (illegal)
         fdb         0                 7 (illegal)
         fdb         UserRegisterA     8
         fdb         UserRegisterB     9
         fdb         UserRegisterCC    A
         fdb         UserRegisterDP    B
         fdb         0                 C (illegal)
         fdb         0                 D (illegal)
         fdb         0                 E (illegal)
         fdb         0                 F (illegal)
         page        Relative branch execution
ExecuteShortBranch ; Execute Short Branch instruction
         ldx         NewUserPC         compute successful branch address
         ldb         InstructionAddress grab offset
         leax        b,x
ExecuteConditionalBranch
         ldb         InstructionOpcode
         andb        #%00001111        mask to get opcode
         ldy         #ExecuteBranchTable
         lda         #3                = size of table entries
         mul
         bsr         LoadUserCC        get user CC bits
         jmp         [b,y]             invoke execution routine

ExecuteLongBranch ; Execute Long Branch instruction
         ldx         NewUserPC         compute successful branch address
         ldd         InstructionAddress grab offset
         leax        d,x
         bra         ExecuteConditionalBranch

ExecuteSuccessfulBranch ; Branch condition met
         stx         NewUserPC
         rts
         page
ExecuteBranchTable ; Table containing branch instructions to execute
         bra         ExecuteSuccessfulBranch   $20
         rts
         brn         ExecuteSuccessfulBranch   $21
         rts
         bhi         ExecuteSuccessfulBranch   $22
         rts
         bls         ExecuteSuccessfulBranch   $23
         rts
         bcc         ExecuteSuccessfulBranch   $24
         rts
         bcs         ExecuteSuccessfulBranch   $25
         rts
         bne         ExecuteSuccessfulBranch   $26
         rts
         beq         ExecuteSuccessfulBranch   $27
         rts
         bvc         ExecuteSuccessfulBranch   $28
         rts
         bvs         ExecuteSuccessfulBranch   $29
         rts
         bpl         ExecuteSuccessfulBranch   $2A
         rts
         bmi         ExecuteSuccessfulBranch   $2B
         rts
         bge         ExecuteSuccessfulBranch   $2C
         rts
         blt         ExecuteSuccessfulBranch   $2D
         rts
         bgt         ExecuteSuccessfulBranch   $2E
         rts
         ble         ExecuteSuccessfulBranch   $2F
         rts
         page        Stack management execution
ExecuteRBorSM ; Relative branch or stack management opcode
         bita        #%00010000     Relative branch opcode ?
         beq         ExecuteShortBranch b/ yes, go handle it
ExecuteStackManagement ; appears to be stack management opcode
         asla                          make word index for branch table
         ldx         #ExecuteStackBranchTable
         jmp         [-$30*2,x]        branch to proper routine
ExecuteStackBranchTable ; Branch table used to get to Stack Mgmt op executers
         #ExecuteLEAX                  $30
         #ExecuteLEAY                  $31
         #ExecuteLEAS                  $32
         #ExecuteLEAU                  $33
         #ExecutePSHS                  $34
         #ExecutePULS                  $35
         #ExecutePSHU                  $36
         #ExecutePULU                  $37
         #DebuggerFault                $38
         #ExecuteRTS                   $39
         #ExecuteABX                   $3A
         #ExecuteRTI                   $3B
         #ExecuteCWAI                  $3C
         #ExecuteMUL                   $3D
         #DebuggerFault                $3E
         #ExecuteSWI                   $3F
         page
ExecuteLEAX ; Execute LEAX instruction
         ldd         EffectiveAddress  set up to copy effective address to X
         ldx         #0                so LEAX gets proper result
         bsr         LoadUserCC        copy user CC bits into CC register
         leax        d,x               execute the instruction
         bsr         StoreUserCC       update user CC bits
         stx         UserRegisterX     as per instruction specification
         rts

ExecuteLEAY ; Execute LEAY instruction
         ldd         EffectiveAddress  set up to copy effective address to Y
         ldy         #0                so LEAY gets proper result
         bsr         LoadUserCC        copy user CC bits into CC register
         leay        d,y               execute the instruction
         bsr         StoreUserCC       update user CC bits
         stx         UserRegisterY     as per instruction specification
         rts

ExecuteLEAU ; Execute LEAU instruction
         ldd         EffectiveAddress  set up to copy effective address to U
         std         UserRegisterU     as per instruction specification
         rts

ExecuteLEAS ; Execute LEAS instruction
         ldd         EffectiveAddress  set up to copy effective address to S
         std         UserRegisterS     as per instruction specification
         rts
         page        PSHS/U Execution
ExecutePSHS ; Execute PSHS instruction
         ldx         UserRegisterS     Initial value of stack pointer
         bsr         ExecutePSHcommon  do work common to PSHS/PSHU*** code from PUSH to here is incorrect!
         ldx         UserRegisterS     Initial value of stack pointer
         bsr         ExecutePSHPC      do common work of pushing PC
         bsr         ExecutePush2Bytes push S if necessary
         bsr         ExecutePSHcommon  do rest of work common to PSHS/PSHU
         stx         UserRegisterS     now update the stack pointer
         rts

*** should EFA be recorded in trace history?? yes???
*** how abourt registers???

ExecutePSHU ; Execute PSHU instruction
         ldx         UserRegisterU     Initial value of stack pointer
         bsr         ExecutePSHPC      do common work of pushing PC
         ldy         #UserRegisterS+2  set up to push S if required
         bsr         ExecutePush2Bytes push S if necessary
         ldy         #UserRegisterY+2  set up to finish PUSH operation
         bsr         ExecutePSHcommon  do rest of work common to PSHS/PSHU
         stx         UserRegisterU     now update the stack pointer
         rts

ExecutePSHPC ; Push PC onto user stack if required
*        (X) contains stack pointer
         ldb         InstructionPostbyte fetch Push/pull post byte
         ldy         #NewUserPC+2      set up pointer push PC next
ExecutePush2bytes ; (X) contains stack location last used
*        (B) contains Push/Pull byte with bit specifying next register in MSB
*        (Y) points to next register to push if MSB(B) is set
         rolb                          need to push this register ?
         bcc         ExecutePush2bytesdone b/ no
         pshs        b,y               save everything!
         leax        -2,x              find new location to store data
         stx         EffectiveAddress
         ldd         ,--y              fetch value to push
         bsr         StoreEFAWord      and go store on the stack
         puls        b,y               restore the registers
         ldx         EffectiveAddress
ExecutePush2bytesDone
         leay        -2,y              set up to push next register
         rts

ExecutePSHcommon ; do work common to PSHS/PSHU
         bsr         ExecutePush2bytes push Y if necessary
         bsr         ExecutePush2bytes push X if necessary
         bsr         ExecutePush1byte  push DPR if necessary
         bsr         ExecutePush1byte  push B if necessary
         bsr         ExecutePush1byte  push A if necessary
*        bsr         ExecutePush1byte  push CC if necessary
*        rts
ExecutePush1byte ; (X) contains stack location last used
*        (B) contains Push/Pull byte with bit specifying next register in MSB
*        (Y) points to next register to push if MSB(B) is set
         lda         ,-y               fetch value to push
         rolb                          need to push this register ?
         bcc         ExecutePush1bytedone b/ no
         dex                           find new location to store data
         pshs        b,y               save everything!
         stx         EffectiveAddress
         bsr         StoreEFAByte      and go store on the stack
         puls        b,y               restore the registers
         ldx         EffectiveAddress
ExecutePush1byteDone
         rts
         page        PULS/U Execution
ExecuteRTI ; Execute RTI instruction
         ldb         #$81              = post byte for PULS of PC and CCR
         stb         InstructionPostByte assume doing RTI from FIRQ
         lda         UserRegisterCC    see if entire state is store on stack
         bpl         ExecutePULS       b/ nope, just get PC and CCR from stack
         ldb         #$FF              yes, get entire context from stack
         stb         InstructionPostByte
*        bra         ExecutePULS
ExecutePULS ; Execute PULS instruction
         ldx         UserRegisterS     Initial value of stack pointer
         bsr         ExecutePullCommon do work common to PULS/U
         bsr         ExecutePull2Bytes pull U if necessary
         bsr         ExecutePULPC      Pull PC if required
         stx         UserRegisterS     now update the stack pointer
         rts

ExecutePULU ; Execute PULU instruction
         ldx         UserRegisterU     Initial value of stack pointer
         bsr         ExecutePullCommon do work common to PULS/U
         ldy         #UserRegisterS    set up to pull S if required
         bsr         ExecutePull2Bytes pull S if necessary
         bsr         ExecutePULPC      Pull PC if required
         stx         UserRegisterU     now update the stack pointer
         rts

ExecutePULPC ; Pull PC using stack point in (X) if required
         ldy         #NewUserPC        where to place pulled value
ExecutePull2bytes ; (X) contains next stack location to be "pull"ed from
*        (B) contains Push/Pull byte with bit specifying next register in MSB
*        (Y) points to next register to fill from stack if MSB(B) is set
         rolb                          need to "pull" this register ?
         bcc         ExecutePull2bytesdone b/ no
         pshs        b,y               save everything!
         stx         EffectiveAddress
         bsr         FetchEFAWord      get data from stack area
         puls        b,y               restore the registers
         std         ,y                fill register with value pulled from stk
         ldx         EffectiveAddress
         leax        2,x               advance stack pointer past pulled data
ExecutePull2bytesDone
         leay        2,y               advance pointer to next register to fill
         rts

ExecutePullCommon ; do work common to PULS/PULU
         ldb         InstructionPostbyte fetch Push/pull post byte
         ldy         #UserRegisterCC   set up pointer to registers to pull
         bsr         ExecutePull1byte  pull CC if necessary
         bsr         ExecutePull1byte  pull A if necessary
         bsr         ExecutePull1byte  pull B if necessary
         bsr         ExecutePull1byte  pull DPR if necessary
         bsr         ExecutePull2bytes pull X if necessary
         bsr         ExecutePull2bytes pull Y if necessary
         rts

ExecutePull1byte ; (X) contains stack location to pull from next
*        (B) contains Push/Pull byte with bit specifying next register in MSB
*        (Y) points to next register to fill from stack if MSB(B) is set
         rorb                          need to push this register ?
         bcc         ExecutePull1bytedone b/ no
         pshs        b,y               save everything!
         stx         EffectiveAddress
         bsr         FetchEFAByte      and go fetch byte from stack area
         puls        b,y               restore the registers
         ldx         EffectiveAddress
         inx                           advance stack pointer past pulled byte
         sta         ,y                fill register with pulled value
ExecutePull1byteDone
         leay        1,y               advance Y to next register to fill
         rts
         page        Execution of other Miscellaneous opcodes
ExecuteRTS ; Execute RTS instruction
         jsr         FetchEFAWord      get a word from user space
         std         NewUserPC         = new program counter for user
         ldx         EffectiveAddress  adjust stack pointer properly
         leax        2,x
         stx         UserRegisterS
         rts

ExecuteABX ; Execute ABX opcode
         ldb         UserRegisterB     fetch B register
         ldx         UserRegisterX     and X register
         bsr         LoadUserCC        copy user CC bits in CC register
         abx                           do what the opcode specifies
         bsr         StoreUserCC       save user CC bits
         stx         UserRegisterX     update user's X register
         rts

ExecuteCWAI ; Execute CWAI instruction
         lda         UserRegisterCC    do what instruction specifies
         anda        InstructionAddress = immediate bits
         sta         NewUserCC         can't simulate Wait for Int, so do NOP
         rts

ExecuteMUL ; Execute MUL opcode
         bsr         LoadUserCC        get user CC bits
         ldd         UserRegisterD     fetch user registers
         mul                           do instruction
         bra         ExecuteArithtoDDone and go store the results
         page        Arithmetic Group Instruction Execution
ExecuteOpcode$1xxxxxxx ; Execute instruction whose MSB is set
         cmpa        #$C0              Appear to be B register reference ?
         bhs         ExecuteOpcode$C0  b/ yes, go handle
         anda        #%11001111        mask off addressing mode bits
         cmpa        #$83              SUBD ?
         beq         ExecuteSUBD       b/ yes
         cmpa        #$87              STA ?
         beq         ExecuteSTA        b/ yes, go handle
         ldx         #UserRegisterA    assume arithmetic to this register
         cmpa        #$8C              CMPX/JSR/LDX/STX ?
         blo         ExecuteByteArith  b/ no
         asla                          double to make word index
         ldx         #Execute$9CBranchTable branch on opcode
         jmp         [-$8C*2,x]
Execute$9CBranchTable ; Table used to decode opcodes $9C,$9D,$9E,$9F
         #ExecuteCMPX                  $9C
         #ExecuteJSR                   $9D
         #ExecuteLDX                   $9E
         #ExecuteSTX                   $9F

ExecuteOpcode$C0 ; Execute opcode with value $C0 or greater
         anda        #%11001111        mask off addressing mode bits
         cmpa        #$C3              ADDD ?
         beq         ExecuteADDD       b/ yes
         cmpa        #$C7              STB ?
         beq         ExecuteSTB        b/ yes, go handle
         ldx         #UserRegisterB    assume arithmetic to this register
         cmpa        #$CC              LDD/STD/LDU/STU ?
         blo         ExecuteByteArith  b/ no
         asla                          double to make word index
         ldx         #Execute$DCBranchTable branch on opcode
         jmp         [-$CC*2,x]
Execute$DCBranchTable ; Table used to decode opcodes $DC,$DD,$DE,$DF
         #ExecuteLDD                   $DC
         #ExecuteSTD                   $DD
         #ExecuteLDU                   $DE
         #ExecuteSTU                   $DF
         page
ExecuteByteArith ; perform arithmetic on 8 bit register selected by (X)
         bsr         ExecuteByteArith1 this places return address under operand
         bsr         StoreUserCC       update CC bits
         sta         ,x                update the register
         rts                           all done! isn't this ingenious?

ExecuteByteArith1 ; set up to do Arithmetic opcode
         pshs        x,a               save pointer to desired reg, opcode
         jsr         fetchEFAbyte      get byte from user space
*        Note: Effective address points at immediate operand if immediate mode
         puls        x,b               restore opcode, pointer to register
         psha                          leave operand on top of stack
         andb        #%00001111        mask to obtain canonical opcode number
         lda         #3                = size of slots in ...ArithTable
         mul                           compute displacement to desired opcode
         ldy         #ExecuteByteArithTable
         leay        a,y               = pointer to routine to execute
         pshs        y                 put address of routine on TOS for RTS
         lda         ,x                fetch register value
         tab                           some routines need it in both registers
         bsr         LoadUserCC        get CC bits before doing instruction
         rts                           invoke routine to execute arithmetic op
         page
ExecuteByteArithTable ; Contains routines to execute byte arith instructions
*        When control is passed to one of these routines,
*        both (A) and (B) contain copies of the register being manipulated,
*        the byte on top of S contains the operand (contents of EFA),
*        (X) points to the slot in the context block for the register,
*        and a return address is stored underneath the operand on top of S.
         suba        ,s+               $90/$D0: Execute SUBA/SUBB instruction
         rts
         cmpb        ,s+               $91/$D1: Execute CMPA/CMPB instruction
         rts                           don't change A, but do set the CC bits!
         sbca        ,s+               $92/$D2: Execute SBCA/SBCB instruction
         rts
         jmp         debuggerfault     $93/$D3: SUBD/ADDD, can't get here!
         anda        ,s+               $94/$D4: Execute ANDA/ANDB instruction
         rts
         bitb        ,s+               $95/$D5: Execute BITA/BITB instruction
         rts                           don't change A, but do set the CC bits!
         lda         ,s+               $96/$D6: Execute LDA/LDB instruction
         rts
         jmp         debuggerfault     $97/$D7: STA/STB, can't get here!
         eora        ,s+               $98/$D8: Execute EORA/EORB instruction
         rts
         adca        ,s+               $99/$D9: Execute ADCA/ADCB instruction
         rts
         ora         ,s+               $9A/$DA: Execute ORA/ORB instruction
         rts
         adda        ,s+               $9B/$DC: Execute ADDA/ADDB instruction
         rts
         page
ExecuteSTA ; Execute STA instruction
         lda         UserRegisterA     = register to store
ExecuteSTAorB ; common code to store 8 bit register
         bsr         LoadUserCC        fetch user CC bits
         sta         scratch           set proper CC bits
         bsr         StoreUserCC       save updated CC bits
         bsr         StoreEFAByte      move to user space
         rts

ExecuteSTB ; Execute STB instruction
         lda         UserRegisterB     = register to store
         bra         ExecuteSTAorB     go do it!

ExecuteSUBD ; Execute SUBD instruction
         jsr         FetchEFAword      go get the operand
         pshd                          save on TOS
         ldd         UserRegisterD     get user register
         bsr         LoadUserCC        and CC bits
         subd        ,s++              do the subtract
ExecuteArithtoDDone ; finish arithmetic operation on D register
         bsr         StoreUserCC       save new user CC bits
         std         UserRegisterD     save the result value
         rts

ExecuteADDD ; Execute ADDD instruction
         jsr         FetchEFAword      go get the operand
         bsr         LoadUserCC        and CC bits
         addd        ,s++              do the subtract
         bra         ExecuteArithtoDDone
         page
***** Need code to allow execution thru a system call!
ExecuteJSR ; Execute JSR instruction, EFA is branch target!
*        This code automatically handles BSR, no special wizardry necessary!
         ldx         UserRegisterS     Push user PC onto stack
         leax        -2,x              first, pre-decrement the SP
         ldd         UserRegisterPC    value to push onto stack
         jsr         StoreUserWord     put old User PC on top of his stack
         ldx         UserRegisterS     now adjust stack pointer
         leax        -2,x              (couldn't do it before,...
         stx         UserRegisterS     because a bkpt might have occurred!)
         ldx         effectiveaddress  = new user PC
         stx         NewUserPC
         rts

ExecuteLDD ; Execute LDD instruction
         ldx         #UserRegisterD    = which register to load
ExecuteLDDouble ; common code for loading 16 bit register
         pshx                          save target register name
         jsr         FetchEFAWord      from value from user space
         bsr         LoadUserCC        set up to update CC bits
         std         [,s++]            store the value, set CC bits
         bra         StoreUserCC

ExecuteLDX ; Execute LDX instruction
         ldx         #UserRegisterX    = which register to load
         bra         ExecuteLDDouble   go do the load

ExecuteLDU ; Execute LDU instruction
         ldx         #UserRegisterU    = which register to load
         bra         ExecuteLDDouble   go do the load

ExecuteSTD ; Execute STD instruction
         ldd         UserRegisterD     = register to store
ExecuteSTDouble ; common code to store 16 bit register
         bsr         LoadUserCC        fetch user CC bits
         std         scratch           set proper CC bits
         bsr         StoreUserCC       save updated CC bits
         bsr         StoreEFAWord      move to user space
         rts

ExecuteSTX ; Execute STX instruction
         ldd         UserRegisterX     = register to store
         bra         ExecuteSTDouble   go do the store

ExecuteSTU ; Execute STU instruction
         ldd         UserRegisterU     = register to store
         bra         ExecuteSTDouble   go do the store

ExecuteSTY ; Execute STY instruction
         ldd         UserRegisterY     = register to store
         bra         ExecuteSTDouble   go do the store

ExecuteCMPD ; Execute CMPD instruction
         ldd         UserRegisterD     = word to compare to
ExecuteCMPDouble ; common code for Compare double register
         pshd                          save contents of register to compare
         jsr         FetchEFAWord      get word to compare against
         pulx                          get register to compare back
         bsr         LoadUserCC        load user CC bits
         pshd                          push value to compare onto stack
         cmpx        ,s++              do the compare
         bsr         StoreUserCC       save user CC bits
         rts

ExecuteCMPX ; Execute CMPX instruction
         ldd         UserRegisterX     = word to compare to
         bra         ExecuteCMPDouble  go do the compare

ExecuteCMPY ; Execute CMPY instruction
         ldd         UserRegisterY     = word to compare to
         bra         ExecuteCMPDouble  go do the compare

ExecuteCMPU ; Execute CMPU instruction
         ldd         UserRegisterU     = word to compare to
         bra         ExecuteCMPDouble  go do the compare

ExecutePrefix ; Instruction has non-zero prefix byte, opcode in in (A)
         cmpb        #$10              $10 prefix ?
         beq         ExecutePrefix$11  b/ no, must be the other kind!
ExecutePrefix10 ; $10 prefix byte seen
         cmpa        #$2F              long branch ?
         bls         ExecuteLongBranch b/ yes
         cmpa        #$3F              SWI2 ?
         beq         ExecuteSWI2       b/ yes
         andb        #%11001111        mask off addressing mode
         cmpb        #$83              CMPD ?
         beq         ExecuteCMPD       b/ yes
         cmpa        #$8C              CMPY ?
         beq         ExecuteCMPY       b/ yes
         cmpa        #$8E              LDY ?
         ldx         #UserRegisterY    Assume LDY instruction
         beq         ExecuteLDDouble   b/ yes
         cmpa        #$8F              STY ?
         beq         ExecuteSTY        b/ yes
         ldx         #UserRegisterS    Assume LDY instruction
         cmpa        #$CE              LDS ?
         beq         ExecuteLDDouble   b/ yes
ExecuteSTS ; Execute STS instruction
         ldd         UserRegisterS     = register to store
         bra         ExecuteSTDouble   go do the store

ExecutePrefix11 ; $11 prefix byte seen
         cmpa        #$3F              SWI3 ?
         beq         ExecuteSWI3       b/ yes, go execute
         anda        #%11001111        mask off addressing mode
         cmpa        #$83              CMPU ?
         beq         ExecuteCMPU       b/ yes
ExecuteCMPS ; Execute CMPS instruction
         ldd         UserRegisterS     = word to compare to
         bra         ExecuteCMPDouble  go do the compare
         page        SWI Execution
ExecuteSWI ; Execute SWI instruction
         ldx         #$FFFC            = where to get new PC from
         lda         #%11010000        set E, F and I bits when done
*        bra         ExecuteSWICommon  save context block on stack
ExecuteSWICommon ; do common work for SWI
*        (X) points to new PC in user space, (A) contains adjustment to CC bits
         ora         UserRegisterCC    adjust CC bits
         sta         NewUserCC
**** this doesn't check read/write address!
         jsr         FetchUserWord     get new value for PC
         std         NewUserPC         and save it
         lda         #$FF              = push/pull post byte with all bits set
         sta         InstructionPostByte fake out PSHS executer
         bra         ExecutePSHS       this does all the real work!
******* shouldn't we pass control to an external debugger here?

ExecuteSWI2 ; Execute SWI2 instruction
         ldx         #$FFFC            = where to get new PC from
         lda         #%10000000        set E bit when done
         bra         ExecuteSWICommon  save context block on stack

ExecuteSWI3 ; Execute SWI3 instruction
         ldx         #$FFFC            = where to get new PC from
         lda         #%10000000        set E bit when done
         bra         ExecuteSWICommon  save context block on stack
