        SUBT    > <wini>arm.NewEmulate.EmuOpcode - 6502 opcode macros and code

; Known deficiencies:
; ===================

; Opcode and argument fetches do not go via LoadByte, and hence may give
; different results if running in the screen after poking it ! (Especially
; now 'shadowing' trapped areas)

; Branches do not wrap within a 64K volume, hence any code in zero page that
; does BRA &FFF4 etc. will not work (deservedly so !)

; xxxI(Y) &FF fetches base pointer from &00FF and &0100.
; No one should have been doing this, as &00FF is the 6502 OS Escape flag.

; xxxIX: If (arg+X) = &FF then result address is fetched from &00FF and &0100.
; No one should have been doing this, as &00FF is the 6502 OS Escape flag.

; Stack only wraps in page &01 if wrapstack set

; IRQ only tested for on JMP,Bxx,CLI,PLP,RTS (affects very little)

; Turbo accesses don't check to see if in 000000..03FFFF so could dump all over
; if page 03 gets corrupted

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Padding macro to get all opcodes evenly spaced
; Also allows GlueEmu to thread the bound language through the image

        GBLA    last    ; Start of code for previous 6502 opcode assembled
        GBLA    spaces  ; How many spaces are there in the emulator ?
        GBLA    useful  ; How many spaces are useful ?
        GBLA    mingap  ; Smallest space

TutuValue *     &75747574 ; "tutu"

 [ turbo :LOR: opfetchdebug
spacingshift    *       7
 |
spacingshift    *       6
 ]
spacing         *       1 :SHL: spacingshift

        MACRO
        PAD
        LCLA    curroff
        LCLA    padding
curroff SETA    .-Module_BaseAddr
padding SETA    (last+spacing) - curroff
spaces  SETA    spaces+padding
 [ padding < mingap
mingap  SETA    padding
 ]
 [ curroff <= (last+spacing)
  [ padding = 4                 ; Then it's no use to us
        DCD     &31534B53       ; 'SKS1'
  |
useful  SETA    useful + padding
        DCD     TutuValue       ; So MakeEmu can suss empty holes in the code
        DCD     padding
   [ padding > 8
        %       padding-8
   ]
  ]
 |
 ! 1, (:STR:(-padding)):CC:" bytes overlap at ":CC:(:STR:(.-Module_BaseAddr))
 ]
        assert   (last+spacing) = .-Module_BaseAddr
last    SETA    .-Module_BaseAddr
        MEND

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Fetch and execute next 6502 instruction

        MACRO
        DoNext  $nopad
 [ opfetchdebug
        BL      DebugOpcode
 ]
 [ debug :LAND: False
        BL      CheckActive
 ]
        LDRB    r0, [P], #1
        ADD     pc, JV, r0, LSL #spacingshift
 [ "$nopad" = ""
        PAD
 ]
        MEND


