; 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     => Middle

; Compatibility fudgery for OS_ReadLine and ReadLineV with 32-bit addresses

ReadLineSWI
        Push    "r4,lr"
        MOV     r4, #0
        SWI     XOS_ReadLine32
        Pull    "r4,lr"
        ; Pass back NZCV bits
        MRS     r11, CPSR
      [ NoARMT2
        BIC     lr,  lr,  #N_bit+Z_bit+C_bit+V_bit
        AND     r11, r11, #N_bit+Z_bit+C_bit+V_bit
        ORR     lr, lr, r11
      |
        ASSERT (N_bit+Z_bit+C_bit+V_bit)=&F0000000
        MOV     r11, r11, LSR #28
        BFI     lr, r11, #28, #4
      ]
        B       SLVK

ReadLine32SWI
        MOV     r11, #OS_ReadLine
        B       VecSwiDespatch

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; VecRdLine - Read line from input stream (OSWORD 0 equivalent)

; In    r0 -> buffer for characters
;       r1 =  max length of line (excluding carriage return)
;       r2 = lowest character put into buffer
;       r3 = highest character put into buffer
;       r4 = flags
;               bit 31 set means don't reflect characters that don't go in the buffer
;               bit 30 set means reflect with the character in R4
;               bits 7-0 = character to echo if r4 bit 30 is set
;       wp -> OsbyteVars

; Out   r0, r2, r3 corrupted
;       r1 = length of line (excluding carriage return)
;       C=0 => line terminated by return (CR or LF)
;       C=1 => line terminated by ESCAPE

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

VecRdLine ROUT

        Push    "R4-R7"

        MOV     R7, R4                  ; R7 = flags + echo byte
        MOV     R4, R0                  ; R4 -> buffer

        MOV     R6, #0                  ; R6 = index into buffer
        STRB    R6, PageModeLineCount   ; reset page lines

        B       %FT10
        LTORG

05
        SWI     XOS_WriteC
        BVS     ReadLine_Vset
10
        SWI     XOS_ReadC
        BVS     ReadLine_Vset
        BCS     %FT70                   ; ESCAPE

        LDRB    R5, WrchDest            ; does output include VDU ?
        TST     R5, #2
        BNE     %FT30                   ; no, then still buffer

        LDRB    R5, VDUqueueItems       ; is VDU queueing ?
        TEQ     R5, #0
        BNE     %BT05                   ; yes, then just print

30
        TEQ     R0, #127                ; is it DELETE ?
        TEQNE   R0, #8                  ; or backspace?
        BNE     %FT40                   ; no, then skip

        TEQ     R6, #0                  ; yes, then have we any chars ?
        BEQ     %BT10                   ; no, then loop
        SUB     R6, R6, #1              ; go back 1 char
        MOV     R0, #127
        B       %BT05                   ; print DEL and loop

40
        TEQ     R0, #21                 ; is it CTRL-U ?
        BNE     %FT50                   ; no, then skip

        TEQ     R6, #0                  ; yes, then have we any chars ?
        BEQ     %BT10                   ; no, then loop

45
        SWI     XOS_WriteI+127          ; print DELs to start of line
        BVS     ReadLine_Vset
        SUBS    R6, R6, #1
        BNE     %BT45
        B       %BT10                   ; then loop

50
        TEQ     R0, #13                 ; is it CR ?
        TEQNE   R0, #10                 ; or LF ?
        MOVEQ   r0, #13                 ; always store CR if so
        STRB    R0, [R4, R6]            ; store byte in buffer
        BEQ     %FT60                   ; Exit if either

        CMP     R6, R1                  ; is buffer full ?
        MOVCS   R0, #7                  ; if so, beep and loop
        BCS     %BT05

        CMP     R0, R2                  ; is char >= min ?
        CMPCS   R3, R0                  ; and char <= max ?
        ADDCS   R6, R6, #1              ; if so, then inc pointer
        BCS     %FT80
        TST     R7, #&80000000          ; no reflection
        BNE     %BT10                   ; of non-entered chars

80      TST     R7, #&40000000
        ANDNE   R0, R7, #&FF            ; echo char -> R0

        B       %BT05                   ; echo character

60      SWI     XOS_NewLine
        BVS     ReadLine_Vset

; insert code here to call NetVec with R0 = &0D

70
        CLRV
