        TTL     => Kernel : SWI Despatch, simple SWIs

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; essential headers
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

        GET     &.Hdr.ListOpts
        GET     &.Hdr.Macros
        GET     &.Hdr.System

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; essential global variables
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                    GET   Time+Date
                    GBLS  VersionNo
VersionNo           SETS  "2.00 ($CurrentDate)" ; " DEVELOPMENT VERSION"

                    GBLS  SystemName
SystemName          SETS  "RISC OS" ; ", p.k.a. Arthur a.k.a. Richard III"

                    GBLS  MosTitle
MosTitle            SETS  "$SystemName $VersionNo"

                    GBLL  AddTubeBashers
AddTubeBashers      SETL  1=0

UserMemStart        * &8000

                    GBLL  ExceptionsAreErrors
ExceptionsAreErrors SETL  1=1

AssemblingArthur    SETL  {TRUE}
; defined in hdr.system to allow conditionals in macros

                    GBLL  DoingVdu
DoingVdu            SETL  {FALSE}       ; so can get KeyWS!
                    GBLL  Module
Module              SETL  {FALSE}

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; now the conditional flags for the version we want
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

     GBLL Fix0
Fix0 SETL {FALSE}
     [ Fix0
     ! 0, "Fix0: no padding of the startup message"
     ]

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; now get the headers
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

        GET     &.Hdr.Heap
        GET     &.Hdr.NewSpace
        GET     &.Hdr.Services
        GET     &.Hdr.NewErrors
        GET     &.Hdr.Proc
        GET     &.Hdr.File
        GET     &.Hdr.Sprite
        GET     &.Hdr.KeyWS
        GET     &.Hdr.RS423
        GET     &.Hdr.ModHand
        GET     &.Hdr.Variables
        GET     &.Hdr.EnvNumbers
        GET     &.Hdr.Sound
        GET     &.Hdr.Podule
        GET     &.Hdr.VduExt
        GET     Source.PMF.DEF          ; Common with 6502 code in the keyboard
        Protocol

        SUBT    Arthur Variables
        OPT     4

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; handy macros:
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

         MACRO
$l       CheckSpaceOnStack   $space, $faildest, $tmp
 [ True ; SKS
$l      MOV     $tmp, sp, LSR #15       ; Stack base on 32K boundary
        SUB     $tmp, sp, $tmp, LSL #15 ; Amount of stack left
        CMP     $tmp, #$space           ; Must have at least this much left
        BMI     $faildest
 |
$l       MOV        $tmp, #32*1024   ; assume stack ends at next 32K boundary
         SUB        $tmp, $tmp, #1
         AND        $tmp, $tmp, stack
         CMP        $tmp, #$space
         BLT        $faildest
 ]
         MEND

        MACRO
        assert  $condition
 [ :LNOT: ($condition)
 ! 1,"Assert failed: $condition"
 ]
        MEND

; one that builds a module command table entry:
; set Module_BaseAddr to module base before use.

                GBLA    Module_BaseAddr
Module_BaseAddr SETA    0

;        Command $cmd, $max, $min   - declared in hdr.macros.

; debug macro: set the border colour

      MACRO
$l    SetBorder  $reg1, $reg2, $red, $green, $blue
  ! 0, "Setborder used"
$l    LDR        $reg1, =VIDCADR
      LDR        $reg2, =&40000000+ $red + $green *16 + $blue *256
      STR        $reg2, [$reg1]
      MEND

    [ AddTubeBashers
DebugTUBE  * &03340000+1*&4000         ; tube in podule #1
; Tube register offsets
 ^ 0
R1STAT # 4
R1DATA # 4
   ]

; routine to stuff a char down the Tube
; should be inside above conditional, but AAsm winges pitifully.
     MACRO
$l   TubeChar $reg1, $reg2, $charset, $stackthere
  !  0, "TubeChar used."
$l
   [ "$stackthere"=""
   Push "$reg1, $reg2"
   ]
     LDR  $reg1, =DebugTUBE
