; 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 [ HAL KbdScanActive # 1 # 2 KbdFlags # 4 | CTRL_Down_Flag # 1 SHIFT_Down_Flag # 1 KB_There_Flag # 1 R_Down_Flag # 1 ; note that these 4 form one word!! T_Down_Flag # 1 Del_Down_Flag # 1 Copy_Down_Flag # 1 KeyDataPtr # 4 Port2Present # 1 ; note that these 4 form one word!! Port3Present # 1 KeyState # 1 KeyMSB # 1 ] ; On ARM600, InitIRQWs is in zero page - check it's big enough ASSERT @ <= ?InitIRQWs ; AddCamEntries ; ; in: r0 -> appropriate part of CAM map ; r1 = ap (+ CB bits in new world) ; r2 = log address ; r7 = amount of cam map to do ; r8 = PageSize ; ; out: r0, r3-r12 preserved ; r1 corrupted ; r2 updated by relevant amount AddCamEntries ROUT Push "r0, lr" MOV lr, r1 ; access privs (PPL) MOV r1, r7 01 STMIA r0!, {r2, lr} ; store logaddr, PPL ADD r2, r2, r8 ; increment address by 1 page SUBS r1, r1, #8 ; decrement count of how much to do BNE %BT01 Pull "r0, pc" ; 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 MOV r6, r11 ; r6 = ap + CB LDR r7, [r4, #DANode_Base] LDR r8, [r4, #DANode_Size] ADD r7, r7, r8 ; r7 -> end of free pool +1 10 CMP r8, r10 ; if no free memory left BCC %FT20 ; then tidy up SUB r7, r7, r10 ; move free pool pointer backwards Push "r0, r1" MOV r0, r7 MOV r1, r3 BL MovePageAtR0ToR1WithAccessR6 Pull "r0, r1" ADD r3, r3, r10 ; advance "to" pointer SUB r8, r8, r10 ; one less page of free memory ADD r5, r5, r10 ; one more page done SUBS r0, r0, r10 BNE %BT10 20 STR r8, [r4, #DANode_Size] 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 [ HAL ! 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 ] [ :LNOT: HAL ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Data tables: VIDC := mode 0, all palette black VIDCTAB ; Program Control Register first, to clear power-down bit ; Now depending upon the VIDCClockSource flag, re-program the clock source. [ VIDCClockSource = "VCO" [ VCOstartfix & &E0000404 ; CR: FIFO load 16 words, 1 bpp, ck/2, vclk (allow for doubled VCO freq) | & &E0000400 ; CR: FIFO load 16 words, 1 bpp, ck/1, vclk ] ] [ VIDCClockSource = "HCLK" & &E0000401 ; CR: FIFO load 16 words, 1 bpp, ck/1, hclk ] [ VIDCClockSource = "RCLK" & &E0000406 ; CR: FIFO load 16 words, 1 bpp, ck/2, rclk ] ; Don't bother programming all 256 palette entries, we'll be here all night ; Since we're setting up a 1 bit-per-pixel mode, just do colours 0 and 1 & &10000000 ; Palette address register = 0 & &00000000 ; Colour 0 = black & &00000000 ; Colour 1 = black & &40000000 ; Border colour = black & &50000000 ; Pointer colour 1 = black & &60000000 ; Pointer colour 2 = black & &70000000 ; Pointer colour 3 = black ; Get a stable display up so we get stable signals & &800003F8 ; HCR = 76 + 88 + 96 + 640 + 96 + 28 & &81000044 ; HSWR = 76 & &82000098 ; HBSR = 76 + 88 & &830000F2 ; HDSR = 76 + 88 + 96 & &84000372 ; HDER = 76 + 88 + 96 + 640 & &850003D8 ; HBER = 76 + 88 + 96 + 640 + 96 & &860000F3 ; HCSR = HDSR & &90000137 ; VCR = 3 + 19 + 16 + 256 + 16 + 2 & &91000002 ; VSWR = 3 & &92000015 ; VBSR = 3 + 19 & &93000025 ; VDSR = 3 + 19 + 16 & &94000125 ; VDER = 3 + 19 + 16 + 256 & &95000135 ; VBER = 3 + 19 + 16 + 256 + 16 & &96000025 ; VCSR = VDSR & &97000025 ; VCER = VDSR & &B1000001 ; SCR: sound disabled (+use 24MHz clock) & &C00F1003 ; EREG = comp sync, DACs on, ereg output ext lut [ VCOstartfix & &D0000302 ; FSYNREG, clk = (3+1)/(2+1) * 24MHz = 32MHz (higher frequency as part of fix) | & &D0000305 ; FSYNREG, clk = (3+1)/(5+1) * 24MHz = 16MHz ] & &F0013000 ; DCR: bus D[31:0], Hdisc ;RCM 29/9/94: changed from &F0012000 at PSwindells request & &FFFFFFFF ; That's the lot VIDCPhys * &03400000 ; used to address VIDC when MMU is off ; Entered here after RESET (or BREAK) ; This code must be capable of being executed at a non-ROM address and with the MMU off, ; and running in 32-bit mode up until the call to MemSize. CONT_Break MOV r1, #1 ; parameter passed to InitMEMC, to indicate Break not Reset B Continue CONT ROUT MOV r1, #0 ; parameter passed to InitMEMC, to indicate Reset not Break Continue ; First bang MEMC to ensure safety BL InitMEMC ; initialise MEMC CR, and turn off MMU if it's on ; VInit etc set on ze mode change: no DMA going yet so don't set owt. MOV R1, #VIDCPhys ; Must ALWAYS initialise VIDC on reset or else ADR R2, VIDCTAB ; we may get vsync interrupts that stiff us 10 LDR R0, [R2], #4 ; permanently as VIDC is in an undefined state CMP R0, #-1 ; so have mode 0 with all black palette STRNE R0, [R1] BNE %BT10 ; Now bang IOC (disable all but keyboard interrupts) MOV R1, #IOC MOV R0, #&FF ; all inputs STRB R0, [R1, #IOCControl] ; in case called by Tim MOV R0, #0 STRB R0, [R1, #IOCIRQMSKA] ; kein interrupts STRB R0, [R1, #IOCFIQMSK] ; disable FIQs STRB R0, [R1, #IOMD_DMAMSK] ; disable DMA interrupts, too STRB R0, [R1, #IOMD_IRQMSKC] ; and the rest... STRB R0, [R1, #IOMD_IRQMSKD] [ Keyboard_Type = "A1A500" :LOR: Keyboard_Type = "PC" MOV R0, #KARTRxBit ; used for Archi keyboard or IOMD PC keyboard ] STRB R0, [R1, #IOCIRQMSKB] ; allow communication with kbd, when I_bit gets cleared ; now bits to allow CMOS read/write : need timer LDR R0, =20000-1 ; R0 = Timer delay (units of 0.5 microsecond) ; 20000*0.5E-6 = 0.01 Seconds (100Hz ticker) ; TMD 21-May-93: "-1" correction applied STRB R0, [R1, #Timer0LL] ; Set up the delay MOV R0, R0, LSR #8 STRB R0, [R1, #Timer0LH] STRB R0, [R1, #Timer0GO] ; and start the ticks MOV R0, #timer0_bit STRB R0, [R1, #IOCIRQCLRA] ; Clear pending t0 interrupt j.i.c. [ VCOstartfix ;2nd part of fix for VCO failing to start on A7000 (esp. 7500FE) - forcing PCOMP high for about 3 ms LDRB R0, [R1,#IOMD_ID0] CMP R0, #&E7 LDREQB R0, [R1,#IOMD_ID1] CMPEQ R0, #&D4 BEQ vcofix_notMorris ; risky to force PCOMP on Risc PC MOV R0, #VIDCPhys LDR R2, =&D0000342 ; VIDC20 FSYNREG, as in VIDCTAB but with force PCOMP high STR R2, [R0] MOV R0, #3072*2 ; time delay of about 3 ms (0.5 us units) STRB R0, [R1, #Timer0LR] ; copy counter into output latch LDRB R2, [R1, #Timer0CL] ; R2 := low output latch vcofix_waitloop STRB R0, [R1, #Timer0LR] ; copy counter into output latch LDRB R3, [R1, #Timer0CL] ; R3 := low output latch TEQ R3, R2 ; unchanged ? BEQ vcofix_waitloop ; then loop MOV R2, R3 ; copy anyway SUBS R0, R0, #1 ; decrement count BNE vcofix_waitloop ; loop if not finished MOV R0, #VIDCPhys LDR R2, =&D0000302 ; VIDC20 FSYNREG, as in VIDCTAB (PCOMP low again) STR R2, [R0] vcofix_notMorris ] ; now size memory BL MemSize ; out: r0 = page size, r1 = memory size, r2 = MEMC CR value, r3-r14 corrupt MemSized MOV R8, R0 ; R8 = page size in bytes MOV R13, R1 ; R13 is now the RAM size MOV R9, R2 ; need this to set soft copy right [ EmulatorSupport ARM_on_emulator R7 MOVEQ R7,#&80 ORREQ R7,R7,#&3E00 ; r7 := &3E80 = 16000 (standard Risc PC value) BLNE TimeCPU ; r7 := CPU speed in kHz/MEMC1a flag | BL TimeCPU ; r7 := CPU speed in kHz/MEMC1a flag ] ; the fixed areas give us : IRQ stack (in cursor), SVC stack (in sysheap base) ; and bottom block makes most sense done here ; now keyboard initialisation: initialise baud rate, send dummy, read dummy MOV R0, #InitKbdWs MOV R1, #0 STRB R1, [R0, #CTRL_Down_Flag] ; clear CTRL down flag, R down flag STRB R1, [R0, #SHIFT_Down_Flag] STRB R1, [R0, #KB_There_Flag] STR R1, [R0, #R_Down_Flag] ; all CMOS reset flags STR R1, [R0, #KeyDataPtr] STR R1, [R0, #Port2Present] ; all KbdRes vars B SetUpKbd ; No stack yet so branch and branch back. SetUpKbdReturn ; set up reset interrupt handler (reads, discards keys, setting flags if CTRL or R) ; NB on ARM600 we need to go into 32-bit mode, so we can safely overwrite vectors MRS r0, CPSR ; switch into IRQ32, still IRQs disabled BIC r0, r0, #&1F ORR r1, r0, #IRQ32_mode MSR CPSR_c, r1 LDR sp_irq, =IRQSTK ; set up sp_irq ADRL R2, MOSROMVecs ; pick up from table LDR R2, [R2, #&18] ; this gets overwritten while active, MOV R3, #0 STR R2, [R3, #&18] ; but hopefully by the same value! ADDR R2, IRQ_Test_CTRL_or_R_Pressed ; (could use ADRL, but ADDR macro is nicer) STR R2, [R3, #InitIRQHandler] ; instruction is now a LDR PC,InitKbdHandler ORR r0, r0, #SVC32_mode ; switch into SVC32 [ StrongARM ;for StrongARM, we need to do an IMB type thing for modifying code in vector area ARM_read_ID r1 AND r1,r1,#&F000 CMP r1,#&A000 BNE vectorpoke_notSA_1 MOV r1,#0 ;we clean one cache entry, 0..1F, = vector area [ SAcleanflushbroken ARMA_clean_DCentry r1 ARMA_flush_DCentry r1 | ARMA_cleanflush_DCentry r1 ] ARMA_drain_WB ARMA_flush_IC vectorpoke_notSA_1 ] BIC r0, r0, #I32_bit ; and enable IRQs MSR CPSR_c, r0 ; in SVC32 from now until we've finished poking around with vectors [ :LNOT: AlwaysClearRAM ; IF por OR FX200 bit set THEN clear memory MOV R0, #IOC LDRB R1, [R0, #IOCIRQSTAA] ANDS R1, R1, #por_bit BNE %FT20 LDR R0, =OsbyteVars + :INDEX: ESCBREAK LDRB R1, [R0] CMP R1, #2 ; unlike popular rumour, bit 1 ain't CMPNE R1, #3 ; a flag BNE %FT30 20 ] BL ClearPhysRAM 30 MOV r0, #0 STR r9, [r0, #MEMC_CR_SoftCopy] ; set soft copy. STR r7, [r0, #MemorySpeed] ; Remember CPU speed/MEMC1a flag STR r8, [r0, #Page_Size] ; r8 is still page size from way up there STR r13, [r0, #RAMLIMIT] ; save sussed memory size in LogRam LDR sp, =SVCSTK ; set up a stack ; do as much other initialisation as possible, to give keyboard stuff time [ StrongARM BL Processor_Type ; Determines the processor type & stores it in page 0. ] ] ; :LNOT: HAL 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). [ ProcessorVectors ; 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 [ :LNOT: No26bitCode ; Now we have set up the hardware vectors we can drop back to SVC26 mode MRS r0, CPSR BIC r0, r0, #&1F ORR r0, r0, #SVC26_mode MSR CPSR_c, 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" ; 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) [ HAL us * 1 | us * 2 ] [ HAL 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 [ EmulatorSupport ARM_on_emulator r0 MOVEQ r0, #us LDRNE r0, =KeyWait*us ; Wait 1/5 second (give keys down a chance to come in). | 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" | [ KeyWait <> 0 ; Check for keyboard there every 1/5 sec. but give up after 2 secs. MOV r2, #IOC MOV r6, #10 ; Check for keyboard 10 times (2 secs max). MOV r4, #InitKbdWs kbdwait LDRB r5, [r4, #KB_There_Flag] [ EmulatorSupport ARM_on_emulator r0 MOVEQ r0, #us LDRNE r0, =KeyWait*us ; Wait 1/5 second (give keys down a chance to come in). | LDR r0, =KeyWait*us ; Wait 1/5 second (give keys down a chance to come in). ] BL DoMicroDelay TEQ r5, #0 ; If keyboard was there 1/5 second ago then BNE kbdthere ; continue reset SUBS r6, r6, #1 ; else wait a maximum of 2 seconds. BNE kbdwait kbdthere ] ] [ 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 ] [ ValidateCMOS :LAND: STB ; ScreenSizeCMOS, RAMDiscCMOS, SysHeapCMOS, RMASizeCMOS and SpriteSizeCMOS ; should be 0. Happily they are at consecutive addresses so we can loop through ; them. MOV R1, #ScreenSizeCMOS reset_loop MOV R0, R1 BL Read TEQ R0, #0 BNE cmos_reset INC R1 TEQ R1, #SpriteSizeCMOS BHI reset_loop ; Year should be >=1995, <=2037 (when 32 bit signed Unix time breaks) MOV R0, #YearCMOS+1 BL Read MOV R1, R0 MOV R0, #YearCMOS+0 BL Read MOV R2, #100 MLA R0, R2, R1, R0 LDR R1, =1995 SUB R0, R0, R1 CMP R0, #2037 - 1995 BHI cmos_reset ; Bit 4 of DBTBCMOS should be 1 (Boot) MOV R0, #DBTBCMOS BL Read TST R0, #(1:SHL:4) BEQ 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! [ HAL 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" [ CheckProtectionLink TST R1, #OSStartFlag_NoCMOSReset BNE no_cmos_reset ] TST R1, #OSStartFlag_CMOSReset BNE cmos_reset | MOV R0, #IOC LDRB R1, [R0, #IOCIRQSTAA] ANDS R1, R1, #por_bit BEQ no_cmos_reset [ CheckProtectionLink LDR r0, =IOMD_MonitorType ; on Issue A's the protection bit is only weakly pulled up, ; so force it high, then read it back LDRB r1, [r0] ORR r1, r1, #IOMD_ProtectionLinkBit STRB r1, [r0] LDRB r1, [r0] TST r1, #IOMD_ProtectionLinkBit BEQ no_cmos_reset ; if zero then CMOS is protected ] [ STB :LAND: IOMD_C_FrontPanelButton <> 0 [ FrontPanelButtClearsCMOS MOV r0, #IOMD_Base ; if front panel button pressed then CMOS reset LDRB r0, [r0, #IOMD_CLINES] TST r0, #IOMD_C_FrontPanelButton BEQ cmos_reset ] ] ] LDR R0, =ZeroPage+InitIRQWs [ HAL LDR R7, [R0, #KbdFlags] TST R7, #KbdFlag_R:OR:KbdFlag_T:OR:KbdFlag_Delete:OR:KbdFlag_Copy | LDR R7, [R0, #R_Down_Flag] ; Picks up R/T/Del/Copy flags all in one CMP R7, #0 ] 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 [ HAL TST R7, #KbdFlag_Copy:OR:KbdFlag_Delete | ASSERT (Del_Down_Flag - R_Down_Flag) = 2 ASSERT (Copy_Down_Flag - Del_Down_Flag) = 1 MOVS R3, R7, LSR #16 ; full reset or just system? ] 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 [ HAL LDR R1, [R0, #KbdFlags] TST R1, #KbdFlag_R:OR:KbdFlag_Delete | LDRB R1, [R0, #R_Down_Flag] CMP R1, #0 LDREQB R1, [R0, #Del_Down_Flag] CMPEQ R1, #0 ] 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 [ SoftResets TST r1, #por_bit BNE hard_reset ; it was a power-on, so it's a hard reset CMP r0, #0 [ DebugForcedReset MOVNE r2, #Reset_CannotResetFlag ] BNE hard_reset_forced ; IF control pressed OR memory implausible (Check SysHpd, CAM map sensible) THEN hard reset LDR R0, =SysHeapStart LDR R8, [R0, #:INDEX: hpdmagic] LDR R2, =magic_heap_descriptor CMP R8, R2 ; check sysheap initialised [ DebugForcedReset MOVNE r2, #Reset_SysHeapCorrupt ] BNE hard_reset_forced ; also check CAM map sensible LDR R5, =ZeroPage LDR R4, [R5, #Page_Size] ; R4 = page size ADRL R3, PageShifts-1 LDRB R4, [R3, R4, LSR #12] ; R4 = log2(pagesize) LDR R3, [R5, #RAMLIMIT] ; R3 = total RAM size MOV R2, R3, LSR R4 ; number of pages=total memory / pagesize CMP R2, #256 ; but if fewer than 128 (eg 64 on A305) (NB if <256 then <=128) MOVCC R2, #128 ; then use 128 (all MEMC1's pages need initialising, ; even if half of them are not in use) SUB R2, R2, #1 LDR R3, =CamEntriesForVicky LDR R4, [R5, #MaxCamEntry] ; get highest CAM entry LDR R5, [R5, #CamEntriesPointer] ; and pointer to CAM soft copy CMP R5, R3 ; if not the same [ DebugForcedReset MOVNE r2, #Reset_WrongCamMapAddress BNE hard_reset_forced ] CMPEQ R4, R2 ; or number of pages not the same [ DebugForcedReset MOVNE r2, #Reset_WrongNumberOfPages ] BNE hard_reset_forced ; then do a hard reset ; now check all cam contains sensible values LDR R4, =ZeroPage LDR R4, [R4, #Page_Size] SUB R4, R4, #1 ORR R4, R4, #&F0000000 ; can have addresses above 64M CamCheck LDR R3, [R5, R2, LSL #2] BIC r3, r3, #&F0000000 ; remove PPL TST R3, R4 [ DebugForcedReset MOVNE r2, #Reset_CamMapCorrupt ] BNE hard_reset_forced ; wally entry: not pagesize multiple, or >= 32M SUBS R2, R2, #1 BPL CamCheck ; leave CTRL test till last, so the keyboard's had as much time to ; wiggle the wet string as we can give it LDR R0, =ZeroPage+InitKbdWs LDRB R1, [R0, #CTRL_Down_Flag] CMP R1, #0 BNE hard_reset soft_reset ; clear out 4K of scratchspace, to use as a reverse CAM soft copy; ; set bytes to indicate page mapped to that address. Can then recalculate ; end of memory. ; This code doesn't currently work on ARM600 versions - ; 4K of workspace isn't enough to do this with a 4K page size ; We'd probably want to do it differently anyway, using the L2PT ; But since we're removing soft resets it's not worth the effort ASSERT MEMM_Type <> "ARM600" MOV R5, #ScratchSpace MOV R1, #4*1024 MOV R2, #0 clrscratch SUBS R1, R1, #4 STRPL R2, [R5, R1] BPL clrscratch LDR r7, =ZeroPage LDR R2, [R7, #Page_Size] ADRL R8, PageShifts-1 LDRB R8, [R8, R2, LSR #12] LDR r2, [r7, #RAMLIMIT] MOV r2, r2, LSR r8 ; last valid page SUB r2, r2, #1 LDR R7, [R7, #CamEntriesPointer] LDR R12, =DuffEntry restoreCAMloop LDR R3, [R7, R2, LSL #2] MOV r11, r3, LSR #28 BIC r3, r3, #&F0000000 MOV R0, R3, LSR R8 ; logram page number LDRB R4, [R5, R0] CMP r4, #0 ; check for doubly mapped pages BEQ rclon ORR r3, r12, #&30000000 ; force to invalid place if so. STR r3, [R7, R2, LSL #2] MOV r3, r12 MOV r11, #3 ; protected MOV R0, R3, LSR R8 LDRB R4, [R5, R0] rclon CMP r3, #16*1024*1024 ; in application space? MOVLT r11, #0 ; noprot if so STRLT r3, [R7, R2, LSL #2] ADD R4, R4, #1 STRB R4, [R5, R0] ; sema for interesting pages BL BangCam SUBS R2, R2, #1 BPL restoreCAMloop ; now do post-scan to see if we need to do more CAM bashing to get pages back. ; any entries that aren't validateable should be remapped. LDR R1, =ZeroPage MOV R12, #ScratchSpace LDR R2, [R1, #Page_Size] MOV R7, #0 findapplend LDRB R3, [R12], #1 CMP R3, #0 ADDNE R7, R7, R2 BNE findapplend STR R7, [R1, #AplWorkSize] ; verified value LDR R3, [R1, #RAMLIMIT] ; calc last valid page: MOV R3, R3, LSR R8 ; RAMLIMIT >> R8 LDR R4, [R1, #CamEntriesPointer] ; no PPL testforremap SUBS R3, R3, #1 BMI finishedremap LDR R0, [R4, R3, LSL #2] BIC r0, r0, #&F0000000 ; remove PPL ADD R1, R0, R2 SWI XOS_ValidateAddress BCC testforremap Push "R2-R4" MOV R0, R0, LSR R8 ; curr logram page number LDRB R4, [R5, R0] SUB R4, R4, #1 STRB R4, [R5, R0] ; dec sema MOV R2, R3 ; entry no MOV R3, R7 ; addr to set to BL BangCamUpdate Pull "R2-R4" holefilled ADD R7, R7, R2 LDRB R0, [R12], #1 ; reinspect our reverse map CMP R0, #0 BNE holefilled [ ZeroPage <> 0 LDR R0, =ZeroPage ] STR R7, [R0, #AplWorkSize] B testforremap finishedremap MOV R12, #NVECTORS-1 LDR R11, =ZeroPage+VecPtrTab freenextvec LDR R2, [R11, R12, LSL #2] loseveclink LDR R3, [R2, #TailPtr] BL FreeSysHeapNode MOVVC R2, R3 BVC loseveclink CMP R3, #0 ; were we at the end of the chain? [ DebugForcedReset MOVNE r2, #Reset_VectorChainCorrupt ] BNE hard_reset_forced SUBS R12, R12, #1 BPL freenextvec ; so that's the code for restore default vectors, basically BL InitVectors LDR R0, =ZeroPage LDR R1, [R0, #AplWorkSize] STR R1, [R0, #MemLimit] LDR R3, =TickNodeChain LDR R2, [R3] loseticknodes CMP R2, #0 BEQ ticknodesallgone LDR R3, [R2] BL FreeSysHeapNode [ DebugForcedReset MOVVS r2, #Reset_TickNodesCorrupt ] BVS hard_reset_forced MOV R2, R3 B loseticknodes ticknodesallgone ; and now it's time to free the IRQ structures MOV R12, #(NoInterrupt-1)*12+8 ; last device link offset LDR R11, =DefaultIRQ1V-DefaultIRQ1Vcode+Devices freenextdev LDR R2, [R11, R12] losedevlink CMP R2, #0 BEQ stepdevice LDR R3, [R2, #8] BL FreeSysHeapNode [ DebugForcedReset MOVVS r2, #Reset_DeviceVectorCorrupt ] BVS hard_reset_forced MOV R2, R3 B losedevlink stepdevice SUBS R12, R12, #12 BPL freenextdev ; now the PIRQ structures and CallBack_Vector LDR R11, =ZeroPage+PIRQ_Chain MOV r4, #PodDesp_Link losepirqchain LDR R2, [R11] CMP r2, #0 ; for CallBack_Vector BEQ doobry losepirqlink LDR R3, [R2, r4] BL FreeSysHeapNode MOVVC R2, R3 BVC losepirqlink CMP R3, #0 ; were we at the end of the chain? [ DebugForcedReset MOVNE r2, #Reset_PoduleOrCallBackCorrupt ] BNE hard_reset_forced LDR R2, =ZeroPage+PIRQ_Chain CMP R11, R2 LDR R2, =ZeroPage+PFIQasIRQ_Chain MOVEQ R11, R2 CMPNE r11, r2 LDREQ r11, =ZeroPage+CallBack_Vector [ PodDesp_Link <> 0 MOVEQ r4, #0 ] BEQ losepirqchain doobry Pull "R1" ; IOCControl restoration LDR R0, =ZeroPage STRB R1, [R0, #IOCControlSoftCopy] ASSERT :LNOT: HAL MOV R0, #IOC ; and bash the hardware STRB R1, [R0, #IOCControl] MOV R0, #SoftReset B ResetPart1Done ] ; SoftResets hard_reset [ DebugForcedReset MOV r2, #0 ; indicate normal hard reset ] hard_reset_forced LDR r8, =ZeroPage [ DebugForcedReset STR r2, [r8] ; store to logical address zero ] Pull "R2" ; discard old IOC state ; fill in relevant CamMap entries, so can soft start. LDR R8, [R8, #Page_Size] ADRL R1, PageShifts-1 LDRB R1, [R1, R8, LSR #12] LDR r2, =ZeroPage LDR r0, [r2, #VideoSizeFlags] ; offset from start of physical pages to static part MOV r0, r0, LSR r1 ; r0 := cam entry number MOV r0, r0, LSL #3 ; r0 := offset into CAM map for start of static part MOV R7, #32*1024*8 MOV R7, R7, LSR R1 ; r7 := cam entry offset for 32K LDR R12, [R2, #RAMLIMIT] ; R12 = total RAM size [ :LNOT:HAL ; new code which allows for MEMC2's small pages MOV R1, R12, LSR R1 ; R1 = number of pages CMP R1, #256 ; but if fewer than 128 (eg 64 on A305) (NB if <256 then <=128) MOVCC R1, #128 ; then use 128 (all MEMC1's pages need initialising, ; even if half of them are not in use) SUB R3, R1, #1 STR R3, [R2, #MaxCamEntry] LDR R1, =CamEntriesForVicky STR R1, [R2, #CamEntriesPointer] ; On ARM600 we must zap all the soft CAM map before adding any entries, ; since the old contents are used in BangCamUpdate Push "r0" ADD r2, r1, r3, LSL #3 ; r2 -> last entry to do LDR r0, =DuffEntry MOV lr, #AP_Duff ; PPL = no access WallopDuffOnes STMDA r2!, {r0, lr} ; store address, PPL CMP r2, r1 BCS WallopDuffOnes Pull "r0" ADD R0, R0, R1 LDR R2, =CursorChunkAddress LDR r1, =AP_CursorChunk BL AddCamEntries CMP R12, #512*1024 SUBEQ R0, R0, R7 ; previous entries ADDNE R0, R0, R7 ; next entries MOV R2, #0 MOV r1, #AP_PageZero BL AddCamEntries CMP R12, #512*1024 SUBEQ R0, R0, R7 ; previous entries ADDNE R0, R0, R7 ; next entries LDR R2, =SysHeapChunkAddress MOV r1, #AP_SysHeap :OR: PageFlags_Unavailable BL AddCamEntries ADD R0, R0, R7 ; next entries (ignore 512K machines) MOV r7, #0 LDR r7, [r7, #L2PTSize] MOV r7, r7, LSR #12-3 ; number of pages * 8 LDR R2, =L2PT LDR r1, =AP_L2PT :OR: PageFlags_Unavailable BL AddCamEntries ADD r2, r0, #((L1PT-L2PT):SHR:(12-3)) ; point at PPL for 1st L1 page ADD r2, r2, #4 LDR r1, =AP_L1PT STR r1, [r2], #8 ; store 4 CAM entries for 4 x 4K = 16K of L1 STR r1, [r2], #8 ; mark them as unavailable for removal STR r1, [r2], #8 STR r1, [r2], #8 ADD R0, R0, R7 ; add on enough pages for L2PT MOV r7, #0 LDR r7, [r7, #SoftCamMapSize] ; number of bytes in soft cam map ADD r7, r7, #UndStackSize MOV r7, r7, LSR #12-3 ; number of bytes of cam map for this LDR R2, =UndStackSoftCamChunk MOV r1, #AP_UndStackSoftCam BL AddCamEntries ] 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, #AP_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, =AP_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" [ LongCommandLines :LAND: (:LNOT: HAL) ;sort out the Kernel buffers dynamic area Push "r0-r12" MOV r1, #ChangeDyn_Kbuffs ; Area number MOV r2, #KbuffsSize ; Initial (and in fact permanent) size LDR r3, =KbuffsBaseAddress ; Base address MOV r4, #AP_Kbuffs ; Area flags MOV r5, #KbuffsMaxSize ; Maximum size MOV r6, #0 ; no handler MOV r7, #0 ADRL r8, AreaName_Kbuffs ; 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" ] ; 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, #AP_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 r0, #RAMDiscCMOS ; find out how much RAM disc configured BL GetConfiguredSize ; in: r0 = CMOS address, out: r2 = size 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, #AP_RAMDisc_SA ; Area flags, if StrongARM (introduced for Ursula) MOVNE r4, #AP_RAMDisc ; Area flags [ {FALSE} MOV r5, #16*1024*1024 ; Limit maximum size to 16MB while fiddling with FileCore | MOV r5, #128*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! 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, #AP_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, #AP_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 ] ] [ HAL LDR R0, =ZeroPage+HAL_StartFlags LDR R1, [R0] TST R1, #OSStartFlag_POR | MOV R0, #IOC LDRB R1, [R0, #IOCIRQSTAA] ANDS R1, R1, #por_bit STRNEB R1, [R0, #IOCIRQCLRA] ; clear POR if set ] ; 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 [ HAL LDR R0, [R1, #KbdFlags] AND R1, R0, #KbdFlag_Shift AND R0, R0, #KbdFlag_Present | LDRB R0, [R1, #KB_There_Flag] LDRB R1, [R1, #SHIFT_Down_Flag] ] 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] [ :LNOT: No26bitCode ; we're poking locations 0 and &18 here, so we'd best go back to SVC32 MRS r2, CPSR BIC r3, r2, #&1F ORR r3, r3, #SVC32_mode MSR CPSR_c, r3 ] [ DebugForcedReset LDR R1, [R0] TEQ R1, #0 ; if normal hard reset LDREQ R1, BranchThroughZeroInstruction2 ; then get branchthruzero code | 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 [ :LNOT:No26bitCode ; now back to SVC26 MSR CPSR_c, r2 ] 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" ] [ DoInitialiseMode :LOR: :LNOT: Embedded_UI 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 [ HAL 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 L1L2PTenhancements ; little tricks on cacheability etc for performance ] 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) [ :LNOT: HAL :LAND: RO371Timings BL finalmemoryspeed ] ; 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 ] [ DoInitialiseMode :LOR: :LNOT: Embedded_UI BL InitialiseMode ] [ :LNOT: Embedded_UI 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 | ! 0, "Banner & printing of processor type disabled" ] 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 [ SoftResets :LAND: STB ! 0, "!!!! SoftReset is true => resets close all open files !!!!" MOV R0, #FSControl_Shut ; Open files get closed at reset SWI XOS_FSControl ] 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_Size] 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 [ HAL :LAND: CheckProtectionLink LDR r1, =ZeroPage+HAL_StartFlags LDR r1, [r1] TST r1, #OSStartFlag_NoCMOSReset BNE %FT75 | [ CheckProtectionLink LDR r1, =IOMD_MonitorType ; check link bit again LDRB r1, [r1] ; no need to preload bus, since should TST r1, #IOMD_ProtectionLinkBit ; be still there from earlier BEQ %FT75 ; zero => protected ] ] ; 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] [ EmulatorSupport ARM_on_emulator r0 ADDEQ r3, r3, #1 ADDNE r3, r3, #10 ; Hang about for a little while | 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 [ DoInitialiseMode :LOR: :LNOT: Embedded_UI 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 [ ProcessorVectors LDR PC, .+ProcVec_Branch0 | B .+Branch0_Trampoline ] 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 ] [ StrongARM :LAND: :LNOT: HAL cputable DCD &6000,0,0 DCD &6100,1,0 DCD &7000,2,0 DCD &7100,3,0 DCD &8100,4,2_11101 DCD &a100,5,2_11011 ;corrected for 3.71 (SA does not abort for vector reads in 26-bit mode) DCD &7500,6,0 DCD &7501,7,0 DCD -1 Processor_Type MOV r0,#IOMD_Base LDRB r1,[r0,#IOMD_ID0] CMP r1,#&E7 LDRB r1,[r0,#IOMD_ID1] CMPEQ r1,#&D4 BEQ PT_RiscPC ; E7,D4 means Risc PC CMP r1,#&5B MOVEQ r0,#&7500 ; 5B means 7500 BEQ PT_lookup CMP r1,#&AA MOVEQ r0,#&7500 ORREQ r0,r0,#&0001 ; AA means 7500FE - mark as 7501 BEQ PT_lookup PT_RiscPC ReadCop R0,CR_ID ; see data sheets for values ; ARM 600 funny TST R0,#&f000 MOVEQ R0,R0, LSL #4 AND R0,R0,#&ff00 PT_lookup ADR R1,cputable 66 LDR R2,[R1],#4 TEQ R2,#0 MOVMI R0,#0 STRMI R2,[R0,#ProcessorType] MOVMI PC,LR TEQ R2,R0 ADDNE R1,R1,#8 BNE %BT66 LDMIA R1,{R0,R2} MOV R1,#0 STRB R0,[R1,#ProcessorType] STR R2,[R1,#ProcessorFlags] MOV PC,LR ] 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] [ EmulatorSupport ARM_on_emulator r1 ADDEQ r3, r3, #1 ADDNE r3, r3, #10 ; Hang about for a little while | 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_Title] 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 [ :LNOT: Embedded_UI [ 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 [ ProcessorVectors LDR PC, .-&18+ProcVec_IRQ | B Initial_IRQ_Code+.-&18 ] ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; 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