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

#set swi_block_0 = 0
#set swi_block_1 = 0
#set swi_block_2 = 0
#set swi_block_3 = 0
#set swi_block_4 = 0
#set swi_block_5 = 0
#set swi_block_6 = 0
#set swi_block_7 = 0

#set swi_X_bit = 1 << 17
#set swi_OS_bits = %1111 << 20

MACRO captureSWI swi_number:I
{
  #set swi_n = swi_number AND %11100000
  #set swi_b = 1 << (31-(swi_number AND %00011111))
  #if swi_n == %00000000
    #set swi_block_0 = swi_block_0 OR swi_b
  #endif
  #if swi_n == %00100000
    #set swi_block_1 = swi_block_1 OR swi_b
  #endif
  #if swi_n == %01000000
    #set swi_block_2 = swi_block_2 OR swi_b
  #endif
  #if swi_n == %01100000
    #set swi_block_3 = swi_block_3 OR swi_b
  #endif
  #if swi_n == %10000000
    #set swi_block_4 = swi_block_4 OR swi_b
  #endif
  #if swi_n == %10100000
    #set swi_block_5 = swi_block_5 OR swi_b
  #endif
  #if swi_n == %11000000
    #set swi_block_6 = swi_block_6 OR swi_b
  #endif
  #if swi_n == %11100000
    #set swi_block_7 = swi_block_7 OR swi_b
  #endif
}

 captureSWI &06				;OS_Byte
 #if report_file_access == 1
   captureSWI &0D			;OS_Find
 #endif
 captureSWI &1C				;OS_Mouse
 captureSWI &1E				;OS_Module
 captureSWI &1F				;OS_Claim
 captureSWI &20				;OS_Release
 captureSWI &2A				;OS_ChangeDynamicArea
 captureSWI &42				;OS_ReadMonotonicTime
 captureSWI &66				;OS_DynamicArea
 #if compile_RO > 311
   captureSWI &07			;OS_Word
   captureSWI &08			;OS_File
   captureSWI &1A			;OS_UpdateMEMC
   captureSWI &29			;OS_FSControl
   captureSWI &2E			;OS_SpriteOp
   captureSWI &31			;OS_ReadVduVariables
   captureSWI &5C			;OS_ReadDynamicArea
   captureSWI &6E			;OS_SynchroniseCodeAreas
   captureSWI &6F			;OS_CallASWI
   captureSWI &71			;OS_CallASWIR12
   captureSWI &400EC			;Wimp_SlotSize
 #endif
 #if compile_RO == 400
   captureSWI &4B			;OS_ClaimDeviceVector
   captureSWI &4C			;OS_ReleaseDeviceVector
 #endif
 #if Managed_ChannelHandler == 1
   captureSWI &40140			;Sound_Configure
   captureSWI &40142			;Sound_Stereo
   captureSWI &40146			;Sound_SampleRate
 #endif
 captureSWI &40541			;FileCore_Create




; ****************************************************************
; routines to stack registers on entry to the SWI handler
; and to clear the stack or restore registers on exit


;SWI_veneer structure
;--------------------
;Entry CPU state.  If this changes, search for "SWI_veneer." and update
;any code that preserves these registers via LDM/STM

STRUCT SWI_veneer
{
  .SPSR		DCD 0
  .CPSR		DCD 0
  .R14		DCD 0
  ;NOTE if SWI_veneer changes size, search for SWI_veneer.* and update LDM/STM
  .size
}


STRUCT SWI_stack	;registers stored in PPUSHSWI
{
  .R11		DCD 0
  .R12		DCD 0
  .R14		DCD 0
  .swi		DCD 0
  .size
}


;PPUSHSWI
;--------
;stacks registers on entry to the SWI handler

MACRO PPUSHSWI
{
 SUB     R13, R13, #SWI_veneer.size + SWI_stack.size		;space for state
 STMIA   R13, {R11-R12, R14}
}


;PULLSWI<CC>
;-------
;restores registers stacked on entry to the SWI handler, but doesn't exit
; R14 bit 1 is set if an error X bit clear in original SWI