01   LDRB $reg2, [$reg1, #R1STAT]
     TST $reg2, #&40
     BEQ %BT01
     $charset
     STRB $reg2, [$reg1, #R1DATA]
   [ "$stackthere"=""
   Pull "$reg1, $reg2"
   ]
     MEND

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Various constants
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

MinAplWork * 40*1024         ; minimum size of AplWork

; Fixed addresses

PHYSICAL * &2000000
IOCADR   * &3200000
VIDCADR  * &3400000
MEMCADR  * &3600000
ROM      * &3800000
OSMD     * &11111111

; Manifests

CR * 13
LF * 10

; Registers

SPIRQ RN R13

; Callback byte bits:
CBack_OldStyle  * 1
CBack_Postpone  * 2
CBack_VectorReq * 4


        SUBT    Arthur Code
        OPT     4

; *****************************************************************************
;
;  Now ready to start the code: off we go!
;
; *****************************************************************************

        ORG     ROM

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; The bit to copy to 0 - has to be at start of ROM.

        B       CONT+ROM
        LDR     PC, UndHan+ROM
        B       SVC+ROM
        LDR     PC, PAbHan+ROM
        LDR     PC, DAbHan+ROM
        LDR     PC, AdXHan+ROM
        B       IRQ_Test_CTRL_or_R_Pressed+ROM
        MOV     R10, #IOC               ; we dunno what to do with it -
                                        ; so cut it off - right off!
        STRB    R10, [R10, #IOCFIQMSK]  ; :LSB: IOC = 0
        SUBS    PC, R14, #4
EndFiq

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Now some initialised workspace/vectors that go at &100

        ASSERT IRQ1V = &100
        & DefaultIRQ1V

        ASSERT ESC_Status = IRQ1V+4
        & &00FF0000       ; IOCControl set to FF on reset

        ASSERT IRQsema = ESC_Status+4
        & 0
EndData

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI return handler: checks callback

SVCDespatcher ROUT

SWIRelocation * SVCDespatcher-SWIDespatch

SLVK_SetV * {PC}-SWIRelocation

        ORR     lr, lr, #V_bit

SLVK_TestV * {PC}-SWIRelocation
 ! 0,"SLVK_TestV at ":CC:(:STR:SLVK_TestV)

        ORRVS   lr, lr, #V_bit

SLVK * {PC}-SWIRelocation
 ! 0,"SLVK       at ":CC:(:STR:SLVK)      

        Pull    r11
        TST     lr, #V_bit
        BNE     %FT50

SWIReturn * {PC}-SWIRelocation
 ! 0,"SWIReturn  at ":CC:(:STR:SWIReturn)

40      MOV     r10, #0
        LDRB    r11, [r10, #CallBack_Flag]
        CMP     r11, #0
        Pull    "r10-r12", EQ
        MOVEQS  pc, lr

        B       callback_checking + SWIRelocation


 ! 0,"VSetReturn at ":CC:(:STR:({PC}-SWIRelocation))
50      TST     r11, #Auto_Error_SWI_bit
        BNE     %BT40

        B       VSet_GenerateError + SWIRelocation

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; The SWI Despatch routine

SVC * {PC}-SWIRelocation

        Push    "r10-r12"

        BIC     r12, r14, #ARM_CC_Mask
        LDR     r11, [r12, #-4]
        BIC     r11, r11, #&FF000000
        Push    r11
        BICS    r11, r11, #Auto_Error_SWI_bit
        BEQ     SWIWriteC + SWIRelocation

        ORR     r10, r14, #SVC_mode
        TEQP    r10, #0                 ; restore caller's IRQ state

        CMP     r11, #OS_BreakPt
        CMPNE   r11, #OS_CallAVector
        BICNE   r14, r14, #V_bit        ; clear V unless BreakPoint/CallVector

        CMP     r11, #OS_WriteI
        LDRCC   pc, [pc, r11, LSL #2]

        B       NotMainMOSSwi + SWIRelocation

 ASSERT {PC}-SVCDespatcher = SWIDespatch_Size

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; The SWI table

JTABLE  & SWIWriteC             ; this entry never gets used (see ^)
        & SWIWriteS
        & SWIWrite0
        & SWINewLine

; next section is one where VectorNumber = SWINumber
        & VecSwiDespatch        ; readc
        & VecSwiDespatch        ; cli
        & NoIrqVecSwiDespatch   ; byte
        & NoIrqVecSwiDespatch   ; word
        & VecSwiDespatch        ; file
        & VecSwiDespatch        ; args
        & BGetSWI               ; bget
        & BPutSWI               ; bput
        & VecSwiDespatch        ; gbpb
        & VecSwiDespatch        ; find
        & VecSwiDespatch        ; readline

        & SCTRL
        & SWI_GetEnv_Code
        & SEXIT
        & SSTENV
        & SINTON
        & SINTOFF
        & SCALLB
        & SENTERSWI
        & SBRKPT
        & SBRKCT
        & SUNUSED
        & SSETMEMC
        & SSETCALL
        & VecMouse
        & HeapEntry
        & ModuleHandler
        & ClaimVector_SWICode
        & ReleaseVector_SWICode
        & ReadUnsigned_Routine
        & GenEvent
        & ReadVarValue
        & SetVarValue
        & GSINIT
        & GSREAD
        & GSTRANS
        & CvtToDecimal
        & FSControlSWI
        & ChangeDynamicSWI
        & GenErrorSWI
        & ReadEscapeSWI
        & ReadExpression
        & SwiSpriteOp
        & SWIReadPalette
        & Issue_Service_SWI
        & SWIReadVduVariables
        & SwiReadPoint
        & DoAnUpCall
        & CallAVector_SWI
        & SWIReadModeVariable
        & SWIRemoveCursors
        & SWIRestoreCursors
        & SWINumberToString_Code
        & SWINumberFromString_Code
        & ValidateAddress_Code
        & CallAfter_Code
        & CallEvery_Code
        & RemoveTickerEvent_Code
        & InstallKeyHandler
        & SWICheckModeValid
        & ChangeEnvironment
        & SWIClaimScreenMemory
        & ReadMetroGnome
        & XOS_SubstituteArgs_code
        & XOS_PrettyPrint_code
        & SWIPlot
        & SWIWriteN
        & Add_ToVector_SWICode
        & WriteEnv_SWICode
        & RdArgs_SWICode
        & ReadRAMFSLimits_Code
        & DeviceVector_Claim
        & DeviceVector_Release
        & Application_Delink
        & Application_Relink
        & HeapSortRoutine
        & TerminateAndSodOff
        & ReadMemMapInfo_Code
        & ReadMemMapEntries_Code
        & SetMemMapEntries_Code
        & AddCallBack_Code
        & ReadDefaultHandler
        & SWISetECFOrigin
        & SerialOp
        & ReadSysInfo_Code
        & Confirm_Code
        & SWIChangedBox
        & CRC_Code
        & ReadDynamicArea
        & SWIPrintChar

MaxSwi * (.-JTABLE)/4

 ASSERT MaxSwi < OS_ConvertStandardDateAndTime

; SWIs for time/date conversion are poked in specially

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; The fudge branch to exit a dirty SWI handler

DirtyBranch
        B       SLVK +DirtyBranch-BranchToSWIExit

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; In    r10-r12 stacked, lr has bits for return

VSet_GenerateError ROUT

        Push    lr
        MOV     r1, #Service_Error
        BL      Issue_Service

        MOV     r10, #ErrorV
        BL      CallVector              ; Normally gets to default handler...

        Pull    lr                      ; which raises error; otherwise just
        BIC     lr, lr, #V_bit          ; return with V clear: error claimed!
        B       SWIReturn

        LTORG

; ....................... default owner of ErrorV .............................
; In    r0  -> error in current error block

; Out   Exits to user's error handler routine as given by ErrHan
;       r1-r9 possibly corrupt. Indeed r10-r12 MAY be duff ... eg. REMOTE

ErrHandler ROUT

        BL      OscliTidy               ; close redirection, restore curr FS

        MOV     r12, #0
        LDR     r11, [r12, #ErrBuf]     ; Get pointer to error buffer

        LDR     sp_svc, =SVCSTK-4*4     ; Just below top of stack
                                        ; Note gives WRONG pc if error
        Pull    r14                     ; generated by any but bottom SWI
        STR     r14, [r11], #4          ; Return PC for error

        LDR     r14, [r0], #4           ; Copy error number
        STR     r14, [r11], #4

10      LDRB    r14, [r0], #1           ; Copy error string
        STRB    r14, [r11], #1
        TEQ     r14, #0
        BNE     %BT10

        LDR     r14, [r12, #ErrHan]     ; And go to error handler
        BIC     r14, r14, #ARM_CC_Mask
        STR     r14, [r12, #Curr_Active_Object]
        LDR     r0,  [r12, #ErrHan_ws]  ; r0 is his wp

        LDRB    r10, [r12, #CallBack_Flag]
        CMP     r10, #0

        Pull    "r10-r12", EQ
        MOVEQS  pc, r14                 ; USR mode, IRQs enabled

        B       Do_CallBack             ; Can't need postponement, r0,r14
                                        ; such that callback code will normally
                                        ; call error handler

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; check for CallBack possible

callback_checking

        TST     lr, #SVC_mode :OR: I_bit ; user mode, ints enabled?
        Pull    "r10-r12", NE
        MOVNES  pc, lr                  ; Skip the branch for SVC code speed

; Further checks: postpone callback if returning V set and R0->RAM

        TST     lr, #V_bit
        BEQ     Do_CallBack
        TST     r11, #CBack_Postpone    ; only one postponement
        BNE     Do_CallBack             ; allowed.
        CMP     r0, #32*1024*1024
        BGE     Do_CallBack

        TEQP    PC, #SVC_mode+I_bit            ; ints off while flag updated
        LDRB    r11, [r10, #CallBack_Flag]
        ORR     r11, r11, #CBack_Postpone      ; signal to IRQs
        STRB    r11, [r10, #CallBack_Flag]
back_to_user
        Pull   "r10-r12"
        MOVS    PC, lr

Do_CallBack                                    ; CallBack allowed:
        TST     r11, #CBack_VectorReq          ; now process any vector entries
        Push    lr, NE
        BLNE    process_callback_chain
        Pull    lr, NE

        TST     r11, #CBack_OldStyle
        BEQ     back_to_user

        TEQP    PC, #SVC_mode+I_bit             ; ints off while flag updated
        LDRB    r11, [r10, #CallBack_Flag]
        BIC     r11, r11, #CBack_Postpone+CBack_OldStyle
        STRB    r11, [r10, #CallBack_Flag]

        MOV     r12, #0
        LDR     R12, [R12, #CallBf]
        STR     r14, [r12, #4*15]             ; user PC
        MOV     r14, r12
        Pull   "r10-r12"
        STMIA   r14, {r0-r14}^                ; user registers

        MOV     R12, #CallAd_ws
        LDMIA   R12, {R12, PC}                ; jump to CallBackHandler

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Also called from source.pmf.key, during readc

process_callback_chain ROUT

        Push   "r0-r6, r10-r12, lr"             ; save some for the callee too.
        MOV     r10, #0

        TEQP    PC, #SVC_mode+I_bit             ; ints off while flag updated
        LDRB    r11, [r10, #CallBack_Flag]
        BIC     r11, r11, #CBack_VectorReq
        STRB    r11, [r10, #CallBack_Flag]

 [ True
01      TEQP    PC, #SVC_mode+I_bit             ; ints off while head updated
        MOV     r10, #0
        LDR     r10, [r10, #CallBack_Vector]
        TEQ     r10, #0
        Pull   "r0-r6, r10-r12, PC",EQ,^

        LDMIA   r10, {r2, r11, r12}             ; link, addr, r12
        MOV     r0, #HeapReason_Free
        STR     r2, [r0, #CallBack_Vector-HeapReason_Free] ; Keep head valid

        TEQP    PC, #SVC_mode                   ; enable ints for long bits
        LDR     r1, =SysHeapStart
        SWI     XOS_Heap

        MOV     lr, pc
        MOV     pc, r11                         ; call im, with given r12

        B       %BT01                           ; loop

 | ; old one

        TEQP    PC, #SVC_mode

        LDR     r10, [r10, #CallBack_Vector]
01      MOV     r2, r10                         ; for freeing
        LDMIA   r10, {r10, r11, r12}            ; link, addr, r12
        MOV     r0, #HeapReason_Free
        STR     r10, [r0, #CallBack_Vector-HeapReason_Free]
        LDR     r1, =SysHeapStart
        SWI     XOS_Heap
        MOV     lr, pc
        MOV     pc, r11                         ; call im
        CMP     r10, #0
        BNE     %BT01
        Pull   "r0-r6, r10-r12, PC",,^
 ]

        LTORG

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_WriteC

; In    r11 = 0 (look, up there ^) !

SWIWriteC ROUT

        TEQP    pc, #SVC_mode           ; enable interrupts

        BIC     lr, lr, #V_bit          ; clear caller's V cos we didn't before
        Push    lr

        LDR     r11, [r11, #VecPtrTab+WrchV*4] ; load top node pointer
        CMP     r11, #ROM
        Push    pc, CS                 ; push address of ReturnFromVectoredWrch
        BCS     PMFWrchDirect
        BCC     WrchThruVector

ReturnFromVectoredWrch
        Pull    lr
        B       SLVK_TestV


WrchThruVector
        MOV     r10, #WrchV
        BL      CallVector
        B       ReturnFromVectoredWrch

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

SWINewLine ROUT

        MOV     r11, lr
        SWI     XOS_WriteI+10
        SWIVC   XOS_WriteI+13
        MOV     lr, r11
        B       SLVK_TestV

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_WriteI+n

SWIWriteI ROUT

        MOV     r10, r0
        AND     r0, r11, #&FF
        MOV     r11, lr                 ; NB. Order !!!
        SWI     XOS_WriteC
        MOVVC   r0, r10
        MOV     lr, r11
        B       SLVK_TestV              ; return setting V

; .............................................................................
; define module SWI node format

ModSWINode_CallAddress * 0
ModSWINode_MListNode   * 4
ModSWINode_Link        * 8
ModSWINode_Number      * 12
ModSWINode_Size        * 16     ; not a field - the node size!

        MACRO
$l      ModSWIHashval   $swino, $startreg
     [ "$startreg"=""
$l      MOV     $swino, $swino, LSR #4
     |
$l      MOV     $swino, $startreg, LSR #4
     ]
        AND     $swino, $swino, #ModuleSHT_Entries*4-1
        ADD     $swino, $swino, #ModuleSWI_HashTab
        MEND



NotMainMOSSwi ; Continuation of SWI despatch

        CMP     R11, #&200
        BCC     SWIWriteI

; .............................................................................
; Look round RMs to see if they want it

ExtensionSWI ROUT

        Push    "r9, lr"                ; first construct the link to pass on.
        AND     r10, lr, #&FC000000     ; copy in user CCodes (inc. IRQ state)
        ADR     lr, %FT02 + SVC_mode
        ORR     lr, lr, r10

        BIC     r12, r11, #Module_SWIChunkSize-1
        BIC     r12, r12, #Auto_Error_SWI_bit
        ModSWIHashval r10, r12
        LDR     r10, [r10]
loopoverhashchain
        CMP     r10, #0
        BEQ     VectorUserSWI
        LDR     r9, [r10, #ModSWINode_Number]
        CMP     r9, r12
        LDRNE   r10, [r10, #ModSWINode_Link]
        BNE     loopoverhashchain

        LDMIA   r10, {r10, r12}
        LDR     r12, [r12, #Module_incarnation_list]  ; preferred life
        CMP     r12, #0
        ANDNE   r11, r11, #Module_SWIChunkSize-1
        ADDNE   r12, r12, #Incarnation_Workspace
        MOVNE   pc, r10


VectorUserSWI                   ; Not in a module, so call vec
        MOV     r10, #UKSWIV    ; high SWI number still in R11
        B       CallVector      ; lr still has user CCs & points at%FT02


02
        Pull    "r9, lr"
        BIC     lr, lr, #&F0000000      ; Can mangle any/all of punter flags
        MOV     r10, pc, LSR #(32-4)
        ORR     lr, lr, r10, LSL #(32-4)
        B       SLVK

; ....................... default owner of UKSWIV .............................
; Call UKSWI handler
; Also used to call the upcall handler

; In    r12 = HiServ_ws (or UpCallHan_ws)

CallUpcallHandler
HighSWI ROUT                          ; no one on vec wants it: give to handler

        Pull    lr                    ; the link pointing at %BT02 to pass in.
        LDMIA   r12, {r12, pc}

; ........................ default UKSWI handler ..............................

NoSuchSWI ROUT

        Push    lr
        BL      NoHighSWIHandler
        Pull    lr
        B       SLVK_SetV

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

NoHighSWIHandler ROUT

        MOV     r0, #0
        LDR     r0, [r0, #IRQsema]
        CMP     r0, #0
        ADR     r0, ErrorBlock_NoSuchSWI ; Must return static error here
        ORRNES  pc, lr, #V_bit

; Not in IRQ: can safely build a dynamic error

        Push    "r1-r3, lr"
        LDR     r1, =EnvString
        LDMIA   r0!, {r2, r3}           ; number, "SWI "
        STMIA   r1!, {r2, r3}
        MOV     r2, #"&"
        STRB    r2, [r1], #1
        MOV     r3, r0
        MOV     r0, r11
        MOV     r2, #256
        SWI     XOS_ConvertHex6         ; SWI argument is 00xxxxxx

; now strip leading 0s

        MOV     r1, r0
02      LDRB    r2, [r1], #1
        CMP     r2, #"0"
        BEQ     %BT02
        CMP     r2, #0
        ADDEQ   r1, r0, #1
        BEQ     %FT03
04      STRB    r2, [r0], #1
        LDRB    r2, [r1], #1
        CMP     r2, #0
        BNE     %BT04
        MOV     r1, r0
03      MOV     r2, #" "
01      STRB    r2, [r1], #1
        CMP     r2, #0
        LDRNEB  r2, [r3], #1
        BNE     %BT01

        Pull    "r1-r3, lr"
        LDR     r0, =EnvString
        ORRS    pc, lr, #V_bit

        MakeErrorBlock NoSuchSWI

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Fast SWI handlers for BGet and BPut caches

BGetSWI ROUT                            ; Done separately for highest speed

        Push    lr
        LDR     r12, =VecPtrTab
        LDR     r10, [r12, r11, LSL #2] ; Load top node pointer for vector
        CMP     r10, #ROM
        BCC     BGetThruVector

; Cache technology deemed to be ok (ensures consistent with ROM FileSwitch)

        LDMIB   r10, {wp}                       ; Get wp from vector node

 ASSERT :INDEX: BGet_shiftedbase = 0
 ASSERT :INDEX: BGet_bufferdata = 4
 ASSERT :INDEX: BGet_scb        = 8
 ASSERT :INDEX: BGet_shift      = 12
 ASSERT :INDEX: BGet_handle     = 16
        LDMIA   wp, {r0, r10, r11, r12, r14}    ; Get cached data
        TEQ     r14, r1                         ; BGet on cached handle ?
        LDREQ   r14, [r11, #:INDEX: scb_fileptr] ; Check fileptr in that buffer
        TEQEQ   r0, r14, LSR r12
        LDREQB  r0, [r10, r14]                  ; Get byte from buffer
        ADDEQ   r14, r14, #1
        STREQ   r14, [r11, #:INDEX: scb_fileptr] ; Increment fileptr
        Pull    lr, EQ                          ; Punter lr has VClear
        BICEQ   lr, lr, #C_bit                  ; CClear -> ~EOF
        BEQ     SLVK

BGetThruVector
        MOV     r10, #BGetV             ; Cache hit failed, call victor
        BL      CallVector
        Pull    lr                      ; Punter lr has VClear
        BIC     lr, lr, #C_bit          ; Copy C,V to punter lr
        ORRCS   lr, lr, #C_bit
        B       SLVK_TestV

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

BPutSWI ROUT                            ; Done separately for highest speed

        Push    "r9, lr"                ; Needs one other temp register
        LDR     r12, =VecPtrTab
        LDR     r10, [r12, r11, LSL #2] ; Load top node pointer for vector
        CMP     r10, #ROM
        BCC     BPutThruVector

; Cache technology deemed to be ok (ensures consistent with ROM FileSwitch)

        LDMIB   r10, {wp}                       ; Get wp from vector node
                                                ; NB. This is not normal wp
;       BPut_shiftedbase                        ; r9
 ASSERT BPut_bufferdata = BPut_shiftedbase + 4  ; r10
 ASSERT BPut_scb        = BPut_shiftedbase + 8  ; r11
 ASSERT BPut_shift      = BPut_shiftedbase + 12 ; r12
 ASSERT BPut_handle     = BPut_shiftedbase + 16 ; r14
        LDMIA   wp, {r9, r10, r11, r12, r14}    ; Get cached data
        TEQ     r14, r1                         ; BPut on cached handle ?
        LDREQ   r14, [r11, #:INDEX: scb_fileptr] ; Check fileptr in that buffer
        TEQEQ   r9, r14, LSR r12
        STREQB  r0, [r10, r14]                  ; Put byte to buffer
        ADDEQ   r14, r14, #1
        STREQ   r14, [r11, #:INDEX: scb_fileptr] ; Increment fileptr
        Pull    "r9, lr", EQ                    ; Destack punter r9 and lr(VC)
        BEQ     SLVK

BPutThruVector
        MOV     r10, #BPutV                     ; Cache hit failed, call victor
        BL      CallVector
        Pull    "r9, lr"                        ; Destack punter r9 and lr(VC)
        B       SLVK_TestV

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI handlers for all the vectored SWIs that have vecnum=swinum

; All defined to affect C & V at most

FSControlSWI ROUT

        MOV     r11, #FSCV              ; Pretend to be vecnum = swinum swi
                                        ; and just drop through to ...

VecSwiDespatch ROUT

        Push    lr                      ; this is user's link
        MOV     r10, r11                ; SWI number from R11->R10
        ORR     r14, lr, #SVC_mode
        BIC     r14, r14, #I_bit        ; Enable IRQs
        TEQP    r14, #0
        BL      CallVector

; So the vectored routine can update the pushed link CCodes if wanted
; No update return is therefore LDMIA stack!, {PC}^ (sort of)
; Update return pulls lr, molests it, then MOVS PC, lr
; Note either return enables IRQ, FIQ

; ???? Is the DEFAULT owner allowed to crap on r10,r11 IFF he claims it ????

        Pull    lr                      ; Punter lr has VClear
        BIC     lr, lr, #C_bit          ; Copy C,V to punter lr
        ORRCS   lr, lr, #C_bit
        B       SLVK_TestV


NoIrqVecSwiDespatch ROUT

        Push    lr                      ; this is user's link
        MOV     r10, r11                ; SWI number from R11->R10
        ORR     r14, lr, #SVC_mode+I_bit ; Disable IRQ
        TEQP    r14, #0
        BL      CallVector
        Pull    lr                      ; Punter lr has VClear
        BIC     lr, lr, #C_bit          ; Copy C,V to punter lr
        ORRCS   lr, lr, #C_bit
        B       SLVK_TestV

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_GetEnv

SWI_GetEnv_Code ROUT

        LDR     r0, =EnvString
        MOV     r1, #0
        LDR     r1, [r1, #MemLimit]
        LDR     r2, =EnvTime
        B       SLVK

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_Exit

SEXIT ROUT

        BL      OscliTidy               ; shut redirection, restore FS

; now see if it's an abort Exit

        LDR     r12, ABEX
        CMP     r1, r12
        TSTEQ   r0, #ARM_CC_Mask
        MOVNE   r2,  #0
        MOV     r12, #0
        STR     r2,  [r12, #ReturnCode]
        LDR     r12, [r12, #RCLimit]
        CMP     r2, r12
        SWIHI   OS_GenerateError        ; really generate an error

        Pull    "r9-r12"                ; junk R9
        MOV     r0, #0
        LDR     lr, [r0, #SExitA]
        STR     lr, [r0, #Curr_Active_Object]
        LDR     r12, [r0, #SExitA_ws]
        LDR     sp_svc, =SVCSTK
        BICS    pc, lr, #ARM_CC_Mask

ABEX    =       "ABEX"                  ; Picked up as word

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_CallBack: Set/read callback buffer and handler

SCALLB  MOV     r10, #CallBackHandler

handlecomm
        Push    "r2, r3, lr"
        MOV     r3, r0          ; buffer
        MOV     r0, r10
        BL      CallCESWI
        MOV     r0, r3
        Pull    "r2, r3, lr"
        B       SLVK_TestV

; .............................................................................
; SWI OS_BreakSet: Set/read breakpoint buffer and handler

SBRKCT  MOV     r10, #BreakPointHandler
        B       handlecomm

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_ReadEscapeState

ReadEscapeSWI ROUT

        MOV     r10, #0
        LDRB    r10, [r10, #ESC_Status]
        TST     r10, #1 :SHL: 6
        BICEQ   lr, lr, #C_bit
        ORRNE   lr, lr, #C_bit
        B       SLVK

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_ServiceCall

Issue_Service_SWI ROUT

        Push    lr
        BL      Issue_Service
        Pull    lr
        B       SLVK

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_GenerateError

GenErrorSWI * SLVK_SetV

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

        LNK     NewIRQs
