;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

MACRO captureSWI swi_number:I
{
  #set swi_n = swi_number AND 255
  #if swi_n < 32
    #set swi_block_0 = swi_block_0 OR (1 << swi_n)
  #endif
  #if swi_n >= 32 AND swi_n < 64
    #set swi_block_1 = swi_block_1 OR (1 << (swi_n-32))
  #endif
  #if swi_n >= 64 AND swi_n < 96
    #set swi_block_2 = swi_block_2 OR (1 << (swi_n-64))
  #endif
  #if swi_n >= 96 AND swi_n < 128
    #set swi_block_3 = swi_block_3 OR (1 << (swi_n-96))
  #endif
  #if swi_n >= 128 AND swi_n < 160
    #set swi_block_4 = swi_block_4 OR (1 << (swi_n-128))
  #endif
  #if swi_n >= 160 AND swi_n < 192
    #set swi_block_5 = swi_block_5 OR (1 << (swi_n-160))
  #endif
  #if swi_n >= 192 AND swi_n < 224
    #set swi_block_6 = swi_block_6 OR (1 << (swi_n-192))
  #endif
  #if swi_n >= 224
    #set swi_block_7 = swi_block_7 OR (1 << (swi_n-224))
  #endif
}


 captureSWI &40541			;FileCore_Create
 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 &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 &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

 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
 .disk_swap_pending	DCD 0		;<>0 if a disk change is pending

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

#set PC_from_stack = 8		;offset to R14 as stacked in PPUSHSWI

;PPUSHSWI<CC>
;--------
;stacks registers on entry to the SWI handler

MACRO PPUSHSWI$cc
{
 STM$cc#FD   R13!, {R11-R12, R14}
}


;PULLSWI<CC>
;-------
;restores registers stacked on entry to the SWI handler, but doesn't exit

MACRO PULLSWI$cc
{
 LDM$cc#FD   R13!, {R11-R12, R14}
}


;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 &08FD9800		;LDMFD R13!, {R11-R12, PC}^
 #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
}
; ****************************************************************


.vectorHandler
 PPUSHSWI

 #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     R11, 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]!
     LDR     R12, instruction_trace_ptr
     LDR     R4, [R12, #-4]
     STR     R11, [R4], #4
     BIC     R4, R4, #jit_trace_buffer_size >> 2
     STR     R4, [R12, #-4]
     LDR     R4, [R13], #4
     ._skip_debug
   #endif
   TEMP    R12
   STR     R11, user_PC
   MRS     R11, SPSR
   STR     R11, user_SPSR
   LOCK    R12
   ._skip_debug2
 #endif

 LDR     R14, [R14, #-4]
 #if compile_RO > 311
   AND     R11, R14, #%1111 << 20	;get OS bits
   TEQ     R11, #JIT_SWI_OS_Flag << 20	;hypervised SWI?
   BEQ     hypervised_SWI		;YES
 #endif

 ADR     R12, swi_captured
 AND     R11, R14, #&FF			;get bits 0-7
 LDRB    R12, [R12, R11, LSR #3]
 AND     R11, R11, #%111
 MOV     R12, R12, LSR R11
 ANDS    R12, R12, #1
 BNE     vector_handler_check

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

.vector_handler_exit
 PULLSWI				;clear down stack
LDR     PC, OS_SWI_Vector







.vector_handler_trap_VS
#if compile_RO == 311
 PULLSWI				;clear down stack
ORRS    PC, R14, #1 << 28		;set V and exit
#else
 MRS     R12, SPSR
 ORR     R12, R12, #1 << 28		;set V
 MSR     SPSR_all, R12
#endif

.vector_handler_trap
EXITSWI ""




;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					;R11 corrupted
 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
   BIC     R14, R14, #&FC000003		;clear flags
   MRS     R11, CPSR
   ORR     R11, R11, #%10000		;switch to SVC32
   MSR     CPSR_all, R11
   NOP
   MRS     R11, CPSR
   BIC     R11, R11, #%10000		;return in SVC26
   MSR     SPSR_all, R11
 #endif
LDR     PC, OS_SWI_Vector

#if compile_RO > 311
.pass_SWI_on2
 ADD     R14, R14, #4			;correct return
 LDR     PC, OS_SWI_Vector
#endif




.vector_handler_check
 BIC     R14, R14, #1 << 17		;clear X bit
 MOV     R14, R14, LSL #12		;shift SWI# to top bits

 #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
   SUB     R13, R13, #4*4
   MOV     R12, R13
   BL      pre_SWI_veneer		;call SWI that follows
   SWI     XReport_Text0
   BL      dontexit_SWI_veneer
   ADD     R13, R13, #4*4
   LDMFD   R13!, {R0, R14}
   ._dont_report
 #endif

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

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

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

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

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

   #if compile_RO > 311
     SUB     R12, R12, #(&40142 - &400EC) << 12
     TEQ     R14, R12			;Wimp_SlotSize
     BEQ     vector_handler_400EC
   #endif
 #endif

 CMP     R14, #&66 << 12		;OS_DynamicArea
 #if compile_RO == 311
   BEQ     RO31_OS_DynamicArea		;YES
   BHI     vector_handler_forward	;hand higher straight back to OS
 #else
   BEQ     vector_handler_66		;YES
 #endif

 #if compile_RO > 311
   CMP     R14, #&6E << 12		;OS_SynchroniseCodeAreas
   BEQ     vector_handler_6E		;YES
   BHI     vector_handler_forward	;hand higher straight back to OS
 #endif

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

 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, #&1F << 12		;OS_Claim?
 BEQ     vector_handler_1F		;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, #7 << 12		;is it OS_Word?
   BEQ     vector_handler_7		;YES

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

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

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

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

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

   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, #PC_from_stack + (3 * 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, #PC_from_stack + (2 * 4)]	;get PC from stack
   STR     R0, [R12, #0]		;store for exit handler
   ORR     R14, R14, #%11 + (%10 << 26)	;return in SVC IRQ 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
   STR     R0, [R12, #8]		;store SVC CPSR
   STR     R14, [R12, #12]		;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 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, #PC_from_stack + 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, #PC_from_stack + 4]
 LDR     R14, [R12, #12]		;preserve SVC R14
EXITSWI "R0"				;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
EXITSWI "R0"				;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
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, #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

 ._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	;PRM5a-30
 BVC     _okay

 ._failed
 LDMFD   R13!, {R0-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

 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}