MACRO PULLSWI$cc
{
 LDM$cc#IA   R13, {R11-R12, R14}
 ADD$cc      R13, R13, #SWI_veneer.size + SWI_stack.size	;release space for state
}

MACRO PULLnoR14SWI$cc
{
 LDM$cc#IA   R13, {R11-R12}
 ADD$cc      R13, R13, #SWI_veneer.size + SWI_stack.size	;release space for state
}


;EXITSWI<CC> "reglist"
;-------
;restores registers stacked on entry to the SWI handler and exits


MACRO EXITSWI$cc exitregs:S
{
 #set l1_ldm = (cc << 28) OR &08BD5800	;LDMFD R13!, {R11-R12, R14}
 #set l1_start = 15
 #set l1_end = 15
 #rept 5
   #if LEN(exitregs) > 0
     #set l1_start = VAL(MID$(exitregs, 2, 2))
     #set l1_tmp = LEN(STR$(l1_start)) + 2
     #strset exitregs = MID$(exitregs, l1_tmp)

     #set l1_ldm = l1_ldm OR (1<<l1_start)
     #if LEFT$(exitregs, 1) == "-"
       #set l1_end = VAL(MID$(exitregs, 3, 2))
       #set l1_tmp = LEN(STR$(l1_end)) + 3
       #rept 13
         #if l1_start <= l1_end AND LEFT$(exitregs, 1) == "-"
           #set l1_ldm = l1_ldm OR (1<<l1_start)
           #set l1_start = l1_start + 1
         #endif
       #endr
       #strset exitregs = MID$(exitregs, l1_tmp)
     #endif
   #endif
   #rept 4
     #if LEFT$(exitregs, 1) == "," OR LEFT$(exitregs, 1) == " "
       #strset exitregs = MID$(exitregs, 2)
     #endif
   #endr
 #endr
 DCD      l1_ldm
 ADD$cc   R13, R13, #4 + SWI_veneer.size	;release space for state
 MOV$cc#S PC, R14
}
; ****************************************************************




 ALIGN   32, 4
 .swi_captured		DCD swi_block_0, swi_block_1, swi_block_2, swi_block_3
			DCD swi_block_4, swi_block_5, swi_block_6, swi_block_7
 .OS_SWI_Vector		DCD 0		;forwarding address for SWI vector

 ALIGN   32, 4