; Fetch and execute next 6502 instruction, checking first for pending IRQ

        MACRO
        DoNext_IRQ  $nopad
 [ fullbbc
        MOV     r0, psr
        TST     OtherFlags, #I_bit_6502
        BEQ     TestIRQ
        TEQP    r0, #0
 ]
 [ opfetchdebug
        BL      DebugOpcode
 ]
 [ debug :LAND: False
        BL      CheckActive
 ]
        LDRB    r0, [P], #1
        ADD     pc, JV, r0, LSL #spacingshift
 [ "$nopad" = ""
        PAD
 ]
        MEND

 [ debug
CheckActive ENTRY "r0"

        GetWS   r0
        LDRB    r14, [r0, #emulatorActive ]
        TEQ     r14, #&FF
        EXITS   EQ

        Pull    "r0, lr"
        MOV     lr, pc
        MOV     pc, #0
 ]

; ************************* Absolute addressing *******************************

        MACRO
        DoA
        LDRB    r0, [P], #1
        LDRB    r1, [P], #1
        ADD     r0, r0, r1, LSL #8
        MEND


        MACRO
        DoAX
        LDRB    r0, [P], #1
        LDRB    r1, [P], #1
        ADD     r0, r0, r1, LSL #8
        ADD     r0, r0, X, LSR #24
 [ wrap
        BIC     r0, r0, #&10000
 ]
        MEND


        MACRO
        DoAY
        LDRB    r0, [P], #1
        LDRB    r1, [P], #1
        ADD     r0, r0, r1, LSL #8
        ADD     r0, r0, Y, LSR #24
 [ wrap
        BIC     r0, r0, #&10000
 ]
        MEND


; ************************* Zero Page addressing ******************************

; Zero page indexed addressing is defined to wrap in page 0

; BASIC IV now relies on this fact, so don't even think of 'optimising' here

        MACRO
        DoZX
        LDRB    r0, [P], #1
        ADD     r0, r0, X, LSR #24
        AND     r0, r0, #255
        MEND

        MACRO
        DoZXzx
        LDRB    r0, [P], #1
        ADD     r0, X, r0, LSL #24
        MEND

        MACRO
        DoZY
        LDRB    r0, [P], #1
        ADD     r0, r0, Y, LSR #24
        AND     r0, r0, #255
        MEND

; ************************* Indirect addressing *******************************

        MACRO
        DoI
 [ turbo
        LDRB    r0, [P], #1     ; Get offset from opcode
        LDRB    r1, [r0, MR]!   ; Get normal arg from ZP+offset
        LDRB    r2, [r0, #1]!   ; And ZP+offset+1. NB. Also adds one for Turbo
                                ; Wrong if xxxI &FF, but no abort possible
        LDRB    r0, [r0, #&300] ; And hi byte from &301+offset
        ADD     r2, r1, r2, LSL #8  ; Form the mid/lo address
        ADD     r0, r2, r0, LSL #16 ; Form the full address
 |
        LDRB    r0, [P], #1
        LDRB    r1, [r0, MR]!   ; Wrong if xxxI &FF, but no abort possible
        LDRB    r0, [r0, #1]
        ADD     r0, r1, r0, LSL #8
 ]
        MEND


        MACRO
        DoIY
 [ turbo
        LDRB    r0, [P], #1     ; Get offset from opcode
        LDRB    r1, [r0, MR]!   ; Get normal arg from ZP+offset
        LDRB    r2, [r0, #1]!   ; And ZP+offset+1. NB. Also adds one for Turbo
                                ; Wrong if xxxIY &FF, but no abort possible
        ADD     r2, r1, r2, LSL #8 ; Form the mid/lo address
        ADD     r2, r2, Y, LSR #24 ; Add index register
 [ wrap
        BIC     r2, r2, #&10000 ; Still wrap result within a volume
 ]
        LDRB    r0, [r0, #&300] ; Get hi byte from &301+offset
        ADD     r0, r2, r0, LSL #16 ; Form the full address
 |
        LDRB    r0, [P], #1
        LDRB    r1, [r0, MR]!
        LDRB    r0, [r0, #1]    ; Wrong if xxxIY &FF, but no abort possible
        ADD     r0, r1, r0, LSL #8
        ADD     r0, r0, Y, LSR #24
  [ wrap
        BIC     r0, r0, #&10000
  ]
 ]
        MEND


; I can't see how one could use Turbo with IX ?! Consult SBF ?

        MACRO
        DoIX
        LDRB    r0, [P], #1
        ADD     r0, r0, X, LSR #24
        AND     r0, r0, #255
        LDRB    r1, [r0, MR]!
        LDRB    r0, [r0, #1]    ; Wrong if (loc+X) = &FF, but no abort possible
        ADD     r0, r1, r0, LSL #8
        MEND

; *************************** Stack operations ********************************

        MACRO
        Push65  $reg
 [ wrapstack
        STRB    $reg, [MR, S]
        SUB     S, S, #1
        ORR     S, S, #&100
 |
        STRB    $reg, [S], #-1
 ]
        MEND


        MACRO
        Pull65  $reg
 [ wrapstack
        SUB     S, S, #&FF
        ORR     S, S, #&100
        LDRB    $reg, [MR, S]
 |
        LDRB    $reg, [S, #1]!
 ]
        MEND

; ************************** Read / Modify / Write ****************************

; Interesting point to note: as RMW cycles all affect N and Z we can use
; TEQ on the loaded byte to determine whether the location we are modifying
; is probably read and write trapped. However we still need to so the full
; StoreByte to put the data back as TrapByte doesn't tell us about just
; write protection. SKS 30-Nov-88

        MACRO
        SETNZ   $reg                    ; Set N, Z on $reg
        MOV     r0, $reg, LSL #24
        TEQ     r0, #0
        MEND

        MACRO
        SETZ                            ; Set Z for TSB, TRB
        MOV     r2, pc
        TST     r1, A, LSR #24
        BIC     r2, r2, #Z_bit
        ORREQ   r2, r2, #Z_bit          ; Set Z bit on (r1 AND A)
        TEQP    r2, #0                  ; Update PSR
        MEND


; *** ASL

        MACRO
        DoASLzx
        LDRB    r1, [MR, r0, LSR #24]
        MOV     r1, r1, LSL #1
        STRB    r1, [MR, r0, LSR #24]
        TST     mpf, r1, LSL #24        ; Tim is a real prevert !
        DoNext
        MEND

        MACRO
        DoASLZ
        LDRB    r1, [MR, r0]
        MOV     r1, r1, LSL #1
        STRB    r1, [MR, r0]
        TST     mpf, r1, LSL #24        ; Tim is a real prevert !
        DoNext
        MEND

        MACRO
        DoASL
        LDRB    r1, [MR, r0]
 [ fullbbc
        TEQ     r1, #TrapByte
        BEQ     DoASLTrapped
 ]
        MOV     r1, r1, LSL #1
        StoreByte r1, r0
        TST     mpf, r1, LSL #24        ; Tim is a real prevert !
        DoNext
        MEND

 [ fullbbc
DoASLTrapped
        LoadByte r1, r0
        MOV     r1, r1, LSL #1
        StoreByte r1, r0
        TST     mpf, r1, LSL #24
        DoNext  NOPAD
 ]


; *** ROL

        MACRO
        DoROLzx
        LDRB    r1, [MR, r0, LSR #24]
        ADC     r1, r1, r1
        STRB    r1, [MR, r0, LSR #24]
        MOVS    r0, r1, LSL #24
        DoNext
        MEND

        MACRO
        DoROLZ
        LDRB    r1, [MR, r0]
        ADC     r1, r1, r1
        STRB    r1, [MR, r0]
        MOVS    r0, r1, LSL #24
        DoNext
        MEND

        MACRO
        DoROL
        LDRB    r1, [MR, r0]
 [ fullbbc
        TEQ     r1, #TrapByte ; Doesn't affect C
        BEQ     DoROLTrapped
 ]
        ADC     r1, r1, r1
        StoreByte r1, r0
        MOVS    r0, r1, LSL #24
        DoNext
        MEND

 [ fullbbc
DoROLTrapped
        LoadByte r1, r0
        ADC     r1, r1, r1
        StoreByte r1, r0
        MOVS    r0, r1, LSL #24
        DoNext  NOPAD
 ]


; *** LSR

        MACRO
        DoLSRzx
        LDRB    r1, [MR, r0, LSR #24]
        MOVS    r1, r1, LSR #1
        STRB    r1, [MR, r0, LSR #24]
        SETNZ   r1
        DoNext
        MEND

        MACRO
        DoLSRZ
        LDRB    r1, [MR, r0]
        MOVS    r1, r1, LSR #1
        STRB    r1, [MR, r0]
        SETNZ   r1
        DoNext
        MEND

        MACRO
        DoLSR
        LDRB    r1, [MR, r0]
 [ fullbbc
        TEQ     r1, #TrapByte
        BEQ     DoLSRTrapped
 ]
        MOVS    r1, r1, LSR #1
        StoreByte r1, r0
        SETNZ   r1
        DoNext
        MEND

 [ fullbbc
DoLSRTrapped
        LoadByte r1, r0
        MOVS    r1, r1, LSR #1
        StoreByte r1, r0
        SETNZ   r1
        DoNext  NOPAD
 ]


; *** ROR

        MACRO
        DoRORzx
        LDRB    r1, [MR, r0, LSR #24]
        ORRCS   r1, r1, #&100
        MOVS    r1, r1, LSR #1
        STRB    r1, [MR, r0, LSR #24]
        SETNZ   r1
        DoNext
        MEND

        MACRO
        DoRORZ
        LDRB    r1, [MR, r0]
        ORRCS   r1, r1, #&100
        MOVS    r1, r1, LSR #1
        STRB    r1, [MR, r0]
        SETNZ   r1
        DoNext
        MEND

        MACRO
        DoROR
        LDRB    r1, [MR, r0]
 [ fullbbc
        TEQ     r1, #TrapByte ; Doesn't affect C
        BEQ     DoRORTrapped
 ]
        ORRCS   r1, r1, #&100
        MOVS    r1, r1, LSR #1
        StoreByte r1, r0
        SETNZ   r1
        DoNext
        MEND

 [ fullbbc
DoRORTrapped
        LoadByte r1, r0
        ORRCS   r1, r1, #&100
        MOVS    r1, r1, LSR #1
        StoreByte r1, r0
        SETNZ   r1
        DoNext  NOPAD
 ]


; *** DEC

        MACRO
        DoDECzx
        LDRB    r1, [MR, r0, LSR #24]
        SUB     r1, r1, #1
        STRB    r1, [MR, r0, LSR #24]
        SETNZ   r1
        DoNext
        MEND

        MACRO
        DoDECZ
        LDRB    r1, [MR, r0]
        SUB     r1, r1, #1
        STRB    r1, [MR, r0]
        SETNZ   r1
        DoNext
        MEND

        MACRO
        DoDEC
        LDRB    r1, [MR, r0]
 [ fullbbc
        TEQ     r1, #TrapByte
        BEQ     DoDECTrapped
 ]
        SUB     r1, r1, #1
        StoreByte r1, r0
        SETNZ   r1
        DoNext
        MEND

 [ fullbbc
DoDECTrapped
        LoadByte r1, r0
        SUB     r1, r1, #1
        StoreByte r1, r0
        SETNZ   r1
        DoNext  NOPAD
 ]


; *** INC

        MACRO
        DoINCzx
        LDRB    r1, [MR, r0, LSR #24]
        ADD     r1, r1, #1
        STRB    r1, [MR, r0, LSR #24]
        SETNZ   r1
        DoNext
        MEND

        MACRO
        DoINCZ
        LDRB    r1, [MR, r0]
        ADD     r1, r1, #1
        STRB    r1, [MR, r0]
        SETNZ   r1
        DoNext
        MEND

        MACRO
        DoINC
        LDRB    r1, [MR, r0]
 [ fullbbc
        TEQ     r1, #TrapByte
        BEQ     DoINCTrapped
 ]
        ADD     r1, r1, #1
        StoreByte r1, r0
        SETNZ   r1
        DoNext
        MEND

 [ fullbbc
DoINCTrapped
        LoadByte r1, r0
        ADD     r1, r1, #1
        StoreByte r1, r0
        SETNZ   r1
        DoNext  NOPAD
 ]


        MACRO
        DoTRB
        LoadByte r1, r0                 ; NB. Not FNZ !
        SETZ                            ; <<< But room for improvement !!!
        BIC     r1, r1, A, LSR #24
        StoreByte r1, r0
        DoNext
        MEND

        MACRO
        DoTSB
        LoadByte r1, r0                 ; NB. Not FNZ !
        SETZ                            ; <<< But room for improvement !!!
        ORR     r1, r1, A, LSR #24
        StoreByte r1, r0
        DoNext
        MEND

; ************************** Bits of ALU bashing ******************************

        MACRO
        DoORA   $reg
        MOV     $reg, $reg, LSL #24     ; Mustn't affect C
        ORRS    A, A, $reg
        DoNext
        MEND

        MACRO
        DoAND   $reg
        MOV     $reg, $reg, LSL #24     ; Don't affect C
        ANDS    A, A, $reg
        DoNext
        MEND

        MACRO
        DoEOR   $reg
        MOV     $reg, $reg, LSL #24
        EORS    A, A, $reg
        DoNext
        MEND

; r0 has NVxxxxxx at the top, ASR'd by 2 gives NNNVxxxx
; this has an N and a V in the ARM PSR positions !
; Then EOR with new PSR to Get the difference in N and V
; AND them out and EOR them back in !!!
        MACRO
        DoBIT   $reg
        MOV     r0, $reg, LSL #24
        TST     r0, A                   ; Set Z on result
        MOV     r1, pc                  ; Pick PSR up
        EOR     r1, r1, r0, ASR #2
        AND     r1, r1, #(N_bit :OR: V_bit)
        TEQP    r1, pc
        DoNext
        MEND

        MACRO
        DoADD
        TST     OtherFlags, #D_bit_6502 ; Using decimal mode? Doesn't affect C
        BNE     ADDBCD
        ORRCS   r1, r1, mpf             ; Set bottom bits to 1 if carry set
        ADCS    A, A, r1, ROR #8        ; Carry ripples thru FF's
        DoNext
        MEND

        MACRO
        DoSBC
        TST     OtherFlags, #D_bit_6502 ; Using decimal mode? Doesn't affect C
        BNE     SUBBCD
        ORRCC   r1, r1, mpf             ; Set bottom bits to 1 if carry clear
        SBCS    A, A, r1, ROR #8        ; Carry ripples thru FF's
        DoNext
        MEND


; Decimal stuff - tries to set NZC correctly, V will probably be clear ?!

        AlignForModule

ADDBCD ; A + r1b in BCD

        AND     r2, r1, #&F             ; Do low nibbles
        AND     r0, A, #&0F000000       ; Mask this one up here
        ADC     r2, r2, r0, LSR #24
        CMP     r2, #10                 ; This one sets carry to next nibble
        SUBCS   r2, r2, #10
        MOV     r2, r2, LSL #24         ; And shift to final field placing

        MOV     r1, r1, LSR #4          ; Do high nibbles
        ADC     A, r1, A, LSR #28
        CMP     A, #10                  ; This one sets full carry from op
        SUBCS   A, A, #10

        ORR     A, r2, A, LSL #28       ; Form the answer. Can't mangle C
        TEQ     A, #0                   ; Set N, Z on result as well
        DoNext  NOPAD                   ; even though some 6502's get it wrong


        AlignForModule

SUBBCD ; A - r1b in BCD

        AND     r2, r1, #&0F            ; Do low nibbles
        AND     r0, A, #&0F000000
        RSCS    r2, r2, r0, LSR #24     ; Half carry
        ADDCC   r2, r2, #10

        MOV     r1, r1, LSR #4
        RSCS    A, r1, A, LSR #28       ; Full carry
        ADDCC   A, A, #10

        ORR     A, r2, A, LSL #4        ; Form the answer
        MOV     A, A, LSL #24
        TEQ     A, #0                   ; set N, Z on result
        DoNext  NOPAD                   ; even though some 6502's get it wrong


        MACRO
        CMP65   $reg65, $reg            ; Compare preserving V (TMD)
        MOV     r2, pc
        CMP     $reg65, $reg, LSL #24
        EOR     r2, r2, pc              ; Get <old EOR new>
        AND     r2, r2, #V_bit          ; Get EOR of old and new V_bits
        TEQP    r2, pc                  ; EOR with new pc and write back
        MEND


        MACRO
        B65     $cc,$ncc
        LDR$cc.B r0, [P], #1            ; Tutu strikes again !
        MOV$cc  r0, r0, LSL #24
        ADD$cc  P, P, r0, ASR #24       ; This fails if a branch wraps out !
                                        ; Well spotted Tim ...
 [ "$cc" <> "AL"                        ; Save yet another S cycle for BRA
        ADD$ncc P, P, #1
 ]
        DoNext_IRQ
        MEND


        MACRO
        DoLDRzx $reg65
        LDRB    $reg65, [MR, r0, LSR #24]
        MOV     $reg65, $reg65, LSL #24
        TEQ     $reg65, #0
        DoNext
        MEND

        MACRO
        DoLDRZ  $reg65
        LDRB    $reg65, [MR, r0]
        MOV     $reg65, $reg65, LSL #24
        TEQ     $reg65, #0
        DoNext
        MEND

        MACRO
        DoLDR   $reg65
        LoadByteFNZ r1, r0
        MOV     $reg65, r1, LSL #24
        TEQ     $reg65, #0
        DoNext
        MEND


N_bit_6502 * 2_10000000
V_bit_6502 * 2_01000000
; Unused bit * 2_00100000
B_bit_6502 * 2_00010000
D_bit_6502 * 2_00001000
I_bit_6502 * 2_00000100
Z_bit_6502 * 2_00000010
C_bit_6502 * 2_00000001

        MACRO
        Do_PHP  $BClear
 [ "$BClear" = "BClear"
        MOVPL   r0, #0                  ; IRQ'ed, so clear B
        MOVMI   r0, #N_bit_6502
 |
        MOVPL   r0, #B_bit_6502         ; Not IRQed, so set B
        MOVMI   r0, #B_bit_6502 :OR: N_bit_6502
 ]
        ORRVS   r0, r0, #V_bit_6502
        ORRCS   r0, r0, #C_bit_6502
        ORREQ   r0, r0, #Z_bit_6502
        ORR     r0, r0, OtherFlags      ; D and I bits
        Push65  r0
        MEND


 [ fullbbc
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; In    P -> next opcode. r0 = psr state

        AlignForModule
TestIRQ
        GetWS   r2                      ; Don't abuse JV
 [ True ; A much faster way to do this
        LDR     r1, [r2, #SystemVIARegs + 12] ; Get xx.15/IER.14/IFR.13/PCR.12
        AND     r1, r1, r1, LSR #8      ; Requesting
        TST     r1, #(IFR_T0_bit :OR: IFR_VSYNC_bit) :SHL 8 ; Just these two
 |
        LDRB    r1, [r2, #SystemVIARegs + VIA_IFR]
        LDRB    r2, [r2, #SystemVIARegs + VIA_IER]
        AND     r2, r2, r1            ; Requesting
        TST     r2, #IFR_T0_bit :OR: IFR_VSYNC_bit ; Just these two
 ]
        BNE     DoIRQ

        TEQP    r0, #0                  ; Restore flags
        DoNext  NOPAD


        AlignForModule

DoIRQ   MOV     r14, r0                 ; Eek !
        TEQP    r0, #0                  ; Restore flags for PHP

        SUB     r1, P, MR
        MOV     r0, r1, LSR #8
        Push65  r0                      ; Push address of current instruction
        Push65  r1
        Do_PHP  BClear                  ; With B bit clear (IRQ)
        ORR     OtherFlags, OtherFlags, #I_bit_6502 ; SEI

        ADD     r0, MR, #&10000         ; Fetch address of IRQ/BRK routine
        LDR     r0, [r0, #-4]           ; from &FFFC
        ADD     P, MR, r0, LSR #16

        TEQP    r14, #0                 ; Restore flags for IRQ code entry
        DoNext  NOPAD
 ]

; *************************** Full instructions *******************************

        MACRO
        BRK
        B       ProcessBRK
        PAD
        MEND


; BRK code is too long to fit in one normal sized opcode slice.
; Push address of BRK+2

ProcessBRK

        SUB     r1, P, MR
        ADD     r1, r1, #1              ; Push address of BRK+2
        MOV     r0, r1, LSR #8
        Push65  r0
        Push65  r1
        Do_PHP                          ; Flags with B bit (not IRQ)

        ADD     r0, MR, #&10000         ; Fetch address of IRQ/BRK routine
        LDR     r0, [r0, #-4]           ; from &FFFC
        ADD     P, MR, r0, LSR #16
        DoNext  NOPAD


        MACRO
        ORAIX
        DoIX
        LoadByteFNZ r1, r0
        DoORA   r1
        MEND

        MACRO
        TSBZ
        LDRB    r0, [P], #1
        DoTSB
        MEND

        MACRO
        ORAZ
        LDRB    r0, [P], #1
        LDRB    r1, [MR, r0]
        DoORA   r1
        MEND

        MACRO
        ASLZ
        LDRB    r0, [P], #1
        DoASLZ
        MEND

        MACRO
        PHP
        Do_PHP
        DoNext
        MEND

        MACRO
        ORAIM
        LDRB    r1, [P], #1
        DoORA   r1
        MEND

        MACRO
        ASLA
        MOVS    A, A, LSL #1
        DoNext
        MEND

        MACRO
        TSB
        DoA
        DoTSB
        MEND

        MACRO
        ORA
        DoA
        LoadByteFNZ r1, r0
        DoORA   r1
        MEND

        MACRO
        ASLB
        DoA
        DoASL
        MEND

        MACRO
        MBPL
        B65     PL,MI
        MEND

        MACRO
        ORAIY
        DoIY
        LoadByteFNZ r1, r0
        DoORA   r1
        MEND

        MACRO
        ORAI
        DoI
        LoadByteFNZ r1, r0
        DoORA   r1
        MEND

        MACRO
        TRBZ
        LDRB    r0, [P], #1
        DoTRB
        MEND

        MACRO
        ORAZX
        DoZXzx
        LDRB    r1, [MR, r0, LSR #24]
        DoORA   r1
        MEND

        MACRO
        ASLZX
        DoZXzx
        DoASLzx
        MEND

        MACRO
        CLC65
        MVN     r0, #C_bit
        TSTP    r0, pc
        DoNext
        MEND

        MACRO
        ORAAY
        DoAY
        LoadByteFNZ r1, r0
        DoORA   r1
        MEND

        MACRO
        INCA
        ADD     A, A, #&01000000
        TEQ     A, #0
        DoNext
        MEND

        MACRO
        TRB
        DoA
        DoTRB
        MEND

        MACRO
        ORAAX
        DoAX
        LoadByteFNZ r1, r0
        DoORA   r1
        MEND

        MACRO
        ASLAX
        DoAX
        DoASL
        MEND

        MACRO
        JSR
        LDRB    r0, [P], #1
        SUB     r2, P, MR
        MOV     r1, r2, LSR #8
        Push65  r1
        Push65  r2
        LDRB    r1, [P], #1
        ADD     P, r0, r1, LSL #8
        ADD     P, P, MR
        DoNext ;_IRQ
        MEND

        MACRO
        ANDIX
        DoIX
        LoadByteFNZ r1, r0
        DoAND   r1
        MEND

        MACRO
        BITZ
        LDRB    r0, [P], #1
        LDRB    r1, [MR, r0]
        DoBIT   r1
        MEND

        MACRO
        ANDZ
        LDRB    r0, [P], #1
        LDRB    r1, [MR, r0]
        DoAND   r1
        MEND

        MACRO
        ROLZ
        LDRB    r0, [P], #1
        DoROLZ
        MEND

        MACRO
        PLP65
        Pull65  r0
        AND     OtherFlags, r0, #D_bit_6502 :OR: I_bit_6502
        AND     r1, r0, #&80            ; Get N
        MOV     r2, r1, LSL #31-7
        AND     r1, r0, #&40            ; Get V
        ORR     r2, r2, r1, LSL #28-6
        AND     r1, r0, #3              ; Get Z,C
        TEQP    r2, r1, LSL #29-0
        DoNext_IRQ
        MEND

        MACRO
        ANDIM
        LDRB    r1, [P], #1
        DoAND   r1
        MEND

        MACRO
        ROLA
        ORRCS   A, A, #&00800000
        MOVS    A, A, LSL #1
        DoNext
        MEND

        MACRO
        BIT
        DoA
        LoadByteFNZ r1, r0
        DoBIT   r1
        MEND

        MACRO
        ANDB
        DoA
        LoadByteFNZ r1, r0
        DoAND   r1
        MEND

        MACRO
        ROLB
        DoA
        DoROL
        MEND

        MACRO
        MBMI
        B65     MI,PL
        MEND

        MACRO
        ANDIY
        DoIY
        LoadByteFNZ r1, r0
        DoAND   r1
        MEND

        MACRO
        ANDI
        DoI
        LoadByteFNZ r1, r0
        DoAND   r1
        MEND

        MACRO
        BITZX
        DoZXzx
        LDRB    r1, [MR, r0, LSR #24]
        DoBIT   r1
        MEND

        MACRO
        ANDZX
        DoZXzx
        LDRB    r1, [MR, r0, LSR #24]
        DoAND   r1
        MEND

        MACRO
        ROLZX
        DoZXzx
        DoROLzx
        MEND

        MACRO
        SEC65
        MOV     r0, #C_bit
        TEQCCP  r0, pc
        DoNext
        MEND

        MACRO
        ANDAY
        DoAY
        LoadByteFNZ r1, r0
        DoAND   r1
        MEND

        MACRO
        DECA
        SUB     A, A, #&01000000
        TEQ     A, #0
        DoNext
        MEND

        MACRO
        BITAX
        DoAX
        LoadByteFNZ r1, r0
        DoBIT   r1
        MEND

        MACRO
        ANDAX
        DoAX
        LoadByteFNZ r1, r0
        DoAND   r1
        MEND

        MACRO
        ROLAX
        DoAX
        DoROL
        MEND

        MACRO
        RTI
        Pull65  r0                      ; Restore flags
        AND     OtherFlags, r0, #D_bit_6502 :OR: I_bit_6502
        AND     r1, r0, #&80            ; Get N
        MOV     r2, r1, LSL #31-7
        AND     r1, r0, #&40            ; Get V
        ORR     r2, r2, r1, LSL #28-6
        AND     r1, r0, #3              ; Get Z,C
        TEQP    r2, r1, LSL #29-0
        Pull65  r0                      ; Get return PC
        Pull65  r1
        ADD     P, r0, r1, LSL #8
        ADD     P, P, MR
        DoNext                          ; Don't test for IRQ here !!!
        MEND

        MACRO
        EORIX
        DoIX
        LoadByteFNZ r1, r0
        DoEOR   r1
        MEND

        MACRO
        EORZ
        LDRB    r0, [P], #1
        LDRB    r1, [MR, r0]
        DoEOR   r1
        MEND

        MACRO
        LSRZ
        LDRB    r0, [P], #1
        DoLSRZ
        MEND

        MACRO
        PHA
        MOV     r0, A, LSR #24
        Push65  r0
        DoNext
        MEND

        MACRO
        EORIM
        LDRB    r1, [P], #1
        DoEOR   r1
        MEND

        MACRO
        LSRA
        MOVS    r0, A, LSR #25
        MOV     A, r0, LSL #24
        TEQ     A, #0
        DoNext
        MEND

        MACRO
        JMP
        LDRB    r0, [P], #1
        LDRB    r1, [P]
        ADD     P, r0, r1, LSL #8
        ADD     P, P, MR
        DoNext_IRQ
        MEND

        MACRO
        EORB
        DoA
        LoadByteFNZ r1, r0
        DoEOR   r1
        MEND

        MACRO
        LSRB
        DoA
        DoLSR
        MEND

        MACRO
        MBVC
        B65     VC,VS
        MEND

        MACRO
        EORIY
        DoIY
        LoadByteFNZ r1, r0
        DoEOR   r1
        MEND

        MACRO
        EORI
        DoI
        LoadByteFNZ r1, r0
        DoEOR   r1
        MEND

        MACRO
        EORZX
        DoZXzx
        LDRB    r1, [MR, r0, LSR #24]
        DoEOR   r1
        MEND

        MACRO
        LSRZX
        DoZXzx
        DoLSRzx
        MEND

        MACRO
        CLI
        BIC     OtherFlags, OtherFlags, #I_bit_6502
        DoNext_IRQ                      ; People use CLI/SEI for IRQ window
        MEND

        MACRO
        EORAY
        DoAY
        LoadByteFNZ r1, r0
        DoEOR   r1
        MEND

        MACRO
        PHY
        MOV     r0, Y, LSR #24
        Push65  r0
        DoNext
        MEND

        MACRO
        EORAX
        DoAX
        LoadByteFNZ r1, r0
        DoEOR   r1
        MEND

        MACRO
        LSRAX
        DoAX
        DoLSR
        MEND

        MACRO
        RTS
        Pull65  r0
        Pull65  r1
        ADD     r0, r0, r1, LSL #8
        ADD     P, r0, #1
        ADD     P, P, MR
        DoNext_IRQ
        MEND

        MACRO
        ADCIX
        DoIX
        LoadByteFNZ r1, r0
        DoADD
        MEND

        MACRO
        CLRZ
        LDRB    r0, [P], #1
        STRB    mpf, [MR, r0]
        DoNext
        MEND

        MACRO
        ADCZ
        LDRB    r0, [P], #1
        LDRB    r1, [MR, r0]
        DoADD
        MEND

        MACRO
        RORZ
        LDRB    r0, [P], #1
        DoROR
        MEND

        MACRO
        PLA
        Pull65  A
        MOV     A, A, LSL #24
        TEQ     A, #0
        DoNext
        MEND

        MACRO
        ADCIM
        LDRB    r1, [P], #1
        DoADD
        MEND

        MACRO
        RORA
        ORRCS   A, A, #1
        MOVS    r0, A, ROR #25
        MOV     A, r0, LSL #24
        TEQ     A, #0
        DoNext
        MEND

; Data aborts from JMI &FFFF taken care of by having an extra page
; We don't care that the result is wrong as this is a no-no !

        MACRO
        JMI
        LDRB    r0, [P], #1
        LDRB    r1, [P]
        ADD     r0, r0, r1, LSL #8
        LDRB    r1, [r0, MR]!
        LDRB    r0, [r0, #1]
        ADD     P, r1, r0, LSL #8
        ADD     P, P, MR
        DoNext ;_IRQ
        MEND

        MACRO
        ADCB
        DoA
        LoadByteFNZ r1, r0
        DoADD
        MEND

        MACRO
        RORB
        DoA
        DoROR
        MEND

        MACRO
        MBVS
        B65     VS,VC
        MEND

        MACRO
        ADCIY
        DoIY
        LoadByteFNZ r1, r0
        DoADD
        MEND

        MACRO
        ADCI
        DoI
        LoadByteFNZ r1, r0
        DoADD
        MEND

        MACRO
        CLRZX
        DoZXzx
        STRB    mpf, [MR, r0, LSR #24]
        DoNext
        MEND

        MACRO
        ADCZX
        DoZXzx
        LDRB    r1, [MR, r0, LSR #24]
        DoADD
        MEND

        MACRO
        RORZX
        DoZXzx
        DoRORzx
        MEND

        MACRO
        SEI
        ORR     OtherFlags, OtherFlags, #I_bit_6502
        DoNext
        MEND

        MACRO
        ADCAY
        DoAY
        LoadByteFNZ r1, r0
        DoADD
        MEND

        MACRO
        PLY
        Pull65  Y
        MOV     Y, Y, LSL #24
        TEQ     Y, #0
        DoNext
        MEND

; Data aborts from JMIX &FFFF taken care of by having an extra page
; We don't care that the result is wrong as this is a no-no !

        MACRO
        JMIX                            ; PC := (arg + X)
        DoA
        ADD     r0, r0, X, LSR #24
        LDRB    r1, [r0, MR]!
        LDRB    r0, [r0, #1]
        ADD     P, r1, r0, LSL #8
        ADD     P, P, MR
        DoNext ;_IRQ
        MEND

        MACRO
        ADCAX
        DoAX
        LoadByteFNZ r1, r0
        DoADD
        MEND

        MACRO
        RORAX
        DoAX
        DoROR
        MEND

        MACRO
        BRA
        B65     AL,NV
        MEND

        MACRO
        STAIX
        DoIX
        MOV     r1, A, LSR #24
        StoreByte r1, r0
        DoNext
        MEND

        MACRO
        STYZ
        LDRB    r0, [P], #1
        MOV     r1, Y, LSR #24
        STRB    r1, [MR, r0]
        DoNext
        MEND

        MACRO
        STAZ
        LDRB    r0, [P], #1
        MOV     r1, A, LSR #24
        STRB    r1, [MR, r0]
        DoNext
        MEND

        MACRO
        STXZ
        LDRB    r0, [P], #1
        MOV     r1, X, LSR #24
        STRB    r1, [MR, r0]
        DoNext
        MEND

        MACRO
        DEY
        SUB     Y, Y, #&01000000
        TEQ     Y, #0
        DoNext
        MEND

        MACRO
        BITIM
        LDRB    r1, [P], #1
        DoBIT   r1
        MEND

        MACRO
        TXA
        MOVS    A, X
        DoNext
        MEND

        MACRO
        STY
        DoA
        MOV     r1, Y, LSR #24
        StoreByte r1, r0
        DoNext
        MEND

        MACRO
        STA
        DoA
        MOV     r1, A, LSR #24
        StoreByte r1, r0
        DoNext
        MEND

        MACRO
        STX
        DoA
        MOV     r1, X, LSR #24
        StoreByte r1, r0
        DoNext
        MEND

        MACRO
        MBCC
        B65     CC,CS
        MEND

        MACRO
        STAIY
        DoIY
        MOV     r1, A, LSR #24
        StoreByte r1, r0
        DoNext
        MEND

        MACRO
        STAI
        DoI
        MOV     r1, A, LSR #24
        StoreByte r1, r0
        DoNext
        MEND

        MACRO
        STYZX
        DoZXzx
        MOV     r1, Y, LSR #24
        STRB    r1, [MR, r0, LSR #24]
        DoNext
        MEND

        MACRO
        STAZX
        DoZXzx
        MOV     r1, A, LSR #24
        STRB    r1, [MR, r0, LSR #24]
        DoNext
        MEND

        MACRO
        STXZY
        DoZY
        MOV     r1, X, LSR #24
        StoreByte r1, r0
        DoNext
        MEND

        MACRO
        TYA
        MOVS    A, Y
        DoNext
        MEND

        MACRO
        STAAY
        DoAY
        MOV     r1, A, LSR #24
        StoreByte r1, r0
        DoNext
        MEND

        MACRO
        TXS
 [ wrapstack
        MOV     S, X, LSR #24
        ORR     S, S, #&100
 |
        ADD     S, MR, #&100
        ADD     S, S, X, LSR #24
 ]
        DoNext
        MEND

        MACRO
        CLR
        DoA
 [ fullbbc
        MOV     r1, #0
        StoreByte r1, r0
 |
        STRB    mpf, [MR, r0]
 ]
        DoNext
        MEND

        MACRO
        STAAX
        DoAX
        MOV     r1, A, LSR #24
        StoreByte r1, r0
        DoNext
        MEND

        MACRO
        CLRAX
        DoAX
 [ fullbbc
        MOV     r1, #0
        StoreByte r1, r0
 |
        STRB    mpf, [MR, r0]
 ]
        DoNext
        MEND

        MACRO
        LDYIM
        LDRB    Y, [P], #1
        MOV     Y, Y, LSL #24
        TEQ     Y, #0
        DoNext
        MEND

        MACRO
        LDAIX
        DoIX
        DoLDR   A
        MEND

        MACRO
        LDXIM
        LDRB    X, [P], #1
        MOV     X, X, LSL #24
        TEQ     X, #0
        DoNext
        MEND

        MACRO
        LDYZ
        LDRB    r0, [P], #1
        DoLDRZ  Y
        MEND

        MACRO
        LDAZ
        LDRB    r0, [P], #1
        DoLDRZ  A
        MEND

        MACRO
        LDXZ
        LDRB    r0, [P], #1
        DoLDRZ  X
        MEND

        MACRO
        TAY
        MOVS    Y, A
        DoNext
        MEND

        MACRO
        LDAIM
        LDRB    A, [P], #1
        MOV     A, A, LSL #24
        TEQ     A, #0
        DoNext
        MEND

        MACRO
        TAX
        MOVS    X, A
        DoNext
        MEND

        MACRO
        LDY
        DoA
        DoLDR   Y
        MEND

        MACRO
        LDA
        DoA
        DoLDR   A
        MEND

        MACRO
        LDX
        DoA
        DoLDR   X
        MEND

        MACRO
        MBCS
        B65     CS,CC
        MEND

        MACRO
        LDAIY
        DoIY
        DoLDR   A
        MEND

        MACRO
        LDAI
        DoI
        DoLDR   A
        MEND

        MACRO
        LDYZX
        DoZXzx
        DoLDRzx  Y
        MEND

        MACRO
        LDAZX
        DoZXzx
        DoLDRzx  A
        MEND

        MACRO
        LDXZY
        DoZY
        DoLDRZ  X
        MEND

        MACRO
        CLV
        MVN     r0, #V_bit
        TSTP    r0, pc
        DoNext
        MEND

        MACRO
        LDAAY
        DoAY
        DoLDR   A
        MEND

        MACRO
        TSX
 [ modulespace :LAND: (:LNOT: wrapstack)
        SUB     X, S, MR                ; MR not always aligned
        MOV     X, X, LSL #24           ; Gets rid of &0100 bits
 |
        MOV     X, S, LSL #24           ; Gets rid of &0100 bits
 ]
        TEQ     X, #0
        DoNext
        MEND

        MACRO
        LDYAX
        DoAX
        DoLDR   Y
        MEND

        MACRO
        LDAAX
        DoAX
        DoLDR   A
        MEND

        MACRO
        LDXAY
        DoAY
        DoLDR   X
        MEND

        MACRO
        CPYIM
        LDRB    r0, [P], #1
        CMP65   Y, r0
        DoNext
        MEND

        MACRO
        CMPIX
        DoIX
;;;        LoadByteFNZ r1, r0 - is too big
        LoadByte r1, r0
        CMP65   A, r1
        DoNext
        MEND

        MACRO
        CPYZ
        LDRB    r0, [P], #1
        LDRB    r1, [MR, r0]
        CMP65   Y, r1
        DoNext
        MEND

        MACRO
        CMPZ
        LDRB    r0, [P], #1
        LDRB    r1, [MR, r0]
        CMP65   A, r1
        DoNext
        MEND

        MACRO
        DECZ
        LDRB    r0, [P], #1
        DoDEC
        MEND

        MACRO
        INY
        ADD     Y, Y, #&01000000
        TEQ     Y, #0
        DoNext
        MEND

        MACRO
        CMPIM
        LDRB    r0, [P], #1
        CMP65   A, r0
        DoNext
        MEND

        MACRO
        DEX
        SUB     X, X, #&01000000
        TEQ     X, #0
        DoNext
        MEND

        MACRO
        CPY
        DoA
        LoadByteFNZ r1, r0
        CMP65   Y, r1
        DoNext
        MEND

        MACRO
        CMPB
        DoA
        LoadByteFNZ r1, r0
        CMP65   A, r1
        DoNext
        MEND

        MACRO
        DEC65
        DoA
        DoDEC
        MEND

        MACRO
        MBNE
        B65     NE,EQ
        MEND

        MACRO
        CMPIY
        DoIY
        LoadByteFNZ r1, r0
        CMP65   A, r1
        DoNext
        MEND

        MACRO
        CMPI
        DoI
        LoadByteFNZ r1, r0
        CMP65   A, r1
        DoNext
        MEND

        MACRO
        CMPZX
        DoZXzx
        LDRB    r0, [MR, r0, LSR #24]
        CMP65   A, r0
        DoNext
        MEND

        MACRO
        DECZX
        DoZXzx
        DoDECzx
        MEND

        MACRO
        MNOP
        DoNext
        MEND

        MACRO
        CLD
        BIC     OtherFlags, OtherFlags, #D_bit_6502
        DoNext
        MEND

        MACRO
        CMPAY
        DoAY
        LoadByteFNZ r1, r0
        CMP65   A, r1
        DoNext
        MEND

        MACRO
        PHX
        MOV     r0, X, LSR #24
        Push65  r0
        DoNext
        MEND

        MACRO
        CMPAX
        DoAX
        LoadByteFNZ r1, r0
        CMP65   A, r1
        DoNext
        MEND

        MACRO
        DECAX
        DoAX
        DoDEC
        MEND

        MACRO
        CPXIM
        LDRB    r1, [P], #1
        CMP65   X, r1
        DoNext
        MEND

        MACRO
        SBCIX
        DoIX
        LoadByteFNZ r1, r0
        DoSBC
        MEND

        MACRO
        CPXZ
        LDRB    r0, [P], #1
        LDRB    r1, [MR, r0]
        CMP65   X, r1
        DoNext
        MEND

        MACRO
        SBCZ
        LDRB    r0, [P], #1
        LDRB    r1, [MR, r0]
        DoSBC
        MEND

        MACRO
        INCZ
        LDRB    r0, [P], #1
        DoINC
        MEND

        MACRO
        INX
        ADD     X, X, #&01000000
        TEQ     X, #0
        DoNext
        MEND

        MACRO
        SBCIM
        LDRB    r1, [P], #1
        DoSBC
        MEND

        MACRO
        CPX
        DoA
        LoadByteFNZ r1, r0
        CMP65   X, r1
        DoNext
        MEND

        MACRO
        SBCB
        DoA
        LoadByteFNZ r1, r0
        DoSBC
        MEND

        MACRO
        INC65
        LDRB    r0, [P], #1
        LDRB    r1, [P], #1
        ADD     r0, r0, r1, LSL #8
        DoINC
        MEND

        MACRO
        MBEQ
        B65     EQ,NE
        MEND

        MACRO
        SBCIY
        DoIY
        LoadByteFNZ r1, r0
        DoSBC
        MEND

        MACRO
        SBCI
        DoI
        LoadByteFNZ r1, r0
        DoSBC
        MEND

        MACRO
        SBCZX
        DoZXzx
        LDRB    r1, [MR, r0, LSR #24]
        DoSBC
        MEND

        MACRO
        INCZX
        DoZXzx
        DoINCzx
        MEND

        MACRO
        SED
        ORR     OtherFlags, OtherFlags, #D_bit_6502
        DoNext
        MEND

        MACRO
        SBCAY
        DoAY
        LoadByteFNZ r1, r0
        DoSBC
        MEND

        MACRO
        PLX
        Pull65  X
        MOV     X, X, LSL #24
        TEQ     X, #0
        DoNext
        MEND

        MACRO
        SBCAX
        DoAX
        LoadByteFNZ r1, r0
        DoSBC
        MEND

        MACRO
        INCAX
        DoAX
        DoINC
        MEND

; ********************* Special communication opcodes ************************

        MACRO
        MACCLI
        B       arf_CLI
        LTORG                           ; Dump some data !
        PAD
        MEND

        MACRO
        MACBYTE
        B       arf_Byte
        LTORG                           ; Dump some data !
        PAD
        MEND

        MACRO
        MACWORD
        B       arf_Word
        LTORG                           ; Dump some data !
        PAD
        MEND

        MACRO
        MACWRCH
        B       arf_Wrch
        LTORG                           ; Dump some data !
        PAD
        MEND

        MACRO
        MACRDCH
        B       arf_Rdch
        LTORG                           ; Dump some data !
        PAD
        MEND

        MACRO
        MACFILE
        B       arf_File
        LTORG                           ; Dump some data !
        PAD
        MEND

        MACRO
        MACARGS
        B       arf_Args
        LTORG                           ; Dump some data !
        PAD
        MEND

        MACRO
        MACBGET
        B       arf_BGet
        LTORG                           ; Dump some data !
        PAD
        MEND

        MACRO
        MACBPUT
        B       arf_BPut
        LTORG                           ; Dump some data !
        PAD
        MEND

        MACRO
        MACGBPB
        B       arf_GBPB
        LTORG                           ; Dump some data !
        PAD
        MEND

        MACRO
        MACFIND
        B       arf_Find
        LTORG                           ; Dump some data !
        PAD
        MEND

        MACRO
        MACQUIT
        B       QuitEmulator
        LTORG                           ; Dump some data !
        PAD
        MEND

        MACRO
        MACLANG
 [ haslang :LAND: tube                  ; Only if Tube with bound language
        Push    JV
        GetWS
        BL      BangLanguage
        Pull    JV
        DoNext  NOPAD
        LTORG                           ; Dump some data !
        PAD
 |
        B       ABORT
        PAD
 ]
        MEND

        MACRO
        MACINSV
 [ fullbbc
        B       arf_INSV
        DoNext  NOPAD
        LTORG                           ; Dump some data !
        PAD
 |
        B       ABORT
        PAD
 ]
        MEND

        MACRO
        MACREMV
 [ fullbbc
        B       arf_REMV
        DoNext  NOPAD
        LTORG                           ; Dump some data !
        PAD
 |
        B       ABORT
        PAD
 ]
        MEND

        MACRO
        MACCNPV
 [ fullbbc
        B       arf_CNPV
        DoNext  NOPAD
        LTORG                           ; Dump some data !
        PAD
 |
        B       ABORT
        PAD
 ]
        MEND


        MACRO
        ABORT
        B       ABORT
        LTORG                           ; Dump some data !
        PAD
        MEND


ABORT
 [ True
        SUB     P, P, #1                ; Back to opcode that caused fault
        WRLN    "Unknown opcode "
        BL      DoOpcodeDebug
        B       QuitEmulator
 |
        DoNext  NOPAD                   ; Be a mindless 6502 and NOP it !
                                        ; Strictly we should do variable length
 ]

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Now put all the code in for the 6502 opcodes

; Align to a 4 word position and dealign +4. Affects speed by 7% !?!
; All this is due to MEMC forcing fetches on 16 byte boundary to N cycles

;        ALIGN   16, 4                   ; ??? correct when code frozen
         ALIGN   16, 0

OpcodeTable

last    SETA    .-Module_BaseAddr
spaces  SETA    0
useful  SETA    0
mingap  SETA    1024

        BRK ; 00
        ORAIX
        ABORT
        MACCLI ; 03
 [ cmos
        TSBZ
 |
        ABORT
 ]
        ORAZ
        ASLZ
        ABORT
        PHP
        ORAIM
        ASLA
        ABORT
 [ cmos
        TSB
 |
        ABORT
 ]
        ORA
        ASLB
        ABORT

        assert .-OpcodeTable = &10*spacing

        MBPL ; 10
        ORAIY
 [ cmos
        ORAI
 |
        ABORT
 ]
        MACBYTE ; 13
 [ cmos
        TRBZ
 |
        ABORT
 ]
        ORAZX
        ASLZX
        ABORT
        CLC65
        ORAAY
 [ cmos
        INCA
 |
        ABORT
 ]
        ABORT
 [ cmos
        TRB
 |
        ABORT
 ]
        ORAAX
        ASLAX
        ABORT

        assert .-OpcodeTable = &20*spacing

        JSR ; 20
        ANDIX
        ABORT
        MACWORD ; 23
        BITZ
        ANDZ
        ROLZ
        ABORT
        PLP65
        ANDIM
        ROLA
        ABORT
        BIT
        ANDB
        ROLB
        ABORT

        assert .-OpcodeTable = &30*spacing

        MBMI ; 30
        ANDIY
 [ cmos
        ANDI
 |
        ABORT
 ]
        MACWRCH ; 33
 [ cmos
        BITZX
 |
        ABORT
 ]
        ANDZX
        ROLZX
        ABORT
        SEC65
        ANDAY
 [ cmos
        DECA
 |
        ABORT
 ]
        ABORT
 [ cmos
        BITAX
 |
        ABORT
 ]
        ANDAX
        ROLAX
        ABORT

        assert .-OpcodeTable = &40*spacing

        RTI ; 40
        EORIX
        ABORT
        MACRDCH ; 43
        ABORT
        EORZ
        LSRZ
        ABORT
        PHA
        EORIM
        LSRA
        ABORT
        JMP
        EORB
        LSRB
        ABORT

        assert .-OpcodeTable = &50*spacing

        MBVC ; 50
        EORIY
 [ cmos
        EORI
 |
        ABORT
 ]
        MACFILE ; 53
        ABORT
        EORZX
        LSRZX
        ABORT
        CLI
        EORAY
 [ cmos
        PHY
 |
        ABORT
 ]
        ABORT
        ABORT
        EORAX
        LSRAX
        ABORT

        assert .-OpcodeTable = &60*spacing

        RTS ; 60
        ADCIX
        ABORT
        MACARGS ; 63
 [ cmos
        CLRZ
 |
        ABORT
 ]
        ADCZ
        RORZ
        ABORT
        PLA
        ADCIM
        RORA
        ABORT
        JMI
        ADCB
        RORB
        ABORT

        assert .-OpcodeTable = &70*spacing

        MBVS ; 70
        ADCIY
 [ cmos
        ADCI
 |
        ABORT
 ]
        MACBGET ; 73
 [ cmos
        CLRZX
 |
        ABORT
 ]
        ADCZX
        RORZX
        ABORT
        SEI
        ADCAY
 [ cmos
        PLY
 |
        ABORT
 ]
        ABORT
 [ cmos
        JMIX
 |
        ABORT
 ]
        ADCAX
        RORAX
        ABORT

        assert .-OpcodeTable = &80*spacing

 [ cmos
        BRA ; 80
 |
        ABORT
 ]
        STAIX
        ABORT
        MACBPUT ; 83
        STYZ
        STAZ
        STXZ
        ABORT
        DEY
 [ cmos
        BITIM
 |
        ABORT
 ]
        TXA
        ABORT
        STY
        STA
        STX
        ABORT

        assert .-OpcodeTable = &90*spacing

        MBCC ; 90
        STAIY
 [ cmos
        STAI
 |
        ABORT
 ]
        MACGBPB ; 93
        STYZX
        STAZX
        STXZY
        ABORT
        TYA
        STAAY
        TXS
        ABORT
 [ cmos
        CLR
 |
        ABORT
 ]
        STAAX
 [ cmos
        CLRAX
 |
        ABORT
 ]
        ABORT

        assert .-OpcodeTable = &A0*spacing

        LDYIM ; A0
        LDAIX
        LDXIM
        MACFIND ; A3
        LDYZ
        LDAZ
        LDXZ
        ABORT
        TAY
        LDAIM
        TAX
        ABORT
        LDY
        LDA
        LDX
        ABORT

        assert .-OpcodeTable = &B0*spacing

        MBCS ; B0
        LDAIY
 [ cmos
        LDAI
 |
        ABORT
 ]
        MACQUIT ; B3
        LDYZX
        LDAZX
        LDXZY
        ABORT
        CLV
        LDAAY
        TSX
        ABORT
        LDYAX
        LDAAX
        LDXAY
        ABORT

        assert .-OpcodeTable = &C0*spacing

        CPYIM ; C0
        CMPIX
        ABORT
        MACLANG ; C3
        CPYZ
        CMPZ
        DECZ
        ABORT
        INY
        CMPIM
        DEX
        ABORT
        CPY
        CMPB
        DEC65
        ABORT

        assert .-OpcodeTable = &D0*spacing

        MBNE ; D0
        CMPIY
 [ cmos
        CMPI
 |
        ABORT
 ]
        MACINSV ; D3
        ABORT
        CMPZX
        DECZX
        ABORT
        CLD
        CMPAY
 [ cmos
        PHX
 |
        ABORT
 ]
        ABORT
        ABORT
        CMPAX
        DECAX
        ABORT

        assert .-OpcodeTable = &E0*spacing

        CPXIM ; E0
        SBCIX
        ABORT
        MACREMV ; E3
        CPXZ
        SBCZ
        INCZ
        ABORT
        INX
        SBCIM
        MNOP
        ABORT
        CPX
        SBCB
        INC65
        ABORT

        assert .-OpcodeTable = &F0*spacing

        MBEQ ; F0
        SBCIY
 [ cmos
        SBCI
 |
        ABORT
 ]
        MACCNPV ; F3
        ABORT
        SBCZX
        INCZX
        ABORT
        SED
        SBCAY
 [ cmos
        PLX
 |
        ABORT
 ]
        ABORT
        ABORT
        SBCAX
        INCAX
        ABORT

        assert .-OpcodeTable = &100*spacing

 ! 0, (:STR:(spaces)):CC:" bytes not used"
 ! 0, (:STR:(useful)):CC:" bytes fillable"
 ! 0, "Smallest gap is ":CC:(:STR:(mingap))

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Deal with 'special' 6502 instructions to do OS interface

; These are allowed to cause errors which we catch with our handler

; Out   wp valid
;       C,V Flags MUST be preserved if calling REMV etc.

EMUMOS ROUT

        SUB     r0, P, MR               ; Executing OS when special
                                        ; instruction found ?
 [ fullbbc
        CMP     r0, #&8000              ; Permit funnies in sideways ROMS
                                        ; so we can do 'ARFS: the fool system'
        BLO     ABORT                   ; 'Unknown' if outside OS
 |
        ADRL    r1, OSOrigin            ; Only permit funnies in MOS code
        LDR     r1, [r1]

        CMP     r0, r1
        BLO     ABORT                   ; 'Unknown' if outside OS
 ]

 [ modulespace
        LDR     r0, =emulatorspaceoffset - saveArea
        SUB     r0, MR, r0              ; Way out of ADR range nowadays
 |
        GetWS   r0
        ADD     r0, r0, #saveArea
 ]
                                        ; Save state in case of error in call
        STMIA   r0, {r4-r12}            ; or Exit from cli call.
                                        ; Now use as temps for calling OS

        MOV     r0, A, LSR #24
        MOV     r1, X, LSR #24
        MOV     r2, Y, LSR #24

        GetWS                           ; r12 := wp

        MOVS    pc, lr                  ; Flags are important on entry !

 [ fullbbc
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

arf_INSV BL      EMUMOS
        MOV     r9, #INSV
        SWI     XOS_CallAVector
        B       RETMOS

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

arf_REMV BL      EMUMOS
        MOV     r9, #REMV
        SWI     XOS_CallAVector
        B       RETMOS

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

arf_CNPV BL      EMUMOS
        MOV     r9, #CNPV
        SWI     XOS_CallAVector
        B       RETMOS
 ]

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

arf_Wrch BL      EMUMOS
        SWI     OS_WriteC

; .............................................................................
; In    wp valid
;       Flags valid too !

RETMOS  ADD     r14, wp, #saveArea      ; Restore state
        LDMIA   r14, {r4-r12}           ; r12 := JV

        MOV     A, r0, LSL #24          ; NB. You better had make sure r0-r2
        MOV     X, r1, LSL #24          ; are really ok when this gets executed
        MOV     Y, r2, LSL #24

Execute6502
        DoNext  NOPAD                   ; Continue 6502 code execution

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

arf_Rdch BL      EMUMOS
        SWI     OS_ReadC
        B       RETMOS

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

arf_Word ROUT

        BL      EMUMOS
        Push    "r1"                    ; Preserve 6502 X

        ADD     r1, r1, r2, LSL #8      ; 6502 cb^

 [ debug
        LDR     r14, [wp, #debuglevel]
        TST     r14, #debug_word
        BEQ     %FT00

        DREG    r0,"OSWord ",cc,Byte
        DREG    r1," cb^ ",,Word
00
 ]
        ADD     r1, r1, MR              ; Real ARM cb^
        TEQ     r0, #0
        BEQ     MOSRDLN

; Now frig for MrFusion

        TEQ     r0, #&10
        BEQ     FudgeOSWord10
        TEQ     r0, #&11
        BEQ     FudgeOSWord11

        SWI     OS_Word                 ; Preserves r2 (6502 Y)


RETMOS_X
        Pull    "r1"                    ; Restore 6502 X
        B       RETMOS


MOSRDLN MOV     r4, r1
        LDRB    r0, [r4, #0]
        LDRB    r1, [r4, #1]
        ADD     r0, r0, r1, LSL #8      ; 6502 buffer^
 [ debug
        LDR     r14, [wp, #debuglevel]
        TST     r14, #debug_word
        BEQ     %FT00

        DREG    r0,"ReadLine 6502 buffer^ ",,Word
00
 ]
        ADD     r0, r0, MR              ; Real ARM buffer^
        LDRB    r1, [r4, #2]
        LDRB    r2, [r4, #3]
        LDRB    r3, [r4, #4]
        SWI     OS_ReadLine
        MOV     r2, r1                  ; 6502 Y := length read
        MOV     r0, #0                  ; 6502 A := 0
        B       RETMOS_X


FudgeOSWord10 ; Transmit OSWord

        ADD     r3, r1, #4
        BL      AddMRToMemory
        ADD     r3, r1, #8
        BL      AddMRToMemory

        SWI     OS_Word

        ADD     r3, r1, #4
        BL      SubMRFromMemory
        ADD     r3, r1, #8
        BL      SubMRFromMemory
        B       RETMOS_X


FudgeOSWord11 ; Receive OSWord

        ADD     r3, r1, #5
        BL      AddMRToMemory
        ADD     r3, r1, #9
        BL      AddMRToMemory

        SWI     OS_Word

        ADD     r3, r1, #5
        BL      SubMRFromMemory
        ADD     r3, r1, #9
        BL      SubMRFromMemory
        B       RETMOS_X

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; In    r3 = core^

AddMRToMemory ENTRY "r0"

        LDRB    r0,  [r3, #0]
        LDRB    r14, [r3, #1]
        ORR     r0, r0, r14, LSL #8
        LDRB    r14, [r3, #2]
        ORR     r0, r0, r14, LSL #16
        LDRB    r14, [r3, #3]
        ORR     r0, r0, r14, LSL #24

        ADD     r0, r0, MR

        STRB    r0, [r3, #0]
        MOV     r0, r0, ROR #8
        STRB    r0, [r3, #1]
        MOV     r0, r0, ROR #8
        STRB    r0, [r3, #2]
        MOV     r0, r0, ROR #8
        STRB    r0, [r3, #3]
        EXITS

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; In    r3 = core^

SubMRFromMemory ENTRY "r0"

        LDRB    r0,  [r3, #0]
        LDRB    r14, [r3, #1]
        ORR     r0, r0, r14, LSL #8
        LDRB    r14, [r3, #2]
        ORR     r0, r0, r14, LSL #16
        LDRB    r14, [r3, #3]
        ORR     r0, r0, r14, LSL #24

        SUB     r0, r0, MR

        STRB    r0, [r3, #0]
        MOV     r0, r0, ROR #8
        STRB    r0, [r3, #1]
        MOV     r0, r0, ROR #8
        STRB    r0, [r3, #2]
        MOV     r0, r0, ROR #8
        STRB    r0, [r3, #3]
        EXITS

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Trap certain OS_Bytes here

arf_Byte ROUT

        BL      EMUMOS
        Push    r0                      ; Save 6502 A

 [ debug
        LDR     r14, [wp, #debuglevel]
        TST     r14, #debug_byte
        BEQ     %FT00

        DREG    r0,"OS_Byte ",cc,Byte
        DREG    r1,,,Byte
        DREG    r2,,,Byte
00
 ]

 [ fullbbc :LAND: False ; Emulator now handles slow bus hardware for kbd scan
        TEQ     r0, #&79                ; Scan keyboard ?
        BNE     %FT10
        CMP     r1, #&82                ; INKEY or CTRL/SHIFT ?
        BLO     %FT15
        CMP     r1, #&90                ; Bottom row ?
        BHS     %FT15
  [ True
        LDR     r1, [wp, #wpvar_osbytevars_pB0] ; Read Arthur fx255 options
        LDRB    r1, [r1, #&FF-&B0]
        EOR     r1, r1, #&FF            ; 0 in option -> keyboard option 'set'
  |
        MOV     r1, #&00                ; All keyboard options 'set' (ie open)
                                        ; MODE 7, NoBoot, DFS preference, SLOW
  ]
        B       %FT20
10
 ]

 [ fullbbc :LAND: False ; Emulator now copes with Video ULA programming
        TEQ     r0, #154                ; Write Video ULA CR ?
        BEQ     %FA60
 ]

        TEQ     r0, #&A0                ; Read VDU Vars ?
        TEQEQ   r1, #&55                ; Read MODE number ?
        BEQ     %FT40

        TEQ     r0, #163                ; Emulator OS_Byte ?
        TEQEQ   r1, #243
        BEQ     %FT30


15 ; Call OS_Byte, but absorb 'Bad Command' errors (eg. no I/O_Podule present)

        SWI     XOS_Byte


20 ; Common exit

 [ debug
        Push    pc                      ; C,V flags matter here
        LDR     r14, [wp, #debuglevel]
        TST     r14, #debug_byte
        BEQ     %FT00

        DREG    r1,": returns ",cc,Byte
        DREG    r2,,,Byte
00
        Pull    lr
        TEQP    lr, #0
 ]
        Pull    r0, VC                  ; Restore 6502 A, VClear
        BVC     RETMOS

        LDR     r14, [r0]
        TEQ     r14, #ErrorNumber_BadCommand
        Pull    r0, EQ                  ; Restore 6502 A, VSet still
        BEQ     RETMOS

        SWI     OS_GenerateError        ; Raise error to ourselves



30 ; Emulator OS_Byte

        TEQ     r2, #6                  ; Reading address of star command ?
        LDREQB  r1,  [wp, #whereIsStar+0] ; YX := star command address
        LDREQB  r2,  [wp, #whereIsStar+1]
        MOVEQ   r14, #0                 ; Clear: just one chance to read it
        STREQ   r14, [wp, #whereIsStar]
        BEQ     %BT20

        TEQ     r2, #4                  ; Reading startup address of code ?
        LDREQB  r1,  [wp, #whereToExecuteIt+0] ; YX := code address
        LDREQB  r2,  [wp, #whereToExecuteIt+1]
        MOVEQ   r14, #0                 ; Clear: just one chance to read it
        STREQ   r14, [wp, #whereToExecuteIt]
                                        ; Do NOT clear lastWhereToExecuteIt
        B       %BT20                   ; Other ones we claim, but ignore


40      MOV     r0, #&87                ; Do proper MODE number read
        SWI     XOS_Byte                ; (helps ViewSpell)
        MOV     r1, r2
        MOV     r2, #0                  ; &356 = mode map type
        B       %BT20


 [ fullbbc :LAND: False ; Emulator now copes with Video ULA programming
60 ; OS_Byte 154 - Write Video ULA + soft copy

        Push    "r1, r2"
        LDR     r2, [wp, #wpvar_osbytevars_pB0] ; Arthur address of OSByte &B0
        STRB    r1, [r2, #&B8-&B0]      ; Update Video ULA CReg soft copy

        LDR     r0, =&FE20              ; Bash Video ULA CReg with r1b
        BL      WriteIO

        LDRB    r1, [r2, #&C2-&B0]      ; Read mark value
        STRB    r1, [r2, #&C1-&B0]      ; Write flash counter with that

        Pull    "r1, r2"
        B       %BT20
 ]

        LTORG

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Translate a register from 6502 address to ARM address
; Need to wrap IO processor addresses if Host

        MACRO
        Translate $reg, $cond
 [ fullbbc
        MOV$cond $reg, $reg, LSL #16    ; New one due to NDR/SKS
        ADD$cond $reg, MR, $reg, LSR #16
 |
        ADD$cond $reg, $reg, MR
 ]
        MEND


arf_File ROUT

        BL      EMUMOS
        Push    "r1, r2"                ; Preserve 6502 X,Y

        ADD     r3, r1, r2, LSL #8      ; 6502 cb^. Use r3 so we can debug
        ADD     r6, r3, MR              ; Real ARM cb^

        LDRB    r1, [r6]
        LDRB    r2, [r6, #1]
        ADD     r1, r1, r2, LSL #8      ; 6502 name^
        ADD     r1, r1, MR              ; Real ARM name^

 [ debug
        LDR     r14, [wp, #debuglevel]
        TST     r14, #debug_file
        BEQ     %FT00

        DREG    r0,"6502 OSFile ",cc,Byte
        DREG    r3," cb^ ",cc,Word
        SWI     XOS_WriteI+space
        BL      writes
00
 ]

        MOV     r5, #17
10      LDRB    r4, [r6, r5]
        STRB    r4, [sp, #-1]!
        SUB     r5, r5, #1
        CMP     r5, #1
        BNE     %BT10

        LDMFD   sp!, {r2, r3, r4, r5}
 [ debug
        LDR     r14, [wp, #debuglevel]
        TST     r14, #debug_file
        BEQ     %FT00

        DREG    r2,", r2 ",cc,Word
        DREG    r3,", r3 ",cc,Word
        DREG    r4,", r4 ",cc,Word
        DREG    r5,", r5 ",,Word
00
 ]


        TEQ     r0, #OSFile_Load        ; Do our own remapping: LOAD
        BNE     %FT30

        TST     r3, #&FF                ; Load at own ?
        Translate r2, EQ                ; LOAD: Load (given) address += MR
        BEQ     %FT40

        MOV     r0, #OSFile_ReadInfo    ; Read info and translate
        SWI     OS_File
        Translate r2                    ; LOAD: Load (own) address += MR
        MOV     r0, #OSFile_Load
        MOV     r3, #0                  ; Force load at given

30      TEQ     r0, #OSFile_Save        ; Do our own remapping: SAVE
        Translate r4, EQ                ; SAVE: Start address += MR
        Translate r5, EQ                ; SAVE: End address += MR

40
 [ debug
        LDR     r14, [wp, #debuglevel]
        TST     r14, #debug_file
        BEQ     %FT00

        DREG    r0,"ARM OSFile ",cc,Byte
        DREG    r2,", r2 ",cc,Word
        DREG    r3,", r3 ",cc,Word
        DREG    r4,", r4 ",cc,Word
        DREG    r5,", r5 ",cc,Word
        SWI     XOS_WriteI+space
        BL      writeln
00
 ]
        SWI     OS_File
        STMFD   sp!, {r2, r3, r4, r5}

        MOV     r5, #2
80      LDRB    r4, [sp], #1
        STRB    r4, [r6, r5]            ; r6 was preserved over call
        ADD     r5, r5, #1
        TEQ     r5, #18
        BNE     %BT80

RETMOS_XY
        Pull    "r1, r2"                ; Restore 6502 X,Y
        B       RETMOS

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

arf_Find ROUT

        BL      EMUMOS
        Push    "r1"                    ; Preserve 6502 X

        TEQ     r0, #0
        MOVEQ   r1, r2                  ; If CLOSE#Y then r1 := Y
        ADDNE   r1, r1, r2, LSL #8      ; 6502 name^
        ADDNE   r1, r1, MR              ; Real ARM name^

 [ debug
        LDR     r14, [wp, #debuglevel]
        TST     r14, #debug_find
        BEQ     %FT00

        DREG    r0,"OSFind ",cc,Byte
        CMP     r0, #0                  ; CLOSE op ?
        SWINE   XOS_WriteI+space
        BLNE    writes
        SWI     XOS_NewLine
00
 ]
        SWI     OS_Find

        B       RETMOS_X

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

arf_Args ROUT

        BL      EMUMOS
        Push    "r1"                    ; Preserve 6502 X

        TEQ     r0, #0                  ; A=0 ?
        TEQEQ   r2, #0                  ; and Y=0 ?
        BEQ     READFS                  ; -> reading filing system number

        LDRB    r3, [r1, MR]!
        LDRB    r4, [r1, #1]
        ORR     r3, r3, r4, LSL #8
        LDRB    r4, [r1, #2]
        ORR     r3, r3, r4, LSL #16
        LDRB    r4, [r1, #3]
        MOV     r1, r2                  ; r1 is handle
        ORR     r2, r3, r4, LSL #24     ; r2 is data

 [ debug
        LDR     r14, [wp, #debuglevel]
        TST     r14, #debug_args
        BEQ     %FT00

        DREG    r0,"OSArgs ",cc,Byte
        DREG    r1,,,Byte
        DREG    r2
00
 ]
        SWI     OS_Args

 [ debug
        LDR     r14, [wp, #debuglevel]
        TST     r14, #debug_args
        BEQ     %FT00

        DREG    r0,": returns ",cc,Byte
        DREG    r2
00
 ]
        MOV     r3, r2                  ; new data
        MOV     r2, r1                  ; handle
        LDR     r1, [sp]                ; Restore X (leave on stack)
        STRB    r3, [r1, MR]!
        MOV     r3, r3, LSR #8
        STRB    r3, [r1, #1]
        MOV     r3, r3, LSR #8
        STRB    r3, [r1, #2]
        MOV     r3, r3, LSR #8
        STRB    r3, [r1, #3]

        B       RETMOS_X


READFS  MOV     r1, #0
        SWI     OS_Args

        B       RETMOS_X

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

arf_BGet ROUT

        BL      EMUMOS

 [ debug
        LDR     r14, [wp, #debuglevel]
        TST     r14, #debug_bget
        BEQ     %FT00

        DREG    r0,"OSBGet ",cc,Byte
        DREG    r2," handle ",,Byte
00
 ]
        Push    "r1"                    ; Preserve 6502 X
        MOV     r1, r2
        SWI     OS_BGet

        B       RETMOS_X

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

arf_BPut ROUT

        BL      EMUMOS

 [ debug
        LDR     r14, [wp, #debuglevel]
        TST     r14, #debug_bput
        BEQ     %FT00

        DREG    r0,"OSBPut ",cc,Byte
        DREG    r2," handle ",,Byte
00
 ]
        Push    "r1"                    ; Preserve 6502 X
        MOV     r1, r2
        SWI     OS_BPut

        B       RETMOS_X

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

arf_GBPB ROUT

        BL      EMUMOS
        Push    "r1, r2"                ; Preserve 6502 X,Y

        ADD     r3, r1, r2, LSL #8      ; 6502 cb^. Use r3 so we can debug
        ADD     r8, r3, MR              ; Real ARM cb^

        MOV     r5, #16+4               ; One more in than out !
MOSGP1  LDRB    r4, [r8, r5]
        STRB    r4, [sp, #-1]!
        SUBS    r5, r5, #1
        BNE     MOSGP1
        LDMFD   sp!, {r2, r3, r4, r5, r6}

        Translate r2                    ; Data pointer += MR
        CMP     r0, #OSGBPB_ReadDirEntries
        LDRLOB  r1, [r8]                ; r1 = handle if not a wierd op
        MOVHS   r1, r5
        Translate r1, HS                ; r1 is optional dirname^ for fudge
        MOVHS   r5, #&100               ; I know what calls get up here
        Translate r6, HS                ; r6 is optional wildpattern^
 [ debug
        LDR     r14, [wp, #debuglevel]
        TST     r14, #debug_gbpb
        BEQ     %FT00

        DREG    r0,"OSGBPB ",cc,Byte
        DREG    r1,,cc
        DREG    r2,,cc
        DREG    r3,,cc
        DREG    r4,,cc
        DREG    r5,,cc
        DREG    r6
00
 ]
        SWI     OS_GBPB
        SUB     r2, r2, MR              ; Remap data pointer after xfer

        STMFD   sp!, {r2, r3, r4}
        MOV     r5, #1                  ; cb+1..13 copied back
MOSGP2  LDRB    r4, [sp], #1
        STRB    r4, [r8, r5]
        ADD     r5, r5, #1
        TEQ     r5, #12+1
        BNE     MOSGP2

        B       RETMOS_XY

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; CLI - the difficult one ! Don't stack anything as it makes life easier

arf_CLI ROUT

        BL      EMUMOS

        ADD     r0, r1, r2, LSL #8      ; 6502 string^. Do before r1,r2 corrupt
        ADD     r0, r0, MR              ; Real ARM string^

 [ debug
        LDR     r14, [wp, #debuglevel]
        TST     r14, #debug_cli
        BEQ     %FT00

        DLINE   "OSCLI ",cc
        MOV     r1, r0
        BL      writeln
00
 ]

 [ tube
        BL      LinkOntoFSVectors       ; Catch unrecognised *commands
 ]
        SWI     XOS_CLI                 ; Do the command ...
        BVC     %FT50

        LDR     r14, [r0]               ; Had we gone *fx 17 or summats ?
        CMP     r14, #ErrorNumber_BadCommand ; If so, ignore. VClear
        SWINE   OS_GenerateError        ; If not, raise error to ourseleves

50 ; OS_CLI returned ok

 [ tube
        BL      DelinkFromFSVectors
 ]
        BL      SetNewHandlers          ; Total paranoia

 [ fullbbc
        B       RETMOS                  ; Never run anything from external CLI
 |
        LDR     r0, [wp, #whereToExecuteIt] ; Running code from this cli call ?
        TEQ     r0, #0
        BEQ     RETMOS

  [ debug
        LDR     r14, [wp, #debuglevel]
        TST     r14, #debug_startup
        BEQ     %FT00

        WRLN    "Entering new code"
00
  ]
        ADD     r14, wp, #saveArea      ; Restore state
        LDMIA   r14, {r4-r12}           ; r12 := JV

        ADD     r0, MR, #&10000         ; Fetch RUN handler addr from
        LDR     r0, [r0, #-8]           ; &FFFA,B (old NMI)
        ADD     P, MR, r0, LSR #16      ; Tutu is sick !

        B       Execute6502             ; Commence new 6502 code execution
 ]

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Exit 'opcode' executed - leave emulator

QuitEmulator ROUT

        GetWS                           ; r12 := wp
        BL      PrepareToExit

 [ False ; I hate this message ...
        LDRB    r14, [wp, #hadStarCommand]
        TEQ     r14, #0
        BNE     %FT90                   ; If had *command to start, keep quiet

        SWI     OS_WriteS
        DCB     "Leaving 6502 emulator", LF,CR, 0
        ALIGN
90
 ]
        SWI     OS_Exit

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

        LNK     EmuDebug
