;vectorHandler
;-------------
;Looks for FileCore_Create and pending disc changes
;Blocks OS_Byte 201 and OS_Module 8/9
;Resets OS_ReadMonotonicTime after a soft boot
;Traps OS_Byte 113 to force VSyncs/slow machine down
;Traps OS_ChangeDynamicArea and OS_DynamicArea on RO3.1
;Tracks OS_Byte 19
;Traps OS_Byte 162
;Tracks OS_ChangeDynamicArea on RO3.5+

 ALIGN   32, 4 + 4
 .OS_SWI_Vector		DCD 0		;forwarding address for SWI vector

.vectorHandler
 STMFD   R13!, {R12, R14}
 #if compile_RO < 450
   BIC     R14, R14, #&FC000003		;clear PC flags on 26bit OS
 #endif

 #if JIT_debug == 1
   CMP     R14, #jit_code_start
   BHI     _skip_debug2
   SUB     R14, R14, #4
   #if JIT_debug == 1 AND JIT_instruction_trace == 1
     LDR     R12, jit_code
     TEQ     R12, #0
     BEQ     _skip_debug
     STR     R4, [R13, #-4]!
     MOV     R12, #instruction_trace_ptr
     LDR     R4, [R12, #-4]
     STR     R14, [R4], #4
     BIC     R4, R4, #&80000
     STR     R4, [R12, #-4]
     LDR     R4, [R13], #4
     ._skip_debug
   #endif
   TEMP    R12
   STR     R14, user_PC
   MRS     R14, SPSR
   STR     R14, user_SPSR
   LDR     R14, user_PC
   LOCK    R12
   ADD     R14, R14, #4
   ._skip_debug2
 #endif

 #if compile_RO > 311
   LDRB    R12, [R14, #-2]		;get bits 16-23
   MOV     R12, R12, LSR #4
   TEQ     R12, #JIT_SWI_OS_Flag	;hypervised SWI?
   BEQ     hypervised_SWI		;YES
 #endif

 LDRB    R12, [R14, #-4]		;get bits 0-7
 CMP     R12, #6			;.. OS_Byte
 BLO     vector_handler_forward		;exit early

 TEQNE   R12, #&1C			;.. OS_Mouse
 TEQNE   R12, #&1E			;.. OS_Module
 TEQNE   R12, #&1F			;.. OS_Claim
 TEQNE   R12, #&2A			;.. OS_ChangeDynamicArea
 TEQNE   R12, #&41			;.. FileCore_Create
 TEQNE   R12, #&42			;.. OS_ReadMonotonicTime
 #if compile_RO == 311
   TEQNE   R12, #&66			;.. OS_DynamicArea
 #endif
 #if compile_RO > 311
   TEQNE   R12, #&07			;.. OS_Word
   TEQNE   R12, #&08			;.. OS_File
   TEQNE   R12, #&1A			;.. OS_UpdateMEMC
   TEQNE   R12, #&29			;.. OS_FSControl
   TEQNE   R12, #&2E			;.. OS_SpriteOp
   TEQNE   R12, #&31			;.. OS_ReadVduVariables
   TEQNE   R12, #&40			;.. Sound_Configure
   TEQNE   R12, #&46			;.. Sound_SampleRate
   TEQNE   R12, #&5C			;.. OS_ReadDynamicArea
   TEQNE   R12, #&66			;.. OS_DynamicArea
   TEQNE   R12, #&6E			;.. OS_SynchroniseCodeAreas
   TEQNE   R12, #&6F			;.. OS_CallASWI
   TEQNE   R12, #&71			;.. OS_CallASWIR12
   #if JIT_WIMP_support == 1
     TEQNE   R12, #&EC			;.. Wimp_SlotSize
   #endif
 #endif
 #if compile_RO == 400
   TEQNE   R12, #&4B			;.. OS_ClaimDeviceVector
   TEQNE   R12, #&4C			;.. OS_ReleaseDeviceVector
 #endif
 BEQ     vector_handler_check		;possibly one of these

.vector_handler_forward
 LDR     R12, disk_swap_pending		;is a disc change pending?
 TEQ     R12, #0
 BLNE    vector_handler_disc_swap	;YES, action it

.vector_handler_exit
 LDMFD   R13!, {R12, R14}		;clear down stack
LDR     PC, OS_SWI_Vector




;pass_SWI_on
;-----------
;Call OS SWI dispatch directly
;
;Entry: in SVC26 on 26bit OS and SVC32 on 32bit
; R14 = SWI to issue

.pass_SWI_on
 ADD     R14, R14, #4			;correct return
 #if compile_RO > 400
   STR     R14, [R13, #-4]!
   MRS     R14, CPSR
   MSR     SPSR_all, R14
   LDR     R14, [R13], #4
 #endif

 #if compile_RO < 400 OR compile_RO > 400
   LDR     PC, OS_SWI_Vector
 #endif

 #if compile_RO == 400
   BIC     R14, R14, #&FC000003		;clear flags
   STR     R14, _R14
   MRS     R14, CPSR
   ORR     R14, R14, #%10000		;switch to SVC32
   MSR     CPSR_all, R14
   NOP
   MRS     R14, CPSR
   BIC     R14, R14, #%10000		;return in SVC26
   MSR     SPSR_all, R14
   LDR     R14, _R14
   LDR     PC, OS_SWI_Vector
 
  ._R14	DCD 0
 #endif




.vector_handler_check
 LDR     R14, [R14, #-4]		;get instruction
 BIC     R14, R14, #1 << 17		;clear X bit
 MOV     R14, R14, LSL #12		;shift SWI# to top bits

 TEQ     R14, #6 << 12			;is it OS_Byte?
 BEQ     os_byte_handler		;YES

 #if compile_RO > 311
   TEQ     R14, #7 << 12		;is it OS_Word?
   BEQ     os_word_handler		;YES

   TEQ     R14, #8 << 12		;is it OS_File?
   BEQ     vector_handler_8		;YES

   TEQ     R14, #&2E << 12		;is it OS_SpriteOp?
   BEQ     os_spriteop_handler		;YES
 #endif

 TEQ     R14, #&1F << 12		;OS_Claim?
 BEQ     vector_handler_1F		;YES

 TEQ     R14, #&66 << 12		;OS_DynamicArea
 #if compile_RO == 311
   BEQ     RO31_OS_DynamicArea		;YES
 #else
   BEQ     vector_handler_66		;YES
 #endif

 MOV     R12, #&40541 << 12
 CMP     R14, R12			;is it FileCore_Create?
 BEQ     vector_handler_40541

 #if Managed_ChannelHandler == 1
   SUB     R12, R12, #(&40541 - &40146) << 12
   CMPLO   R14, R12			;Sound_SampleRate?
   BEQ     vector_handler_40146

   SUB     R12, R12, #(&40146 - &40142) << 12
   CMPLO   R14, R12			;Sound_Stereo?
   BEQ     vector_handler_40142

   SUB     R12, R12, #(&40142 - &40140) << 12
   CMPLO   R14, R12			;Sound_Configure?
   BEQ     vector_handler_40140

   #if JIT_WIMP_support == 1 AND Managed_ChannelHandler == 1
     SUB     R12, R12, #(&40140 - &400EC) << 12
     CMPLO   R14, R12			;Wimp_SlotSize
     BEQ     vector_handler_400EC
   #endif
 #else
   SUB     R12, R12, #(&40541 - &40142) << 12
   CMPLO   R14, R12			;Sound_Stereo?
   BEQ     vector_handler_40142

   #if JIT_WIMP_support == 1 AND Managed_ChannelHandler == 0
     SUB     R12, R12, #(&40142 - &400EC) << 12
     CMPLO   R14, R12			;Wimp_SlotSize
     BEQ     vector_handler_400EC
   #endif
 #endif

 #if compile_RO > 311
   CMPLO   R14, #&71 << 12		;OS_CallASWIR12
   BEQ     vector_handler_6F_71		;YES
 #endif

 BHI     vector_handler_forward		;hand higher straight back to OS

 TEQ     R14, #&1C << 12		;is it OS_Mouse?
 BEQ     vector_handler_1C		;YES

 TEQ     R14, #&1E << 12		;is it OS_Module?
 BEQ     vector_handler_1E		;YES

 TEQ     R14, #&42 << 12		;is it OS_ReadMonotonicTime?
 BEQ     vector_handler_42		;YES

 TEQ     R14, #&2A << 12		;OS_ChangeDynamicArea?
 #if compile_RO == 311
   BEQ     RO31_OS_ChangeDynamicArea
 #endif
 #if compile_RO > 311
   BEQ     vector_handler_2A

   TEQ     R14, #&6E << 12		;OS_SynchroniseCodeAreas
   BEQ     vector_handler_6E		;YES

   TEQ     R14, #&6F << 12		;OS_CallASWI
   BEQ     vector_handler_6F_71		;YES

   TEQ     R14, #&29 << 12		;OS_FSControl?
   BEQ     vector_handler_29		;YES

   TEQ     R14, #&31 << 12		;OS_ReadVduVariables?
   BEQ     vector_handler_31		;YES

   TEQ     R14, #&1A << 12		;OS_UpdateMEMC
   BEQ     vector_handler_1A		;ignore it

   TEQ     R14, #&5C << 12		;OS_ReadDynamicArea?
   BEQ     vector_handler_5C		;YES
 #endif
 #if compile_RO == 400
   TEQ     R14, #&4B << 12		;OS_ClaimDeviceVector?
   BEQ     vector_handler_4B		;YES

   TEQ     R14, #&4C << 12		;OS_ReleaseDeviceVector?
   BEQ     vector_handler_4C		;YES
 #endif

B       vector_handler_forward




;pre_SWI_veneer
;--------------
;ensures the CPU returns from an SWI call in SVCxx, suitable for the CPU/OS
;we're currently running on
;
;Entry:
; R12 - pointer to buffer,  0  - SPSR
;                          +4  - CPSR
;                          +8  - SVC CPSR
;                          +12 - SVC R14
; R14 - +4 used to return to the code after the SWI returns
;
;Exit: in SVC26 on 26bit OS and SVC32 on 32bit OS
; Registers as per SWI being called

.pre_SWI_veneer
 STMFD   R13!, {R0-R1, R14}

 #if compile_RO == 311
   LDR     R0, [R13, #4 * 4]		;get R14 from stack
   STR     R0, [R12, #0]		;store for exit handler
   ORR     R14, R14, #(%11 << 26) + %11	;SVC IRQ/FIQ disabled
 #endif
 #if compile_RO > 311
   MRS     R1, SPSR			;32bit
   STR     R1, [R12, #0]		; |  store SPSR
   MRS     R0, CPSR			; |
   STR     R0, [R12, #4]		; |  and CPSR
   BIC     R0, R0, #%1111 << 28		; |
   AND     R1, R1, #%1111 << 28		; |
   ORR     R0, R0, R1			; |+ add in SPSR flags
   #if compile_RO == 400
     BIC     R0, R0, #%11111		;return in SVC26
   #endif
   #if compile_RO > 400
     BIC     R0, R0, #%01111		;return in SVC32
   #endif
   ORR     R0, R0, #%11000011		;SVCxx IRQ/FIQ disabled
   MSR     SPSR_all, R0			;switch SPSR to current mode

   MSR     CPSR_all, R0			;switch to SVC preserving flags
   #if compile_IOMD == 1
     NOP
   #endif
   MRS     R1, CPSR
   STR     R1, [R12, #8]		;store SVC CPSR
   STR     R14, [R12, #12]		;store SVC R14
   LDR     R1, [R12, #4]
   MSR     CPSR_all, R1			;switch back to original CPU mode
   #if compile_IOMD == 1
     NOP
   #endif
 #endif

 LDR     R0, OS_SWI_Vector
 ADD     R14, R14, #4			;correct R14
 STR     R0, [R13, #2 * 4]		;stack address
LDMFD   R13!, {R0-R1, PC}		;let SWI run its course




;hv_pre_SWI_veneer
;-----------------
;Similar to pre_SWI_veneer, except it passes the SWI to our SWI handler
;
;Entry:
; R12 - pointer to buffer,  0  - SPSR
;                          +4  - CPSR
;                          +8  - SVC CPSR
;                          +12 - SVC R14
; R14 - +4 used to return to the code after the SWI returns
;
;Exit: in SVC26 on 26bit OS and SVC32 on 32bit OS
; Registers as per SWI being called

.hv_pre_SWI_veneer
 STMFD   R13!, {R0-R1}

 #if compile_RO == 311
   LDR     R0, [R13, #4 * 4]		;get R14 from stack
   STR     R0, [R12, #0]		;store for exit handler
   ORR     R14, R14, #(%11 << 26) + %11	;SVC IRQ/FIQ disabled
 #endif
 #if compile_RO > 311
   MRS     R1, SPSR			;32bit
   STR     R1, [R12, #0]		; |  store SPSR
   MRS     R0, CPSR			; |
   STR     R0, [R12, #4]		; |  and CPSR
   BIC     R0, R0, #%1111 << 28		; |
   AND     R1, R1, #%1111 << 28		; |
   ORR     R0, R0, R1			; |+ add in SPSR flags
   #if compile_RO == 400
     BIC     R0, R0, #%11111		;return in SVC26
   #endif
   #if compile_RO > 400
     BIC     R0, R0, #%01111		;return in SVC32
   #endif
   ORR     R0, R0, #%11000011		;SVCxx IRQ/FIQ disabled
   MSR     SPSR_all, R0			;switch SPSR to current mode

   MSR     CPSR_all, R0			;switch to SVC preserving flags
   #if compile_IOMD == 1
     NOP
   #endif
   MRS     R1, CPSR
   STR     R1, [R12, #8]		;store SVC CPSR
   STR     R14, [R12, #12]		;store SVC R14
   LDR     R1, [R12, #4]
   MSR     CPSR_all, R1			;switch back to original CPU mode
   #if compile_IOMD == 1
     NOP
   #endif
 #endif

 ADD     R14, R14, #4			;correct R14
 LDMFD   R13!, {R0-R1}			;let SWI run its course
B       vectorHandler




#if compile_RO > 311
;same as pre_SWI_veneer except loads R12 from the stack before calling the SWI
.pre_SWI_veneer_R12
 STMFD   R13!, {R0-R1, R14}

 MRS     R1, SPSR			;32bit
 STR     R1, [R12, #0]			; |  store SPSR
 MRS     R0, CPSR			; |
 STR     R0, [R12, #4]			; |  and CPSR
 BIC     R0, R0, #%1111 << 28		; |
 AND     R1, R1, #%1111 << 28		; |
 ORR     R0, R0, R1			; |+ add in SPSR flags
 #if compile_RO == 400
   BIC     R0, R0, #%11111		;return in SVC26
 #endif
 #if compile_RO > 400
   BIC     R0, R0, #%01111		;return in SVC32
 #endif
 ORR     R0, R0, #%11000011		;SVCxx IRQ/FIQ disabled
 MSR     SPSR_all, R0			;switch SPSR to current mode

 MSR     CPSR_all, R0			;switch to SVC preserving flags
 #if compile_IOMD == 1
   NOP
 #endif
 MRS     R1, CPSR
 STR     R1, [R12, #8]			;store SVC CPSR
 STR     R14, [R12, #12]		;store SVC R14
 LDR     R1, [R12, #4]
 MSR     CPSR_all, R1			;switch back to original CPU mode
 #if compile_IOMD == 1
   NOP
 #endif

 ADD     R14, R14, #4			;correct R14
 LDR     R0, OS_SWI_Vector
 STR     R0, [R13, #2 * 4]		;stack address
 LDR     R12, [R13, #3 * 4]		;get R12 from stack
LDMFD   R13!, {R0-R1, PC}		;let SWI run its course
#endif




;post_SWI_veneer
;---------------
;updates SPSR flags
;
;Entry: in SVC26 on 26bit OS and SVC32 on 32bit
; R12 - pointer to buffer,  0  - SPSR or R14 on ARM3
;                          +4  - CPSR
;                          +8  - SVC CPSR
;                          +12 - SVC R14
; CPSR contains flags (32bit only)

.post_SWI_veneer				;PRESERVES FLAGS
 STR     R14, [R13, #-4]!
 LDR     R14, [R12, #0]			;entry PSR
 BICVC   R14, R14, #%0001 << 28		;clear V
 ORRVS   R14, R14, #%0001 << 28		;set V
 STR     R14, [R12, #0]			;correct SPSR
LDR     PC, [R13], #4




;post_SWI_veneerC
;----------------
;updates SPSR flags
;
;Entry: in SVC26 on 26bit OS and SVC32 on 32bit
; R12 - pointer to buffer,  0  - SPSR or R14 on ARM3
;                          +4  - CPSR
;                          +8  - SVC CPSR
;                          +12 - SVC R14
; CPSR contains flags (32bit only)

.post_SWI_veneerC				;PRESERVES FLAGS
 STR     R14, [R13, #-4]!
 LDR     R14, [R12, #0]			;entry PSR
 BIC     R14, R14, #%0011 << 28		;clear C,V
 ORRVS   R14, R14, #%0001 << 28		;set V
 ORRCS   R14, R14, #%0010 << 28		;set C
 STR     R14, [R12, #0]			;correct SPSR
LDR     PC, [R13], #4




;exit_SWI_veneer
;---------------
;restores SVC flags and R14, then puts the CPU back into it's original
;mode, restores CPSR / SPSR and exits back to the caller
;sets V if set at entry
;
;Entry: in SVC32
; R12 - pointer to buffer,  0  - SPSR or R14 on ARM3
;                          +4  - CPSR
;                          +8  - SVC CPSR
;                          +12 - SVC R14
; V flag set if V needs setting on exit

.exit_SWI_veneer				;EXITS TO ADFFS, V FLAG PASSED THROUGH
  STR     R0, [R13, #-4]!		;preserve R0
#if compile_RO == 311
  LDR     R14, [R13, #2 * 4]		;get exit PC from stack
  BIC     R14, R14, #%1111 << 28	;clear flags
  ORRVS   R14, R14, #1 << 28		;set V
  LDR     R0, [R12, #0]			;get our exit flags
  AND     R0, R0, #%1111 << 28		;mask flags
  ORR     R14, R14, R0			;set exit flags
  STR     R14, [R13, #2 * 4]
  LDR     R14, [R12, #12]		;preserve SVC R14
LDMFD   R13!, {R0, R12, PC}^		;return to original caller
#endif
#if compile_RO > 311
  LDR     R14, [R12, #12]		;preserve SVC R14
  LDRVS   R0, [R12, #0]
  ORRVS   R0, R0, #1 << 28		;set V
  STRVS   R0, [R12, #0]

  LDR     R0, [R12, #8]
  MSR     CPSR_all, R0			;preserve SVC CPSR flags
  #if compile_IOMD == 1
    NOP
  #endif
  LDR     R0, [R12, #4]
  MSR     CPSR_all, R0			;correct CPSR
  #if compile_IOMD == 1
    NOP
  #endif
  LDR     R0, [R12, #0]
  MSR     SPSR_all, R0			;correct SPSR
LDMFD   R13!, {R0, R12, PC}^		;return to original caller




;dontexit_SWI_veneer
;-------------------
;restores SVC flags and R14, then puts the CPU back into it's original
;mode, restores CPSR / SPSR and then returns to ADFFS caller
;
;Entry: in SVC26 on 26bit OS, SVC32 otherwise
; R12 - pointer to buffer,  0  - SPSR or R14 on ARM3
;                          +4  - CPSR
;                          +8  - SVC CPSR
;                          +12 - SVC R14
;Exit: in SVC32

.dontexit_SWI_veneer				;RETURNS IN SVC32 WITH SPSR RESTORED
 #if compile_RO == 400
   STR     R14, _return

   LDR     R14, [R12, #12]		;preserve SVC R14
   STR     R0, [R12, #12]
   LDR     R0, [R12, #8]
   MSR     CPSR_all, R0			;preserve SVC CPSR flags
   NOP
   LDR     R0, [R12, #4]
   MSR     CPSR_all, R0			;correct CPSR
   NOP
   LDR     R0, [R12, #0]
   MSR     SPSR_all, R0			;correct SPSR
   LDR     R14, _return
   MRS     R0, CPSR
   BIC     R0, R0, #1<<28
   AND     R14, R14, #1<<28
   ORR     R0, R0, R14
   MSR     CPSR_all, R0			;copy V from SVC26 to SVC32
   LDR     R0, [R12, #12]
   LDR     R14, _return
  BIC     PC, R14, #&FC000003

   ._return DCD 0
 #endif
 #if compile_RO > 400
   STR     R14, [R13, #-4]!

   LDR     R14, [R12, #0]
   MSR     SPSR_all, R14		;correct SPSR
  LDR     PC, [R13], #4
 #endif
#endif




;Claim_SWI_Vector
;----------------
;Inserts itself onto the SWI hardware vector
;and looks for FileCore_Create calls

.Claim_SWI_Vector
 STMFD   R13!, {R0-R12, R14}

 LDR     R14, OS_SWI_Vector		;do we have the vector
 TEQ     R14, #0
 LDMNEFD R13!, {R0-R12, PC}		;YES, exit

 BL      claim_EventV

 LDR     R0, os_version
 CMP     R0, #&350 << 8			;are we on RISC OS lower than 3.5?
 BHS     _RO350				;NO
					;claim vector on RISC OS <3.5
 MOV     R0, #Vector_SWI << 2		;hardware vector address
 LDR     R1, [R0]
 MOV     R2, R1, LSR #24
 TEQ     R2, #&EA			;does &8 contain a B xxxx command
 MOVEQ   R1, R1, LSL #2			;YES, shift address up
 ADDEQ   R1, R1, #16			;..correct the address
 BICEQ   R1, R1, #%11111100 << 24	;..clear the ARM command bits
 STREQ   R1, OS_SWI_Vector		;..save the original vector
 ADREQ   R1, vectorHandler - 16		;..our vector handler, -16 to correct
 MOVEQ   R1, R1, LSR #2			;..shift address down
 ORREQ   R1, R1, #&EA000000		;..set the ARM command
 STREQ   R1, [R0]			;..and replace the vector
 BEQ     _exit

 ._failed
 LDMFD   R13!, {R0-R12, R14}		;clear down stack
 MOV     R0, #1<<31
 ADDS    R0, R0, R0			;set V
 ADR     R0, Error_Vector_Claim		;..and exit with an error
 SWI     OS_GenerateError
MOV     PC, R14				;should never get here

 ._RO350
 MOV     R0, #Vector_SWI + (1<<8)	;claim vector on RISC OS 3.5+
 ADR     R1, vectorHandler
 SWI     XOS_ClaimProcessorVector	;PRM5a-30
 BVS     _failed
 STR     R1, OS_SWI_Vector		;save the original vector

 ._exit
LDMFD   R13!, {R0-R12, PC}




;Release_SWI_Vector
;------------------
;Releases the InsV and SWI vectors

.Release_SWI_Vector
 STMFD   R13!, {R0-R12, R14}

 LDR     R0, OS_SWI_Vector		;do we have the vector
 TEQ     R0, #0
 LDMEQFD R13!, {R0-R12, PC}		;NO, exit

 BL      release_EventV

 LDR     R6, os_version
 CMP     R6, #&350 << 8			;Are we on RISC OS lower than 3.5?
 BHS     _RO350
					;release vector on RISC OS <3.5
 MOV     R0, #8				;SWI hardware vector address
 ADR     R1, vectorHandler		;..get our handler
 SUB     R1, R1, #16			;..correct its address
 MOV     R1, R1, LSR #2			;..shift address down
 ORR     R1, R1, #&EA000000		;..set the ARM command
 LDR     R2, [R0]
 TEQ     R1, R2				;check we still own the vector
 BNE     _failed			;NO, report an error
 LDR     R1, OS_SWI_Vector		;YES, replace with original vector
 SUB     R1, R1, #16			;..correct the address
 MOV     R1, R1, LSR #2			;..shift address down
 ORR     R1, R1, #&EA000000		;..set the ARM command
 STR     R1, [R0]			;..and replace the vector
 B       _okay

 ._RO350
 ADR     R2, vectorHandler		;release vector on RISC OS 3.5+
 LDR     R1, OS_SWI_Vector		;original vector
 MOV     R0, #Vector_SWI
 SWI     XOS_ClaimProcessorVector	;...release vector
 BVC     _okay

 ._failed
 LDMFD   R13!, {R0-R12, R14}		;clear down stack
 ADR     R0, Error_Vector_Release	;oops, can't release vector
 SWI     OS_GenerateError
MOV     PC, R14				;should never get here

 ._okay
 MOV     R0, #0
 STR     R0, OS_SWI_Vector

 MOV     R0, #Module_ReInit		;FileCore is about to kill us
 ADR     R1, ADFS_Module
 SWI     XOS_Module			;Re-init ADFS to redirect DiscOp/MiscOp

 SUBS    R0, R0, R0			;clear V
LDMFD   R13!, {R0-R12, PC}