EndReadLine
        MOVVC   R0, R4                  ; restore R0
        LDR     R5, =ZeroPage
        LDRB    R5, [R5, #ESC_Status]
        MOVS    R5, R5, LSL #(32-6)     ; shift esc bit into carry

        MOV     R1, R6                  ; R1 := length
        Pull    "R4-R7, pc"             ; Always claiming vector

ReadLine_Vset
        SETV
        B       EndReadLine

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_Control (deprecated): set handlers

SCTRL   Push    "R0-R3, lr"

        WritePSRc SVC_mode+I_bit, R0    ; need IRQs off to get consistent state
        MOV     R0, #EventHandler
        MOV     R1, R3
        BL      CallCESWI
        STR     R1, [stack, #3*4]

        MOV     R0, #EscapeHandler
        LDR     R1, [stack, #2*4]
        BL      CallCESWI
        STR     R1, [stack, #2*4]

        MOV     R0, #ErrorHandler
        Pull    "R1, R3"
        BL      CallCESWI
        MOV     R0, R1
        MOV     R1, R3

        Pull    "R2, R3, lr"
        ExitSWIHandler


CallCESWI
        Push    lr
        MOV     r2, #0                  ; readonly
        SWI     XOS_ChangeEnvironment
        Pull    pc

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_SetEnv (deprecated): Environment setting

SSTENV  Push    "R0, R1, lr"
        WritePSRc SVC_mode+I_bit, R0    ; no irqs - want consistent set.
        MOV     R0, #AddressExceptionHandler
        MOV     R1, R7
        SWI     XOS_ChangeEnvironment
        MOV     R7, R1

        MOV     R0, #DataAbortHandler
        MOV     R1, R6
        SWI     XOS_ChangeEnvironment
        MOV     R6, R1

        MOV     R0, #PrefetchAbortHandler
        MOV     R1, R5
        SWI     XOS_ChangeEnvironment
        MOV     R5, R1

        MOV     R0, #UndefinedHandler
        MOV     R1, R4
        SWI     XOS_ChangeEnvironment
        MOV     R4, R1

        MOV     R0, #MemoryLimit
        LDR     R1, [stack, #4]
        SWI     XOS_ChangeEnvironment
        STR     R1, [stack, #4]

        MOV     R0, #ExitHandler
        Pull    "R1"
        BL      CallCESWI
        Push    "R1"

        LDR     R12, =ZeroPage
        LDR     R2, [R12, #RAMLIMIT]    ; this is read-only
        CMP     R2, #DynArea_PMP_BigPageCount
        MOVLO   R2, R2, LSL #12
        LDRHS   R2, =DynArea_PMP_BigByteCount ; more RAM than any Brazil could hope for
        MOV     R3, #0                  ; never any Brazil-type buffering
                                        ; m2 tools will complain if there is!
        Pull    "R0, R1, lr"
        ExitSWIHandler

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Change user state SWIs
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

SINTON  BIC     lr, lr, #I32_bit
        ExitSWIHandler

SINTOFF ORR     lr, lr, #I32_bit
        ExitSWIHandler

SENTERSWI
        TST   lr, #2_11100
        ORREQ lr, lr, #SVC26_mode       ; 26-bit modes -> SVC26
        BICNE lr, lr, #2_11111
        ORRNE lr, lr, #SVC32_mode       ; others -> SVC32
        ExitSWIHandler

SLEAVESWI
        BIC   lr, lr, #2_01111
        ExitSWIHandler

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_BreakPt: user breakpoint - unsuitable for debugging SVC mode code!

SBRKPT ROUT

        ADD     sp, sp, #4              ; discard stacked SWI number
        LDR     r10, =ZeroPage
        LDR     r10, [r10, #BrkBf]
        STR     r12, [r10, #16*4]       ; original PSR (with V)
        Pull    r14
        TST     r12, #T32_bit
        SUBEQ   r14, r14, #4
        SUBNE   r14, r14, #2            ; r14 = PC of the SWI
        TST     r12, #2_01111
        STR     r14, [r10, #15*4]       ; PC of the SWI put in.
        BNE     %FT01                   ; NE if not in user mode
        STR     r0, [r10], #4
        MOV     r0, r10
        LDMFD   sp, {r10-r12}

  [ SASTMhatbroken
        STMIA   r0!,{r1-r12}
        STMIA   r0, {r13_usr,r14_usr}^ ; user mode case done.
        SUB     r0, r0, #12*4
  |
        STMIA   r0, {r1-r12, r13_usr, r14_usr}^ ; user mode case done.
        NOP
  ]

10
        BL      TaskControl_ResetStacks ; R0-R3 corrupt, R13 reset
        LDR     r12, =ZeroPage+BrkAd_ws
        LDMIA   r12, {r12, pc}          ; call breakpoint handler

; Non-user mode case
01      AND     r11, r12, #2_01111      ; SVC26/SVC32 mode?
        TEQ     r11, #SVC_mode
        BEQ     %FT02                   ; [yes]

; Non-user, non-supervisor - must be IRQ, ABT, UND or SYS (no SWIs from FIQ)
        STR     r0, [r10], #4
        MOV     r0, r10
        BIC     r14, r12, #T32_bit      ; don't go into Thumb mode
        LDMFD   sp, {r10-r12}           ; Not banked
        MSR     CPSR_c, R14             ; get at registers r13 and r14
        STMIA   r0, {r1-r12}
        STR     sp, [r0, #12*4]
        STR     r14, [r0, #13*4]
        WritePSRc SVC_mode, r12
        B       %BT10

; Supervisor mode case
02      MOV     r14, r10                ; supervisor mode. R14 in buffer dead
        LDMFD   sp!, {r10-r12}
        STMIA   r14, {r0-r12}
        STR     r13, [r14, #13*4]
        LDR     r12, =&DEADDEAD
        STR     r12, [r14, #14*4]       ; mark R14 as dead
        B       %BT10

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_UnusedSWI (deprecated): Set the unused SWI handler

SUNUSED Push    "R1, lr"
        MOV     R1, R0
        MOV     R0, #UnusedSWIHandler
        SWI     XOS_ChangeEnvironment
        MOV     R0, R1
        Pull    "R1, lr"
        ExitSWIHandler

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_SetCallBack: Set callback flag

SSETCALL ROUT

        MSR     CPSR_c, #I32_bit + SVC32_mode
        LDR     r10, =ZeroPage
        LDRB    r11, [r10, #CallBack_Flag]
        ORR     r11, r11, #CBack_OldStyle
        STRB    r11, [r10, #CallBack_Flag]
        ADD     sp, sp, #4              ; Skip saved R11
        B       back_to_user_irqs_already_off
                                        ; Do NOT exit via normal mechanism

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI read mouse information
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

VecMouse
     WritePSRc SVC_mode+I_bit, R10
     MOV   R10, #MouseV
     Push "lr"
     BL    CallVector
     Pull "lr"
     ExitSWIHandler

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_SerialOp when not in kernel
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

SerialOp ROUT
        MOV     r10, #SerialV
        Push    lr
        BL      CallVector
        Pull    lr
        BICCC   lr, lr, #C_bit
        ORRCS   lr, lr, #C_bit
        B       SLVK_TestV

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Supervisor routines to set default handlers
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

; Reset Error and Escape handlers

DEFHAN LDR  R1, =GeneralMOSBuffer         ; decent length error buffer
       ADR  R0, ERRORH
       ADR  R2, ESCAPH
       MOV  R3, #0
       MOV  R4, R14
       SWI  XOS_Control

       MOV  r0, #UpCallHandler
       ADR  r1, DefUpcallHandler
       MOV  r2, #0
       SWI  XOS_ChangeEnvironment

       MOV  PC, R4

; Reset Exception, Event, BreakPoint, UnusedSWI, Exit and CallBack handlers

DEFHN2 MOV  R12, R14
       MOV  R0, #0
       MOV  R1, #0
       MOV  R2, #0
       ADR  R3, EVENTH
       SWI  XOS_Control
       LDR  R0, =ZeroPage+DUMPER
       ADR  R1, NOCALL
       SWI  XOS_CallBack
       ADRL R0, CLIEXIT
       MOV  R1, #0
       MOV  R2, #0
       ADRL R4, UNDEF
       ADRL R5, ABORTP
       ADRL R6, ABORTD
       ADRL R7, ADDREX
       SWI  XOS_SetEnv
       LDR  R0, =ZeroPage+DUMPER
       ADR  R1, DEFBRK
       SWI  XOS_BreakCtrl
       ADRL R0, NoHighSWIHandler
       SWI  XOS_UnusedSWI
       MOV  PC, R12

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; system handlers
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

DefUpcallHandler
ESCAPH
EVENTH  MOV     pc, lr


NOCALL  LDR     r0, =ZeroPage               ; default callback routine
        LDR     r14, [r0, #CallBf]
        LDR     r0, [r14, #4*16]
        MSR     SPSR_cxsf, r0
        LDMIA   r14, {r0-r12, r13_usr, r14_usr}^ ; load user's regs
        NOP
        LDR     r14, [r14, #4*15]
        MOVS    pc, r14


ERRORH ROUT

      [ International
        SWI     XOS_EnterOS

        LDR     R0,=ZeroPage+KernelMessagesBlock+4
        ADR     R1,ErrorToken
        MOV     R2,#0
        SWI     XMessageTrans_Lookup
        MOVVC   R12,R2
        ADRVS   R12,ErrorText

01
        LDRB    R0,[R12],#1
        CMP     R0,#32
        BLT     %FT99
        CMP     R0,#"%"
        SWINE   XOS_WriteC
        BVS     %FT99
        BNE     %BT01

        LDRB    R0,[R12],#1              ; Found a %
        CMP     R0,#32
        BLT     %FT99

        CMP     R0,#"0"
        LDREQ   R0,=GeneralMOSBuffer+8
        BEQ     %FT10
        CMP     R0,#"1"
        BNE     %BT01

        LDR     R3,=GeneralMOSBuffer+4
        LDR     R0,[R3]
        LDR     R1,=ZeroPage+MOSConvertBuffer
        MOV     R2,#12
        SWI     XOS_ConvertHex8

02
        LDRB    R1, [R0], #1
        CMP     R1, #"0"
        BEQ     %BT02
        CMP     R1, #0
        SUBEQ   R0, R0, #1
        SUB     R0, R0, #1

10
        SWI     XOS_Write0
        BVC     %BT01

99
        SWI     XOS_NewLine

        LDR     R0, =ZeroPage
        STRB    R0, [R0, #ErrorSemaphore]                 ; Enable error translation, in case we got here in the
                                                        ; middle of looking up an error

        B       GOSUPV                          ; switches back to User mode for us

ErrorToken      =       "Error:"
ErrorText       =       "Error: %0 (Error Number &%1)",0
        ALIGN
      |

        SWI     OS_WriteS
        =       10,13,"Error:",10,13, 0
        ALIGN
        LDR     r0, =GeneralMOSBuffer+4
        BL      PrintError
        B       GOSUPV
      ]


DEFBRK
      [ International
        WritePSRc 0, lr
        MOV     r0, r0
        LDR     r13, =ZeroPage
        LDR     r13, [r13, #BrkBf]
        LDR     r0, [r13, #15*4]
        LDR     r1, =GeneralMOSBuffer
        MOV     r2, #?GeneralMOSBuffer
        SWI     OS_ConvertHex8

; r0 -> address

        MOV     R4,R0
        LDR     R0,=ZeroPage+KernelMessagesBlock+4
        ADR     R1,BreakToken
        LDR     R2,=GeneralMOSBuffer+16
        MOV     R3,#256-16
        SWI     XMessageTrans_Lookup
        MOVVC   R0,R2
        ADRVS   R0,BreakText
        SWI     OS_Write0
        SWI     OS_NewLine

      |
        SWI     OS_WriteS
        = "Stopped at break point at &", 0
        ALIGN
        WritePSRc 0, lr
        MOV     r0, r0
        LDR     r13, =ZeroPage
        LDR     r13, [r13, #BrkBf]
        LDR     r0, [r13, #15*4]
        LDR     r1, =GeneralMOSBuffer
        MOV     r2, #?GeneralMOSBuffer
        SWI     OS_ConvertHex8
        SWI     OS_Write0
        SWI     OS_NewLine
      ]

Quit_Code
        SWI     OS_Exit

      [ International

BreakToken      =       "BreakPt:"
BreakText       =       "Stopped at break point at &%0",0
        ALIGN

      ]

PrintError
        MOV    R12, R14
        LDR    R10, [R0], #4
        SWI    XOS_Write0
        BVS    %FT02
      [ :LNOT: International
        SWI    XOS_WriteS
        =     " (Error number &", 0
        BVS    %FT02
      ]
        LDR    R1,=GeneralMOSBuffer
        MOV    R2, #&E0
        MOV    R0, R10
        SWI    XOS_ConvertHex8       ; can't fail!
01      LDRB   R1, [R0], #1
        CMP    R1, #"0"
        BEQ    %BT01
        CMP    R1, #0
        SUBEQ  R0, R0, #1
      [ International                   ; We might not have any stack so ..
        SUB    R11,R0, #1               ; R11 -> Error number
        LDR    R0, =ZeroPage+KernelMessagesBlock+4
        ADR    R1, PrintErrorString
        MOV    R2,#0                    ; Don't copy message
        SWI    XMessageTrans_Lookup
        ADRVS  R2,PrintErrorString+4    ; If no MessageTrans point at english text.
11
        LDRB   R0,[R2],#1
        CMP    R0,#32
        BLT    %FT13
        CMP    R0,#"%"
        SWINE  XOS_WriteC
        BVS    %FT13
        BNE    %BT11

        LDRB    R0,[R2],#1
        CMP     R0,#32
        BLT     %FT13                   ; Just in case the % is the last character !

        CMP     R0,#"0"                 ; We only know about %0
        BNE     %BT11

12
        LDRB    R0,[R11],#1              ; Print error number.
        CMP     R0,#32
        BLT     %BT11
        SWI     XOS_WriteC
        BVC     %BT12

13
      |
        SUB    R0, R0, #1
        SWI    XOS_Write0
        SWIVC  XOS_WriteI+")"
      ]
        SWIVC  XOS_NewLine
02      MOV    PC, R12

      [ International
PrintErrorString
        =     "Err: (Error number &%0)", 0
        ALIGN
      ]

        LTORG

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Exception handling

DumpyTheRegisters  ROUT
; R0 points at r8 in register dump. r0-r7, PC, PSR saved
; R1 is PSR
; R4 is offset from saved PC for error message, or -1 if error should be used verbatim
; R14 points at error block
; In ABT32 or UND32
        MOV     R7, R14                 ; put error address into unbanked register
        TST     R1, #&0F
  [ SASTMhatbroken
        STMEQIA R0!,{R8-R12}
        STMEQIA R0, {R13,R14}^        ; user mode case done.
        SUBEQ   R0, R0, #5*4
  |
        STMEQIA R0, {R8-R14}^         ; user mode case done.
  ]
        BEQ     UNDEF2

        MRS     R3, CPSR
        AND     R3, R3, #&0F

        ORR     R2, R1, #I32_bit :OR: F32_bit
        BIC     R2, R2, #T32_bit
        MSR     CPSR_c, R2              ; change into original mode
        STMIA   R0, {R8-R12}            ; save the banked registers

        AND     R2, R1, #&0F
        CMP     R2, R3                  ; did abort come from our abort-handling mode?
        MOV     R3, SP
        ADDEQ   R3, R3, #17*4           ; adjust stored SP if so
        LDREQ   R14, =&DEADDEAD         ; and mark R14 as corrupt
        STR     R3, [R0, #5*4]
        EORS    R2, R2, #FIQ_mode       ; Was we in FIQ ? Zero if so
        STR     R14, [R0, #6*4]

        BNE     UNDEF2
        MSR     CPSR_c, #I32_bit+F32_bit+ABT32_mode ; into ABT mode so we have a stack (try and preserve SVC stack for any exception dump that's produced)
        Push    "r0"
      [ ZeroPage <> 0
        LDR     R2, =ZeroPage
      ]
        AddressHAL R2
        CallHAL HAL_FIQDisableAll
        Pull    "r0"
UNDEF2
; ... and fall into
UNDEF1
        ; R0 points at R8 in register dump
        ; R7 points at error block
        MSR     CPSR_c, #I32_bit+F32_bit+ABT32_mode ; into ABT mode for exception dump
        SUB     R0, R0, #8*4            ; Make R0 sensible for vector
        MOV     R1, R7
        MOV     R2, #SeriousErrorV_Collect
        MOV     R10, #SeriousErrorV
        BL      CallVector

        ; Unwind & flatten all the stacks.
        ; This does leave the register dump floating somewhere in the abort
        ; stack, but with all interrupts turned off it should be safe enough,
        ; especially as we copy it away immediately afterwards.
        ADD     R10, R0, #8*4
        BL      TaskControl_ResetStacks ; R0-R3 corrupt, R13 reset

        MSR     CPSR_c, #I32_bit+F32_bit+SVC32_mode ; into SVC mode

        ; Copy the register dump from its unsafe location on the abort stack,
        ; to a temp location on the SVC stack
        LDMIA   R10, {R0-R3, R5-R6, R8-R9, R11} ; R8-R15, PSR
        Push    "R0-R3, R5-R6, R8-R9, R11"
        LDMDB   R10, {R0-R3, R5-R6, R8-R9} ; R0-R7
        Push    "R0-R3, R5-R6, R8-R9"

        MSR     CPSR_c, #SVC32_mode+I32_bit ; Restore FIQs, we don't need them to be blocked now that the register dump is safe

        ; Check that ExceptionDump is safe to use
        Push    "R7"                    ; Preserve error ptr
        LDR     R5, =ZeroPage
        LDR     R1, [R5, #ExceptionDump]
        MOV     R0, #24
        ADD     R2, R1, #17*4
        ; Must be SVC-writable, user+SVC readable, word aligned
        SWI     XOS_Memory
        AND     r1, r1, #CMA_Completely_UserR+CMA_Completely_PrivR+CMA_Completely_PrivW
        TEQ     r1, #CMA_Completely_UserR+CMA_Completely_PrivR+CMA_Completely_PrivW
        TSTEQ   r2, #3
        BEQ     %FT05
        ; Reset to default location. Unfortunately the Debugger module is a bit
        ; braindead and will only show the contents of the register dump located
        ; within its workspace, so resetting it to the kernel buffer isn't the
        ; best for debugging. But it's better than an infinite abort loop!
        MOV     R0, #ExceptionDumpArea
        LDR     R1, =ZeroPage+DUMPER
        SWI     XOS_ChangeEnvironment
05
        Pull    "R14"                   ; Restore error ptr

        ; Now move the dump from the SVC stack to ExceptionDump
        LDR     R0, [R5, #ExceptionDump]
        Pull    "R1-R2,R5-R10"          ; R0-R7
        STMIA   R0!, {R1-R2,R5-R10}
        Pull    "R1-R2,R5-R11"          ; R8-R15, PSR
        STMIA   R0, {R1-R2,R5-R11}

        SUB     R0, R0, #8*4
                                        ; try and put back user R10-R12
        Push    "R5-R7"                 ; for error handler to find on stack
        LDR     R1, [R0, #15*4]
        Push    R1

        CMP     r4, #-1
        BNE     %FT07
        ; Custom error provided, try and copy it to the stack to make sure it
        ; doesn't get overwritten before we're able to report it (there's a
        ; chance it's in a shared MessageTrans buffer)
        LDR     r10, =ZeroPage
        LDRB    r10, [r10, #ErrorSemaphore]
        TEQ     r10, #0
        MOV     r0, r14                 ; Error block to copy from
        MOVNE   r10, r14                ; !=R0 if we want to copy, = if we don't
        B       %FT11                   ; Jump to the copy check

07
        LDR     R0, =GeneralMOSBuffer+128 ; so can do deviant sharing !

       [ International
        LDR     r10, =ZeroPage
        LDRB    r10, [r10, #ErrorSemaphore]
        TEQ     r10, #0                 ; if ok to translate error
        MOVEQ   r10, r14
        BEQ     %FT10
       ]

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

01      LDRB    r11, [r14], #1          ; Copy error string
        STRB    r11, [r0], #1
        CMP     r11, #"%"               ; Test for "%" near end of string
        BNE     %BT01
10
        SUB     r1, r0, #1              ; point, ready for conversion

        LDR     R2, =GeneralMOSBuffer+?GeneralMOSBuffer
        SUB     r2, r2, r1              ; amount left in buffer

        LDR     R0, =ZeroPage
        LDR     R0, [R0, #ExceptionDump]
        LDR     R0, [R0, #15*4]         ; saved PC
        SUB     R0, R0, R4
        SWI     XOS_ConvertHex8

      [ International
        LDR     r4, =ZeroPage
        LDRB    r4, [r4, #ErrorSemaphore]
        TEQ     r4, #0
        LDRNE   R0, =GeneralMOSBuffer+128
        BNE     %FT20
        MOV     R4, R0
        MOV     R0, R10
        BL      TranslateError_UseR4
        ; If the exception dump processing takes too long then there's a good
        ; chance the error buffer MessageTrans gave us will get overwritten
        ; before we're able to call OS_GenerateError. Copy the error to the
        ; stack, then copy it back into a MessageTrans block before calling
        ; OS_GenerateError.
11
        EORS    R4, R0, R10 ; Did TranslateError work?
        BEQ     %FT20
        SUB     SP, SP, #256
        MOV     R4, SP
        MOV     R5, #4
        LDR     R6, [R0]
        STR     R6, [R4]
15
        LDRB    R6, [R0, R5]
        CMP     R6, #0
        STRB    R6, [R4, R5]
        ADD     R5, R5, #1
        BNE     %BT15
        MOV     R0, R4
20
      |
        LDR     R0, =GeneralMOSBuffer+128
      ]

        ; Let everyone know that the stacks have been reset
        MOV     R2, #SeriousErrorV_Recover
        MOV     R10, #SeriousErrorV
        BL      CallVector

        ; Now enable IRQs and trigger exception dump processing
        MSR     CPSR_c, #SVC32_mode
        MOV     R2, #SeriousErrorV_Report
        MOV     R10, #SeriousErrorV
        BL      CallVector

      [ International
        ; Try and copy error block from stack back to MessageTrans
        LDR     R3, =ZeroPage
        LDRB    R3, [R3, #ErrorSemaphore]
        TEQ     R3, #0
        BNE     %FT30
        CMP     R4, #0 ; Check if original TranslateError call worked (if not, no error block to copy)
        BEQ     %FT30
        SWI     XMessageTrans_CopyError
        ; If TranslateError worked, assume MessageTrans_CopyError worked too
        ADD     SP, SP, #256
30
      ]
        SWI     OS_GenerateError

        LTORG

UNDEF ROUT
        ; In UND32 mode, with a stack
        ; Place exception dump on stack until we can be sure ExceptionDump is safe
        STR     R14, [SP, #-8]!
        SETPSR  F_bit :OR: I_bit, R14
        SUB     SP, SP, #17*4-8
        MOV     R14, SP
        STMIA   R14!, {R0-R7}
        MRS     R1, SPSR
        STR     R1, [R14, #(16-8)*4]            ; save PSR
        TST     R1, #T32_bit
        MOV     R0, R14
        MOVEQ   R4, #4
        MOVNE   R4, #2
        BL      DumpyTheRegisters
        MakeErrorBlock UndefinedInstruction

ABORTP ROUT
        ; In ABT32 mode, with a stack
        STR     R14, [SP, #-8]!
        SETPSR  F_bit :OR: I_bit, R14
        SUB     SP, SP, #17*4-8
        MOV     R14, SP
        STMIA   R14!, {R0-R7}
        MRS     R1, SPSR
        STR     R1, [R14, #(16-8)*4]            ; save PSR
        MOV     R0, R14
        MOV     R4, #4
        BL      DumpyTheRegisters
        MakeErrorBlock InstructionAbort

ABORTD ROUT
        ; In ABT32 mode, with a stack
        STR     R14, [SP, #-8]!
        SETPSR  F_bit :OR: I_bit, R14
        SUB     SP, SP, #17*4-8
        MOV     R14, SP
        STMIA   R14!, {R0-R7}
        MRS     R1, SPSR
        STR     R1, [R14, #(16-8)*4]            ; save PSR
        MOV     R0, R14
        MOV     R4, #8
        BL      DumpyTheRegisters
        MakeErrorBlock DataAbort


ADDREX ROUT
; This really can't happen. Honest
        ; ??? in ABT32 mode, with a stack?
        STR     R14, [SP, #-8]!
        SETPSR  F_bit :OR: I_bit, R14
        SUB     SP, SP, #17*4-8
        MOV     R14, SP
        STMIA   R14!, {R0-R7}
        MRS     R1, SPSR
        STR     R1, [R14, #(16-8)*4]            ; save PSR
        MOV     R0, R14
        MOV     R4, #0
        BL      DumpyTheRegisters
        MakeErrorBlock AddressException


; Can branch through zero in any mode
; We go through a trampoline which stores R1 and R14 (at R14 on entry)

Branch0_NoTrampoline_DummyRegs
        &       &DEADDEAD, &DEADDEAD
RESET1 ROUT
Branch0_NoTrampoline
        ADR     R14, Branch0_NoTrampoline_DummyRegs
Branch0_FromTrampoline

        LDR     R1, =ZeroPage
        LDR     R1, [R1, #ExceptionDump]
        STMIA   R1, {R0-R12}
        STR     R13, [R1, #13*4]
        LDR     R0, [R14, #0]
        STR     R0, [R1, #1*4]
        LDR     R0, [R14, #4]
        STR     R0, [R1, #14*4]
 [ XScaleJTAGDebug
        MRS     R0, CPSR
        AND     R0, R0, #&1F
        TEQ     R0, #&15        ; Debug mode?
        BNE     %FT20
        LDR     R13, =ZeroPage
        LDR     R0, [R13, #ProcessorFlags]
        ORR     R0, R0, #CPUFlag_XScaleJTAGconnected
        STR     R0, [R13, #ProcessorFlags]
        LDMIA   R1, {R0, R1}
        B       DebugStub
20
 ]
        MOV     R0, #0
        STR     R0, [R1, #15*4]
        MRS     R0, CPSR
        STR     R0, [R1, #16*4]
        SWI     XOS_EnterOS

        LDR     R0, =ZeroPage
        LDR     R0, [R0, #ExceptionDump]
        ADD     R0, R0, #8*4

        ADR     R7, ErrorBlock_BranchThrough0
        MOV     R4, #0
        B       UNDEF1
        MakeErrorBlock BranchThrough0

 [ XScaleJTAGDebug
        ; Magic from the Multi-ICE User Guide
        ALIGN   32
DebugStub ROUT
        ARM_read_control R13
        AND     R13, R13, #MMUC_I
        ORR     R14, R14, R13, LSR #12
        ARM_read_control R13
        ORR     R13, R13, #MMUC_I
        ARM_write_control R13
        ADR     R13, DebugStubLine2
        MCR     p15, 0, R13, C7, C5, 1
        MCR     p15, 0, R13, C7, C5, 6
10      MRC     p14, 0, R15, C14, C0
        BVS     %BT10
        MOV     R13, #&00B00000
        MCR     p14, 0, R13, C8, C0
20      MRC     p14, 0, R15, C14, C0
        BPL     %BT20
        ARM_read_control R13
        TST     R14, #1
        BICEQ   R13, R13, #MMUC_I
        ARM_write_control R13
        MRC     p14, 0, R13, C9, C0
        MOV     PC, R13
        ALIGN   32
DebugStubLine2
        SPACE   32
 ]

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI to call the UpCall vector
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

DoAnUpCall ROUT

        Push    lr                  ; better have one of these to pull later !
        MRS     r12, CPSR
      [ NoARMT2
        BIC     r12, r12, #&F0000000
        BIC     r12, r12, #I32_bit:OR:F32_bit
        AND     r10, lr, #&F0000000 ; copy user flags (I bit clear)
        ORR     r10, r10, r12
      |
        MOV     lr, lr, LSR #28
        BIC     r10, r12, #I32_bit:OR:F32_bit
        BFI     r10, lr, #28, #4 ; copy user flags (I bit clear)
      ]
        MSR     CPSR_cf, r10        ; ints on, stay in SVC mode, flags in psr
        MOV     r10, #UpCallV
        BL      CallVector
 [ NoARMT2
        Pull    lr
        BIC     lr, lr, #&F0000000
        MRS     R10, CPSR
        MOV     R10, R10, LSR #(32-4)
        ORR     lr, lr, R10, LSL #(32-4)
 |
        MRS     R10, CPSR
        Pull    lr
        MOV     R10, R10, LSR #28
        BFI     lr, R10, #28, #4
 ]
        ExitSWIHandler

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_ChangeEnvironment: Call the environment change vector
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

ChangeEnvironment ROUT

        Push    lr
        MOV     R10, #ChangeEnvironmentV
        BL      CallVector
        Pull    lr
        B       SLVK_TestV


; ..... and the default handler .....

AdjustOurSet
        WritePSRc SVC_mode+I_bit, R14
        CMP     R0, #MaxEnvNumber
        BHI     AOS_Silly

  [ {FALSE}
        CMP     r0, #CallBackHandler
        BLEQ    testcallbackpending
  ]

        ADR     R10, AOS_Table
        ADD     R11, R0, R0, LSL #1   ; number * 3
        ADD     R10, R10, R11, LSL #2 ; point at entry

        MOV     R12, R1
        LDR     R11, [R10]
        CMP     R11, #0
        LDRNE   R1,  [R11]
        CMPNE   R12, #0
        STRNE   R12, [R11]

        MOV     R12, R2
        LDR     R11, [R10, #4]
        CMP     R11, #0
        LDRNE   R2,  [R11]
        CMPNE   R12, #0
        STRNE   R12, [R11]

        MOV     R12, R3
        LDR     R11, [R10, #8]
        CMP     R11, #0
        LDRNE   R3,  [R11]
        CMPNE   R12, #0
        STRNE   R12, [R11]

        Pull    pc

AOS_Silly
        ADR     r0, ErrorBlock_BadEnvNumber
      [ International
        BL      TranslateError
      ]
exit_AOS
        SETV
        Pull    "pc"
        MakeErrorBlock BadEnvNumber

AOS_Table
        &  ZeroPage+MemLimit     ;  MemoryLimit
        &  0
        &  0

        &  ZeroPage+UndHan       ; UndefinedHandler
        &  0
        &  0

        &  ZeroPage+PAbHan       ; PrefetchAbortHandler
        &  0
        &  0

        &  ZeroPage+DAbHan       ; DatabortHandler
        &  0
        &  0

        &  ZeroPage+AdXHan       ; AddressExceptionHandler
        &  0
        &  0

        &  0            ; OtherExceptionHandler
        &  0
        &  0

        &  ZeroPage+ErrHan       ; ErrorHandler
        &  ZeroPage+ErrHan_ws
        &  ZeroPage+ErrBuf

        &  ZeroPage+CallAd       ; CallBackHandler
        &  ZeroPage+CallAd_ws
        &  ZeroPage+CallBf

        &  ZeroPage+BrkAd        ; BreakPointHandler
        &  ZeroPage+BrkAd_ws
        &  ZeroPage+BrkBf

        &  ZeroPage+EscHan       ; EscapeHandler
        &  ZeroPage+EscHan_ws
        &  0

        &  ZeroPage+EvtHan       ; EventHandler
        &  ZeroPage+EvtHan_ws
        &  0

        &  ZeroPage+SExitA       ; ExitHandler
        &  ZeroPage+SExitA_ws
        &  0

        &  ZeroPage+HiServ       ; UnusedSWIHandler
        &  ZeroPage+HiServ_ws
        &  0

        &  ZeroPage+ExceptionDump ; ExceptionDumpArea
        &  0
        &  0

        &  ZeroPage+AplWorkSize  ; application space size
        &  0
        &  0

        &  ZeroPage+Curr_Active_Object
        &  0
        &  0

        &  ZeroPage+UpCallHan
        &  ZeroPage+UpCallHan_ws
        &  0

        assert (.-AOS_Table)/12 = MaxEnvNumber

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; SWI OS_ReadDefaultHandler

; In    r0 = environment number

ReadDefaultHandler ROUT

        CMP     r0, #(dhte-defhantab)/12
        MOVHS   r0, #0                  ; return wally value
        ADD     r10, r0, r0, LSL #1     ; *3
        ADD     r10, pc, r10, LSL #2    ; *4 (pc = defhantab-4)
        LDMIB   r10, {r1-r3}            ; gives additional +4
        ExitSWIHandler

defhantab
     & 0                ; wally entry
     & 0
     & 0

     & UNDEF            ; UndefinedHandler
     & 0
     & 0

     & ABORTP           ; PrefetchAbortHandler
     & 0
     & 0

     & ABORTD           ; DataAbortHandler
     & 0
     & 0

     & ADDREX           ; AddressExceptionHandler
     & 0
     & 0

     & 0                ; OtherExceptionHandler
     & 0
     & 0

     & ERRORH           ; ErrorHandler
     & 0
     & GeneralMOSBuffer

     & NOCALL           ; CallBackHandler
     & 0
     & ZeroPage+DUMPER

     & DEFBRK           ; BreakPointHandler
     & 0
     & ZeroPage+DUMPER

     & ESCAPH           ; EscapeHandler
     & 0
     & GeneralMOSBuffer

     & EVENTH           ; EventHandler
     & 0
     & 0

     & CLIEXIT          ; ExitHandler
     & 0
     & 0

     & NoHighSWIHandler ; UnusedSWIHandler
     & 0
     & 0

     & 0                ; exception dump
     & 0
     & 0

     & 0                ; app space size
     & 0
     & 0

     & 0                ; cao pointer
     & 0
     & 0

     & DefUpcallHandler ; upcall handler
     & 0
     & 0

dhte

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; In    r0 = sysinfo handle

; Out   r0 = sysinfo for r0in

ReadSysInfo_Code ROUT
        CMP     r0,#16 ;R0 > 15, so illegal value
        ADDLO   PC, PC, R0,LSL #2
        B       ReadSysInfo_InvalidReason

        B       %FT00
        B       %FT10
        B       %FT20
        B       %FT30
        B       %FT40
        B       %FT50
        B       %FT60
        B       %FT70
        B       %FT80
        B       %FT90
        B       ReadSysInfo_InvalidReason ; ROL's "read OS version" call
        B       %FT110
        B       %FT120
        B       %FT130
        B       %FT140
        B       %FT150

ReadSysInfo_InvalidReason
        ADR     r0, ErrorBlock_BadReadSysInfo
      [ International
        Push    "lr"
        BL      TranslateError
        Pull    "lr"
      ]
        ORR     lr, lr, #V_bit
        ExitSWIHandler

        MakeErrorBlock BadReadSysInfo

; ReadSysInfo(0) - return configured screensize in r0

00
        Push    "r1, r2, lr"
        MOV     r0, #ReadCMOS
        MOV     r1, #ScreenSizeCMOS
        SWI     XOS_Byte
        AND     r0, r2, #&7F            ; top bit is reserved
        LDR     r10, =ZeroPage
        LDR     r10, [r10, #Page_Size]
        MUL     r0, r10, r0
        BL      MassageScreenSize       ; adjust for min and max or default values
        Pull    "r1, r2, lr"
        ExitSWIHandler

; ReadSysInfo(1) - returns configured mode/wimpmode in r0
;                          configured monitortype in r1
;                          configured sync in r2
;                          (all de-autofied)

10
        Push    "r3-r5, lr"
        BL      Read_Configd_Sync
        MOV     r2, r0
        LDR     r1, =ZeroPage+VduDriverWorkSpace+CurrentMonitorType      ; read current monitortype
        LDR     r1, [r1]
        TEQ     r1, #MonitorTypeEDID :SHR: MonitorTypeShift              ; equate EDID=auto in this context
        MOVEQ   r1, #-1
        BL      Read_Configd_Mode
        CMP     r0, #-1                         ; if none of the three are auto, don't bother with translation
        CMPNE   r1, #-1
        CMPNE   r2, #-1
        BNE     %FT15
        BL      TranslateMonitorLeadType        ; issue service or work it out ourselves
        CMP     r0, #-1                         ; if mode auto
        MOVEQ   r0, r3                          ; then replace with default
        CMP     r1, #-1                         ; if monitortype auto
        MOVEQ   r1, r4                          ; then replace with default
        CMP     r2, #-1                         ; if sync auto
        MOVEQ   r2, r5                          ; then replace with default
15
        Pull    "r3-r5, lr"
        ExitSWIHandler

; ReadSysInfo(2)
;
; in:   r0 = 2
;
; out:  r0 = hardware configuration word 0
;               bits 0-7 = special functions chip type
;                               0 => none
;                               1 => IOEB
;               bits 8-15 = I/O control chip type
;                               0 => IOC
;                               1 => IOMD
;                             255 => none
;               bits 16-23 = memory control chip type
;                               0 => MEMC1/MEMC1a
;                               1 => IOMD
;                             255 => none
;               bits 24-31 = video control chip type
;                               0 => VIDC1a
;                               1 => VIDC20
;                             255 => none
;       r1 = hardware configuration word 1
;               bits 0-7 = I/O chip type
;                               0 => absent
;                               1 => 82C710/711 or SMC'665 or similar
;               bits 8-31 reserved (set to 0)
;       r2 = hardware configuration word 2
;               bits 0-7 = LCD controller type
;                               0 => absent
;                               1 => present (type 1) eg A4 portable
;                               2 => present (type 2) eg Stork portable
;               bits 8-15 = IOMD variant (when marked as present in word 0)
;                               0 => IOMD
;                               1 => IOMDL ie ARM7500 (Morris)
;               bits 16-23 = VIDC20 variant (when marked as present in word 0)
;                               0 => VIDC20
;                               1 => VIDC2L ie ARM7500 (Morris)
;               bits 24-31 = miscellaneous flags
;                      bit 24   0 => IIC bus slow (100kHz)
;                               1 => IIC bus fast (400kHz)
;                      bit 25   0 => keep I/O clocks running during idle
;                               1 => stop I/O clocks during idle
;                      bits 26-31 reserved (set to 0)
;       r3 = word 0 of unique machine ID, or 0 if unavailable
;       r4 = word 1 of unique machine ID, or 0 if unavailable

20
        Push    "r9,r14"
        AddressHAL
        SUB     sp, sp, #12
        ADD     a1, sp, #0
        ADD     a2, sp, #4
        ADD     a3, sp, #8
        CallHAL HAL_HardwareInfo
        LDR     r12, =ZeroPage
        LDR     r3, [r12, #RawMachineID+0]
        LDR     r4, [r12, #RawMachineID+4]
        MOV     r3, r3, LSR #8                  ; lose first 8 bits
        ORR     r3, r3, r4, LSL #24             ; and put bits 0..7 of r3 into bits 24..31 of r2
        MOV     r4, r4, LSL #8                  ; lose CRC bits
        MOV     r4, r4, LSR #16                 ; and move the rest down to the bottom
        Pull    "r0-r2,r9,r14"
        ExitSWIHandler

; ReadSysInfo(3)
;
; in:   r0 = 3
;
; out:  r0 = I/O chip base features mask                710     711     665     669     UMC669
;               Bits 0..3   Base IDE type               1       1       1       1       1
;               Bits 4..7   Base FDC type               1       1       1       1       1
;               Bits 8..11  Base parallel type          1       1       1       1       1
;               Bits 12..15 Base 1st serial type        1       1       1       1       1
;               Bits 16..19 Base 2nd serial type        0       1       1       1       1
;               Bits 20..23 Base Config type            1       2       3       4       5
;               Bits 24..31 Reserved                    0       0       0       0       0
;
;       r1 = I/O chip extra features mask               710     711     665     669     UMC669
;               Bits 0..3   IDE extra features          0       0       0       0       0
;               Bits 4..7   FDC extra features          0       0       0       0       0
;               Bits 8..11  parallel extra features     0       0       1       1       1
;               Bits 12..15 1st serial extra features   0       0       1       1       1
;               Bits 16..19 2nd serial extra features   0       0       1       1       1
;               Bits 20..23 config extra features       0       0       0       0       0
;               Bits 24..31 Reserved                    0       0       0       0       0
;
;       r2-r4 undefined (reserved for future expansion)
;

30
        Push    "r9,r14"
        AddressHAL
        SUB     sp, sp, #8
        ADD     a1, sp, #0
        ADD     a2, sp, #4
        CallHAL HAL_SuperIOInfo
        Pull    "a1,a2,r9,r14"
        ExitSWIHandler

; ReadSysInfo(4)
;
; On entry:       r0 = 4 (reason code)
;
; On exit:        r0 = LS32bits of Ethernet Network Address (or 0)
;                 r1 = MS16bits of Ethernet Network Address (or 0)
;
; Use:            Code loaded from the dedicated Network Expansion Card or
;                 from a normal Expansion Card should use the value returned
;                 by this call in preference to a locally provided value.

40
        Push    "r2-r3,r9,r14"
        AddressHAL
        MOV     r0, #0
        CallHAL HAL_ExtMachineID
        Pull    "r2-r3,r9,r14"
        TEQ     r0, #0
        BNE     ExitNoEthernetAddress                   ; Extended machine ID is implemented - don't attempt to extract a MAC from RawMachineID, it's just a hash of the extended ID
        LDR     r0, =ZeroPage
        LDRB    r1, [ r0, #RawMachineID ]               ; The family byte
        TEQ     r1, #&81                                ; Excellent,a custom part - we'll use it
        BNE     ExitNoEthernetAddress
        LDR     r1, [ r0, #RawMachineID+4 ]             ; Acorn's ID and part#
        BIC     r1, r1, #&FF000000                      ; Remove the CRC
        LDR     r0, =&0050A4                            ; Acorn's ID is &005
        TEQ     r1, r0                                  ; Is this an Acorn part?
        LDR     r0, =ZeroPage
        BNE     %FT45
        LDR     r0, [ r0, #RawMachineID ]
        MOV     r0, r0, LSR #8                          ; Lose family byte
        LDR     r1, =&0000A4100000
        ADD     r0, r1, r0                              ; Add Acorn base Ethernet address to number from Dallas
        MOV     r1, #0                                  ; Top 16 bits are zero in Acorn's MAC address allocation
        ExitSWIHandler
45
        MOV     r1, r1, LSR #8                          ; It's unique,but not an Acorn part - extract MAC address verbatim
        Push    "r2"
        LDR     r2, [ r0, #RawMachineID ]
        MOV     r2, r2, LSR #8
        LDRB    r0, [r0, #RawMachineID+4]
        ORR     r0, r2, r0, LSL#24
        Pull    "r2"
        ExitSWIHandler

ExitNoEthernetAddress
        MOV     r0, #0
        MOV     r1, #0
        ExitSWIHandler

; ReadSysInfo(5)
;
; On entry:       r0 = 5 (reason code)
;
; On exit:        r0 = LSW of Raw data from unique id chip
;                 r1 = MSW of Raw data from unique id chip

50
        LDR     r0, =ZeroPage
        LDR     r1, [r0, #RawMachineID+4]
        LDR     r0, [r0, #RawMachineID+0]
        ExitSWIHandler

; ReadSysInfo(6) - read kernel values (Acorn use only; eg. SoftLoad, ROMPatch)
;
; On entry:       r0 =  6 (reason code)
;                 r1 -> input block, 1 word per entry, giving number of value required, terminated by -1
;           OR:   r1 =  0 if just 1 value is required, and this is to beturned in r2
;                 r2 -> output block, 1 word per entry, will be filled in on output
;           OR:   r2 =  number of single value required, if r1 = 0
;
; On exit:
;   if r1 entry != 0:
;         r0,r1,r2 preserved
;         output block filled in, filled in value(s) set to 0 if unrecognised/no longer meaningful value(s)
;   if r1 entry = 0:
;         r0,r1 preserved
;         r2 = single value required, or set to 0 if if unrecognised/no longer meaningful value
;
;  valid value numbers available - see table below
;

60
        Push    "r0-r4"
        SUB     sp,sp,#8
        ADR     r3,osri6_table
        CMP     r1,#0
        MOVEQ   r4,#-1
        STMEQIA sp,{r2,r4} ; Set up single-entry list on stack
        MOVEQ   r1,sp      ; r1 -> input list
        ADDEQ   r2,sp,#8+8 ; r2 -> stacked R2 for result
62
        LDR     r4,[r1],#4
        CMP     r4,#-1
        BEQ     %FT66
        CMP     r4,#osri6_maxvalue
        LDRLS   r0,[r3,r4,LSL #2]
        MOVHI   r0,#0
    [ LongDesc :LAND: ShortDesc
        ; Zero the ShortDesc page table pointers if LongDesc is in use
        TEQ     r4,#OSRSI6_L1PT
        TEQNE   r4,#OSRSI6_L2PT
        BEQ     %FT63
    ]
        ; Fix up the DevicesEnd values
        TEQ     r4,#OSRSI6_Danger_DevicesEnd
        TEQNE   r4,#OSRSI6_DevicesEnd
        STRNE   r0,[r2],#4
        BNE     %BT62
        LDR     r4,=ZeroPage
        LDR     r4,[r4,#IRQMax]
        ADD     r0,r0,r4,LSL #3
        ADD     r0,r0,r4,LSL #2
        STR     r0,[r2],#4
        B       %BT62
 [ LongDesc :LAND: ShortDesc
63
        PTWhich r4
        MOVNE   r0,#0
        STR     r0,[r2],#4
        B       %BT62
 ]
66
        ADD     sp,sp,#8
        Pull    "r0-r4"
        ExitSWIHandler

osri6_table
    DCD  ZeroPage+CamEntriesPointer                   ;0
    DCD  ZeroPage+MaxCamEntry                         ;1
    DCD  PageFlags_Unavailable                        ;2
    DCD  ZeroPage+PhysRamTable                        ;3
    DCD  0                                            ;4 (was ARMA_Cleaner_flipflop)
    DCD  ZeroPage+TickNodeChain                       ;5
    DCD  ZeroPage+ROMModuleChain                      ;6
    DCD  ZeroPage+DAList                              ;7
    DCD  ZeroPage+AppSpaceDANode                      ;8
    DCD  ZeroPage+Module_List                         ;9
    DCD  ZeroPage+ModuleSHT_Entries                   ;10
    DCD  ZeroPage+ModuleSWI_HashTab                   ;11
    DCD  0                                            ;12 (was IOSystemType)
  [ ShortDesc
    DCD  L1PT                                         ;13
    DCD  L2PT                                         ;14
  |
    DCD  0
    DCD  0
  ]
    DCD  UNDSTK                                       ;15
    DCD  SVCSTK                                       ;16
    DCD  SysHeapStart                                 ;17
    ; **DANGER** - this block conflicts with ROL's allocations
    ; ROL use:
    ; 18 = kernel messagetrans block
    ; 19 = error semaphore
    ; 20 = OS_PrettyPrint dictionary
    ; 21 = Timer 0 latch value
    ; 22 = FastTickerV counts per second
    ; 23 = Vector claimants table
    DCD  JTABLE-SWIRelocation                         ;18 - relocated base of OS SWI despatch table
    DCD  DefaultIRQ1V+(Devices-DefaultIRQ1Vcode)      ;19 - relocated base of IRQ device head nodes
    DCD  DefaultIRQ1V+(Devices-DefaultIRQ1Vcode)      ;20 - relocated end of IRQ device head nodes. NOTE: Gets fixed up when read
    DCD  IRQSTK                                       ;21 - top of the IRQ stack
    DCD  SoundWorkSpace                               ;22 - workspace (8K) and buffers (2*4K)
    DCD  ZeroPage+IRQsema                             ;23 - the address of the IRQ semaphore

    ; ROL compatable:
    DCD  NVECTORS                                     ;24 - Number of vectors supported
    DCD  IRQSTK                                       ;25 - top of the IRQ stack
    DCD  JTABLE-SWIRelocation                         ;26 - relocated base of OS SWI despatch table
    DCD  SLVK                                         ;27 - Address of branch back to OS after SWIs
    %    (256-(.-osri6_table))
    ; Use 64+ for a repeat of the danger zone, and our new allocations
    DCD  JTABLE-SWIRelocation                         ;64 - relocated base of OS SWI despatch table
    DCD  DefaultIRQ1V+(Devices-DefaultIRQ1Vcode)      ;65 - relocated base of IRQ device head nodes
    DCD  DefaultIRQ1V+(Devices-DefaultIRQ1Vcode)      ;66 - relocated end of IRQ device head nodes. NOTE: Gets fixed up when read
    DCD  IRQSTK                                       ;67 - top of the IRQ stack
    DCD  SoundWorkSpace                               ;68 - workspace (8K) and buffers (2*4K)
    DCD  ZeroPage+IRQsema                             ;69 - the address of the IRQ semaphore
    ; New allocations
    DCD  ZeroPage+DomainId                            ;70 - current Wimp task handle
    DCD  ZeroPage+OsbyteVars-&A6                      ;71 - OS_Byte vars (previously available via OS_Byte &A6/VarStart)
    DCD  ZeroPage+VduDriverWorkSpace+FgEcfOraEor      ;72
    DCD  ZeroPage+VduDriverWorkSpace+BgEcfOraEor      ;73
    DCD  DebuggerSpace                                ;74
    DCD  DebuggerSpace_Size                           ;75
    DCD  ZeroPage+CannotReset                         ;76
    DCD  ZeroPage+MetroGnome                          ;77 - OS_ReadMonotonicTime
    DCD  ZeroPage+CLibCounter                         ;78
    DCD  ZeroPage+RISCOSLibWord                       ;79
    DCD  ZeroPage+CLibWord                            ;80
    DCD  ZeroPage+FPEAnchor                           ;81
    DCD  ZeroPage+ESC_Status                          ;82
    DCD  ZeroPage+VduDriverWorkSpace+ECFYOffset       ;83
    DCD  ZeroPage+VduDriverWorkSpace+ECFShift         ;84
    DCD  ZeroPage+VecPtrTab                           ;85
    DCD  NVECTORS                                     ;86
    DCD  1                                            ;87 CAM format: 0 = 8 bytes/entry, 1 = 16 bytes/entry
    DCD  ABTSTK                                       ;88
    DCD  1                                            ;89 PhysRamTable format: 0 = addresses are in byte units, 1 = addresses are in 4KB units
osri6_maxvalue * (.-4-osri6_table) :SHR: 2


; ReadSysInfo(7)  - read 32-bit Abort information for last unexpected abort
;                      (prefetch or data)
;
; On entry:       r0 = 7 (reason code)
;
; On exit:        r1 = 32-bit PC for last abort
;                 r2 = 32-bit PSR for last abort
;                 r3 = fault address for last abort (same as PC for prefetch abort)
;
70
        LDR     r1, =ZeroPage+Abort32_dumparea
        LDMIA   r1, {r1-r3}
        ExitSWIHandler

; ReadSysInfo(8) - Returns summary information on host platform.
;
; On entry:
;    r0 = 8 (reason code 8)
;
; On exit:
;    r0 = platform class
;         currently defined classes are:
;            0 = unspecified platform (r1,r2 will be 0)
;            1 = Medusa   (currently returned for Risc PC only)
;            2 = Morris   (currently returned for A7000 only)
;            3 = Morris+  (currently returned for A7000+ only)
;            4 = Phoebe   (currently returned for Risc PC 2 only)
;            5 = HAL      (returned for machines running a HAL)
;            6 = VirtualRPC
;            7 = A9Home
;            16 = Pyromaniac
;            all other values currently reserved
;    r1 = 32 additional platform specifier flags (if defined)
;         bits 0..31 = value of flags 0..31 if defined, 0 if undefined
;    r2 = defined status of the 32 flags in r1
;         bits 0..31 = status of flags 0..31
;                      0 = flag is undefined in this OS version
;                      1 = flag is defined in this OS version
;
; The current flag definitions for r1 (1=supported, 0=unsupported) are :
;
;     0     = Podule expansion card(s)
;     1     = PCI expansion card(s)
;     2     = additional processor(s)
;     3     = software power off
;     4     = OS in RAM, else executing in ROM
;     5     = OS uses rotated loads          } If both clear and flagged as
;     6     = OS uses unaligned loads/stores } defined, OS makes no unaligned accesses
;     7..31 reserved (currently undefined)
;
80
        Push    "r9,r14"
        AddressHAL
        SUB     sp, sp, #8
        ADD     a2, sp, #0
        ADD     a3, sp, #4
        CallHAL HAL_PlatformInfo
        Pull    "a2,a3,r9,r14"
        MOV     r0, #5
    [ :LNOT: NoUnaligned
      [ :LNOT: NoARMv6
        ORR     r1, r1, #1:SHL:6 ; ARMv6+
      ELIF :LNOT: SupportARMv6
        ORR     r1, r1, #1:SHL:5 ; <=ARMv5
      ]
    ]
        ORR     r2, r2, #3:SHL:5
        ExitSWIHandler

; OS_ReadSysInfo 9 - Read ROM info
;
; On entry:
;    r0 = 9 (reason code 9)
;    r1 = item number to return
;
; On exit:
;    r0 = pointer to requested string (NULL terminated) or NULL if it wasn't found
;
; Currently defined item numbers are:
;
;    0   = OS name
;    1   = Part number
;    2   = Build date
;    3   = Dealer name
;    4   = User name
;    5   = User address
;    6   = Printable OS description
;    7   = Hardware platform

90
        CMP     R1, #0
        CMPNE   R1, #6
        ADREQ   R0, RSI9_OSname     ; The OS name or description
        BEQ     %FT95
        CMP     R1, #2              ; The build date (dynamically generated)
        BEQ     %FT92
        CMP     R1, #7              ; The hardware platform
        MOVNE   R0, #0              ; Other ones are unimplemented
        BNE     %FT95

        Push    "r1-r3,r9,lr"
        AddressHAL
        MOV     a1,#0               ; Return NULL if HAL doesn't implement it
        CallHAL HAL_PlatformName
        Pull    "r1-r3,r9,lr"
        B       %FT95
92
        LDR     R0, =ROMBuildDate
        LDRB    R1, [R0]
        CMP     R1, #0
        MOVNE   R1, #2              ; Restore R1
        BNE     %FT95
        ; Build date string hasn't been generated yet. Generate it.
        Push    "r0-r3,lr"
        MOV     R0, #ExtROMFooter_BuildDate
        BL      ExtendedROMFooter_FindTag
        CMP     R0, #0              ; Found it?
        STREQ   R0, [R13]
        BEQ     %FT93
        ; For compatability, make this string match the same format as the old
        ; string. Conveniently, this matches the format string used by OS_Word
        ; 14
        LDR     R1, [R13]
        MOV     R2, #?ROMBuildDate
        ADRL    R3, TimeFormat
        SWI     XOS_ConvertDateAndTime
        MOVVS   R0, #0
        STRVS   R0, [R13]
93
        Pull    "r0-r3,lr"
95
        ExitSWIHandler

; OS_ReadSysInfo 11 - Read debug information
;
; On entry:
;    r0 = 11 (reason code 11)
;
; On exit:
;    r0 = pointer to function for debug character output
;    r1 = pointer to function for debug character input
;

110
        ; Check if both HAL_DebugTX and HAL_DebugRX are available
        Push    "r8-r9,r14"
        MOV     R8, #OSHW_LookupRoutine
        MOV     R9, #EntryNo_HAL_DebugTX
        SWI     XOS_Hardware
        MOVVC   R8, #OSHW_LookupRoutine
        MOVVC   R9, #EntryNo_HAL_DebugRX
        SWIVC   XOS_Hardware
        Pull    "r8-r9,r14"
        BVS     ReadSysInfo_InvalidReason
        ADR     R0, RSI_DebugTX
        ADR     R1, RSI_DebugRX
        ExitSWIHandler

RSI_DebugTX
        ; In:
        ; R0 = char
        ; Privileged mode
        ; Out:
        ; R0-R3, PSR corrupt
        Push    "r9,r12,r14"
        AddressHAL
        CallHAL HAL_DebugTX
        Pull    "r9,r12,pc"

RSI_DebugRX
        ; In:
        ; Privileged mode
        ; Out:
        ; R0=char read, or -1
        ; R1-R3, PSR corrupt
        Push    "r9,r12,r14"
        AddressHAL
        CallHAL HAL_DebugRX
        Pull    "r9,r12,pc"

; OS_ReadSysInfo 12 - Read extended machine ID
;
; On entry:
;    r0 = 12 (reason code 12)
;    r1 = Pointer to word-aligned buffer, or 0 to read size
;
; On exit:
;    r0 = Size of extended machine ID, or 0 if none/corrupt
;    Buffer in R1 filled, if applicable
;

120
        Push    "r1-r3,r9,r14"
        AddressHAL
        MOV     R0, R1 ; HAL takes the buffer pointer in R0
        CallHAL HAL_ExtMachineID
        Pull    "r1-r3,r9,r14"
        ExitSWIHandler

; OS_ReadSysInfo 13 - Validate key handler
;
; On entry:
;    r0 = 13 (reason code 13)
;    r1 = key handler address (0 to just return valid flags)
;
; On exit:
;    r0 = Mask of supported key handler flags
;         Or pointer to error block
;

130
        LDR     R0, =KeyHandler_Flag_Wide
        CMP     R1, #0
        ExitSWIHandler EQ
        Push    "R2"
        LDR     R2, [R1, #KeyHandler_KeyTranSize]
        TST     R2, #KeyHandler_HasFlags
        LDRNE   R2, [R1, #KeyHandler_Flags]
        BICNES  R2, R2, R0
        Pull    "R2"
        ExitSWIHandler EQ
        ADR     R0, ErrorBlock_BadKeyHandler
      [ International
        Push    "lr"
        BL      TranslateError
        Pull    "lr"
      ]
        ORR     lr, lr, #V_bit
        ExitSWIHandler

        MakeErrorBlock BadKeyHandler

; OS_ReadSysInfo 14 - Return IIC bus count
;
; On entry:
;    r0 = 14 (reason code 14)
;
; On exit:
;    r0 = Number of IIC buses (as per HAL_IICBuses)
;

140
        Push    "r1-r3,sb,lr"
        AddressHAL
        CallHAL HAL_IICBuses
        Pull    "r1-r3,sb,lr"
        ExitSWIHandler

; OS_ReadSysInfo 15 - Enumerate extended ROM footer entries
;
; On entry:
;    r0 = 15 (reason code 15)
;    r1 = location to start (from previous call) or 0 to begin
;
; On exit:
;    r1 = data pointer, or 0 if end
;    r2 = entry ID (corrupt if r1 == 0)
;    r3 = entry length (corrupt if r1 == 0)

150
        Push    "lr"
        BL      ExtendedROMFooter_Find
        CMP     r0, #-1
        BEQ     %FT158
        MOV     lr, r0                  ; Footer end
        CMP     r1, #0
        LDREQ   r1, [lr]
        MOVEQ   r1, r1, LSL #16
        SUBEQ   r1, lr, r1, LSR #16     ; Footer start
        LDRNEB  r3, [r1, #-1]
        ADDNE   r1, r1, r3              ; If not starting enumeration, advance by length of previous entry
        CMP     r1, lr
        BEQ     %FT158
        LDRB    r2, [r1], #1
        LDRB    r3, [r1], #1
        B       %FT159
158
        MOV     r1, #0
159
        MOV     r0, #15
        Pull    "lr"
        ExitSWIHandler

;
; Extended ROM footer functions
;
; These operate on a new tag-based structure located at the end of the ROM
; image. Each entry consists of a one-byte ID, a one-byte length, and then N
; bytes of data. The length byte doesn't count the two initial header bytes.
;
; The end of the list is implicity terminated by a footer word; the footer word
; contains the length of the structure in the low two bytes (minus the length of
; the footer word), and a 16-bit CRC in the top two bytes (again, minus the
; footer word). The footer word will be word-aligned, but everything else is
; assumed to be byte aligned.
;
; Current tags:
;
; 0     ROM build date, stored as 5-byte time (length = 5)
; 1     Compressed ROM softload hint (length = 8). First word is negative
;       checksum of uncompressed image, second word is OS header offset.
; 2     Debug symbols offset (length = 4). Byte offset from the start of the ROM
;       to the debug symbols.
;

ExtendedROMFooter_Find  ROUT
        ; Find the header word for the extended ROM footer. Returns -1 if not found.
        Push    "r1-r4,lr"
        LDR     r4, =ZeroPage
        LDR     r0, [r4, #ExtendedROMFooter]
        CMP     r0, #0
        BNE     %FT10
        ; Examine the end of the ROM image
        ; Footer should be located just before the standard 20 byte footer
        LDR     r2, =ROM+OSROM_ImageSize*1024-24
        LDR     r1, [r2]
        CMP     r1, #-1
        MOVEQ   r0, r1
        BEQ     %FT09
        ; Check CRC
        MOV     r1, r1, LSL #16
        SUB     r1, r2, r1, LSR #16
        MOV     r3, #1
        SWI     XOS_CRC
        MOVVS   r0, #-1
        BVS     %FT09
        LDR     r1, [r2]
        CMP     r0, r1, LSR #16
        MOVNE   r0, #-1
        MOVEQ   r0, r2
09
        STR     r0, [r4, #ExtendedROMFooter]
10
        Pull    "r1-r4,pc"

ExtendedROMFooter_FindTag  ROUT
        ; Find the tag number given in R0.
        ; Returns data pointer in R0 & length in R1 on success.
        ; Returns 0 in R0 (and corrupt R1) for failure.
        Push    "r2-r3,lr"
        MOV     r2, r0
        BL      ExtendedROMFooter_Find
        CMP     r0, #-1
        BEQ     %FT09
        MOV     r3, r0
        LDR     r0, [r0]
        MOV     r0, r0, LSL #16
        SUB     r0, r3, r0, LSR #16
05
        CMP     r0, r3
        BEQ     %FT09
        LDRB    lr, [r0], #1
        LDRB    r1, [r0], #1
        CMP     lr, r2
        BEQ     %FT10
        ADD     r0, r0, r1
        B       %BT05
09
        MOV     r0, #0
10
        Pull    "r2-r3,pc"

RSI9_OSname    = "$SystemName $VString",0

        ALIGN
        LTORG

        END