#base 0
#type &FFC
#name "<ADFFS$Dir>.SetVars"

#area external_constants .readonly
  #include "<Tmp$Dir>.riscos.constants"
#end


;detect_CPU
;----------
;Detects ARM2, ARM3, ARM610, ARM710, ARM7500, StrongARM

.detect_CPU
 STMFD   R13!, {R0-R6, R11-R12, R14}

 MOV     R0, #Module_Lookup		;check OS version
 ADR     R1, UtilityModule		;..via UtilityModule version
 SWI     XOS_Module			;PRM1-249

 MOV     R0, #Module_EnumerateROM	;request module version
				;NOTE manual is wrong, R1 is not module +1
 MVN     R2, #0
 SWI     XOS_Module			;PRM1-252
 AND     R2, R6, #&FF0000
 TEQ     R2, #&60000			;RO6?
 SUBEQ   R6, R6, #&20000		;YES, drop it to 4.x
 MOV     R12, R6			;R12=OS version

 ADR     R1, value
 STR     R12, [R1]			;store the OS version
 ADR     R0, Set_OSVersion		;create a variable for Obey files to use
 MOV     R2, #4
 MOV     R3, #0
 MOV     R4, #1
 SWI     XOS_SetVarVal			;PRM1-316

 BL      detect_VIDC20
 BL      detect_Overlays

 MOV     R1, #&523 << 8			;only valid on RO5.23+
 CMP     R12, R1
 MOVLO   R0, #0				;Low vectors
 BLO     _lowvectors

 MOV     R0, #32
 SWI     XOS_PlatformFeatures
 CMP     R0, #0				;High Vectors?
 MOVNE   R0, #1				;YES

 ._lowvectors
 ADR     R1, value
 STR     R0, [R1]
 ADR     R0, Set_HighVectors
 MOV     R2, #4
 MOV     R3, #0
 MOV     R4, #1
 SWI     XOS_SetVarVal			;PRM1-316

 MOV     R0, #0				;assume ARMv6 or lower
 CMP     R12, #&500 << 8		;only valid on RO5.00+
 BLO     _notARMv7

 SWI     XOS_EnterOS
 MRS     R0, CPSR
 ORR     R0, R0, #%11 << 6		;disable IRQ/FIQ

 MOV     R4, #1				;assume ARMv7
 ADR     R1, _aborted
 MOV     R0, #4 + (1<<8)		;claim Data abort
 SWI     XOS_ClaimProcessorVector	;PRM5a-30   R1=existing owner

 MOV     R0, #1
 STR     R0, value
 LDR     R0, value + 1			;will abort if rotated loads unsupported
 TEQ     R0, #1 << 24
 MOVEQ   R4, #0

 ._aborted
 MOV     R0, #4				;release Data abort vector
 ADR     R2, _aborted
 SWI     XOS_ClaimProcessorVector	;PRM5a-30

 MRS     R0, CPSR
 BIC     R0, R0, #%11 << 6		;enable IRQ/FIQ
 SWI     XOS_LeaveOS

 MOV     R0, R4

 ._notARMv7
 ADR     R1, value
 STR     R0, [R1]
 ADR     R0, Set_ARMv7
 MOV     R2, #4
 MOV     R3, #0
 MOV     R4, #1
 SWI     XOS_SetVarVal			;PRM1-316

 TEQ     PC, #0				;clear Z flag
 TEQ     PC, PC
 MOVNE   R11, PC
 MRSEQ   R11, CPSR
 SWI     XOS_EnterOS

 CMP     R12, #&350 << 8
 BHS     _P1

 MOV     R0, PC
 BIC     R0, R0, #%11 << 26		;disable IRQ/FIQ
 TEQP    R0, #0
 NOP
 MOV     R4, #Vector_UndefinedInstr << 2	;hardware vector address
 LDR     R5, [R4]			;get old value
 ADR     R1, _detected_ARM2 - 12	;get our vector handler,
					;..-12 to correct address
 MOV     R1, R1, LSR #2			;..shift address down
 ORR     R1, R1, #&EA000000		;..set the ARM command
 STR     R1, [R4]			;..and replace the vector
 ._P1

 MOV     R2, #&A10			;presume StrongARM

 MRC     P15, 0, R0, C0, C0		;this will error on an ARM2

 TEQ     PC, #0				;clear Z flag
 TEQ     PC, PC
 TEQNEP  R11, #0
 MSREQ   CPSR_c, R11
 NOP

 CMP     R12, #&350 << 8
 BHS     _P2

 STR     R5, [R4]			;reset hardware vector on RISC OS <3.5
 MOV     R6, PC
 BIC     R6, R6, #%11 << 26		;enable interrupts
 TEQP    R6, #0
 NOP
 ._P2

 AND     R1, R0, #&FF00
 TEQ     R1, #&300			;ARM3
 MOVEQ   R2, #3
 BEQ     _exit

 CMP     R12, #&350 << 8
 BLO     _exit

 AND     R3, R0, #&00F0			;Add extra bits in for higher processors
 ORR     R1, R1, R3

 TEQ     R1, #&600			;ARM600
 TEQNE   R1, #&610			;ARM610
 TEQNE   R1, #&620			;ARM620
 MOVEQ   R2, R1
 BEQ     _exit

 TEQ     R1, #&7000			;ARM700
 TEQNE   R1, #&7100			;ARM710
 TEQNE   R1, #&8100			;ARM810
 TEQNE   R1, #&A100			;SA-110
 MOVNE   R6, #&A110			;SA-1100
 TEQNE   R1, R6
 MOV     R2, R1, LSR #4
 ADDNE   R2, R2, #&1000			;&12C3 - Intel 80321 (Iyonix)
					;&1411 - Intel PXA270/272
 ._exit
 ADR     R1, value
 STR     R2, [R1]			;store the cpu id
 ADR     R0, Set_CPUID			;create a variable for Obey files to use
 MOV     R2, #4
 MOV     R3, #0
 MOV     R4, #1
 SWI     XOS_SetVarVal			;PRM1-316

