; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
        TTL     => Kernel : SWI Despatch, simple SWIs
        SUBT    Arthur Variables
        OPT     4

; -----------------------------------------------------------------------------
;
; mjs Oct 2000 kernel/HAL split
;
; macros that can be switched between doing real HAL calls and pseudo
; HAL calls with r9-> mjs pseudo HAL workspace
;
; these have been handy for interim HALising of kernel code in-situ
; (particularly used for video stuff), but can probably disappear later
;

  [ HAL

        MACRO
        mjsAddressHAL $zero
        AddressHAL $zero
        MEND

        MACRO
        mjsCallHAL $rout
        CallHAL $rout
        MEND

        MACRO
        DebugTX $str
    [ DebugHALTX
        BL      DebugHALPrint
        =       "$str", 0
        ALIGN
    ]
        MEND
  |

        MACRO
        mjsAddressHAL
        LDR     r9, =mjs_tempHALworkspace
        LDR     r9, [r9]                  ; sb -> pseudo HAL workspace
        MEND

        MACRO
        mjsCallHAL $rout
        BL      $rout
        MEND

  ] ;HAL

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; 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

; **************************************
; ***  BYTEWS - Point to OsbyteVars  ***
; **************************************
        MACRO
$label  BYTEWS  $reg
$label  LDR     $reg,=ZeroPage+OsbyteVars
        MEND

; ***************************************
; ***  LDROSB - Load Osbyte variable  ***
; ***************************************
        MACRO