.vectorHandler
 PPUSHSWI

 #if JIT_debug == 1
   CMP     R14, #jit_appspace_end
   BHI     _skip_debug
   #if JIT_debug == 1 AND JIT_instruction_trace == 1
     LDR     R12, jit_code
     SUB     R14, R14, #4
     TEQ     R12, #0
     LDRNE   R12, instruction_trace_ptr
     LDRNE   R11, [R12, #-4]
     STRNE   R14, [R11], #4
     BICNE   R11, R11, #jit_trace_buffer_size
     STRNE   R11, [R12, #-4]
     TEMP    R12
     STR     R14, user_PC
     MRS     R11, SPSR
     STR     R11, user_SPSR
     LOCK    R12
     ADD     R14, R14, #4
   #endif
   #if JIT_debug == 1 AND JIT_instruction_trace == 0
     TEMP    R12
     SUB     R11, R14, #4
     STR     R11, user_PC
     MRS     R11, SPSR
     STR     R11, user_SPSR
     LOCK    R12
   #endif
;   #if JIT_debug == 1 AND JIT_report_immediate == 1
;     MOV     R11, R14
;     BL      report_JIT			;display JIT information
;     MOV     R14, R11
;   #endif
   ._skip_debug
 #endif

 #if compile_RO == 311
   BIC     R14, R14, #&FC000003		;clear PC flags on 26bit OS
 #endif
 LDR     R14, [R14, #-4]		;get the SWI
 STR     R14, [R13, #SWI_stack.swi]

.callASWI_check
 #if compile_RO > 311
   ANDS    R11, R14, #swi_OS_bits	;hypervised SWI?
   BNE     hypervised_SWI_check		;YES
 #endif

 ADR     R12, swi_captured
 AND     R11, R14, #%11100000
 LDR     R12, [R12, R11, LSR #3]
 AND     R11, R14, #%00011111
 MOVS    R12, R12, LSL R11
 BMI     vector_handler_check

.vector_handler_forward			;exit to OS SWI dispatch after checking floppy
 ADR     R11, VARS
 LDRB    R14, [R11, #disk_swap_pending - VARS]	;is a disc change pending?
 TEQ     R14, #0
 BNE     vector_handler_disc_swap	;YES, action it

.vector_handler_exit			;exit to OS SWI dispatch
 PULLSWI				;clear down stack
LDR     PC, OS_SWI_Vector




#if compile_RO > 311
.vector_handler_6F			;OS_CallASWI
 MOV     R14, R10
 B       callASWI_check

.vector_handler_71			;OS_CallASWIR12
 LDR     R14, [R13, #SWI_stack.R12]
 B       callASWI_check
#endif




.vector_handler_trap_VS		;exit to app, V set, reporting error if required
#if compile_RO == 311
 LDR     R14, [R13, #SWI_stack.R14]
 ORR     R14, R14, #1 << 28		;set V for return
 STR     R14, [R13, #SWI_stack.R14]
#else
 MRS     R12, SPSR
 ORR     R12, R12, #1 << 28		;set V
 MSR     SPSR_all, R12
#endif

.vector_handler_trap		;exit to app, reporting error if required
 #if compile_RO == 311
   LDR     R14, [R13, #SWI_stack.R14]
 #else
   MRS     R14, SPSR
 #endif
 TST     R14, #1 << 28			;V set?
 EXITSWIEQ ""				;NO, exit

 LDR     R12, [R13, #SWI_stack.swi]	;get the instruction
; #if compile_RO > 311
;   BIC     R11, R12, #swi_X_bit		;clear X bit
;   MOV     R11, R11, LSL #12		;shift SWI# to top bits
;   TEQ     R11, #OS_CallASWI << 12	;OS_CallASWI
;   MOVEQ   R12, R10
;   TEQ     R11, #OS_CallASWIR12 << 12	;OS_CallASWIR12
;   LDREQ   R12, [R13, #SWI_stack.R12]
; #endif

 TST     R12, #swi_X_bit		;is the X bit set?
 PULLSWI				; |  clear down stack
 MOVNES  PC, R14			; |+ YES, exit

 STMFD   R13!, {R2-R3, R6-R7}		; |+ NO, report error via current Error handler
 MOV     R7, R14
 MOV     R6, R0
 MOV     R0, #6				;Error handler
 MOV     R1, #0
 MOV     R2, #0
 MOV     R3, #0
 BL      pass_SWI_on
 SWI     XOS_ChangeEnvironment		;R1>PC, R2>R0, R3=buffer
 MOV     R0, R2
 
 STR     R7, [R3], #4			;store error addresss
 LDR     R7, [R6], #4			;copy the error number
 STR     R7, [R3], #4
 ._L1
   LDRB    R7, [R6], #1
   STRB    R7, [R3], #1
   TEQ     R7, #0
 BNE      _L1
 
 LDMFD   R13!, {R2-R3, R6-R7}
 MSR     CPSR_c, #%10000		;USR IRQ/FIQ enabled
 #if compile_IOMD == 1
   NOP
 #endif
MOV     PC, R1




;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			;Entry SVCxx, pass to OS SWI dispatch
 ADD     R14, R14, #4			;correct return
 #if compile_RO == 400
   BIC     R14, R14, #&FC000003		;clear flags
 #endif
 #if compile_RO > 311
   STR     R14, [R13, #-4]!
   MRS     R14, CPSR
   MSR     SPSR_all, R14
   LDR     R14, [R13], #4
 #endif
 LDR     PC, OS_SWI_Vector




;Entry: in SVCxx
.pass_SWI_on2			;pass to OS SWI dispatch
 ADD     R14, R14, #4			;correct return
 LDR     PC, OS_SWI_Vector



.vector_handler_check
 ADR     R11, VARS
 BIC     R14, R14, #swi_X_bit		;clear X bit
 MOV     R14, R14, LSL #12		;shift SWI# to top bits
 ADD     R12, R13, #SWI_stack.size	;R12=address for state
 CMP     R14, #&100 << 12		;quick check for <256
 BHS     _check_hi

 #if report_file_access == 1
   TEQ     R14, #&0D << 12		;OS_Find
   TEQEQ   R0, #64
   TEQNE   R14, #&08 << 12		;OS_File
   BNE     _dont_report
   STMFD   R13!, {R0, R14}
   MOV     R0, R1
   BL      pre_SWI_veneer		;call SWI that follows
   SWI     XReport_Text0
   BL      dontexit_SWI_veneer
   LDMFD   R13!, {R0, R14}
   ._dont_report
 #endif

 CMP     R14, #(_last_SWI_captured - _first_SWI_captured) << (12 - 2)
 ADDLO   PC, PC, R14, LSR #12 - 2
 B       vector_handler_forward

 ._first_SWI_captured
 B       vector_handler_forward		;00
 B       vector_handler_forward		;01
 B       vector_handler_forward		;02
 B       vector_handler_forward		;03
 B       vector_handler_forward		;04
 B       vector_handler_forward		;05
 B       os_byte_handler		;06 - OS_Byte
 #if compile_RO > 311
   B       vector_handler_7		;07 - OS_Word
 #else
   B       vector_handler_forward
 #endif
 #if compile_RO > 311
   B       vector_handler_8		;08 - OS_File
 #else
   B       vector_handler_forward
 #endif
 B       vector_handler_forward		;09
 B       vector_handler_forward		;0A
 B       vector_handler_forward		;0B
 B       vector_handler_forward		;0C
 B       vector_handler_forward		;0D
 B       vector_handler_forward		;0E
 B       vector_handler_forward		;0F
 B       vector_handler_forward		;10
 B       vector_handler_forward		;11
 B       vector_handler_forward		;12
 B       vector_handler_forward		;13
 B       vector_handler_forward		;14
 B       vector_handler_forward		;15
 B       vector_handler_forward		;16
 B       vector_handler_forward		;17
 B       vector_handler_forward		;18
 B       vector_handler_forward		;19
 #if compile_RO > 311
   B       vector_handler_1A		;1A - OS_UpdateMEMC
 #else
   B       vector_handler_forward
 #endif
 B       vector_handler_forward		;1B
 B       vector_handler_1C		;1C - OS_Mouse
 B       vector_handler_forward		;1D
 B       vector_handler_1E		;1E - OS_Module
 B       vector_handler_1F		;1F - OS_Claim
 B       vector_handler_20		;20 - OS_Release
 B       vector_handler_forward		;21
 B       vector_handler_forward		;22
 B       vector_handler_forward		;23
 B       vector_handler_forward		;24
 B       vector_handler_forward		;25
 B       vector_handler_forward		;26
 B       vector_handler_forward		;27
 B       vector_handler_forward		;28
 #if compile_RO > 311
   B       vector_handler_29		;29 - OS_FSControl
 #else
   B       vector_handler_forward
 #endif
 #if compile_RO > 311
   B       vector_handler_2A		;2A - OS_ChangeDynamicArea
 #else
   B       RO31_OS_ChangeDynamicArea
 #endif
 B       vector_handler_forward		;2B
 B       vector_handler_forward		;2C
 B       vector_handler_forward		;2D
 #if compile_RO > 311
   B       vector_handler_2E		;2E - OS_SpriteOp
 #else
   B       vector_handler_forward
 #endif
 B       vector_handler_forward		;2F
 B       vector_handler_forward		;30
 #if compile_RO > 311
   B       vector_handler_31		;31 - OS_ReadVduVariables
 #else
   B       vector_handler_forward
 #endif
 B       vector_handler_forward		;32
 B       vector_handler_forward		;33
 B       vector_handler_forward		;34
 B       vector_handler_forward		;35
 B       vector_handler_forward		;36
 B       vector_handler_forward		;37
 B       vector_handler_forward		;38
 B       vector_handler_forward		;39
 B       vector_handler_forward		;3A
 B       vector_handler_forward		;3B
 B       vector_handler_forward		;3C
 B       vector_handler_forward		;3D
 B       vector_handler_forward		;3E
 B       vector_handler_forward		;3F
 B       vector_handler_forward		;40
 B       vector_handler_forward		;41
 B       vector_handler_42		;42 - OS_ReadMonotonicTime
 B       vector_handler_forward		;43
 B       vector_handler_forward		;44
 B       vector_handler_forward		;45
 B       vector_handler_forward		;46
 B       vector_handler_forward		;47
 B       vector_handler_forward		;48
 B       vector_handler_forward		;49
 B       vector_handler_forward		;4A
 #if compile_RO == 400
   B       vector_handler_4B		;4B - OS_ClaimDeviceVector
   B       vector_handler_4C		;4C - OS_ReleaseDeviceVector
 #else
   B       vector_handler_forward
   B       vector_handler_forward
 #endif
 B       vector_handler_forward		;4D
 B       vector_handler_forward		;4E
 B       vector_handler_forward		;4F
 B       vector_handler_forward		;50
 B       vector_handler_forward		;51
 B       vector_handler_forward		;52
 B       vector_handler_forward		;53
 B       vector_handler_forward		;54
 B       vector_handler_forward		;55
 B       vector_handler_forward		;56
 B       vector_handler_forward		;57
 B       vector_handler_forward		;58
 B       vector_handler_forward		;59
 B       vector_handler_forward		;5A
 B       vector_handler_forward		;5B
 #if compile_RO > 311
   B       vector_handler_5C		;5C - OS_ReadDynamicArea
 #else
   B       vector_handler_forward
 #endif
 B       vector_handler_forward		;5D
 B       vector_handler_forward		;5E
 B       vector_handler_forward		;5F
 B       vector_handler_forward		;60
 B       vector_handler_forward		;61
 B       vector_handler_forward		;62
 B       vector_handler_forward		;63
 B       vector_handler_forward		;64
 B       vector_handler_forward		;65
 #if compile_RO == 311
   B       RO31_OS_DynamicArea		;66 - OS_DynamicArea
 #else
   B       vector_handler_66
   B       vector_handler_forward	;67
   B       vector_handler_forward	;68
   B       vector_handler_forward	;69
   B       vector_handler_forward	;6A
   B       vector_handler_forward	;6B
   B       vector_handler_forward	;6C
   B       vector_handler_forward	;6D
   B       vector_handler_6E		;6E - OS_SynchroniseCodeAreas
   B       vector_handler_6F		;6F - OS_CallASWI
   B       vector_handler_forward	;70
   B       vector_handler_71		;71 - OS_CallASWIR12
 #endif
._last_SWI_captured

 ._check_hi
 SUBS    R14, R14, #&40541 << 12		;FileCore_Create?
 BEQ     vector_handler_40541

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

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

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

   ADDS    R14, R14, #(&40140 - &400EC) << 12	;Wimp_SlotSize
   BEQ     vector_handler_400EC
 #else
   ADDS    R14, R14, #(&40541 - &40142) << 12	;Sound_Stereo?
   BEQ     vector_handler_40142

   #if Managed_ChannelHandler == 0 AND compile_RO > 311
     ADDS    R14, R14, #(&40142 - &400EC) << 12	;Wimp_SlotSize
     BEQ     vector_handler_400EC
   #endif
 #endif
B       vector_handler_forward


;.vector_handler_40540
; LDR     R14, [R11, #ADFS_FileCore_Private - VARS]	;store the FileCore details returned
; TEQ     R8, R14					;ADFS?
; BNE     vector_handler_forward			;NO
;
; ANDS    R14, R1, #%1111 + (%111 << 29)		;DiscOp and drive
; BEQ     vector_handler_forward			;ignore DiscOp 0 to drive 0
;
; CMP     R14, #2				;DiscOp 2?
; BHI     vector_handler_forward			;ignore DiscOp 3+ and drive 1+
;
;; its DiscOp 1/2 to drive 0, check if we need to rewrite the file
; LDRB    R14, [R11, #Type_Mounted - VARS]
; TEQ     R14, #Type_JFD				;is it a JFD?
; BNE     vector_handler_forward
;
; LDR     R14, [R11, #JFD_tmp - VARS + JFD_MinVersion]
; SUBS    R14, R14, #JFD_Supports_Autoflush	;do we need to upgrade the file?
; BPL     vector_handler_forward			;NO
;
; LDR     R14, [R11, #JFD_tmp - VARS + JFD_Bit_Flags]
; TST     R14, #JFD_BF_AutoFlush			;does the floppy need to be auto-flushed?
; LDRNE   R14, [R11, #Current_File_Mounted - VARS]
; TEQNE   R14, #0				;YES, do we have a filename?
; BEQ     vector_handler_forward			;NO
;
; BL      pre_SWI_veneer
; SWI     XADFFS_DoNothing
; STMFD   R13!, {R0, R12}
; MOV     R12, R11
; LDR     R0, [R11, #Current_File_Mounted - VARS]
; STRB    R1, [R11, #flush_in_progress - VARS]	;set to non-zero
; BL      Entry_ADFSave				;rewrite the file
; SUBS    R0, R0, R0				;ignore errors
; LDMFD   R13!, {R0, R12}
; BL      dontexit_SWI_veneer
;
;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 SWI_veneer struct
; 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			;switch to SVCxx and pass to OS SWI dispatch
 STMFD   R13!, {R0-R1, R14}

 #if compile_RO == 311
   LDR     R0, [R13, #3*4 + SWI_stack.R14]	;get R14 from stack
   STR     R0, [R12, #SWI_veneer.SPSR]		;store for exit handler
   ORR     R14, R14, #(%11 << 26) + %11	;SVC IRQ/FIQ disabled
 #endif
 #if compile_RO > 311
   MRS     R1, SPSR			;32bit
   BIC     R1, R1, #%1 << 28		;clear V
   MRS     R0, CPSR
   STR     R1, [R12, #SWI_veneer.SPSR]	;store SPSR
   STR     R0, [R12, #SWI_veneer.CPSR]	;and CPSR
   BIC     R0, R0, #%1111 << 28
   AND     R1, R1, #%1110 << 28		;with V clear
   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
   STR     R14, [R12, #SWI_veneer.R14]	;store SVC R14
   LDR     R1, [R12, #SWI_veneer.CPSR]
   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 SWI_veneer struct
; 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			;pass to our SWI dispatch
 STMFD   R13!, {R0-R1}

 #if compile_RO == 311
   LDR     R0, [R13, #2*4 + SWI_stack.R14]	;get PC from stack
   STR     R0, [R12, #SWI_veneer.SPSR]		;store for exit handler
   ORR     R14, R14, #%11 + (%10 << 26)	;return in SVC IRQ disabled
 #endif
 #if compile_RO > 311
   MRS     R1, SPSR			;32bit
   MRS     R0, CPSR			; |
   STR     R1, [R12, #SWI_veneer.SPSR]	; |  store SPSR
   STR     R0, [R12, #SWI_veneer.CPSR]	; |  and CPSR
   STR     R14, [R12, #SWI_veneer.R14]	;store SVC R14
   BIC     R0, R0, #(%1111 << 28) OR (%11 << 6)	;R0=CPSR_cf
   AND     R1, R1, #(%1111 << 28) OR (%11 << 6)	;R1=SPSR_cf
   ORR     R0, R0, R1			; |+ add in SPSR_cf
   MSR     SPSR_all, R0			;switch SPSR to current mode
 #endif

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




;post_SWI_veneer
;---------------
;updates SPSR flags
;
;Entry: in SVC26 on 26bit OS and SVC32 on 32bit
; R12 - pointer to SWI_veneer struct
; CPSR contains flags (32bit only)

.post_SWI_veneer				;PRESERVES FLAGS
 STR     R14, [R13, #-4]!
 LDR     R14, [R12, #SWI_veneer.SPSR]	;entry PSR
 BICVC   R14, R14, #%0001 << 28		;clear V
 ORRVS   R14, R14, #%0001 << 28		;set V
 STR     R14, [R12, #SWI_veneer.SPSR]	;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 SWI_veneer struct
; CPSR contains flags (32bit only)

.post_SWI_veneerC				;PRESERVES FLAGS
 STR     R14, [R13, #-4]!
 LDR     R14, [R12, #SWI_veneer.SPSR]	;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, #SWI_veneer.SPSR]	;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 on 32bit OS, SVC on 26bit OS
; R12 - pointer to SWI_veneer struct
; V flag set if V needs setting on exit

.exit_SWI_veneer				;exit to app, V FLAG PASSED THROUGH
#if compile_RO == 311
 LDR     R14, [R13, #SWI_stack.R14]	;get exit PC from stack
 BIC     R14, R14, #%1111 << 28		;clear flags
 ORRVS   R14, R14, #1 << 28		;set V
 LDR     R11, [R12, #SWI_veneer.SPSR]	;get our exit flags
 AND     R11, R11, #%1111 << 28		;mask flags
 ORR     R14, R14, R11			;set exit flags
 STR     R14, [R13, #SWI_stack.R14]
 LDR     R14, [R12, #SWI_veneer.R14]	;preserve SVC R14
EXITSWI ""				;return to original caller
#endif
#if compile_RO > 311
 LDR     R14, [R12, #SWI_veneer.R14]	;preserve SVC R14
 LDRVS   R11, [R12, #SWI_veneer.SPSR]
 ORRVS   R11, R11, #1 << 28		;set V
 STRVS   R11, [R12, #SWI_veneer.SPSR]

 LDR     R11, [R12, #SWI_veneer.CPSR]
 MSR     CPSR_all, R11			;correct CPSR
 #if compile_IOMD == 1
   NOP
 #endif
 LDR     R11, [R12, #SWI_veneer.SPSR]
 MSR     SPSR_all, R11			;correct SPSR
EXITSWI ""				;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 SWI_veneer struct
;Exit: in SVC32

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

   LDR     R14, [R12, #SWI_veneer.R14]	;preserve SVC R14
   STR     R0, [R12, #SWI_veneer.R14]	;preserve R0
   LDR     R0, [R12, #SWI_veneer.CPSR]
   MSR     CPSR_all, R0			;correct CPSR
   NOP
   LDR     R0, [R12, #SWI_veneer.SPSR]
   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_f, R0			;copy V from SVC26 to SVC32
   LDR     R0, [R12, #SWI_veneer.R14]	;preserve R0
   LDR     R14, _return
  BIC     PC, R14, #&FC000003

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

   LDR     R14, [R12, #SWI_veneer.SPSR]
   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

;Entry:
; R12 - pointer to VARS

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

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

 BL      claim_EventV

 #if compile_RO == 311			;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
   BNE     _failed			;NO
   MOV     R1, R1, LSL #2		;YES, shift address up
   ADD     R1, R1, #16			;..correct the address
   BIC     R1, R1, #%11111100 << 24	;..clear the ARM command bits
   STR     R1, OS_SWI_Vector		;..save the original vector
   ADR     R1, vectorHandler - 16	;..our vector handler, -16 to correct
   MOV     R1, R1, LSR #2			;..shift address down
   ORR     R1, R1, #&EA000000		;..set the ARM command
   STR     R1, [R0]			;..and replace the vector
 #else
   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
 #endif
LDMFD   R13!, {R0-R2, PC}

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




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

;Entry:
; R12 - pointer to VARS

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

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

 BL      release_EventV

 #if compile_RO == 311			;release vector on RISC OS <3.5
   MOV     R0, #Vector_SWI << 2		;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
 #else
   ADR     R2, vectorHandler		;release vector on RISC OS 3.5+
   LDR     R1, OS_SWI_Vector		;original vector
   MOV     R0, #Vector_SWI
   SWI     XOS_ClaimProcessorVector	;PRM5a-30
   BVC     _okay
 #endif
 ._failed
 LDMFD   R13!, {R1-R12, R14}		;clear down stack
 MOV     R0, #1<<31
 ADDS    R0, R0, R0			;set V
 ADR     R0, Error_Vector_Release	;oops, can't release vector
MOV     PC, R14				;should never get here

 ._okay
 MOV     R0, #0
 STR     R0, OS_SWI_Vector

 BL      reinit_ADFS			;reinit will cause FileCore to rmkill us

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