LDMFD   R13!, {R0-R6, R11-R12, PC}


 ._detected_ARM2
 MOV     R2, #2				;ARM2 / 250
 STR     R5, [R4]			;reset hardware vector
 TEQP    R11, #0
 NOP
B       _exit



.detect_VIDC20
 STMFD   R13!, {R0-R6, R14}

 CMP     R12, #&350 << 8		;are we on RISC OS lower than 3.5?
 MOVLO   R1, #0 			;YES
 MOVHS   R0, #9				;NO,
 MOVHS   R1, #3 << 8			; |  get VIDC20 address
 SWIHS   XOS_Memory			; |+ PRM5a-70

 ADR     R2, value
 STR     R1, [R2]			;store the VIDC20 address

 ADR     R0, Set_VIDC20			;create a variable for Obey files to use
 MOV     R1, R2
 MOV     R2, #4
 MOV     R3, #0
 MOV     R4, #1
 SWI     XOS_SetVarVal			;PRM1-316
LDMFD   R13!, {R0-R6, PC}


.detect_Overlays
 STMFD   R13!, {R0-R6, R9, R14}

 CMP     R12, #&520 << 8		;are we on RISC OS 5.21+?
 MOVLS   R1, #0				;NO
 BLS     _ignore

 SUB     R13, R13, #4
 MOV     R0, #11
 MOV     R1, #-1
 SWI     XOS_ScreenMode			;current driver
 MOV     R4, R1, LSL #24
 MOV     R0, #5				;overlays supported
 MOV     R1, R13
 MOV     R2, #4
 ORR     R4, R4, #18
 MOV     R9, #42			;GraphicsV 18
 SWI     XOS_CallAVector
 LDR     R1, [R13], #4
 TEQ     R4, #0
 MOVNE   R1, #0
 ._ignore
 ADR     R2, value
 STR     R1, [R2]			;store the VIDC20 address

 ADR     R0, Set_Overlays		;create a variable for Obey files to use
 MOV     R1, R2
 MOV     R2, #4
 MOV     R3, #0
 MOV     R4, #1
 SWI     XOS_SetVarVal			;PRM1-316
LDMFD   R13!, {R0-R6, R9, PC}

.value			DCD 0

.UtilityModule		DCB "UtilityModule", 0
			ALIGN
.Set_OSVersion		DCB "ADFFS$OSVersion", 0
			ALIGN
.Set_CPUID		DCB "ADFFS$CPUID", 0
			ALIGN
.Set_VIDC20		DCB "ADFFS$VIDC20", 0
			ALIGN
.Set_HighVectors	DCB "ADFFS$HighVectors", 0
			ALIGN
.Set_ARMv7		DCB "ADFFS$ARMv7", 0
			ALIGN
.Set_Overlays		DCB "ADFFS$Overlays", 0
			ALIGN