; 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.
;
        SUBT    => NewReset

; Reset types
SoftReset       * 0
PowerOnReset    * 1
ControlReset    * 2

; CMOS RAM resetting stuff:
CMOSLimit       * &F0

; Keyboard flags
                ^ 1
KbdScanActive   # 1
                # 2
KbdFlags        # 4

; On ARM600, InitIRQWs is in zero page - check it's big enough

        ASSERT  @ <= ?InitIRQWs


; GetConfiguredSize - convert CMOS address into amount of memory
; in:   r0 = CMOS address
; out:  r0 corrupted
;       r2 = amount in bytes

; NB this routine doesn't do screen size mangling (yet!)

GetConfiguredSize Entry "r1"
        LDR     r1, =ZeroPage
        LDR     r1, [r1, #Page_Size]
        ADRL    lr, PageShifts-1
        LDRB    r1, [lr, r1, LSR #12]   ; r1 = log2 pagesize
        MOV     r2, #127                ; mask of value

        TEQ     r0, #FontCMOS           ; if fontsize
        MOVEQ   r1, #12                 ; then in units of 4K, not pagesize
        MOVEQ   r2, #255                ; and use full byte

        BL      Read                    ; read CMOS ram
        AND     r2, r0, r2              ; value anded with mask
        MOV     r2, r2, LSL r1          ; and shifted up accordingly
        EXIT

; FudgeConfigureRMA - move pages from free pool to somewhere
; r0 = number of pages to attempt to move
; r1 = where to store number of bytes moved
; r3 = base address of where to put memory
; r11 = ap + CB
FudgeConfigureRMA
        Push    lr
        LDR     R10, =ZeroPage
        LDR     R10, [R10, #Page_Size]
        MUL     R0, R10, R0             ; get size in bytes
        MOV     R5, #0                  ; amount moved
        CMP     R0, #0
        BEQ     NoMoreMemory

        LDR     r4, =ZeroPage+FreePoolDANode
        LDR     r7, [r4, #DANode_PMP]
        LDR     r8, [r4, #DANode_PMPSize]
10
        CMP     r8, #0                          ; if no free memory left
        BEQ     %FT20                           ; then tidy up
        SUB     r8, r8, #1                      ; move free pool pointer backwards
        MOV     lr, #-1
        LDR     r2, [r7, r8, LSL #2]
        STR     lr, [r7, r8, LSL #2]
        BL      Call_CAM_Mapping
        ADD     r3, r3, r10                     ; advance "to" pointer
        ADD     r5, r5, r10                     ; one more page done
        SUBS    r0, r0, r10
        BNE     %BT10
20
        STR     r8, [r4, #DANode_PMPSize]
NoMoreMemory
        STR     R5, [R1]
        Pull    "PC"

; MassageScreenSize - called from screen DA creation and ReadSysInfo

MassageScreenSize ROUT
        Push    lr
        LDR     lr, =ZeroPage
        LDR     lr, [lr, #VideoSizeFlags]
        TST     lr, #OSAddRAM_VRAMNotForGeneralUse
        MOVNE   r0, lr, LSR #12
        MOVNE   r0, r0, LSL #12
        Pull    pc, NE

        CMP     r0, #0
        BNE     CmosScreenWillDo
      [ ZeroPage <> 0
        LDR     r0, =ZeroPage
      ]
        LDR     r0, [r0, #RAMLIMIT]
        CMP     r0, #512*1024
        MOVEQ   r0, #80*1024
        MOVNE   r0, #160*1024
CmosScreenWillDo
        CMP     r0, #20*1024            ; ensure mode 0 gettable
        ADDCC   r0, r0, r10             ; if not, then add another page
        BCC     CmosScreenWillDo
        CMP     r0, #ScreenMaxSize
        MOVHI   r0, #ScreenMaxSize
        Pull    pc

        LTORG

    ! 0, "*** DUMMY CONT_Break, soft breaks/resets will not work yet with HAL"
CONT_Break
        AddressHAL
        MOV     a1, #1
        LDR     a2, =L1PT
        CallHAL HAL_Reset

Continue_after_HALInit

;StrongARM: OK, there is quite a bit of code poking below, to various addresses. We'll
;           defer IMB consideration till the poking's done, then do a full IMB (full
;           data cache clean). This avoids various little IMB's and removes chance of leaving
;           some unnoticed poked code in data cache. The deferral should be safe, because none
;           of the poked code will be used yet awhile (given that current IRQ hardware vector is
;           not actually changed below).

; Copy default processor vector table and default preveneers.
; Code relies on preveneers being immediately after processor vector table
; but could easily be changed into 2 copy loops.
        ASSERT  ProcVecPreVeneers = ProcVec_End
        ASSERT  DefaultPreVeneers = DefaultProcVecs+ProcVec_End-ProcVec_Start

        ADRL    R0, DefaultProcVecs
        LDR     R1, =ZeroPage+ProcVec_Start
        MOV     R2, #ProcVec_End-ProcVec_Start+ProcVecPreVeneersSize
39
        LDR     R3, [R0], #4
        STR     R3, [R1], #4
        SUBS    R2, R2, #4
        BNE     %BT39

; copy handler addresses
        ADRL    R1, MOSROMVecs+4        ; don't copy to 0: key stuff is using
                                        ; it as workspace!
        LDR     R0, =ZeroPage+4
        LDR     R3, =ZeroPage+EndMOSROMVecs-MOSROMVecs

40
        LDR     R2, [R1], #4            ; N.B. IRQ handler better be same as the one in there
        STR     R2, [R0], #4
        TEQ     R0, R3
        BNE     %BT40

        ChangedProcVecs r0

 [ CacheCMOSRAM
        DebugTX "InitCMOSCache entry"
        BL      InitCMOSCache           ; initialise cache of CMOS RAM
        DebugTX "InitCMOSCache done"
        TEQ     R0, #0                  ; returns zero on failure
      [ ZeroPage <> 0
        LDREQ   R0, =ZeroPage
      ]
        LDREQ   R1, [R0, #HAL_StartFlags]
        ORREQ   R1, R1, #OSStartFlag_NoCMOS
        STREQ   R1, [R0, #HAL_StartFlags]
 ]

; Now copy the initialised data
        LDR     R0, =ZeroPage+IRQ1V

; first save IOC soft copy so can restore it

        LDRB    R2, [R0, #IOCControlSoftCopy-IRQ1V]
        Push    "R2"
        LDRB    R2, [R0, #CannotReset-IRQ1V]
        Push    "R2"

        ADRL    r1, StartData
        LDR     R3, =ZeroPage+(EndData-StartData+IRQ1V)
DatCopy
        LDR     R2, [R1], #4
        STR     R2, [R0], #4
        TEQ     R0, R3
        BNE     DatCopy

        ADR     r2, CONT_Break
        LDR     r0, =ZeroPage
        STR     r2, [r0, #ResetIndirection]

        MOV     r3, #0                  ; initialise abort list
        STR     r3, [r0, #AbortIndirection]

; Now the SWI despatch + low part of SWI table
        ADRL    R3, DirtyBranch
        LDR     R0, =SWIDespatch
SVCTabCopy                              ; so copy the table
        LDR     R2, [R1], #4
        STR     R2, [R0], #4
        TEQ     R1, R3
        BNE     SVCTabCopy

; pad to 1K table here, rather than use ROM space
        ADRL    R2, NoSuchSWI
        LDR     R4, =1024+SvcTable      ; end of table
PadSVCTable
        CMP     R0, R4
        STRNE   R2, [R0], #4
        BNE     PadSVCTable

; now the dirty branch
        LDR     R1, [R1]
        STR     R1, [R0]

; conversion SWIs all go through same despatch point
        LDR     R0, =SvcTable
        ADRL    R1, despatchConvert
        STR     R1, [R0, #OS_ConvertStandardDateAndTime * 4]
        STR     R1, [R0, #OS_ConvertDateAndTime * 4]

        MOV     R2, #OS_ConvertHex1
conversionSWIfill
        STR     R1, [R0, R2, LSL #2]
        ADD     R2, R2, #1
        CMP     R2, #OS_ConvertVariform
        BLS     conversionSWIfill

; OK, that completes the poking around, some of which is code. Now let's
; do a full IMB type thing, to be safe
;
        LDR     r0, =ZeroPage
        ARMop   IMB_Full,,,r0
        DebugTX "IMB_Full done"

      [ CacheablePageTables
; If we want cacheable page tables, now is a good time to enable them
; (can't easily enable them earlier on due to the page tables being temporarily
; doubly-mapped during MMU init)
        BL      MakePageTablesCacheable
      ]

; Initialise CAO ptr to none.

        LDR     R0, =ZeroPage
        LDR     R1, =DuffEntry          ; nothing will be here!!
        STR     R1, [R0, #Curr_Active_Object]

KeyWait * 200000                 ; 1/5 sec wait (in microseconds)
us      * 1

        AddressHAL
        MOV     r6, #25                 ; Check for keyboard 25 times (5 secs max).
        LDR     r4, =ZeroPage+InitIRQWs

kbdwait
        CallHAL HAL_KbdScan
        STR     r0, [r4, #KbdFlags]

        TST     r0, #KbdFlag_Done
        BNE     kbddone

        LDR     r0, =KeyWait*us         ; Wait 1/5 second (give keys down a chance to come in).
        CallHAL HAL_CounterDelay
        SUBS    r6, r6, #1              ; else wait a maximum of 5 seconds.
        BNE     kbdwait
kbddone
        MSR     CPSR_c, #I32_bit+SVC32_mode
        CallHAL HAL_KbdScanFinish
        LDR     r1, =ZeroPage+InitIRQWs
        MOV     r0, #0
        STRB    r0, [r1, #KbdScanActive]
        MSR     CPSR_c, #SVC32_mode
        DebugTX "Keyboard scan complete"

 [ ValidateCMOS
; Do a POR if some super-critical values are shagged or if checksum is invalid.
        MOV     R3, #-1                 ; do all RAM if we do any
        BL      ValChecksum             ; Always check the checksum
        BNE     cmos_reset
 ]

; IF power-on bit set AND R/T/Del/Copy pressed THEN reset CMOS RAM
; note that memory cleared if POR, so key info has had plenty of time!

        LDR     R0, =ZeroPage+HAL_StartFlags
        LDR     R1, [R0]
        TST     R1, #OSStartFlag_NoCMOS ; If no CMOS, reset for sensible cache
        BNE     cmos_reset
        TST     R1, #OSStartFlag_POR
        BEQ     no_cmos_reset           ; not a power on reset
        DebugTX "POR detected"
        TST     R1, #OSStartFlag_NoCMOSReset
        BNE     no_cmos_reset
        TST     R1, #OSStartFlag_CMOSReset
        BNE     cmos_reset

        LDR     R0, =ZeroPage+InitIRQWs
        LDR     R7, [R0, #KbdFlags]
        TST     R7, #KbdFlag_R:OR:KbdFlag_T:OR:KbdFlag_Delete:OR:KbdFlag_Copy
        LDRNE   R3, =ZeroPage
        MOVNE   R14, #1
        STRNEB  R14, [R3, #MentionCMOSReset]
        BEQ     no_cmos_reset           ; power on bit checked again there

; CMOS reset detectified.
; Wipe it, then squirt in the MOS's table of default values

        TST     R7, #KbdFlag_Copy:OR:KbdFlag_Delete
        MOVNE   R3, #-1                 ; Del or Copy does all RAM
        MOVEQ   R3, #UserCMOS           ; R or T just system
    [ ChecksumCMOS
        BL      ValChecksum             ; unless the CMOS ram's corrupt ..
        MOVNE   R3, #-1                 ; .. then blast it anyway.
    ]
cmos_reset
        DebugTX "Reset CMOS"
        ADD     sp, sp, #4              ; junk CannotReset flag from stack

        MOV     R4, #0
cmrlp
        CMP     R3, #-1
        BEQ     cmrall                  ; ignore system-only wipe checks
        CMP     R4, #UserCMOS
        MOVEQ   R4, #&50                ; skip User (30-45) & 3rd party (46-59) & high podules (60-79)
        BEQ     cmrall
        CMP     R4, #PoduleCMOS
        MOVEQ   R4, #&80                ; skip low podules (112-127)
        BEQ     cmrall
        TEQ     R4, #NewADFSCMOS        ; documented in 'Troubleshooting' in
        TEQNE   R4, #CountryCMOS        ; the RISC OS 3.7 user guide as preserved
        BEQ     cmrskip
cmrall
        MOV     R1, R4
        BL      NVMemory_ResetValue     ; get the reset value
        MOVS    R1, R2                  ; when -ve, leave alone
        MOVPL   R0, R4
        BLPL    Write                   ; CMOS(R0) := R1
cmrskip
        ADD     R4, R4, #1
        CMP     R4, #CMOSLimit
        BCC     cmrlp

; IF R or Delete pressed THEN set sync 0 ELSE set sync Auto
        LDR     R0, =ZeroPage+InitIRQWs
        LDR     R1, [R0, #KbdFlags]
        TST     R1, #KbdFlag_R:OR:KbdFlag_Delete
        MOV     R0, #VduCMOS
        MOVNE   R1, #MonitorTypeAuto :OR: Sync_Auto     ; if R or Del
        MOVEQ   R1, #MonitorTypeAuto :OR: Sync_Separate ; if T or Copy
        BL      Write

    [ ChecksumCMOS
        BL      MakeChecksum            ; create a valid checksum
    ]
        B       hard_reset              ; CMOS reset only checked on power on, so was hard

no_cmos_reset                           ; R1 has por_bit set if power on
        Push    "r1"
        MOV     r0, #SystemSpeedCMOS
        BL      Read
        BIC     r1, r0, #CMOSResetBit   ; clear bit indicating CMOS reset
        MOV     r0, #SystemSpeedCMOS
        BL      Write
        Pull    "r1"

        Pull    r0                      ; always pull CannotReset flag

hard_reset
hard_reset_forced
        LDR     r8, =ZeroPage

        Pull    "R2"                    ; discard old IOC state

        DebugTX "InitDynamicAreas"

; let's boogie with the CMOS for a bit
; read info and move as much memory as we can

        BL      InitDynamicAreas

; RMA
        Push    "r0-r12"
        MOV     r1, #ChangeDyn_RMA      ; Area number
        MOV     r2, #4096               ; Initial size
        MOV     r3, #RMAAddress         ; Base address
        MOV     r4, #AreaFlags_RMA      ; Area flags
        MOV     r5, #RMAMaxSize         ; Maximum size
        ADRL    r6, DynAreaHandler_RMA  ; Pointer to handler
        MOV     r7, r3                  ; Workspace ptr points at area itself
        ADRL    r8, AreaName_RMA        ; Title string - node will have to be reallocated
                                        ; after module init, to internationalise it
        BL      DynArea_Create          ; ignore any error, we're stuffed if we get one!
        Pull    "r0-r12"

; Screen
        Push    "r0-r12"
        MOV     r0, #ScreenSizeCMOS
        BL      Read

        LDR     r5, =ZeroPage
        LDR     r10, [r5, #Page_Size]   ; needed by MassageScreenSize
        MUL     r0, r10, r0             ; convert to bytes
        LDR     r5, [r5, #VideoSizeFlags] ; maximum size
        MOV     r5, r5, LSR #12
        MOV     r5, r5, LSL #12
        BL      MassageScreenSize

        MOV     r1, #ChangeDyn_Screen   ; area number
        MOV     r2, r0                  ; initial size
        MOV     r3, #-1                 ; Base address dynamic
        LDR     r4, =AreaFlags_Screen   ; area flags
        ADRL    r6, DynAreaHandler_Screen ; handler
        VDWS    r7                      ; workspace pointer
        MOV     r8, #0
        STR     r8, [r7, #CursorFlags]  ; put zero in CursorFlags as an indication that VDU not yet inited
        STR     r2, [r7, #TotalScreenSize]
        ADRL    r8, AreaName_Screen     ; area name
        BL      DynArea_Create
        STR     r3, [r7, #ScreenEndAddr]
        Pull    "r0-r12"

; SpriteArea
        Push    "r0-r12"
        MOV     r0, #0                  ; initialise SpriteSize to zero
      [ ZeroPage = 0
        STR     r0, [r0, #SpriteSize]   ; (fixes bug MED-00811)
      |
        LDR     r1, =ZeroPage
        STR     r0, [r1, #SpriteSize]   ; (fixes bug MED-00811)
      ]

        MOV     r0, #SpriteSizeCMOS     ; find out how much spritesize configured
        BL      GetConfiguredSize       ; in: r0 = CMOS address, out: r2 = size

        MOV     r1, #ChangeDyn_SpriteArea ; Area number
        MOV     r3, #-1                 ; Base address dynamic
        MOV     r4, #AreaFlags_Sprites  ; Area flags
        MOV     r5, #16*1024*1024       ; Maximum size (changed from -1, address space preservation)
        ADRL    r6, DynAreaHandler_Sprites ; Pointer to handler
        MOV     r7, #-1                 ; Use base address as workspace ptr
        ADRL    r8, AreaName_SpriteArea ; Title string - node will have to be reallocated
                                        ; after module init, to internationalise it
        BL      DynArea_Create          ; ignore any error, we're stuffed if we get one!
        Pull    "r0-r12"

; RAMDisc
        Push    "r0-r12"

        MOV     r1, #ChangeDyn_RamFS    ; Area number
        MOV     r3, #-1                 ; Base address dynamic
        ARM_read_ID r4
        AND     r4, r4, #&F000
        CMP     r4, #&A000
        MOVEQ   r4, #AreaFlags_RAMDisc_SA ; Area flags, if StrongARM  (introduced for Ursula)
        MOVNE   r4, #AreaFlags_RAMDisc  ; Area flags
      [ PMPRAMFS
        MOV     r5, #PMPRAMFS_Size*4096
        ORR     r4, r4, #DynAreaFlags_PMP
        MOV     r2, #0
        ORR     r4, r4, #DynAreaFlags_NeedsSpecificPages
        MOV     r9, #0
      |
        MOV     r0, #RAMDiscCMOS        ; find out how much RAM disc configured
        BL      GetConfiguredSize       ; in: r0 = CMOS address, out: r2 = size
        MOV     r5, #MaxRAMFS_Size*1024*1024      ; A trade off between nice big disc and complete waste of address space
      ]
        ADRL    r6, DynAreaHandler_RAMDisc ; Pointer to handler
        MOV     r7, #-1                 ; Use base address as workspace ptr
        ADRL    r8, AreaName_RAMDisc    ; Title string - node will have to be reallocated
                                        ; after module init, to internationalise it
        BL      DynArea_Create          ; ignore any error, we're stuffed if we get one!
      [ PMPRAMFS
        ; Currently, physical memory pools must be created with 0 size, then resized afterwards
        MOV     r0, #RAMDiscCMOS        ; find out how much RAM disc configured
        BL      GetConfiguredSize       ; in: r0 = CMOS address, out: r2 = size
        MOVS    r1, r2
        MOV     r0, #ChangeDyn_RamFS
        SWINE   XOS_ChangeDynamicArea
      ]
        Pull    "r0-r12"

; FontArea
        Push    "r0-r12"
        MOV     r0, #FontCMOS           ; find out how much font cache configured
        BL      GetConfiguredSize       ; in: r0 = CMOS address, out: r2 = size

        MOV     r1, #ChangeDyn_FontArea ; Area number
        MOV     r3, #-1                 ; Base address dynamic
        MOV     r4, #AreaFlags_FontArea ; Area flags
        MOV     r5, #32*1024*1024       ; Maximum size changed from -1 for Ursula (limit address
                                        ; space usage on large memory machines)
        ADRL    r6, DynAreaHandler_FontArea ; Pointer to handler
        MOV     r7, #-1                 ; Use base address as workspace ptr
        ADRL    r8, AreaName_FontArea   ; Title string - node will have to be reallocated
                                        ; after module init, to internationalise it
        BL      DynArea_Create          ; ignore any error, we're stuffed if we get one!
        Pull    "r0-r12"

        LDR     R0, =(1024*1024):SHR:12 ; 1MB of RAM in aplspace should be plenty for ROM init. Theoretically we don't need any at all, but having some there should make it easier to debug any ROM init failures.
        MOV     R3, #32*1024            ; aplwork start
        LDR     R1, =ZeroPage+AplWorkSize ; aplwork size
        MOV     r11, #AreaFlags_AppSpace
        BL      FudgeConfigureRMA       ; put some memory in aplspace

        LDR     R0, =ZeroPage
        LDR     R1, [R0, #AplWorkSize]
        ADD     R1, R1, #32*1024
        STR     R1, [R0, #AplWorkSize]
        STR     R1, [R0, #MemLimit]

        DebugTX "InitVectors"
        BL      InitVectors               ; ready for OsByte to read mode

        LDR     R1, =ZeroPage+ModuleSWI_HashTab
        MOV     R2, #ModuleSHT_Entries
      [ ZeroPage <> 0
        MOV     R0, #0
      ]
clearmswis
        SUBS    R2, R2, #1
        STR     R0, [R1, R2, LSL #2]
        BGT     clearmswis

      [ ZeroPage <> 0
        LDR     R2, =ZeroPage
      ]

     [  International
        MOV     R1, #-1                                 ; We don't have a message file yet !
        STRB    R1, [R2, #ErrorSemaphore]               ; Don't translate errors.
        STR     R0, [R2, #KernelMessagesBlock]          ; No message file open.
      [ CacheCommonErrors
        STR     R0, [R2, #CachedErrorBlocks]            ; No cached errors
      ]
     ]

        LDR     R0, =ZeroPage+HAL_StartFlags
        LDR     R1, [R0]
        TST     R1, #OSStartFlag_POR

        ; Make the choice between PowerOn and Hard reset based purely on
        ; the state of the POR bit and NOT on whether memory was cleared.
 [ {FALSE}
        LDREQ   R0, =ZeroPage+OsbyteVars + :INDEX: LastBREAK
        LDREQB  R0, [R0]
        TSTEQ   R0, #&80                ; tbs set if memory cleared
 ]
        MOVNE   R0, #PowerOnReset
        MOVEQ   R0, #ControlReset


ResetPart1Done                          ; R0 is reset type
        WritePSRc SVC_mode + I_bit, r1  ; interrupts off since kbd bash done
        LDR     R1, =ZeroPage+OsbyteVars + :INDEX: LastBREAK
        STRB    R0, [R1]

        LDR     R1, =ZeroPage+InitIRQWs
        LDR     R0, [R1, #KbdFlags]
        AND     R1, R0, #KbdFlag_Shift
        AND     R0, R0, #KbdFlag_Present
        Push    "R0, R1"                ; save until after MOSInit

        DebugTX "InitIRQ1"
        BL      InitialiseIRQ1Vtable

        LDR     R3, =ZeroPage
        ADRL    R1, Default_PIRQHandler_Node
        STR     R1, [R3, #PIRQ_Chain]
        STR     R1, [R3, #PFIQasIRQ_Chain]
 ASSERT Default_PFIQasIRQHandler_Node = Default_PIRQHandler_Node

        MOV     R0, #0                  ; put in IRQ handler, word at 0
        STRB    r0, [r3, #FIQclaim_interlock]
        STRB    r0, [r3, #CallBack_Flag]
        STR     r0, [r3, #CallBack_Vector]

; Create the Branch Through 0 Trampoline in the system heap
        MOV     R3, #Branch0_Trampoline_Size
        BL      ClaimSysHeapNode
        ADRVCL  R0, Branch0_Trampoline
        ASSERT  Branch0_Trampoline_Init = 20
        LDMVCIA R0, {R1,R3,R4,R5,R14}
        STMVCIA R2, {R1,R3,R4,R5,R14}
        LDRVC   R0, =ZeroPage
        STRVC   R2, [R0, #ProcVec_Branch0]

        LDR     R1, BranchThroughZeroInstruction2
        STR     R1, [R0]                                ; put branch through 0 code at 0

        LDR     R1, RealIRQHandler
        STR     R1, [R0, #&18]

        LDR     R2, =ZeroPage+InitIRQWs                 ; clear temp ws
        MOV     R3, #0
        MOV     R4, #0
        STMIA   R2!, {R3,R4}
        STMIA   R2!, {R3,R4}
        DebugTX "IMB_Full"

   ;we need to do an IMB type thing for modifying code in vector area,
   ;and for copying irq handler code
   ;
        ARMop   IMB_Full,,,r0
        ChangedProcVecs r0
        LDR     r0,=ZeroPage

        MOV     R1, #&100
        STR     R1, [R0, #RCLimit]
        MOV     R1, #0
        STR     R1, [R0, #ReturnCode]
        STR     R1, [R0, #TickNodeChain]

; clear the keyboard workspace (tidy!)
        ADD     R0, R0, #&1C
        MOV     R2, #InitWsEnd - &1C
        BL      memset

;now put in error handler and escape handler
        BL      DEFHAN
        BL      DEFHN2
        MOV     R0, #ExceptionDumpArea
        LDR     R1, =ZeroPage+DUMPER
        SWI     XOS_ChangeEnvironment

        VDWS    WsPtr                   ; main MOS initialisation
        DebugTX "VduInit"
        BL      VduInit
        DebugTX "ExecuteInit"
        BL      ExecuteInit
        DebugTX "KeyInit"
        BL      KeyInit
        DebugTX "MouseInit"
        BL      MouseInit
        DebugTX "OscliInit"
        BL      OscliInit               ; before initialising modules

        DebugTX "Enabling IRQs"
        WritePSRc SVC_mode, R14         ; enable IRQs
        DebugTX "IRQs on"

 [ DebugTerminal
        MOV     R0, #RdchV
        ADRL    R1, DebugTerminal_Rdch
        LDR     R2, =ZeroPage
        LDR     R2, [R2, #HAL_Workspace]
        SWI     XOS_Claim
        MOV     R0, #WrchV
        ADRL    R1, DebugTerminal_Wrch
        SWI     XOS_Claim
        DebugTX "Debug terminal on"
 ]

        BL      InitialiseMode          ; select correct screen mode, in case any
                                        ; module prints anything in initialisation

        MOV     R0, #&FD                ; read last reset type
        MOV     R1, #0
        MOV     R2, #&FF
        SWI     XOS_Byte
        CMP     R1, #SoftReset          ; soft reset?
        BEQ     SkipHardResetPart2

; HardResetPart2
        DebugTX "HAL_InitDevices"
        AddressHAL
        MOV     R0, #0
      [ ZeroPage = 0
        STR     R0, [R0, #DeviceCount]
        STR     R0, [R0, #DeviceTable]
      |
        LDR     R1, =ZeroPage
        STR     R0, [R1, #DeviceCount]
        STR     R0, [R1, #DeviceTable]
      ]
        CallHAL HAL_InitDevices         ; get HAL to register any devices it has
        BL      LookForHALCacheController
        DebugTX "InitVariables"
        BL      InitVariables
        DebugTX "AMBControl_Init"
        BL      AMBControl_Init         ; initialise AMBControl section
        DebugTX "ModuleInit"
        BL      ModuleInit              ; initialise modules
                                        ; scan podules, copy modules.

        MOV     R0, #0                  ; shrink sysheap as far as will go.
        SUB     R1, R0, #4*1024*1024
        SWI     XOS_ChangeDynamicArea
        MOV     R0, #ReadCMOS
        MOV     R1, #SysHeapCMOS
        SWI     XOS_Byte
        AND     R2, R2, #2_111111       ; mask to same size as status
        LDR     R0, =ZeroPage
        LDR     R0, [R0, #Page_Size]
        MUL     R3, R0, R2              ; size spare wanted
        BL      ClaimSysHeapNode
        MOV     R0, #HeapReason_Free
        SWI     XOS_Heap

        MOV     R0, #ReadCMOS
        MOV     R1, #FileLangCMOS
        SWI     XOS_Byte
        MOV     R1, R2
        MOV     R0, #FSControl_SelectFS ; set configured filing system
        SWI     XOS_FSControl

        ; Update RTC now all the modules are running
        SWI     XOS_ResyncTime

        ; OS_ReadSysInfo 9,2 now relies on the Territory module, which may
        ; enable IRQs. But the PRMs say OS_ReadSysInfo shouldn't alter the IRQ
        ; state. So call it once here just to initialise the string which it
        ; uses the Territory module to generate.
        ; This won't account for any modules using it during ModuleInit, but
        ; that should be pretty rare (or at least rare from within IRQ-sensitive
        ; code)
        MOV     R0, #9
        MOV     R1, #2
        SWI     XOS_ReadSysInfo

  [ UseNewFX0Error
        ; Also, *FX 0
        BL      InitNewFX0Error
  ]
  [ DebugROMInit
        SWI     XOS_WriteS
        =       "Service_PostInit",0
        SWI     XOS_NewLine
  ]
        MOV     r1, #Service_PostInit   ; issue post-initialisation service
        BL      Issue_Service

; New code added here by TMD 01-Apr-92
; Changed to use OS_LeaveOS 16-Oct-02

  [ DebugROMInit
        SWI     XOS_WriteS
        =       "callbacks",0
        SWI     XOS_NewLine
  ]
        SWI     XOS_LeaveOS
        SWI     XOS_EnterOS             ; switch back to SVC mode (IRQs, FIQs enabled)
; end of added code

     [ International                    ; Open the kernel messages file.
        LDR     r0, =ZeroPage+KernelMessagesBlock+4
        ADR     r1, MessageFileName
        MOV     r2, #0                  ; Use file directly.
        SWI     XMessageTrans_OpenFile
        MOVVC   r0, #-1
      [ ZeroPage = 0
        STRVC   r0, [r0, #KernelMessagesBlock+1]  ; Message file is now open.
      |
        LDR     lr, =ZeroPage
        STRVC   r0, [lr, #KernelMessagesBlock]  ; Message file is now open.
      ]
     ]

SkipHardResetPart2                      ; code executed on all types of reset
      [ International
        LDR     r0, =ZeroPage
        LDR     r1, [r0, #KernelMessagesBlock] ; if we've managed to open message file
        TEQ     r1, #0
        ASSERT  (ZeroPage :AND: 255) = 0
        STRNEB  r0, [r0, #ErrorSemaphore] ; then allow errors to be translated
      ]

        BL      InitialiseMode
        LDR     R0, =ZeroPage
        LDRB    R14, [R0, #MentionCMOSReset]
        TEQ     R14, #0
        BEQ     %FT12
      [ International
        SWI     XOS_WriteI+10
        BVS     %FT09
        BL      WriteS_Translated
        =       "CmosRst:CMOS RAM reset, press ESCAPE to continue",0
        ALIGN
09
      |
        SWI     XOS_WriteS
        =       10,"CMOS RAM reset, press ESCAPE to continue",0
        ALIGN
      ]
10
        SWI     XOS_ReadEscapeState
        BCC     %BT10
        MOV     R0, #124
        SWI     XOS_Byte                ; Clear the condition
        SWI     XOS_WriteI+12           ; Clear the screen
12
        SWI     XOS_WriteS
        =       10, "$SystemName ", 0   ; now RISC OS (no +) again
        ALIGN

        MOV     R0, #8
        ORR     R0, R0, #&500
        SWI     XOS_Memory              ; returns amount of soft ROM (pages) in r1
        MOVVS   R1, #0

        LDR     R0, =ZeroPage
        LDR     R0, [R0, #RAMLIMIT]
        MLA     R0, R1, R2, R0          ; convert pages to bytes and add in

        MOV     R0, R0, LSR #20         ; /(1024*1024) down to megabytes
        LDR     R1, =GeneralMOSBuffer
        MOV     R2, #?GeneralMOSBuffer
        SWI     XOS_ConvertInteger4
        SWI     XOS_Write0
        SWI     XOS_WriteS
        =       "MB", 10,13, 10, 0      ; title complete
        ALIGN

        BL      ARM_PrintProcessorType

        MOV     r0, #0                  ; Set DomainId to 0 every reset
      [ ZeroPage = 0
        STR     r0, [r0, #DomainId]     ; before calling anyone
      |
        LDR     r1, =ZeroPage
        STR     r0, [r1, #DomainId]     ; before calling anyone
      ]

; issue reset service call

        MOV     R1, #Service_Reset
        SWI     XOS_ServiceCall

; now set up the default FIQ owner

        MOV     R1, #Service_ClaimFIQ
        SWI     XOS_ServiceCall

        MOV     R1, #Service_ReleaseFIQ
        SWI     XOS_ServiceCall

        BL      PostInit

        MOV     r0, #&FD                ; read last reset type (again!)
        MOV     r1, #0
        MOV     r2, #&FF
        SWI     XOS_Byte
        CMP     r1, #SoftReset          ; a softie?
        SWINE   XOS_WriteI+7            ; go beep! Yaay!

; Now that ROM modules have mostly finished allocating memory, move a large
; chunk of the free memory from the free pool into application space so that
; the boot sequence and configured language have something to play around with
; (particularly if booting into BASIC!)
; However be careful not to move everything, otherwise anything which locks
; application space during boot could cripple important background processes
; like USB
        Push    "r1"
        LDR     r0, =ZeroPage
        LDR     r1, [r0, #AplWorkSize]
        LDR     r0, [r0, #FreePoolDANode+DANode_PMPSize]
        CMP     r0, #DynArea_PMP_BigPageCount
        MOVLO   r0, r0, LSL #12
        LDRHS   r0, =DynArea_PMP_BigByteCount
        SUB     r1, r1, #32*1024
        SUB     r1, r1, r0
        MOV     r1, r1, ASR #1          ; 50% each sounds fair
        MOV     r0, #ChangeDyn_FreePool
        SWI     XOS_ChangeDynamicArea
        Pull    "r1"

        CMP     r1, #PowerOnReset
        BNE     %FT75

        LDR     r1, =ZeroPage+HAL_StartFlags
        LDR     r1, [r1]
        TST     r1, #OSStartFlag_NoCMOSReset
        BNE     %FT75

; if any monitor key pressed, reconfigure, otherwise hang around for a bit
; till keys get a chance to come in again after being reset for the umpteenth
; time by yet another keyboard handler! SKS 07-Jun-88

        LDR     r3, =ZeroPage
        LDR     r3, [r3, #MetroGnome]
        ADD     r3, r3, #10             ; Hang about for a little while

KeypadStar_key  * -92

HorologicalDelayLoop1
        MOV     r0, #&79                        ; scan keyboard
        MOV     r1, #&FF                        ; starting at (&FF + 1) AND &FF
60
        ADD     r1, r1, #1
        AND     r1, r1, #&FF
        SWI     XOS_Byte
        TEQ     r1, #&FF                        ; if no key down
        BEQ     %FT70                           ; then check if we've run out of time

        ADR     r2, MonitorKeypadTable
62
        LDRB    r14, [r2], #2                   ; search for key in table
        TEQ     r14, #&FF
        BEQ     %FT70
        TEQ     r1, r14
        BNE     %BT62
        LDRB    r3, [r2, #-1]                   ; get corresponding CMOS bits
        MOV     r0, #ReadCMOS
        MOV     r1, #VduCMOS
        SWI     XOS_Byte
        BIC     r2, r2, #MonitorTypeBits
        ORR     r2, r2, r3
        MOV     r0, #WriteCMOS
        SWI     XOS_Byte

        TEQ     r3, #MonitorTypeAuto            ; if we're setting monitortype auto
        BNE     %FT64
        ADRL    r0, ModeCMOSTable +8            ; then configure mode auto
        LDR     r2, [r0, #-8]                   ; (load auto value)
        BL      WriteMultiField
        ADRL    r0, SyncCMOSTable +8            ; and configure sync auto
        LDR     r2, [r0, #-8]                   ; (load auto value)
        BL      WriteMultiField

64
        BL      InitialiseMode

      [ International
        SWI     XOS_WriteI+10
        BVS     %FT65
        BL      WriteS_Translated
        =       "MonType:Monitor type reconfigured",10,13,10,0
        ALIGN
65
      |
        SWI     XOS_WriteS
        =       10,"Monitor type reconfigured",10,13,10,0
        ALIGN
      ]
        B       %FT75

BranchThroughZeroInstruction2
        LDR     PC, .+ProcVec_Branch0

        LTORG

MonitorKeypadTable      ; internal key number, CMOS bits
        =       106, MonitorType0
        =       107, MonitorType1
        =       124, MonitorType2
        =       108, MonitorType3
        =       122, MonitorType4
        =       123, MonitorType5
        =       26,  MonitorType6
        =       27,  MonitorType7
        =       42,  MonitorType8
        =       43,  MonitorType9
        =       76,  MonitorTypeAuto    ; keypad dot
        =       &FF
        ALIGN 32

      [ International
MessageFileName DCB     "Resources:$.Resources.Kernel.Messages",0
        ALIGN
      ]

70
        LDR     r14, =ZeroPage
        LDR     r14, [r14, #MetroGnome]
        CMP     r14, r3
        BLO     HorologicalDelayLoop1
75


; Deal with SHIFT pressed/SHIFT-BREAK configured:
; do appropriate FSControl if wanted

        Pull    "R0"                    ; first check kbd there

        CMP     R0, #0
        BEQ     AutoBootCosNoKbd

        MOV     R0, #&FF
        MOV     R1, #0
        MOV     R2, #&FF                ; read shifty state
        SWI     XOS_Byte
        AND     R0, R1, #8              ; picka da bit
        EOR     R0, R0, #8              ; invert sense
        Pull    "R1"
        CMP     R1, #0
        MOVNE   R1, #8
        EORS    R1, R1, R0
        BEQ     %FT80

Hortoculture_Kicking
        MOV     R0, #FSControl_BootupFS
        SWI     XOS_FSControl
        BVC     %FT80

        Push    "r3,r4"
        ADD     r1, r0, #4              ; Set Boot$Error if it failed (Desktop will report it).
        ADR     r0, str_booterror
        MOV     r2, #1024               ; Big enough that terminator will be reached.
        MOV     r3, #0
        MOV     r4, #VarType_String
        SWI     XOS_SetVarVal
        SUBVS   r0, r1, #4              ; If setting Boot$Error failed then report original error as before.
        BLVS    PrintError
        SWIVS   XOS_NewLine
        Pull    "r3,r4"
80
; if either * pressed, drop into * prompt, otherwise hang around for a bit
; till keys get a chance to come in again after being reset for the umpteenth
; time by yet another keyboard handler! SKS 01-Jun-88

        LDR     r3, =ZeroPage
        LDR     r3, [r3, #MetroGnome]
        ADD     r3, r3, #10             ; Hang about for a little while

HorologicalDelayLoop2
        MOV     r1, #KeypadStar_key :AND: &FF
        BL      IsKeyPressedAtReset
        BEQ     DoStartSuper            ; EQ -> start up supervisor

        LDR     r0, =ZeroPage
        LDR     r0, [r0, #MetroGnome]
        CMP     r0, r3
        BLO     HorologicalDelayLoop2


; Start configured language module if keypad-* wasn't pressed

        MOV     R0, #ReadCMOS
        MOV     R1, #LanguageCMOS
        SWI     XOS_Byte

        MOV     R0, #ModHandReason_GetNames
        SUB     R1, R2, #1
        MOV     R2, #0                  ; preferred incarnation
        SWI     XOS_Module
        ADRVSL  R3, UtilityMod
        LDR     R2, [R3, #Module_TitleStr]
        CMP     R2, #0
        ADDNE   R1, R3, R2
DoStartSuper
        ADREQL  R1, UtilModTitle        ; ALWAYS enter via SWI: sets CAO etc.
        MOV     R0, #ModHandReason_Enter
        ADRL    R2, crstring            ; no environment
        SWI     XOS_Module
        CMP     r0, r0                  ; set EQ if failed to enter config.lang
        B       DoStartSuper            ; -> force Super entry


str_booterror   DCB     "Boot$$Error",0
                ALIGN


AutoBootCosNoKbd
      [ International
        SWI     XOS_WriteI+7
        BVS     %FT81
        BL      WriteS_Translated
        =       "NoKbd:No keyboard present - autobooting", 10,13,0
        ALIGN
81
      |
        SWI     XOS_WriteS
        =       7, "No keyboard present - autobooting", 10,13,0
        ALIGN
      ]
        B       Hortoculture_Kicking


RealIRQHandler
        LDR     PC, .-&18+ProcVec_IRQ

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; In    r1 = INKEY -ve key code to look for

; Out   EQ: key pressed
;       NE: key not pressed

IsKeyPressedAtReset Entry "r0-r2"

        MOV     r0, #129
        MOV     r2, #&FF
        SWI     XOS_Byte
        TEQ     r1, #&FF
        TEQEQ   r2, #&FF
        EXIT

        END