; 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 scan
KbdFlag_Ctrl    * 1:SHL:0
KbdFlag_Shift   * 1:SHL:1
KbdFlag_R       * 1:SHL:4
KbdFlag_T       * 1:SHL:5
KbdFlag_Delete  * 1:SHL:6
KbdFlag_Copy    * 1:SHL:7
KbdFlag_Present * 1:SHL:30
KbdFlag_Done    * 1:SHL:31

; 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

; 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

CONT_Break
        AddressHAL
        MOV     a1, #1
        LDR     a2, =L1PT
        CallHAL HAL_Reset

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Entry point from HALInit

Continue_after_HALInit

; 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

; Now copy the initialised data
        LDR     R0, =ZeroPage+IRQ1V
        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                  ; zero-initialise abort list, and other key workspace
        STR     r3, [r0, #AbortIndirection]
 [ CompatibilityPage
        STRB    r3, [r0, #CompatibilityPageEnabled]
 ]

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

 [ CacheCMOSRAM
        DebugTX "InitCMOSCache entry"
        BL      InitCMOSCache           ; initialise cache of CMOS RAM
        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]
        BEQ     %FT41
        DebugTX "InitCMOSCache done"
        B       %FT42
41
        DebugTX "InitCMOSCache failed"
42
 ]

; Initialise CAO ptr to none.

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

; Get creating the essential areas

        DebugTX "InitDynamicAreas"
        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       ; Clamps the initial size regardless of the
                                        ; contents of the ScreenSizeCMOS

        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"

        MOV     R0, #ChangeDyn_FreePool ; 512k of RAM in AplSpace should be plenty for ROM init.
        MOV     R1, #512*1024           ; Theoretically we don't need any at all, but having some there
        RSB     R1, R1, #0              ; should make it easier to debug any ROM init failures.
        SWI     XOS_ChangeDynamicArea
        LDR     R1, =ZeroPage
        LDR     R2, [R1, #AplWorkSize]
        STR     R2, [R1, #MemLimit]

        MOV     R0, #AppSpaceStart
        MOV     R1, #0
        SUB     R2, R2, R0
        BL      memset                  ; Clear AplSpace

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

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

     [  International
      [ ZeroPage <> 0
        LDR     R2, =ZeroPage
      ]
        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
      ]
     ]

        ; Make the choice between PowerOn and Hard reset based purely on
        ; the state of the POR bit and NOT on whether memory was cleared.
        LDR     R0, =ZeroPage+HAL_StartFlags
        LDR     R1, [R0]
        TST     R1, #OSStartFlag_POR
        MOVNE   R0, #PowerOnReset
        MOVEQ   R0, #ControlReset
        LDR     R1, =ZeroPage+OsbyteVars + :INDEX: LastBREAK
        STRB    R0, [R1]

        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]
        STR     r0, [r3, #TickNodeChain]

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

        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]

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

        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

        AddressHAL
        CallHAL HAL_KbdScanDependencies
        MOV     r5, r0
        DebugTX "ModuleInitForKbdScan"
        BL      ModuleInitForKbdScan

; minimal post module setup for keyboard scan

        BL      KeyPostInit

; scan keyboard for interesting keypresses R/T/Delete/End + Ctrl/Shift or timeout

        LDR     r3, =ZeroPage
        LDR     r6, [r3, #HAL_StartFlags]
        TST     r6, #OSStartFlag_RAMCleared
        MOVEQ   r6, #0                  ; RAM clear from start of free pool
        MOVNE   r6, #-1                 ; RAM clear not needed

        LDR     r3, [r3, #MetroGnome]
        ADD     r3, r3, #300            ; timeout (cs)
02
        CMP     r5, #-1                 ; HAL gave no KbdScan details
        BEQ     %FT04

        TST     r4, #KbdFlag_Present
        BNE     %FT03

        LDR     r0, =ZeroPage+KeyWorkSpace
        LDRB    r0, [r0, #:INDEX:KbId]  ; check if anyone registered with KeyV
        CMP     r0, #&20                ; same limit as GetCountry
        BCS     %FT04

        ORR     r4, r4, #KbdFlag_Present
        DebugTX "KbdFlag_Present"
03
        MOV     r0, #OsByte_INKEY
        MOV     r1, #0 :EOR: &7F        ; scan from shift upwards
        MOV     r2, #255
        SWI     XOS_Byte
        TEQ     r1, #0
        ORREQ   r4, r4, #KbdFlag_Shift
        TEQ     r1, #1
        ORREQ   r4, r4, #KbdFlag_Ctrl
        TEQ     r1, #51
        ORREQ   r4, r4, #KbdFlag_R
        TEQ     r1, #35
        ORREQ   r4, r4, #KbdFlag_T
        TEQ     r1, #89
        ORREQ   r4, r4, #KbdFlag_Delete
        TEQ     r1, #105
        ORREQ   r4, r4, #KbdFlag_Copy
04
        SWI     XOS_LeaveOS
        SWI     XOS_EnterOS             ; callbacks

        ; Prior to getting here, ClearWkspRAM cleared low OS workspace & ScratchSpace, and
        ; Init_MapInRAM_Clear has selectively cleared other early allocations. That leaves
        ; everything from InitDynamicAreas
        ;   RMA => not cleared, it's in use
        ;   Screen => not cleared, the next CLS will do that
        ; and
        ;   AplSpace (first 512k) => cleared unconditionally
        ;   Free pool => clear now if HAL didn't
        ; left to do.
        MOV     r0, r6
        BL      ClearFreePoolSection
        MOV     r6, r0
        CMP     r6, #-1
        BNE     %BT02                   ; the show's not over until the RAM clear is done

        CMP     r5, #-1
        BEQ     %FT05                   ; HAL gave no KbdScan details

        TST     r4, #KbdFlag_Shift :OR: KbdFlag_Ctrl :OR: KbdFlag_R :OR: KbdFlag_T :OR: KbdFlag_Delete
        BNE     %FT05                   ; exciting key press beats a timeout

        LDR     r0, =ZeroPage
        LDR     r0, [r0, #MetroGnome]
        CMP     r0, r3                  ; timed out?
        BCC     %BT02
05
        ORR     r4, r4, #KbdFlag_Done
        Push    "r4"                    ; save until after MOSInit

; Clear temp ws skipped earlier
        LDR     R0, =ZeroPage+InitWsStart
        MOV     R1, #0
        MOV     R2, #InitWsEnd - InitWsStart
        BL      memset

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

; IF power-on bit set AND R/T/Del/Copy pressed THEN reset CMOS RAM

        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

        TST     R4, #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     R4, #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"

        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     R4, [SP]
        TST     R4, #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       init_other_modules

no_cmos_reset
        MOV     r0, #SystemSpeedCMOS
        BL      Read
        BIC     r1, r0, #CMOSResetBit   ; clear bit indicating CMOS reset
        MOV     r0, #SystemSpeedCMOS
        BL      Write

init_other_modules

; init that's deferrable until the CMOS is sanitised
        DebugTX "ReadDefaults"
        BYTEWS  WsPtr
        BL      ReadHardCMOSDefaults
        BL      ReadCMOSDefaults
        DebugTX "InitHostedDAs"
        BL      InitHostedDAs
        DebugTX "MouseInit"
        BL      MouseInit

; now go back and load the other modules, scan podules, accounting for frugal bits
        DebugTX "ModuleInit"
        BL      ModuleInit

        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 territory in case it changed after ModuleInitForKbdScan
        MOV     R0, #ReadCMOS
        MOV     R1, #TerritoryCMOS
        SWI     XOS_Byte
        EOR     R0, R2, #1              ; encoded so that 0 => TerritoryNum_UK
        SWI     XTerritory_Select

        ; Update RTC now all the modules are running
        SWI     XOS_ResyncTime

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

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

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

        ASSERT  (ZeroPage :AND: 255) = 0  ; if we've managed to open message file
        STRVCB  lr, [lr, #ErrorSemaphore] ; then allow errors to be translated
      ]

        ; 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)
        ;
        ; Must also be after Service_PostInit to give TerritoryManager opportunity
        ; to load disc based territories.
        MOV     R0, #9
        MOV     R1, #2
        SWI     XOS_ReadSysInfo

      [ UseNewFX0Error
        ; Also, *FX 0
        BL      InitNewFX0Error
      ]
      [ CompatibilityPage
        ; Enable low zero page compatibility page
        MOV     R0, #OSMemReason_Compatibility
        MOV     R1, #1
        SWI     XOS_Memory
      ]

        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, #OsByte_ClearEscape
        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

        SWI     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
        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

        MOV     r0, #OsByte_RW_LastResetType
        MOV     r1, #0
        MOV     r2, #&FF
        SWI     XOS_Byte
        CMP     r1, #PowerOnReset
        BNE     %FT70

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

; if any keypad-numeric key pressed, reconfigure monitor type

        MOV     r0, #OsByte_ScanKeyboard        ; 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 give up

        ADR     r2, MonitorKeypadTable
62
        LDRB    r14, [r2], #2                   ; search for key in table
        TEQ     r14, #&FF
        BEQ     %FT70                           ; give up, key not in table
        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       %FT70

RealIRQHandler
        LDR     PC, .-&18+ProcVec_IRQ

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

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

        Pull    "R4"                    ; recover KbdFlag bits

        TST     R4, #KbdFlag_Present    ; first check kbd there
        BNE     shifty_boot

      [ International
        BL      WriteS_Translated
        =       "NoKbd:No keyboard present - autobooting", 10,13,0
        ALIGN
      |
        SWI     XOS_WriteS
        =       7, "No keyboard present - autobooting", 10,13,0
        ALIGN
      ]
        B       Hortoculture_Kicking

shifty_boot
        MOV     R0, #OsByte_RW_StartupOptions
        MOV     R1, #0
        MOV     R2, #&FF                ; read shifty state
        SWI     XOS_Byte
        TST     R4, #KbdFlag_Shift
        EORNE   R1, R1, #8              ; invert sense
        TST     R1, #8
        BNE     %FT80                   ; no boot when set

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 keypad-* pressed, drop into * prompt

        MOV     r0, #OsByte_INKEY
        MOV     r1, #KeyScan_NumPadStar :AND: &FF
        MOV     r2, #&FF
        SWI     XOS_Byte
        TEQ     r1, #&FF
        TEQEQ   r2, #&FF
        BEQ     DoStartSuper            ; EQ -> start up supervisor

; 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

        END