$label  LDROSB  $reg, $var, $cond
$label  LDR$cond $reg, =ZeroPage
        LDR$cond.B $reg, [$reg, #OsbyteVars+$var-OSBYTEFirstVar]
        MEND

; ****************************************
; ***  STROSB - Store Osbyte variable  ***
; ****************************************
        MACRO
$label  STROSB  $reg, $var, $temp, $cond
$label  LDR$cond $temp, =ZeroPage
        STR$cond.B $reg, [$temp, #OsbyteVars+$var-OSBYTEFirstVar]
        MEND

; ****************************************************
; ***  VDWS - Point to our new VduDriverWorkSpace  ***
; ****************************************************
        MACRO
$label  VDWS    $reg
$label  LDR     $reg, =ZeroPage+VduDriverWorkSpace
        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, $delay
        ! 0, "Setborder used"
$l      LDR     $reg1, =VIDC
; Note $reg, $green and $blue are 4 bit values
        LDR     $reg2, =&40000000+(($red)*&11)+(($green)*&1100)+(($blue)*&110000)
        STR     $reg2, [$reg1]
 [ "$delay"<>""
        MOV     $reg1, #$delay
10
        SUBS    $reg1, $reg1, #1
        BNE     %BT10
 ]
        MEND

; Fake a 26-bit pc, given a PSR currently in lr (or reg), and the 32-bit address on
; the stack. The stacked address is pulled, and the result is left in lr.

        MACRO
        FakeLR  $temp, $dontpull, $reg
 [ "$reg" = ""
        AND     $temp,lr,#&F0000003
 |
        AND     $temp,$reg,#&F0000003
 ]
        AND     lr,lr,#I32_bit+F32_bit
        ORR     $temp,$temp,lr,LSL #IF32_26Shift
 [ "$dontpull" = "dontpull"
        LDR     lr,[sp]
 |
        LDR     lr,[sp],#4
 ]
        BIC     lr,lr,#ARM_CC_Mask
        ORR     lr,lr,$temp
        MEND

;

    [ AddTubeBashers
 [ TubeType = Tube_Normal
DebugTUBE  * &03340000+3*&4000         ; tube in podule #3
; Tube register offsets
 ^ 0
R1STAT # 4
R1DATA # 4
 |
DebugTUBE * &03000000           ; simulator tube address
R1DATA * 0
 ]
   ]

; 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
 [ TubeType = Tube_Normal               ; normal tubes have status register, simulator one doesn't
01   LDRB $reg2, [$reg1, #R1STAT]
     TST $reg2, #&40
     BEQ %BT01
 ]
     $charset
     STRB $reg2, [$reg1, #R1DATA]
   [ "$stackthere"=""
   Pull "$reg1, $reg2"
   ]
     MEND

        MACRO
$l      TubeString $reg1, $reg2, $reg3, $string, $cc
        LDR     $reg1, =DebugTUBE
        ADR     $reg2, %FT20
10
 [ TubeType = Tube_Normal
        LDRB    $reg3, [$reg1, #R1STAT]
        TST     $reg3, #&40
        BEQ     %BT10
 ]

        LDRB    $reg3, [$reg2], #1
        TEQ     $reg3, #0
        STRNEB  $reg3, [$reg1, #R1DATA]
        BNE     %BT10
        B       %FT30
20
        =       "$string"
 [ "$cc" = ""
        =       10, 13
 ]
        =       0
        ALIGN
30
        MEND

        MACRO
$l      TubeDumpNoStack $dump, $t1, $t2, $t3
$l      MOV    $t1, #7
01
        ADRL   $t2, HexTable
        TubeChar $t3, $t2, "LDRB $t2, [$t2, $dump, LSR #28]", NoStack
        MOV    $dump, $dump, ROR #28
        SUBS   $t1, $t1, #1
        BPL    %BT01
        TubeChar $t3, $t2, "MOV $t2, #"" """, NoStack
        MEND

        MACRO
$l      TubeNewlNoStack $t1, $t2
$l      TubeChar $t1, $t2, "MOV $t2, #10", NoStack
        TubeChar $t1, $t2, "MOV $t2, #13", NoStack
        MEND


a1      RN      0
a2      RN      1
a3      RN      2
a4      RN      3
v1      RN      4
v2      RN      5
v3      RN      6
v4      RN      7
v5      RN      8
v6      RN      9
sb      RN      9
v7      RN      10
v8      RN      11

; Set sb up ready for CallHAL.
        MACRO
        AddressHAL $zero
 [ "$zero" <> ""
        LDR     sb, [$zero, #HAL_Workspace]
 |
        LDR     sb, =ZeroPage
        LDR     sb, [sb, #HAL_Workspace]
 ]
        MEND

; Calls the HAL. $rout is the routine. sb must have been set up by AddressHAL
        MACRO
        CallHAL $rout, $cond
        MOV$cond lr, pc
        LDR$cond pc, [sb, #-(EntryNo_$rout+1) * 4]
        MEND

; Checks whether a HAL routine exists. If it does, a1 points to it (probably
; not useful), and Z is clear. lr corrupted.
        MACRO
        CheckHAL $rout
        LDR     a1, [sb, #-(EntryNo_$rout+1) * 4]
        ADRL    lr, NullHALEntry
        TEQ     a1, lr
        MEND


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

PageSize          * (4*1024)       ;MMU page size (normal pages)
Log2PageSize      * 12             ;for shifts

MinAplWork * 40*1024         ; minimum size of AplWork

; Fixed addresses

MEMCADR  * &03600000
        GBLL    ROMatTop
 [ HAL32 :LAND: {TRUE}
ROM      * &FC000000
ROMatTop SETL {TRUE}
 |
ROM      * &03800000
ROMLimit * &04000000
 ]
OSMD     * &11111111

VideoPhysRam *  &02000000               ; Amazing - it's in the same place!
DRAM0PhysRam *  &10000000               ; 4 DRAM banks
DRAM1PhysRam *  &14000000
DRAM2PhysRam *  &18000000
DRAM3PhysRam *  &1C000000
DRAMBaseAddressMask * &1C000000         ; used to mask off bits after stealing video RAM
PhysSpaceSize * &20000000               ; IOMD physical map is 512M big
PhysROM *       &00000000               ; and real ROM starts at 0
 [ STB
PhysExtROM *    &01000000               ; 2nd ROM bank starts at 16M
 ]
SAMLength *     512*4                   ; SAM length in bytes for 1 bank of VRAM
 [ :LNOT: HAL
EASISpacePhys * &08000000
EASISpace *     PhysSpace + EASISpacePhys
 ]

; Manifests

CR * 13
LF * 10
space * " "

; Registers

SPIRQ RN R13

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

; Set up symbols for the SWIs which aren't really there yet


        SUBT    Arthur Code
        OPT     4

  [ HAL
        ORG     ROM + OSROM_HALSize
  |
        ORG     ROM
  ]

        AREA    |!!!!OSBase|,CODE,READONLY

        ENTRY                   ; Not really, but we need it to link
KernelBase

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

  [ HAL
;        ORG     ROM + OSROM_HALSize
  |
;        ORG     ROM
  ]

        GBLS    DoMorrisROMHeader
        GBLS    DoTestThings
DoMorrisROMHeader SETS ""
DoTestThings      SETS ""

  [ HAL
;        BIN     HAL.L7200.HAL

; RISC OS image header
RISCOS_Header
        =       "OSIm"
        DCD     0
        DCD     OSROM_ImageSize*1024 - OSROM_HALSize
        DCD     RISCOS_Entries - RISCOS_Header
        DCD     (RISCOS_Entries_End - RISCOS_Entries) / 4

RISCOS_Entries
        DCD     RISCOS_InitARM   - RISCOS_Entries
        DCD     RISCOS_AddRAM    - RISCOS_Entries
        DCD     RISCOS_Start     - RISCOS_Entries
        DCD     RISCOS_MapInIO   - RISCOS_Entries
        DCD     RISCOS_AddDevice - RISCOS_Entries
        DCD     RISCOS_LogToPhys - RISCOS_Entries
        DCD     RISCOS_IICOpV    - RISCOS_Entries
RISCOS_Entries_End

  |


 [ MorrisSupport
DoMorrisROMHeader SETS  " GET s.Morris"
 ]

; now include the test code, if there is any


 [ IncludeTestSrc
DoTestThings    SETS    " GET TestSrc.Begin"
 ]
        $DoTestThings

 [ IncludeTestSrc
DoMorrisROMHeader SETS  ""
 ]

        $DoMorrisROMHeader
  ]


; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; If there is no test code then we want a branch table at the start of ROM to
; handle reset and any aborts etc. in the reset code.
; If MorrisSupport we've already generated 16/32 ROM entry code, so skip this bit

  [ :LNOT: IncludeTestSrc :LAND: :LNOT: MorrisSupport :LAND: :LNOT: HAL
        LDR     pc, .+ResetIndirection ; load PC, PC relative
        B       UndInstInReset
        B       SWIInReset
        B       PrefAbInReset
        B       DataAbInReset
        B       AddrExInReset
        B       IRQInReset

UndInstInReset
        SUB     pc, pc, #8
SWIInReset
        SUB     pc, pc, #8
PrefAbInReset
        SUB     pc, pc, #8
DataAbInReset
        SUB     pc, pc, #8
AddrExInReset
        SUB     pc, pc, #8
IRQInReset
        SUB     pc, pc, #8
  ]

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; This bit (up to EndFiq) is copied to location 0.  Processor vectors are
; indirected through 0 page locations so that they can be claimed using
; OS_ClaimProcessorVector.  IRQs are initially handled specially so that the
; keyboard can be handled during reset but the load is replaced with the
; standard one later on.

MOSROMVecs
        LDR     pc, MOSROMVecs+ProcVec_Branch0
        LDR     pc, MOSROMVecs+ProcVec_UndInst
        LDR     pc, MOSROMVecs+ProcVec_SWI
        LDR     pc, MOSROMVecs+ProcVec_PrefAb
        LDR     pc, MOSROMVecs+ProcVec_DataAb
        LDR     pc, MOSROMVecs+ProcVec_AddrEx
        LDR     pc, MOSROMVecs+InitIRQHandler
EndMOSROMVecs

        ASSERT  InitIRQHandler >= EndMOSROMVecs - MOSROMVecs

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; This is the table of default processor vectors which is copied to 0 page.

DefaultProcVecs
        &       Branch0_NoTrampoline
        &       UndPreVeneer
        &       SVC
        &       PAbPreVeneer
        &       DAbPreVeneer
        &       AdXPreVeneer
        &       Initial_IRQ_Code

        ASSERT  (.-DefaultProcVecs) = ProcVec_End-ProcVec_Start

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; These are preveneers which must be copied to 0 page locations so that the
; relevant handler can be branched to.  This is mainly for non-ARM600 platforms
; although the address exception preveneer (which should not actually be required
; on ARM600) is always copied.

DefaultPreVeneers
 [ No26bitCode
UndPreVeneer    *       ProcVecPreVeneers+(.-DefaultPreVeneers)
        LDR     PC, DefaultPreVeneers-ProcVecPreVeneers+UndHan
   [ ChocolateAMB
        DCD     0
   |
PAbPreVeneer    *       ProcVecPreVeneers+(.-DefaultPreVeneers)
        LDR     PC, DefaultPreVeneers-ProcVecPreVeneers+PAbHan
   ]
        DCD     0
 |
        DCD     0
        DCD     0
        DCD     0
 ]
AdXPreVeneer    *       ProcVecPreVeneers+(.-DefaultPreVeneers)
        LDR     PC, DefaultPreVeneers-ProcVecPreVeneers+AdXHan

        ASSERT  (.-DefaultPreVeneers) = ProcVecPreVeneersSize

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; This is the trampoline in the system heap used to handle branch through 0.

Branch0_Trampoline
        STR     r1, Branch0_Trampoline + Branch0_Trampoline_SavedR1
        STR     lr, Branch0_Trampoline + Branch0_Trampoline_SavedR14
        ADD     lr, pc, #4
        LDR     pc, .+4
        &       Branch0_FromTrampoline
Branch0_Trampoline_Init     * .-Branch0_Trampoline
Branch0_Trampoline_SavedR1  * .-Branch0_Trampoline
Branch0_Trampoline_SavedR14 * .-Branch0_Trampoline+4
Branch0_Trampoline_Size     * .-Branch0_Trampoline+8


 [ :LNOT: IncludeTestSrc :LAND: :LNOT: HAL

; We now waste space until the offset into the ROM is the same as the RAM address of ResetIndirection
; This is so that
;  a) on a reset, ROM is paged in at the bottom, so we jump to CONT, and
;  b) on a break, RAM is paged in at the bottom, so we jump to CONT_Break

        ASSERT  .-ROM <= ResetIndirection
        %       ResetIndirection-(.-ROM)
        &       CONT-ROM+PhysROM        ; address of reset code in physical space
 ]

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

; All the stuff from here to after the DirtyBranch instruction is read
; consecutively out of ROM, so don't put anything in between without changing
; the code


StartData
        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
; no branches or interlocks in the common case: V clear, no 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)
Local_SLVK

        LDR     r12, [sp], #4
      [ ZeroPage = 0
        MOV     r10, #0
      |
        LDR     r10, SWIRelocationZeroPage
      ]
      [ FixCallBacks
        MSR     CPSR_c, #I32_bit + SVC32_mode           ; IRQs off makes CallBackFlag atomic; 32bit so ready for SPSR use
      ]
        LDRB    r11, [r10, #CallBack_Flag]

        TST     lr, #V_bit
        BNE     %FT50

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

40      TEQ     r11, #0

      [ :LNOT: FixCallBacks
        MSREQ   CPSR_c, #I32_bit + SVC32_mode           ; IRQs off for SPSR use
      ]
        MSREQ   SPSR_cxsf, lr
        LDREQ   lr, [sp], #4
        Pull    "r10-r12", EQ
        MOVEQS  pc, lr

        B       callback_checking + SWIRelocation

 ! 0,"VSetReturn at ":CC:(:STR:({PC}-SWIRelocation))
50      TST     r12, #Auto_Error_SWI_bit
      [ FixCallBacks
        BNE     callback_checking + SWIRelocation       ; we need to do this for X errors even if the callback flags
                                                        ; are all clear, so that the postpone flag can be set
      |
        BNE     %BT40
      ]

        B       VSet_GenerateError + SWIRelocation

      [ ZeroPage <> 0
SWIRelocationZeroPage
        DCD     ZeroPage
      ]

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

SVC * {PC}-SWIRelocation

        Push    "r10-r12"
 [ No26bitCode
        MRS     r12, SPSR               ; r12 = saved PSR
        TST     r12, #T32_bit           ; depending on processor state (ARM/Thumb)
        LDREQ   r11, [r14, #-4]         ; extract SWI number to r11
        LDRNEB  r11, [r14, #-2]         ; (ordering to prevent interlocks)
        BICEQ   r11, r11, #&FF000000
 |
        LDR     r11, [r14, #-4]         ; extract SWI number to r11
        MRS     r12, SPSR               ; r12 = saved PSR
        BIC     r11, r11, #&FF000000    ; (ordering to prevent interlocks)
 ]

        Push    "r11,r14"               ; push SWI number and return address

        AND     r10, r12, #I32_bit+F32_bit
        ORR     r10, r10, #SVC2632      ; set IFTMMMMM = IF0x0011
        MSR     CPSR_c, r10             ; restore caller's IRQ state

        BIC     r14, r12, #V_bit        ; clear V (some SWIs need original PSR in r12)

SVC_CallASWI * {PC}-SWIRelocation       ; CallASWI,CallASWIR12 re-entry point

        BIC     r11, r11, #Auto_Error_SWI_bit

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

        B       NotMainMOSSwi + SWIRelocation

 ASSERT {PC}-SVCDespatcher = SWIDespatch_Size

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

JTABLE  & SWIWriteC
        & 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
 [ No26bitCode
        & ReadLineSWI
 |
        & 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
        & ChangeRedirection
        & RemoveCallBack
        & FindMemMapEntries_Code
        & SWISetColour
        & NoSuchSWI                     ; Added these to get round OS_ClaimSWI and
        & NoSuchSWI                     ; OS_ReleaseSWI (should not have been allocated here).
 [ AssemblePointerV
        & PointerSWI
 |
        & NoSuchSWI
 ]
        & ScreenModeSWI
        & DynamicAreaSWI
        & NoSuchSWI                     ; OS_AbortTrap
        & MemorySWI
 [ ProcessorVectors
        & ClaimProcVecSWI
 |
        & NoSuchSWI
 ]
        & PerformReset
        & MMUControlSWI
 [ STB
        & NoSuchSWI
 |
        & ResyncTimeSWI
 ]
 [ StrongARM
        & PlatFeatSWI
        & SyncCodeAreasSWI
        & CallASWI
        & AMBControlSWI
        & CallASWIR12
 |
        & NoSuchSWI
        & NoSuchSWI
        & NoSuchSWI
        & NoSuchSWI
        & NoSuchSWI
 ]
; The following SWIs are not available in this kernel.
        & NoSuchSWI     ; SpecialControl
        & NoSuchSWI     ; EnterUSR32SWI
        & NoSuchSWI     ; EnterUSR26SWI
; End of unavailable SWIs.
; Should not cause any problems on any machine.  STB flag just to be safe though.
 [ STB :LAND: {FALSE}
        & VIDCDividerSWI
 |
    ! 0, "mjsHAL - VIDCDividerSWI not implemented"
        & NoSuchSWI
 ]
        & NVMemorySWI
        & NoSuchSWI
        & NoSuchSWI
        & NoSuchSWI
        & HardwareSWI
        & IICOpSWI
        & SLEAVESWI
        & ReadLine32SWI
        & XOS_SubstituteArgs32_code
        & HeapSortRoutine32


 ASSERT (.-JTABLE)/4 = MaxSwi
 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

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

 [ StrongARM
;StrongARM needs these

;SWI number passed in r10
CallASWI ROUT
        LDR     r11, [sp, #8]        ;pick-up target SWI code (r10 pushed by dispatcher)
        BIC     r11, r11, #&FF000000 ;just in case
        STR     r11, [sp, #0]        ;CallASWI now incognito as target SWI
        B       SVC_CallASWI         ;re-dispatch

;SWI number passed in r12 (better for C veneers)
CallASWIR12 ROUT
        LDR     r11, [sp, #16]       ;pick-up target SWI code (r12 pushed by dispatcher)
        BIC     r11, r11, #&FF000000 ;just in case
        STR     r11, [sp, #0]        ;CallASWIR12 now incognito as target SWI
        B       SVC_CallASWI         ;re-dispatch
 ]


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

VSet_GenerateError ROUT

        Push    lr
      [ FixCallBacks
        BIC     lr, lr, #&0F
        ORR     lr, lr, #SVC_mode
        MSR     CPSR_c, lr              ; Set caller's interrupt state and 26/32bitness
      ]
        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!

        LDR     r10, =ZeroPage          ; set up r10 and r11 as required
      [ FixCallBacks
        MSR     CPSR_c, #I32_bit + SVC32_mode   ; IRQs off makes CallBackFlag atomic; 32bit so ready for SPSR use
      ]
        LDRB    r11, [r10, #CallBack_Flag]
        B       SWIReturnWithCallBackFlag

        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

        LDR     r10, =ZeroPage
        LDR     r11, [r10, #ErrBuf]     ; Get pointer to error buffer

  [ No26bitCode
        LDR     sp_svc, =SVCSTK-4*4     ; Just below top of stack
        Pull    r14
        STR     r14, [r11], #4          ; Return PC for error
  |
        LDR     sp_svc, =SVCSTK-5*4     ; Just below top of stack
        Pull    r14                     ; PSR will be on stack if error at top level
        FakeLR  r12                     ; Fake up the PC+PSR
        STR     r14, [r11], #4
  ]

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

        ; Copy error string - truncating at 252
        MOV     r12, #256-4

10      LDRB    r14, [r0], #1
        SUBS    r12, r12, #1
        MOVLS   r14, #0
        STRB    r14, [r11], #1
        TEQ     r14, #0
        BNE     %BT10

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

      [ :LNOT: FixCallBacks
        LDRB    r11, [r10, #CallBack_Flag]
        CMP     r11, #0
      ]

        MRS     r12, CPSR
        BIC     r12, r12, #I32_bit+F32_bit+&0F  ; USR26/32 mode, ARM, IRQs enabled

      [ FixCallBacks
        MSR     CPSR_c, #I32_bit+SVC32_mode ; disable interrupts for SPSR use and CallBackFlag atomicity
        LDRB    r11, [r10, #CallBack_Flag]
        CMP     r11, #0
      |
        MSREQ   CPSR_c, #I32_bit+SVC32_mode ; disable interrupts for SPSR use
      ]
        MSREQ   SPSR_cxsf, r12

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

        Push    r14                     ; Stack return address
        MOV     r14, r12                ; Put PSR in R14
        B       Do_CallBack             ; Can't need postponement, r0,r14,stack
                                        ; such that callback code will normally
                                        ; call error handler

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

callback_checking

        TST     lr, #I32_bit+&0F        ; user 26/32 mode, ints enabled?
      [ :LNOT: FixCallBacks             ; already entered with this CPSR
        MSRNE   CPSR_c, #I32_bit + SVC32_mode
      ]
        MSRNE   SPSR_cxsf, lr
        LDRNE   lr, [sp], #4
        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              ; if no error then do callbacks
        BEQ     Do_CallBack
        TST     r11, #CBack_Postpone
      [ FixCallBacks
        TSTNE   r11, #CBack_OldStyle :OR: CBack_VectorReq ; can only postpone if not already or if no callbacks pending
      ]
        BNE     Do_CallBack
 [ ROMatTop
        CMP     r0, #ROM
        BHS     Do_CallBack
 |
        CMP     r0, #ROM
        RSBHIS  r12, r0, #ROMLimit
        BHI     Do_CallBack
 ]
      [ :LNOT: FixCallBacks
        MSR     CPSR_c, #I32_bit + SVC32_mode  ; 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
      [ :LNOT: FixCallBacks                    ; already entered with this CPSR
        MSR     CPSR_c, #I32_bit + SVC32_mode
      ]
back_to_user_irqs_already_off
        MSR     SPSR_cxsf, lr
        LDR     lr, [sp], #4
        Pull    "r10-r12"
        MOVS    pc, lr

Do_CallBack                                    ; CallBack allowed:
      [ FixCallBacks
        ; Entered in SVC32 mode with IRQs off, r10 = 0
        TST     r11, #CBack_Postpone
        BICNE   r11, r11, #CBack_Postpone
        STRNEB  r11, [r10, #CallBack_Flag]
Do_CallBack_postpone_already_clear
      ]
        TST     r11, #CBack_VectorReq          ; now process any vector entries
        MOV     r12,lr
        BLNE    process_callback_chain
        MOV     lr,r12

      [ FixCallBacks
        LDRB    r11, [r10, #CallBack_Flag]     ; non-transient callback may have been set during transient callbacks
      ]
        TST     r11, #CBack_OldStyle
        BEQ     back_to_user
 [ :LNOT:No26bitCode
        TST     r14, #&10                       ; must be returning to 26-bit
        BNE     back_to_user                    ; on 26-bit systems
 ]
 [ {TRUE}                                       ; LRust, Fix RP-0609
; Check that SVC_sp is empty (apart from r14,r10-r12), i.e. system truly is idle

        LDR     r12, =SVCSTK-4*4                ; What SVC_sp should be if system idle
        CMP     sp, r12                         ; Stack empty?
        BLO     back_to_user                    ; No then no call back
 ]
      [ FixCallBacks
      [ :LNOT: No26bitCode
        MSR     CPSR_c, #I32_bit + SVC2632      ; back to 26-bit mode
      ]
        BIC     r11, r11, #CBack_OldStyle
      |
        MSR     CPSR_c, #I32_bit + SVC2632      ; ints off while flag updated
        LDRB    r11, [r10, #CallBack_Flag]
        BIC     r11, r11, #CBack_Postpone+CBack_OldStyle
      ]
        STRB    r11, [r10, #CallBack_Flag]

        LDR     R12, [R10, #CallBf]
  [ No26bitCode
        STR     r14, [r12, #4*16]             ; user PSR
        Pull    r14
        STR     r14, [r12, #4*15]             ; user PC
  |
        FakeLR  r10
        STR     r14, [r12, #4*15]             ; user PC/PSR
  ]
        MOV     r14, r12
        Pull   "r10-r12"
  [ SASTMhatbroken
        STMIA   r14!,{r0-r12}
        STMIA   r14,{r13,r14}^                ; user registers
        NOP                                   ; doesn't matter that r14 is different
  |
        STMIA   r14, {r0-r14}^                ; user registers
  ]

        LDR     R12, =ZeroPage+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.
      [ FixCallBacks :LAND: No26bitCode
        MRS     r0, CPSR
        Push   "r0"
      ]
        LDR     r10, =ZeroPage

        MSR     CPSR_c, #I32_bit + SVC2632      ; ints off while flag updated
        LDRB    r11, [r10, #CallBack_Flag]
        BIC     r11, r11, #CBack_VectorReq
        STRB    r11, [r10, #CallBack_Flag]

01
        MSR     CPSR_c, #I32_bit + SVC2632      ; ints off while flag updated
        LDR     r2, =ZeroPage
        LDR     r2, [r2, #CallBack_Vector]
        TEQ     r2, #0
      [ No26bitCode
      [ FixCallBacks
        Pull   "r0", EQ
        MSREQ   CPSR_c, r0                      ; restore original interrupt state and 32bitness
      |
        MSREQ   CPSR_c, #SVC2632                ; ensure exit with ints on
      ]
        Pull   "r0-r6, r10-r12, PC",EQ
      |
        Pull   "r0-r6, r10-r12, PC",EQ,^
      ]

        LDMIA   r2, {r10, r11, r12}             ; link, addr, r12
        MOV     r0, #HeapReason_Free
      [ ZeroPage = 0
        STR     r10, [r0, #CallBack_Vector-HeapReason_Free] ; Keep head valid
      |
        LDR     r1, =ZeroPage
        STR     r10, [r1, #CallBack_Vector] ; Keep head valid
      ]

        MSR     CPSR_c, #SVC2632                ; enable ints for long bits

  [ ChocolateSysHeap
        ASSERT  ChocolateCBBlocks = ChocolateBlockArrays + 0
      [ ZeroPage = 0
        MOV     r1,#ChocolateBlockArrays
        LDR     r1,[r1,#0]
      |
        LDR     r1, [r1, #ChocolateBlockArrays]
      ]
        BL      FreeChocolateBlock
        LDRVS   r1, =SysHeapStart
        SWIVS   XOS_Heap
  |
        LDR     r1, =SysHeapStart
        SWI     XOS_Heap
  ]

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

        B       %BT01                           ; loop

        LTORG

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

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

SWIWriteC ROUT

        MSR     CPSR_c, #SVC2632        ; enable interrupts

        Push    lr

 [ ROMatTop
      [ ZeroPage <> 0
        LDR     r11, =ZeroPage
      ]
        LDR     r11, [r11, #VecPtrTab+WrchV*4] ; load top node pointer
        CMP     r11, #ROM
  [ StrongARM
        BCC     WrchThruVector
        Push    pc, CS                 ; need to get to ReturnFromVectoredWrch - push PC+12 (old ARM) or PC+8 (StrongARM)
        BCS     PMFWrchDirect
        MOV     R0,R0                  ; NOP for PC+8
  |
        Push    pc, CS                 ; push address of ReturnFromVectoredWrch (PC+12)
        BCS     PMFWrchDirect
        BCC     WrchThruVector
  ]
 |
        B       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      ModSWIHashvalOffset     $swino, $startreg
     [ "$startreg"=""
$l      MOV     $swino, $swino, LSR #4
     |
$l      MOV     $swino, $startreg, LSR #4
     ]
        AND     $swino, $swino, #(ModuleSHT_Entries-1)*4
        MEND

        MACRO
$l      ModSWIHashval   $swino, $startreg
$l      ModSWIHashvalOffset $swino, $startreg
        ADD     $swino, $swino, #ModuleSWI_HashTab
      [ ZeroPage <> 0
        ASSERT ZeroPage = &FFFF0000
        ADD     $swino, $swino, #&FF000000
        ADD     $swino, $swino, #&00FF0000
      ]
        MEND



NotMainMOSSwi ; Continuation of SWI despatch

        CMP     R11, #&200
        BCC     SWIWriteI

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

ExtensionSWI ROUT

      [ No26bitCode
        ASSERT  FixR9CorruptionInExtensionSWI
        Push    "lr"
      |
        Push    "r9, lr"                        ; first construct the link to pass on.
        AND     r10, lr, #&F0000000             ; copy in user CCodes
        AND     r12, lr, #F32_bit+I32_bit       ; (inc. IRQ state)
        ORR     r10, r10, r12, LSL #IF32_26Shift
        ADR     lr, %FT02 + SVC_mode
        ORR     lr, lr, r10
      ]

        BIC     r12, r11, #Module_SWIChunkSize-1
        ModSWIHashvalOffset r10, r12
      [ ZeroPage = 0
        LDR     r10, [r10, #ModuleSWI_HashTab]
      |
        LDR     lr, =ZeroPage+ModuleSWI_HashTab
        LDR     r10, [r10, lr]
      ]
loopoverhashchain
        CMP     r10, #0
        BEQ     VectorUserSWI
 [ No26bitCode
        LDR     lr, [r10, #ModSWINode_Number]
        CMP     lr, r12
 |
        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

 [ FixR9CorruptionInExtensionSWI:LAND::LNOT:No26bitCode
        Pull    "r9", NE                ; restore corrupted r9 before calling SWI handler
                                        ;RCM added 'NE' above to fix MED=04655
 ]

        ANDNE   r11, r11, #Module_SWIChunkSize-1
        ADDNE   r12, r12, #Incarnation_Workspace
 [ No26bitCode
        ADRNE   lr, %FT02
 ]
        MOVNE   pc, r10


VectorUserSWI                   ; Not in a module, so call vec
 [ FixR9CorruptionInExtensionSWI:LAND::LNOT:No26bitCode
        Pull    "r9"            ; restore corrupted r9 before calling UKSWIV
 ]
        MOV     r10, #UKSWIV    ; high SWI number still in R11
 [ No26bitCode
        BL      CallVector
 |
        B       CallVector      ; lr still has user CCs (if 26bit) & points at%FT02
 ]


02
 [ FixR9CorruptionInExtensionSWI
        Pull    "lr"                    ; r9 already pulled off stack before calling SWI handler or UKSWIV
 |
        Pull    "r9,lr"
 ]
        MRS     r10, CPSR
        BIC     lr, lr, #&FF000000      ; Can mangle any/all of punter flags
        AND     r10, r10, #&FF000000
        ORR     lr, lr, r10
        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

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; .................... default Unused SWI handler .............................

NoHighSWIHandler ROUT

        LDR     r0, =ZeroPage
        LDR     r0, [r0, #IRQsema]
        CMP     r0, #0
        ADR     r0, ErrorBlock_NoSuchSWI ; Must return static error here
 [ No26bitCode
        BEQ     %FT01
        SETV
        MOV     pc, lr
01
 |
        ORRNES  pc, lr, #V_bit
 ]

; Not in IRQ: can safely build a dynamic error
      [ International
        Push    "r1-r4, lr"
        SUB     sp, sp,#12
        MOV     r1, sp
        MOV     r2, #12
        MOV     r0, r11
        SWI     XOS_ConvertHex6         ; SWI argument is 00xxxxxx

        MOV     r4, r0                  ; now strip leading 0s
02      LDRB    r2, [r4], #1
        CMP     r2, #"0"
        BEQ     %BT02

        SUB     r4,r4,#1
        ADR     r0, ErrorBlock_NoSuchSWI1
        BL      TranslateError_UseR4
        ADD     sp,sp,#12

        Pull    "r1-r4, lr"
 [ No26bitCode
        SETV
        MOV     pc, lr
 |
        ORRS    pc, lr, #V_bit
 ]

        MakeErrorBlock NoSuchSWI1

      |
        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
 [ No26bitCode
        SETV
        MOV     pc, lr
 |
        ORRS    pc, lr, #V_bit
 ]
       ]

        MakeErrorBlock NoSuchSWI


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

BGetSWI ROUT                            ; Done separately for highest speed

        Push    lr
        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    "lr"
        MOV     r10, #BPutV                     ; Cache hit failed, call victor
        BL      CallVector
        Pull    "lr"                            ; Destack 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 (or PSR in 32-bit case)
        MOV     r10, r11                ; SWI number from R11->R10

  [ No26bitCode
        MRS     r11, CPSR
        AND     r14, r14, #&F0000000    ; extract caller's CCs
        BIC     r11, r11, #&F0000000    ; mask out ours
        BIC     r11, r11, #I32_bit      ; enable IRQs
        ORR     r11, r11, r14           ; add in CCs
        MSR     CPSR_cf, r11            ; and set it all up
  |
        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 corrupt r10,r11 IFF he claims it ????

        Pull    lr                      ; Punter lr has VClear
        BICCC   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
  [ No26bitCode
        MRS     r11, CPSR
        AND     r14, r14, #&F0000000    ; extract caller's CCs
        BIC     r11, r11, #&F0000000    ; mask out ours
        ORR     r11, r11, #I32_bit      ; disable IRQs
        ORR     r11, r11, r14           ; add in CCs
        MSR     CPSR_cf, r11            ; and set it all up
  |
        ORR     r14, lr, #SVC_mode+I_bit ; Disable IRQ
        TEQP    r14, #0
  ]
        BL      CallVector
        Pull    lr                      ; Punter lr has VClear
        BICCC   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
        LDR     r1, =ZeroPage
        LDR     r1, [r1, #MemLimit]
        LDR     r2, =ZeroPage+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
 [ No26bitCode
        TSTEQ   r0, #3
 |
        TSTEQ   r0, #ARM_CC_Mask
 ]
        MOVNE   r2,  #0
        LDR     r12, =ZeroPage
        STR     r2,  [r12, #ReturnCode]
        LDR     r12, [r12, #RCLimit]
        CMP     r2, r12
        SWIHI   OS_GenerateError        ; really generate an error

        ADD     sp, sp, #8              ; junk SWI no and R14 on stack
        Pull    "r10-r12"
        LDR     r0, =ZeroPage
        LDR     lr, [r0, #SExitA]
        STR     lr, [r0, #Curr_Active_Object]
        LDR     r12, [r0, #SExitA_ws]
        LDR     sp_svc, =SVCSTK
 [ No26bitCode
        MRS     r0, CPSR
        MSR     CPSR_c, #I32_bit+SVC2632 ; IRQs off (to protect SPSR_svc)
        BIC     r0, r0, #I32_bit+F32_bit+&0F
        MSR     SPSR_cxsf, r0            ; Get ready for USR26/32, IRQs on
        MOVS    pc, lr                  ; lr->pc, SPSR->CPSR
 |
        BICS    pc, lr, #ARM_CC_Mask
 ]

ABEX    =       "ABEX"                  ; Picked up as word

        LTORG

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; 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

        LDR     r10, =ZeroPage
        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

 [ StrongARM
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI XOS_PlatformFeatures

PlatFeatSWI ROUT
        Push    lr
        CMP     r0, #0                  ;Is it a known reason code?
        BNE     %FT50                   ;No, so send out a service call

        ;Ok, it's the 'code_features' reason code.
      [ ZeroPage <> 0
        LDR     r0, =ZeroPage
      ]
        LDR     r0,[r0, #ProcessorFlags]
        TST     r0, #CPUFlag_InterruptDelay
        ADRNE   r1, platfeat_irqinsert  ;Yep, so point R1 to the delay routine
        MOVEQ   r1, #0
        Pull    lr
        B       SLVK                    ;Return

platfeat_irqinsert
        MOV     r0, r0
        MOV     r0, r0
        MOV     r0, r0
        MOV     r0, r0
        MOV     r0, r0
        MOV     pc, lr

50
  [ {FALSE}
        Push    "r1-r8"
        MOV     r1, #Service_UnknownPlatformFeatures
        Pull    "r2-r9"
        BL      Issue_Service
        CMP     r1, #0
        BNE     %FT75
        Push    "r2-r9"
        Pull    "r1-r8"
        B       SLVK                    ;Return
  ]

75      ;Get here if the service call isn't claimed.
        ADR     R0, ErrorBlock_BadPlatReas
    [ International
        Push    "lr"
        BL      TranslateError
        Pull    "lr"
    ]
        B       SLVK_SetV

        MakeErrorBlock BadPlatReas
  ]

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

GenErrorSWI * SLVK_SetV

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

        END