;References:
;swi - pre_SWI_veneer, post_SWI_veneer, exit_SWI_veneer, dontexit_SWI_veneer


;NOTE:
; To pass SWI's through to our SWI handler the following code sequence must be used.
; SWI's cannot be passed on via vector_handler_forward or issued directly:
;
; BL      hv_pre_SWI_veneer		;call SWI that follows
; SWI     XSound_Configure
; BL      post_SWI_veneer

; to exit if V set in saved SPSR
; B       error_SWI
;
; or if V set in actual SPSR
; B       error_SWI2
;
; to exit setting V and R12 points to pre_swi_veneer:
; B       hv_exit_SWI_veneer_VS
;
; to exit if V state unknown and R12 points to a pre_swi_veneer:
; B       hv_exit_SWI_veneer

; to exit when V is definately clear and SPSR isn't corrupt:
; B       hv_vector_handler_trap
; or
; EXITSWI ""

#set last_device_to_track = IOC_SSBC		;last IOC device to track



STRUCT device_table
{
  .entry_code		DCD 0
  .private		DCD 0
  .original_code	DCD 0
  .taskID		DCD 0
  .size				;MUST BE 16 as code below uses "LSL #4"
}




;hypervised_SWI
;--------------
;handles an OS SWI that we need to manage
;
;Entry:
; stack: {SWI stack}
; R11 - OS bits
; R14 - SWI number
;
;NOTE: SWI's added here also need to be added to hv_OS_CallASWI_check_SWI
;      and i.SWI

.hypervised_SWI_check
 TEQ     R11, #JIT_SWI_OS_Flag
 BNE     vector_handler_exit

.hypervised_SWI
 BIC     R11, R14, #swi_OS_bits + swi_X_bit	;clear OS and X bit
 ORR     R14, R11, #swi_X_bit		;ensure we don't generate errors
 MOV     R11, R11, LSL #12		;R11=SWI # << 12
 STR     R14, swi_to_pass_to_OS
 ADD     R12, R13, #SWI_stack.size	;R12=buffer for C/SPSR (pre_swi_veneer)

					;check for Module entries, must occur
					;before V is cleared in SPSR (fixes Inferno)
 SUB     R14, R11, #ADFFS_LastSWI << 12
 CMP     R14, #(_not_an_ADFFS_SWI-_ADFFS_SWIs) << (12 - 2)
 ADDLO   PC, PC, R14, LSR #12 - 2
 B       _not_an_ADFFS_SWI
 ._ADFFS_SWIs
 B       call_module_entry		;ADFFS_CallModuleEntry
 B       call_module_entry_INIT		;ADFFS_CallModuleEntryInit
 B       call_module_entry_INIT_END	;ADFFS_CallModuleEntryInitEnd
 B       call_module_entry_R0		;ADFFS_CallModuleEntryR0
 B       swi_ADFFS_UnSqueeze		;ADFFS_UnSqueeze
 ._not_an_ADFFS_SWI
 MRS     R14, SPSR
 BIC     R14, R14, #1 << 28		;clear V in SPSR
 MSR     SPSR_all, R14
 STR     R14, [R12, #SWI_veneer.SPSR]

 #if JIT_debug == 1
   STMFD   R13!, {R11-R12}
   TEMP    R14
   LDR     R12, jit_joysticks		;PJSRA
   BIC     R11, R11, #%11 << 12
   TEQ     R11, #&42EC0 << 12		;Parallel_HardwareAddress/Parallel_Op
   ORREQ   R12, R12, #%10000
   TEQ     R11, #&CFFC0 << 12		;RTFM Joy_Read0/Joy_Read1/Joy_Test
   ORREQ   R12, R12, #%01000
   TEQ     R11, #&81540 << 12		;VTJoystick_Status
   ORREQ   R12, R12, #%00100
   TEQ     R11, #&43F40 << 12		;Joystick_Read
   ORREQ   R12, R12, #%00001
   STR     R12, jit_joysticks
   LOCK    R14
   LDMFD   R13!, {R11-R12}
 #endif

 TEQ     R11, #&01 << 12		;OS_WriteS		PRM1-517
 BEQ     hv_OS_WriteS

 TEQ     R11, #&0C << 12		;OS_GBPB		PRM2-69
 BEQ     hv_OS_GBPB

 #if compile_RO > 400
   TEQ     R11, #&0E << 12		;OS_ReadLine		PRM1-941
   BEQ     hv_OS_ReadLine

   TEQ     R11, #&1D << 12		;OS_Heap		PRM1-375
   BEQ     hv_OS_Heap
 #endif

 TEQ     R11, #&0F << 12		;OS_Control		PRM1-299
 BEQ     hv_OS_Control

 TEQ     R11, #&10 << 12		;OS_GetEnv		PRM1-301
 BEQ     hv_OS_GetEnv

 TEQ     R11, #&12 << 12		;OS_SetEnv		PRM1-305
 BEQ     hv_OS_SetEnv

 TEQ     R11, #&15 << 12		;OS_CallBack		PRM1-307
 BEQ     hv_OS_CallBack

 TEQ     R11, #&18 << 12		;OS_BreakCtrl		PRM1-310
 BEQ     hv_OS_BreakCtrl

 TEQ     R11, #&1E << 12		;OS_Module		PRM1-228
 BEQ     hv_OS_Module

 TEQ     R11, #&1F << 12		;OS_Claim		PRM1-66
 TEQNE   R11, #&3B << 12		;OS_CallAfter		PRM1-441
 TEQNE   R11, #&3C << 12		;OS_CallEvery		PRM1-443
 TEQNE   R11, #&47 << 12		;OS_AddToVector		PRM1-72
 BEQ     hv_OS_Claim

 TEQ     R11, #&20 << 12		;OS_Release		PRM1-68
 BEQ     hv_OS_Release

 TEQ     R11, #&29 << 12		;OS_FSControl		PRM2-96
 BEQ     hv_OS_FSControl

 TEQ     R11, #&30 << 12		;OS_ServiceCall		PRM1-254
 BEQ     hv_OS_ServiceCall

 TEQ     R11, #&3D << 12		;OS_RemoveTickerEvent	PRM1-445
 BEQ     hv_OS_RemoveTickerEvent

 TEQ     R11, #&40 << 12		;OS_ChangeEnvironment	PRM1-320
 BEQ     hv_OS_ChangeEnvironment

 TEQ     R11, #&41 << 12		;OS_ClaimScreenMemory	PRM1-388
 BEQ     hv_OS_ClaimScreenMemory

 TEQ     R11, #&4B << 12		;OS_ClaimDeviceVector	PRM1-123
 BEQ     hv_OS_ClaimDeviceVector

 TEQ     R11, #&4C << 12		;OS_ReleaseDeviceVector	PRM1-125
 BEQ     hv_OS_ReleaseDeviceVector

 TEQ     R11, #&4F << 12		;OS_HeapSort		PRM1-970
 BEQ     hv_OS_HeapSort

 TEQ     R11, #&51 << 12		;OS_ReadMemMapInfo	PRM1-391
 BEQ     hv_OS_ReadMemMapInfo

 TEQ     R11, #&54 << 12		;OS_AddCallBack		PRM1-324
 BEQ     hv_OS_AddCallBack

 TEQ     R11, #&58 << 12		;OS_ReadSysInfo		PRM1-746
 BEQ     hv_OS_ReadSysInfo

 TEQ     R11, #&5F << 12		;OS_RemoveCallBack	PRM1-327
 BEQ     hv_OS_RemoveCallBack

 TEQ     R11, #&65 << 12		;OS_ScreenMode		PRM5a-133
 BEQ     hv_OS_ScreenMode

 TEQ     R11, #&68 << 12		;OS_Memory		PRM5a-70
 BEQ     hv_OS_Memory

 TEQ     R11, #&69 << 12		;OS_ClaimProcessorVector	PRM5a-30
 BEQ     hv_OS_ClaimProcessorVector

 TEQ     R11, #&6D << 12		;OS_PlatformFeatures
 BEQ     hv_OS_PlatformFeatures

 TEQ     R11, #OS_CallASWI << 12	;OS_CallASWI
 BEQ     hv_OS_CallASWI

 TEQ     R11, #OS_CallASWIR12 << 12	;OS_CallASWIR12
 BEQ     hv_OS_CallASWIR12

 TEQ     R11, #6 << 12			;OS_Byte
 TEQEQ   R1, #11			;key transition?
 BLEQ    os_byte_13_14_check		;YES

 SUB     R14, R11, #&40000 << 12
 TEQ     R14, #(&400C0 - &40000) << 12	;Wimp_Initialise	PRM3-85
 BEQ     hv_Wimp_Initialise
 TEQ     R14, #(&400DE - &40000) << 12	;Wimp_StartTask		PRM3-174
 BEQ     hv_Wimp_StartTask
 TEQ     R14, #(&400EC - &40000) << 12	;Wimp_SlotSize		PRM3-203
 BEQ     hv_Wimp_SlotSize
 TEQ     R14, #(&400EE - &40000) << 12	;Wimp_ClaimFreeMemory	PRM3-288
 BEQ     hv_Wimp_ClaimFreeMemory

 SUBS    R14, R14, #(&40144 - &40000) << 12
 BEQ     hv_Sound_Mode			;Sound_Mode		PRM5a-603

 TEQ     R14, #(&40145 - &40144) << 12	;Sound_LinearHandler	PRM5a-605
 BEQ     hv_Sound_LinearHandler

 TEQ     R14, #(&40183 - &40144) << 12	;Sound_InstallVoice	PRM4-29
 BEQ     hv_Sound_InstallVoice

 TEQ     R14, #(&40184 - &40144) << 12	;Sound_RemoveVoice	PRM4-35
 BEQ     hv_Sound_RemoveVoice

 TEQ     R14, #(&401C1 - &40144) << 12	;Sound_QSchedule	PRM4-48
 BEQ     hv_Sound_QSchedule

 SUB     R14, R14, #(&42544 - &40144) << 12
 TEQ     R14, #(&42640 - &42544) << 12	;Filter_RegisterPreFilter	;PRM3-304
 TEQNE   R14, #(&42641 - &42544) << 12	;Filter_RegisterPostFilter	;PRM3-306
 BEQ     hv_Filter_RegisterPre_PostFilter

 SUB     R14, R14, #(&42700 - &42544) << 12
 TEQ     R14, #(&42701 - &42700) << 12	;Squash_Decompress	PRM4-106
 BEQ     hv_Squash_Decompress

 SUBS    R14, R14, #((&80680+(1<<18)) - &42700) << 12
 BLEQ    hv_SharedCLibrary_LibInitAPCS_A	;SharedCLibrary_LibInitAPCS_A
 TEQ     R14, #(1 + (1 << 6)) << 12		;SharedCLibrary_LibInitAPCS_R
 TEQNE   R14, #(3 + (1 << 6)) << 12		;SharedCLibrary_LibInitAPCS_32
 BLEQ    hv_SharedCLibrary_LibInitAPCS_R

#if swi_flag_preservation == 1
					;****** CHECK SWI FOR FLAGS TO RETAIN *****
 MVN     R14, #%0001 << 28		;retain V
 TST     R11, #(1 << 19) << 12		;3rd party / user SWI?
 BNE     _preserve_flags		;YES, assume NZC need preserving

 TEQ     R11, #4 << 12			;OS_ReadC
 TEQNE   R11, #&A << 12			;OS_BGet
; TEQNE   R11, #&C << 12			;OS_GBPB
; TEQNE   R11, #&E << 12			;OS_ReadLine
 TEQNE   R11, #&26 << 12		;OS_GSRead
 TEQNE   R11, #&27 << 12		;OS_GSTrans
 TEQNE   R11, #&2C << 12		;OS_ReadEscapeState
 TEQNE   R11, #&35 << 12		;OS_ReadModeVariable
 TEQNE   R11, #&3A << 12		;OS_ValidateAddress
 TEQNE   R11, #&3F << 12		;OS_CheckModeValid
; TEQNE   R11, #&41 << 12		;OS_ClaimScreenMemory
 BEQ     _retain_C

 TEQ     R11, #&57 << 12		;OS_SerialOp
 TEQEQ   R0, #3				;OS_SerialOp 3?
 BEQ     _retain_C

 TEQ     R11, #6 << 12			;OS_Byte
 BNE     _P1
 TEQ     R0, #129			;OS_Byte 129 (Humanoids and Robotix)
 TEQNE   R0, #138			;OS_Byte 138
 TEQNE   R0, #145			;OS_Byte 145
 TEQNE   R0, #152			;OS_Byte 152
 TEQNE   R0, #153			;OS_Byte 153
 BEQ     _retain_C

 TEQ     R0, #19			;these OS_Byte forcibly clear C
 MRSEQ   R11, SPSR			;OS_Byte doesn't actually preserve C
 BICEQ   R11, R11, #%0010 << 28
 MSREQ   SPSR_all, R11
 B       _preserve_flags

 ._P1
 TEQ     R11, #7 << 12			;OS_Word
 BNE     _P2
 TEQ     R0, #0				;OS_Word 0
 BEQ     _retain_C
 TEQ     R0, #15
 BNE     _preserve_flags
 LDRB    R11, [R1, #0]
 TEQ     R11, #15			;OS_Word 15,15
 TEQNE   R11, #24			;OS_Word 15,24
 BEQ     _retain_C
 B       _preserve_flags

 ._P2
 TEQ     R11, #&59 << 12		;OS_Confirm
 BICEQ   R14, R14, #%0110 << 28		;retain Z, C
 B       _preserve_flags

 ._retain_C
 BIC     R14, R14, #%0010 << 28		;retain C

 ._preserve_flags
 MRS     R11, SPSR
 AND     R11, R11, R14			;R11=flags to preserve
 AND     R14, R14, #%1111 << 28
 EOR     R14, R14, #%1111 << 28		;R14=flag mask to retain from SWI
 STMFD   R13!, {R11, R14}		;store mask and flags
#endif

 BL      hv_pre_SWI_veneer		;call SWI that follows
 .swi_to_pass_to_OS SWI 0
 BL      hv_post_SWI_veneer
 BL      dontexit_SWI_veneer

 #if swi_flag_preservation == 1
   LDMFD   R13!, {R11, R12}		;pull flag mask and flags to preserve
   MRS     R14, SPSR			;get flags returned from SWI
   AND     R14, R14, R12		;R14=flags to keep
   ORR     R14, R14, R11
   MSR     SPSR_all, R14		;preserve flags
   TST     R14, #1 << 28		;V set?
   EXITSWIEQ ""				;NO, exit
   B       error_SWI2
 #endif

.hv_exit_SWI_veneer
 LDR     R14, [R13, #SWI_stack.size + SWI_veneer.SPSR]
 MSR     SPSR_all, R14
 TST     R14, #1 << 28			;V set?
 EXITSWIEQ ""				;NO, exit

 .error_SWI2
 LDR     R12, [R13, #SWI_stack.swi]	;get the instruction
 BIC     R11, R12, #swi_X_bit		;clear X bit
 MOV     R11, R11, LSL #12		;shift SWI# to top bits

 TEQ     R11, #&6F << 12		;OS_CallASWI
 MOVEQ   R12, R10

 TEQ     R11, #&71 << 12		;OS_CallASWIR12
 LDREQ   R12, [R13, #SWI_stack.R12]

 TST     R12, #swi_X_bit		;is the X bit set?
 EXITSWINE ""				;YES, exit

 #if JIT_debug == 0			;did an error occur during a module
   ADR     R12, VARS			;finalise?
   LDR     R12, [R12, #trap_aborts_in_Finalise - VARS]
   TEQ     R12, #0
 #endif
 PULLSWI
 #if JIT_debug == 0
   ADRNE   R14, handle_module_error	;YES, redirect to our handler
   MOVNES  PC, R14
 #endif

 STMFD   R13!, {R2-R3, R6-R7}
 SUB     R7, R14, #jit_code_start
 MOV     R6, R0
 MOV     R0, #6				;get the current error handler
 MOV     R1, #0
 MOV     R2, #0
 MOV     R3, #0
 BL      pass_SWI_on
 SWI     XOS_ChangeEnvironment		;R1>PC, R2>R0, R3=buffer
; EOR     R0, R1, R2
; EORS    R0, R0, R3			;is it pointing at Obey?
; MOVEQ   R9, #Vector_ErrorV		;YES, call its handler
; MOVEQ   R14, R7
; LDMEQFD R13!, {R2-R3, R6-R7}
; BEQ     pass_SWI_on
; SWIEQ   OS_CallAVector

 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




.hv_exit_SWI_veneer_VS
 MRS     R12, SPSR
 ORR     R12, R12, #1 << 28		;set V
 MSR     SPSR_all, R12
B       error_SWI2




.error_SWI
 LDR     R14, [R13, #SWI_stack.size + SWI_veneer.SPSR]
 MSR     SPSR_all, R14
 B       error_SWI2




.os_byte_13_14_check
 TEQ     R0, #13			;Disable event?
 TEQNE   R0, #14			;Enable event?
 MOVNE   PC, R14			;NO
 LDR     R1, JIT_event11_active
 TEQ     R0, #13			;disable event?
 ADDNES  R2, R1, #1			;NO, increase counter
 SUBEQS  R2, R1, #1			;YES, decrease counter
 MOVMI   R2, #0				;ensure it's not negative
 TEMP    R14
 STR     R2, JIT_event11_active
 LOCK    R14
.hv_vector_handler_trap
EXITSWI ""




.hv_SharedCLibrary_LibInitAPCS_A
 STMFD   R13!, {R0-R12, R14}
 ADR     R1, _load_APCS_A
 B       hv_SharedCLibrary_LibInitAPCS_load

 ._load_APCS_A DCB "ADFFS:extras.CLibAPCS-A",0
 ALIGN




.hv_SharedCLibrary_LibInitAPCS_R
 STMFD   R13!, {R0-R12, R14}
 ADR     R1, _load_APCS_R
 B       hv_SharedCLibrary_LibInitAPCS_load

 ._load_APCS_R DCB "ADFFS:extras.CLibAPCS-R",0
 ALIGN




 .hv_SharedCLibrary_LibInitAPCS_load
 MOV     R0, #Module_Load		;load the Module
 SUB     R11, R12, #4			;preserve SWI_veneer.* and SWI_stack.swi
 LDMIA   R11, {R2-R5}
 MRS     R6, SPSR
 LDR     R7, swi_to_pass_to_OS

 BL      resetVectors			;reset key vectors
 BL      hv_pre_SWI_veneer		;call SWI that follows
 SWI     XOS_Module
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
 BL      resetVectors			;reset key vectors

 STR     R7, swi_to_pass_to_OS
 MSR     SPSR_all, R6
 STMIA   R11, {R2-R5}			;preserve SWI_veneer.*
LDMFD   R13!, {R0-R12, PC}




;hv_report_unimplemented
;-----------------------
;aborts on an SWI that's not been implemented
;
;Entry:
; stack: {SWI stack}
; R12 - identifier

.hv_report_unimplemented
 TEMP    R14
 ADD     R12, R12, #&ADFF5000
 STR     R12, current_abort_type
 LOCK    R14
 ADR     R14, DAV_r0			;report via abort
 STMIA   R14!, {R0-R7}
 MOV     R0, R14
 PULLSWI				;clear stack
 SUB     R14, R14, #4
 SUB     R14, R14, #jit_code_start	;correct PC
 STR     R14, [R0, #(15-8) * 4]

 MRS     R1, SPSR			;get original CPU state
 TST     R1, #%1111			;is abort in User mode?
 TEMP    R2
 STR     R1, DAV_CPSR			;store it for exit and..
					;..fix for errata on SA-110 rev.2
 LOCK    R2
 STMEQIA R0, {R8-R14}^			;get User mode registers
 BEQ     report_abort

 MSR     CPSR_all, R1			;switch to faulting mode
 #if compile_IOMD == 1
   NOP
 #endif
 STMIA   R0, {R8-R14}			;get aborting mode registers
B       report_abort




;hv_post_SWI_veneer
;-------------------
;updates all 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)

.hv_post_SWI_veneer				;PRESERVES FLAGS
 STMFD   R13!, {R0, R14}

 LDR     R0, [R12, #SWI_veneer.CPSR]
 #if compile_RO == 400
   MRS     R14, CPSR
   AND     R0, R0, #%11 << 6
   BIC     R14, R14, #%11 << 6
   ORR     R0, R14, R0
 #endif
 MSR     CPSR_c, R0			;set IRQ state
 #if compile_IOMD == 1
   NOP
 #endif
 LDR     R0, [R12, #SWI_veneer.SPSR]	;entry PSR
 BIC     R0, R0, #%1111 << 28		;clear flags
 MRS     R14, CPSR
 AND     R14, R14, #%1111 << 28		;keep flags
 ORR     R0, R0, R14
 STR     R0, [R12, #SWI_veneer.SPSR]	;correct SPSR
LDMFD   R13!, {R0, PC}




;no_such_SWI_below_RO350
;-----------------------
;Returns SWI not known if emulating below RO350

.no_such_SWI_below_RO350
 STR     R14, [R13, #-4]!

 LDR     R14, emulate_RISCOS
 CMP     R14, #&350 << 8		;are we emulating RISCOS 3.5+
 LDRHS   PC, [R13], #4			;YES, exit

 ADD     R13, R13, #4			;drop R14 from stack
.no_such_SWI
 ADR     R0, error_SWI_not_known	;return error
B       hv_exit_SWI_veneer_VS





;hv_OS_GBPB
;----------
;Resets the JIT area to match where data is loaded within application space
;
;Entry:
; R0  - operation
; R2  - start address
; R3  - size
; R12 - pointer to pre_SWI_veneer block

.hv_OS_GBPB					;PRM2-66
 MOV     R11, R2			;R11=load address
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_GBPB
 BL      post_SWI_veneerC
 BL      dontexit_SWI_veneer
 BVS     error_SWI2			;exit on error

 TEQ     R0, #3				;is it a load operation?
 TEQNE   R0, #4				;PRM2-69
 EXITSWINE ""				;NO, exit

 CMP     R11, #jit_appspace_end		;is it in application space?
 EXITSWIHI ""		;NO, exit

 STMFD   R13!, {R2, R4}			;preserve R2, R4
 SUBS    R4, R2, R11			;R4=size
 MOVGT   R2, R11			;R2=start address
 BLGT    hv_reset_memory_block		;reset JIT appspace
EXITSWI "R2, R4"




;hv_OS_WriteS
;------------
;redirect OS_WriteS to appspace using OS_Write0
;
;Entry:
;R12 - pointer to pre_SWI_veneer block

.hv_OS_WriteS					;PRM1-517
 STR     R0, [R13, #-4]!		;preserve R0

 LDR     R0, [R13, #4 + SWI_stack.R14]	;get PC from stack
 SUB     R0, R0, #jit_code_start	;correct to application space

 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_Write0
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer

 ADD     R0, R0, #3
 BIC     R0, R0, #%11			;word align
 ADD     R0, R0, #jit_code_start	;R0=next instruction

 STR     R0, [R13, #4 + SWI_stack.R14]	;restack PC
EXITSWI "R0"				;return to original caller




;hv_OS_Claim
;-----------
;Hypervize OS_Claim, OS_CallAfter, OS_CallEvery, OS_AddToVector,
;OS_ClaimDeviceVector
;
;reference PRM1-143 / 121 for IOC registers used by OS_ClaimDeviceVector
;
;Entry:
; R11    - SWI # << 12
; R12    - pointer to pre_SWI_veneer block
; hv_R14 - +4 = codelet

.hv_OS_Claim					;PRM1-66
 STMFD   R13!, {R6-R10}				;preserve R6-R8

 BL      return_taskID				;R10=taskID
 TEQ     R11, #&3B << 12			;OS_CallAfter	PRM1-441
 TEQNE   R11, #&3C << 12			;OS_CallEvery	PRM1-443
 MVNEQ   R6, #0					;YES, no parameter
 MOVNE   R6, R0					;NO, R6=vector

 LDR     R7, jit_claimed_vectors		;check for duplicate claim
 MOV     R8, #max_vectors_to_track
 ._L1						;find a free vector slot
   LDR     R14, [R7, #vector_table.entry_code]	;get the managed entry
   TEQ     R14, #0				;is it being used?
   BEQ     _P1					;NO
   CMN     R6, #1				;do we need to check R0?
   LDRNE   R14, [R7, #vector_table.parameter]	;YES
   TEQNE   R14, R0				;does the vector match?
   LDREQ   R14, [R7, #vector_table.original_code]
   TEQEQ   R14, R1				;does the entry match
   LDREQ   R14, [R7, #vector_table.private]	;YES,
   TEQEQ   R14, R2				; |  does the R12 value match?
   LDREQ   R14, [R7, #vector_table.taskID]	;YES,
   TEQEQ   R14, R10				; |  does the taskID match?
   BNE     _P1					;vector doesn't match
   LDR     R14, [R7, #vector_table.type]
   TEQ     R11, #&3B << 12			;OS_CallAfter
   TEQNE   R11, #&3C << 12			;OS_CallEvery can we share claims?
   BNE     _type_must_match			;NO
   TEQ     R14, #&3B << 12			;OS_CallAfter
   TEQNE   R14, #&3C << 12			;OS_CallEvery
   BEQ     _found_match				;we can share this claim
   B       _P1

   ._type_must_match
   TEQ     R14, R11				;does the claim type match?
   ._found_match
   LDREQ   R1, [R7, #vector_table.entry_code]	;get the managed entry
   BEQ     _already_exists			;skip vector allocation

   ._P1
   ADD     R7, R7, #vector_table.size
   SUBS    R8, R8, #1
 BNE     _L1

 LDR     R7, jit_claimed_vectors
 SUB     R7, R7, #vector_table.size
 MOV     R8, #max_vectors_to_track
 ._L2						;find a free vector slot
   ADD     R7, R7, #vector_table.size
   LDR     R14, [R7, #vector_table.entry_code]
   TEQ     R14, #0
   SUBNES  R8, R8, #1
 BNE     _L2

 TEQ     R8, #0
 MOVEQ   R12, #&12				;NO, ADFF5012
 LDMEQFD R13!, {R6-R10}				; |
 BEQ     hv_report_unimplemented		; |+ report

 STR     R1, [R7, #vector_table.original_code]	;original entry point
 LDR     R14, Vector_Claim_Handlers		;our managed entries
 RSB     R8, R8, #max_vectors_to_track		;R8=our vector handler#
 ADD     R1, R14, R8, LSL #4			;4 instructions per handler
 STR     R1, [R7, #vector_table.entry_code]	;store the claim for cleaning up
 STR     R11, [R7, #vector_table.type]		;store for removal later
 STR     R0, [R7, #vector_table.parameter]	;SWI parameter
 STR     R2, [R7, #vector_table.private]	;R12 private word
 STR     R10, [R7, #vector_table.taskID]	;taskID

 ._already_exists
 TEQ     R11, #&1F << 12			;OS_Claim	PRM1-66
 BEQ     _OS_Claim
 TEQ     R11, #&3B << 12			;OS_CallAfter	PRM1-441
 BEQ     _OS_CallAfter
 TEQ     R11, #&3C << 12			;OS_CallEvery	PRM1-443
 BEQ     _OS_CallEvery
						;OS_AddToVector	PRM1-72
 ._OS_AddToVector
 BL      pre_SWI_veneer				;call SWI that follows
 SWI     XOS_AddToVector
 B       _exit

 ._OS_CallAfter
 BL      pre_SWI_veneer				;call SWI that follows
 SWI     XOS_CallAfter
 B       _exit

 ._OS_CallEvery
 BL      pre_SWI_veneer				;call SWI that follows
 SWI     XOS_CallEvery
 B       _exit

 ._OS_Claim
 BL      hv_pre_SWI_veneer			;call SWI that follows
 SWI     XOS_Claim

 ._exit
 LDR     R1, [R7, #vector_table.counter]	;increase the claim counter
 BVC     _ok
						;claim failed
 TEQ     R1, #0					;any previous claimants?
 STREQ   R1, [R7, #vector_table.entry_code]	;NO, free claim then
; STREQ   R1, [R7, #vector_table.type]		;need to retain these for error reporting
; STREQ   R1, [R7, #vector_table.parameter]
; STREQ   R1, [R7, #vector_table.private]
 STREQ   R1, [R7, #vector_table.taskID]
 B       _failed_return

 ._ok
 ADD     R1, R1, #1
 STR     R1, [R7, #vector_table.counter]

 ._failed_return
 BL      post_SWI_veneer
 LDR     R1, [R7, #vector_table.original_code]	;restore original address

 BL      dontexit_SWI_veneer
 LDMFD   R13!, {R6-R10}
B       hv_exit_SWI_veneer			;return to original caller




;hv_OS_AddCallBack
;-----------------
;Hypervize OS_AddCallBack
;
;Entry:
; R11 - SWI # << 12
; R12 - pointer to pre_SWI_veneer block
; R0  - Address to call
; R1  - R12 value

.hv_OS_AddCallBack				;PRM1-324
 STMFD   R13!, {R7-R8, R10}

 BL      return_taskID				;R10=taskID
 LDR     R7, jit_claimed_vectors		;check for duplicate claim
 MOV     R8, #max_vectors_to_track
 ._L1						;find a free vector slot
   LDR     R14, [R7, #vector_table.original_code]
   TEQ     R14, R0				;does the entry match
   LDREQ   R14, [R7, #vector_table.private]	;YES,
   TEQEQ   R14, R1				; |  does the R12 value match?
   LDREQ   R14, [R7, #vector_table.type]	; |  does the type match
   TEQEQ   R14, #&54 << 12			;     |
   LDREQ   R14, [R7, #vector_table.taskID]	;    YES,
   TEQEQ   R14, R10				;     |  does the taskID match?
   LDREQ   R0, [R7, #vector_table.entry_code]	;     |   get the managed entry
   BEQ     _already_exists			;     |+  skip vector allocation

   ADD     R7, R7, #vector_table.size
   SUBS    R8, R8, #1
 BNE     _L1

 LDR     R7, jit_claimed_vectors
 SUB     R7, R7, #vector_table.size
 MOV     R8, #max_vectors_to_track
 ._L2						;find a free vector slot
   ADD     R7, R7, #vector_table.size
   LDR     R14, [R7, #vector_table.entry_code]
   TEQ     R14, #0
   SUBNES  R8, R8, #1
 BNE     _L2

 TEQ     R8, #0
 MOVEQ   R12, #&12				;NO, ADFF5012
 LDMEQFD R13!, {R7-R8, R10}			; |
 BEQ     hv_report_unimplemented		; |+ report

 STR     R11, [R7, #vector_table.type]		;store the claim for cleaning up
 STR     R1, [R7, #vector_table.private]

 STR     R0, [R7, #vector_table.original_code]	;original entry point
 LDR     R14, Vector_Claim_Handlers		;our managed entries
 RSB     R8, R8, #max_vectors_to_track		;R8=our vector handler#
 ADD     R0, R14, R8, LSL #4			;4 instructions per handler
 STR     R0, [R7, #vector_table.entry_code]	;store the claim for cleaning up
 STR     R10, [R7, #vector_table.taskID]

 ._already_exists
 BL      pre_SWI_veneer				;call SWI that follows
 SWI     XOS_AddCallBack
 BL      post_SWI_veneer
 LDR     R8, [R7, #vector_table.counter]	;increase the claim counter
 BVC     _ok
						;claim failed
 TEQ     R8, #0					;any previous claimants?
 STREQ   R8, [R7, #vector_table.entry_code]	;NO, free claim then
 STREQ   R8, [R7, #vector_table.type]
 STREQ   R8, [R7, #vector_table.parameter]
 STREQ   R8, [R7, #vector_table.private]
 STREQ   R8, [R7, #vector_table.taskID]
 STREQ   R8, [R7, #vector_table.original_code]
 B       _failed_return

 ._ok
 ADD     R8, R8, #1
 STR     R8, [R7, #vector_table.counter]
 LDR     R0, [R7, #vector_table.original_code]	;restore original address

 ._failed_return
 BL      dontexit_SWI_veneer
 LDMFD   R13!, {R7-R8, R10}
B       hv_exit_SWI_veneer			;return to original caller




;hv_OS_Release
;-------------
;Changes code address to hypervised entry
;
;Entry:
; R0  - vector number
; R1  - address of routine
; R2  - value given in R2 when claimed
; R12 - pointer to pre_SWI_veneer block

.hv_OS_Release					;PRM1-68
 STMFD   R13!, {R1, R7-R8, R10}			;preserve R1, R7-R8
 BL      return_taskID				;R10=taskID
 LDR     R7, jit_claimed_vectors
 MOV     R8, #max_vectors_to_track
 ._L1						;find the matching claim
   LDR     R14, [R7, #vector_table.original_code]
   TEQ     R14, R1
   LDREQ   R14, [R7, #vector_table.parameter]
   TEQEQ   R14, R0
   LDREQ   R14, [R7, #vector_table.private]
   TEQEQ   R14, R2
   LDREQ   R14, [R7, #vector_table.taskID]
   TEQEQ   R14, R10
   ADDNE   R7, R7, #vector_table.size		;go to next vector
   SUBNES  R8, R8, #1				;is it the last?
 BNE     _L1					;NO

 TEQ     R8, #0					;did we find the vector
 LDMEQFD R13!, {R1, R7-R8, R10}			;NO,
 #if JIT_report_unknown_vectors == 1
   MOVEQ   R12, #4				;NO, ADFF5004
   BEQ     hv_report_unimplemented		; |+ report
 #endif
 ADREQ   R0, error_bad_vector_release		; |
 BEQ     hv_exit_SWI_veneer_VS			; |+ report "Bad vector release"

 LDR     R1, [R7, #vector_table.counter]	;decrease the claim counter
 SUBS    R1, R1, #1
 LDR     R8, [R7, #vector_table.entry_code]
 STRPL   R1, [R7, #vector_table.counter]
 STREQ   R1, [R7, #vector_table.original_code]	;allow the slot to be reused
 STREQ   R1, [R7, #vector_table.entry_code]
 STREQ   R1, [R7, #vector_table.type]
 STREQ   R1, [R7, #vector_table.taskID]

 MOV     R1, R8					;get our entry address
 BL      hv_pre_SWI_veneer			;call SWI that follows
 SWI     XOS_Release
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
 LDMFD   R13!, {R1, R7-R8, R10}
B       hv_exit_SWI_veneer			;return to original caller




;hv_OS_RemoveTickerEvent
;-----------------------
;Changes code address to hypervised entry
;
;Entry:
; R12 - pointer to pre_SWI_veneer block

.hv_OS_RemoveTickerEvent			;PRM1-445
 STMFD   R13!, {R0, R7-R8, R10}			;preserve R7-R8
 BL      return_taskID				;R10=taskID
 LDR     R7, jit_claimed_vectors
 MOV     R8, #max_vectors_to_track
 ._L1						;find the matching claim
   LDR     R14, [R7, #vector_table.original_code]
   TEQ     R14, R0				;does the address match?
   LDREQ   R14, [R7, #vector_table.private]	;YES,
   TEQEQ   R14, R1				; |  does R12 value match?
   LDREQ   R14, [R7, #vector_table.taskID]	;        YES,
   TEQEQ   R14, R10				;         |+ does the taskID match?
   BNE     _ignore_type				; |+ NO
   LDR     R14, [R7, #vector_table.type]	;YES
   TEQ     R14, #&3B << 12			;is it an OS_CallAfter?
   TEQNE   R14, #&3C << 12			;is it an OS_CallEvery?

   ._ignore_type
   ADDNE   R7, R7, #vector_table.size
   SUBNES  R8, R8, #1				;is it the last?
 BNE     _L1					;NO

 TEQ     R8, #0					;did we find the vector
 #if JIT_report_unknown_vectors == 1
   MOVEQ   R12, #4				; | ADFF5004
   LDMEQFD R13!, {R0, R7-R8, R10}		; |
   BEQ     hv_report_unimplemented		; |+ report
 #endif
 BEQ     _exit					;NO, trigger error

 LDR     R8, [R7, #vector_table.counter]	;decrease the claim counter
 SUBS    R8, R8, #1
 LDR     R0, [R7, #vector_table.entry_code]	;get our new entry address
 STRPL   R8, [R7, #vector_table.counter]
 STREQ   R8, [R7, #vector_table.original_code]	;allow the slot to be reused
 STREQ   R8, [R7, #vector_table.entry_code]
 STREQ   R8, [R7, #vector_table.type]
 STREQ   R8, [R7, #vector_table.taskID]

 ._exit
 BL      pre_SWI_veneer				;call SWI that follows
 SWI     XOS_RemoveTickerEvent			;doesn't return an error
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
 ADDVS   R13, R13, #4
 LDMVSFD R13!, {R7-R8, R10}
 LDMVCFD R13!, {R0, R7-R8, R10}
B       hv_exit_SWI_veneer




;hv_OS_RemoveCallBack
;-----------------------
;Changes code address to hypervised entry
;
;Entry:
; R12 - pointer to pre_SWI_veneer block

.hv_OS_RemoveCallBack				;PRM1-327
 STMFD   R13!, {R7-R8, R10}			;preserve R7-R8
 BL      return_taskID				;R10=taskID
 LDR     R7, jit_claimed_vectors
 MOV     R8, #max_vectors_to_track
 ._L1						;find the matching claim
   LDR     R14, [R7, #vector_table.original_code]
   TEQ     R14, R0				;does the address match?
   LDREQ   R14, [R7, #vector_table.private]	;YES,
   TEQEQ   R14, R1				; |+  does the R12 value match?
   LDREQ   R14, [R7, #vector_table.type]	;     |+ YES,
   TEQEQ   R14, #&54 << 12			;         |  is it a callback?
   LDREQ   R14, [R7, #vector_table.taskID]	;        YES,
   TEQEQ   R14, R10				;         |+ does the taskID match?
   ADDNE   R7, R7, #vector_table.size
   SUBNES  R8, R8, #1				;is it the last?
 BNE     _L1					;NO

 TEQ     R8, #0					;did we find the vector
 BEQ     _exit					;NO, generate error

 MOV     R8, #0					;clear callback
 STR     R8, [R7, #vector_table.counter]
 LDR     R0, [R7, #vector_table.entry_code]	;get our new entry address
 STR     R8, [R7, #vector_table.entry_code]	;allow the slot to be used
 STR     R8, [R7, #vector_table.type]
 STR     R8, [R7, #vector_table.taskID]

 ._exit
 BL      pre_SWI_veneer				;call SWI that follows
 SWI     XOS_RemoveCallBack			;doen't return an error
 BL      post_SWI_veneer
 LDRVC   R0, [R7, #vector_table.original_code]	;restore original address
 STRVC   R8, [R7, #vector_table.original_code]	;allow the slot to be used
 BL      dontexit_SWI_veneer
 LDMFD   R13!, {R7-R8, R10}
B       hv_exit_SWI_veneer



;hv_OS_GetEnv
;------------
;Reduces RAM limit to below the JIT space
;
;Entry:
; R12 - pointer to pre_SWI_veneer block
;
;Exit:
; R0  - pointer to environment string
; R1  - permitted RAM limit (ie highest address +1)
; R2  - pointer to real time the program was started

.hv_OS_GetEnv					;PRM1-301
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_GetEnv
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
 LDR     R1, pre_JIT_wimp_slot_size	;new end of appspace
 ADD     R1, R1, #&8000			;correct value
B       hv_exit_SWI_veneer




;hv_OS_SetEnv
;------------
;Prevents the RAM limit from being reduced
;
;Entry:
; R0  - pointer to exit handler, or 0 to read
; R1  - permitted RAM limit (ie highest address +1), or 0 to read
; R4  - pointer to undefined instruction handler, or 0 to read
; R5  - pointer to prefetch abort handler, or 0 to read
; R6  - pointer to data abort handler, or 0 to read
; R7  - pointer to address exception handler, or 0 to read
; R12 - pointer to pre_SWI_veneer block
;
;Exit:
; R0  - pointer to previous exit handler                     (env 11)
; R1  - previous permitted RAM limit (ie highest address +1) (env 0)
; R4  - pointer to previous undefined instruction handler    (env 1)
; R5  - pointer to previous prefetch abort handler           (env 2)
; R6  - pointer to previous data abort handler               (env 3)
; R7  - pointer to previous address exception handler        (env 4)

.hv_OS_SetEnv					;PRM1-305
 STMFD   R13!, {R2-R3}

 LDR     R14, pre_JIT_wimp_slot_size	;return correct slotsize
 ADD     R14, R14, #&8000		;correct value
 STR     R14, [R13, #-4]!		;stack now: R1-R3, {SWI stack}
 TEMP    R2
 TEQ     R1, #0				;set RAM limit?
 SUBNE   R1, R1, #&8000			;YES, correct value
 STRNE   R1, pre_JIT_wimp_slot_size	; |+  update slot size
 LOCK    R2

 MOV     R2, #0
 MOV     R1, R0
 MOV     R0, #11			;Exit handler
 BL      change_environment_handler
 STR     R1, [R13, #-4]!		;old handler, stack now: R0-R3, {SWI stack}

 MOV     R2, #0
 MOV     R1, R4
 MOV     R0, #1				;Undefined instruction handler
 BL      change_environment_handler
 MOV     R4, R1				;old handler

 MOV     R2, #0
 MOV     R1, R5
 MOV     R0, #2				;Prefetch abort handler
 BL      change_environment_handler
 MOV     R5, R1				;old handler

 MOV     R2, #0
 MOV     R1, R6
 MOV     R0, #3				;Data abort handler
 BL      change_environment_handler
 MOV     R6, R1				;old handler

 MOV     R2, #0
 MOV     R1, R7
 MOV     R0, #4				;Address exception handler
 BL      change_environment_handler
 MOV     R7, R1				;old handler
EXITSWI "R0-R3"




;hv_OS_ChangeEnvironment
;-----------------------
;Prevents the RAM limit from being reduced
;
;Entry:
; R0  - handler number
; R1  - pointer to new handler, or 0 to read
; R2  - value of R12 passed to handler, or 0 to read
; R3  - pointer to buffer (if appropriate), or 0 to read
; R12 - pointer to pre_SWI_veneer block
;
;Exit:
; R0  - preserved
; R1  - pointer to previous handler
; R2  - R12 value passed to previous handler
; R3  - pointer to previous buffer

.hv_OS_ChangeEnvironment			;PRM1-320
 BL      change_environment_handler
EXITSWI ""




;hv_OS_BreakCtrl
;---------------
;manages changes to the BreakPoint handler
;
;Entry:
; R0  - pointer to BreakPoint register block, or 0 to read
; R1  - pointer to BreakPoint handler, or 0 to read
; R12 - pointer to pre_SWI_veneer block
;
;Exit:
; R0  - pointer to previous BreakPoint register save block (env 8)
; R1  - pointer to previous BreakPoint handler             (env 8)

.hv_OS_BreakCtrl					;PRM1-310
 STMFD   R13!, {R2-R3}
 MOV     R3, R0				;buffer
 MOV     R2, #0				;R12 value
 MOV     R0, #8
 BL      change_environment_handler
 MOV     R0, R3
EXITSWI "R2-R3"




;hv_OS_CallBack
;-----------------
;Hypervize OS_CallBack
;
;Entry:
; R0  - pointer to CallBack register save block, or 0 to read
; R1  - pointer to CallBack handler, or 0 to read
; R12 - pointer to pre_SWI_veneer block
;
;Exit:
; R0  - pointer to previous CallBack register save block  (env 7)
; R1  - pointer to previous CallBack handler              (env 7)

.hv_OS_CallBack					;PRM1-307
 STMFD   R13!, {R2-R3}			;preserve R2, R3
 MOV     R3, R0				;buffer address
 MOV     R2, #0				;no R12 value
 MOV     R0, #7				;CallBack handler
 BL      change_environment_handler
 MOV     R0, R3				;R0=register save block
EXITSWI "R2-R3"




;hv_OS_Control
;-------------
;manages changes to Error, Escape and Event handlers
;
;Entry:
; R0  - pointer to error handler, or 0 to read
; R1  - pointer to error buffer, or 0 to read
; R2  - pointer to escape handler, or 0 to read
; R3  - pointer to event handler, or 0 to read
; R12 - pointer to pre_SWI_veneer block
;
; Exit:
; R0  - pointer to previous error handler  (env 6)
; R1  - pointer to previous error buffer   (env 6)
; R2  - pointer to previous escape handler (env 9)
; R3  - pointer to previous event handler  (env 10)

.hv_OS_Control					;PRM1-299
 STMFD   R13!, {R2-R3, R4-R6}		;preserve plus space for return R0-R2
 MOV     R3, R1				;Error buffer (256 bytes)
 MOV     R2, #0
 MOV     R1, R0
 MOV     R0, #6				;Error handler
 BL      change_environment_handler
 STR     R1, [R13, #2 * 4]		;overwrite R4, R5 on stack
 STR     R3, [R13, #3 * 4]

 LDR     R1, [R13], #4			;pull R2 from stack
 MOV     R2, #0
 MOV     R0, #9 			;Escape handler
 BL      change_environment_handler
 STR     R1, [R13, #3 * 4]		;overwrite R6 on stack

 LDR     R1, [R13], #4			;pull R3 from stack
 MOV     R2, #0
 MOV     R0, #10			;Event handler
 BL      change_environment_handler
 MOV     R3, R1
EXITSWI "R0-R2"




;hv_OS_Module
;------------
;Checks for module loads
;
;Entry:
; R12 - pointer to pre_SWI_veneer block

.hv_OS_Module					;PRM1-228
 TEQ     R0, #Module_Claim
 BEQ     _claim
 TEQ     R0, #Module_Free
 BEQ     _free
 TEQ     R0, #Module_ExtendBlock
 BEQ     _extend
 TEQ     R0, #Module_Lookup
 BEQ     _lookup			;point to 26bit Module (K.V.)

 TEQ     R0, #Module_InsertFromMemory
 TEQNE   R0, #Module_InsertFromMemoryToRMA
 TEQNE   R0, #Module_Run
 TEQNE   R0, #Module_Load
 BEQ     load_26bit_module

 BL      hv_pre_SWI_veneer		;call SWI that follows
 SWI     XOS_Module			;PRM1-228
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
B       hv_exit_SWI_veneer


;Entry:
; R2 - pointer to block
; R3 - change in size in bytes

 ._extend				;PRM1-244
 STMFD   R13!, {R0-R1}			;preserve R0-R1
 MOV     R0, #Heap_Extend
 B       _heap_operation


;Entry:
; R3 - size to claim

 ._claim				;PRM1-237
 STMFD   R13!, {R0-R1}			;preserve R0-R1
 MOV     R0, #Heap_Claim
 CMP     R3, #32
 MOVLO   R3, #32			;ensure block matches RMA minimum size
 ._heap_operation
 MOV     R1, #jit_RMA_heap
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_Heap			;PRM1-379
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
 STRVS   R0, [R13]
 LDMFD   R13!, {R0-R1}
B       hv_exit_SWI_veneer


;Entry:
; R2 - pointer to block

 ._free					;PRM1-238
 STMFD   R13!, {R0-R4}			;preserve registers
 MOV     R0, #Heap_BlockSize
 MOV     R1, #jit_RMA_heap
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_Heap			;PRM1-383
 BVS     _free_error			;exit if it's invalid
 MOV     R4, R3				;size of block

 MOV     R0, #Heap_Free
 SWI     XOS_Heap			;PRM1-380
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
 BLVC    hv_reset_memory_block		;flush any instructions in it
 LDMFD   R13!, {R0-R4}
B       hv_exit_SWI_veneer

 ._free_error
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
 ADD     R13, R13, #4			;drop R0
 LDMFD   R13!, {R1-R4}
B       error_SWI

;Entry:
; R1 - pointer to Module name

 ._lookup
 TEMP    R14
 LDR     R11, emulate_RISCOS
 LOCK    R14
 CMP     R11, #&200 << 8			;RO 2.01 or newer?
 BLS     _lookup_ok				;NO
 CMP     R11, #&500 << 8			;RO 5.00+
 BHS     _lookup_ok				;YES
 STMFD   R13!, {R0, R2-R3}			;check for ARM3Support or ARM
 CMP     R11, #&350 << 8			;RO 2.01 to 3.49?
 BHS     _lookup_arm				;NO

 ADR     R11, _ARM3Support
 MOV     R2, #11
 BL      _strcmp

 ._exit_valid
 LDMFD   R13!, {R0, R2-R3}
 MOV     R1, #0					;point at the kernel Module
 MOV     R2, #0					;instance 0
B       hv_vector_handler_trap

 ._lookup_arm
 ADR     R11, _ARM
 MOV     R2, #3
 BL      _strcmp
 B       _exit_valid

 ._strcmp
   LDRB    R0, [R11, R2]
   LDRB    R3, [R1, R2]
   ORR     R3, R3, #32
   TEQ     R3, R0
   LDMNEFD R13!, {R0, R2-R3}
   BNE     _lookup_ok
   SUBS    R2, R2, #1
 BPL     _strcmp
 MOV     PC, R14

 ._ARM3Support	DCB "arm3support", 32
 ._ARM		DCB "arm", 32

 ._lookup_ok
 BL      pre_SWI_veneer				;call SWI that follows
 SWI     XOS_Module
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
 BVS     error_SWI				;exit on error

 LDR     R11, [R3, #Module_Header.ADFFS]
 EORS    R11, R11, #Module_Validation		;one of ours?
 LDREQ   R3, [R3, #Module_Header.Address]	;YES, get 26bit address
EXITSWI ""




;hv_Wimp_SlotSize
;----------------
;prevents appspace from being reduced
;
;Entry:
; R0 - new current slot size
; R1 - new next slot size
; R12 - pointer to pre_SWI_veneer block
;
;Exit:
; R0 - current slot size
; R1 - next size
; R2 - free size

.hv_Wimp_SlotSize				;PRM3-203
 CMN     R0, #1				;read or set current slot?
 BEQ     _skip

 LDR     R2, current_PageSize
 SUB     R2, R2, #1			;pagesize bitmask
 ADD     R0, R0, R2
 BIC     R0, R0, R2			;round slotsize up
 MOV     R2, #jit_allocate_memory - &8000	;Appspace limit
 CMP     R0, R2				;cap to our max
 MOVHI   R0, R2
 TEMP    R2
 STR     R0, pre_JIT_wimp_slot_size	;set - update slot size
 LOCK    R2

 ._skip
 MVN     R0, #0				;read size
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XWimp_SlotSize
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer

 LDR     R0, pre_JIT_wimp_slot_size	;return size app requested
 RSB     R2, R0, #jit_allocate_memory	;cap free pool to our max
B       hv_exit_SWI_veneer




;hv_OS_ClaimDeviceVector
;-----------------------
;emulates IOC devices
;
;Entry:
; R12 - pointer to pre_SWI_veneer block

.hv_OS_ClaimDeviceVector			;PRM1-113
 TEQ     R0, #IOC_VSync_Pulse		;check it's a device we support
 TEQNE   R0, #IOC_Timer_0
 TEQNE   R0, #IOC_Timer_1
 TEQNE   R0, #IOC_SSBC			;Sound System Buffer Change (Rockfall)
 MOVNE   R12, #3			;ADFF5003
 BNE     hv_report_unimplemented	;NO, report it

 STMFD   R13!, {R10}
 BL      return_taskID			;R10=taskID
 ADR     R12, DeviceVectors
 ADD     R12, R12, R0, LSL #4		;go to device offset in table
 STR     R1, [R12, #device_table.original_code]
 ADD     R14, R1, #jit_code_start	;correct entry address
 STR     R14, [R12, #device_table.entry_code]
 STR     R2, [R12, #device_table.private]
 STR     R10, [R12, #device_table.taskID]
EXITSWI "R10"				;return to original caller




;hv_OS_ReleaseDeviceVector
;-------------------------
;emulates IOC devices
;
;Entry:
; R12 - pointer to pre_SWI_veneer block

.hv_OS_ReleaseDeviceVector			;PRM1-125
 TEQ     R0, #IOC_VSync_Pulse		;check it's a device we support
 TEQNE   R0, #IOC_Timer_0
 TEQNE   R0, #IOC_Timer_1
 TEQNE   R0, #IOC_SSBC			;Sound System Buffer Change (Rockfall)
 MOVNE   R12, #3			;ADFF5003
 BNE     hv_report_unimplemented	;NO, report it

 ADR     R12, DeviceVectors
 ADD     R12, R12, R0, LSL #4		;go to device offset in table
 MOV     R14, #0
 STR     R14, [R12, #device_table.entry_code]
 STR     R14, [R12, #device_table.original_code]
 STR     R14, [R12, #device_table.taskID]

 #if compile_IOMD == 1
   EXITSWI ""		;return to original caller
 #endif
 #if compile_IOMD == 0
   MOV     R14, #1
   MOV     R14, R14, LSL R0		;R14=IRQ mask bit
   STR     R0, [R13, #-4]!		;preserve R0
   ADR     R0, IOC_registers

   CMP     R14, #1 << 8			;IRQA or IRQB mask?
   LDRLO   R12, [R0, #IOC_IRQA_mask]
   BICLO   R12, R12, R14		;turn off the IRQ
   STRLO   R12, [R0, #IOC_IRQA_mask]
   LDRHS   R12, [R0, #IOC_IRQB_mask]
   BICHS   R12, R12, R14, LSR #8	;turn off the IRQ
   STRHS   R12, [R0, #IOC_IRQB_mask]
  EXITSWI "R0"		;return to original caller
 #endif




;hv_OS_ClaimScreenMemory
;-----------------------
;Allows space screen memory in RO3.1 address space to be claimed
;
;Entry:
; R0 = 0 for release, 1 for claim
; R1 = length required in bytes if R0=1
;
;Exit:
; C flag clear if claim successful
;	R1 = length available
;	R2 = start address
; C flag set if claim failed
;	R1 = length that is available

.hv_OS_ClaimScreenMemory			;PRM1-388
 TEQ     R0, #0				;release memory
 BEQ     _exit

 MRS     R14, SPSR
 BIC     R14, R14, #1 << 29		;clear C
 MSR     SPSR_all, R14

 MOV     R2, #&2000000
 SUB     R2, R2, R1			;just give the app what it wants
 ._exit
EXITSWI ""				;return to original caller




;hv_Wimp_ClaimFreeMemory
;-----------------------
;Allocates the Wimp Free pool
;
;Entry:
; R0 = 0 for release, 1 for claim
; R1 = length required in bytes if R0=1
;
;Exit:
; R0 = corrupt
; R1 = amount available (0 if none/already claimed)
; R2 = start address (0 if claim failed because not enough memory)

.hv_Wimp_ClaimFreeMemory			;PRM3-208
 MOV     R1, #0
 MOV     R2, #0				;silently fail
EXITSWI ""				;return to original caller




;hv_Sound_LinearHandler
;----------------------
;Manages 16bit linear handler entries
;
;Entry:
; R0 = 1 if registering/unregistering a handler

.hv_Sound_LinearHandler				;PRM5a-605
 BL      no_such_SWI_below_RO350	;SWI only applicable on RISCOS 3.5+
 TEQ     R0, #1				;PRM5a-608
 BNE     _exit

 TEQ     R1, #0				;registering a handler?
 STREQ   R1, linear_handler_entry
 BEQ     _exit				;NO, unregistering it

 CMP     R1, #jit_appspace_end		;is it in appspace?
 ADDLO   R1, R1, #jit_code_start	;YES, change to JIT appspace
 STRLO   R1, linear_handler_entry	; |   store entry
 ADRLO   R1, _our_linear_handler_entry  ; |+  switch to our entry
 MOVHI   R14, #0			;NO, clear handler
 STRHI   R14, linear_handler_entry

 ._exit
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XSound_LinearHandler
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
B       hv_exit_SWI_veneer

 ._our_linear_handler_entry
 STMFD   R13!, {R0-R1, R14}		;stack return
 LDR     R14, jit_managed_ldr_pc_r13	;change to return into appspace
 MRS     R0, CPSR
 AND     R1, R0, #&F0000003		;flags and CPU mode
 AND     R0, R0, #%11 << 6
 ORR     R14, R14, R1
 ORR     R14, R14, R0, LSL #20		;FIQ/IRQ
 LDMFD   R13!, {R0-R1}
 LDR     PC, linear_handler_entry	;call handler

 .linear_handler_entry DCD 0




;hv_Sound_Mode
;-------------
;Returns 8bit only when emulating RO3.11
;
;Entry:
; R0 = 0 if querying sound capabilities
;
;Exit:
; R0 = 0 for 8bit and 1 for 16bit sound
; R1 = 0

.hv_Sound_Mode					;PRM5a-603
 BL      no_such_SWI_below_RO350	;SWI only applicable on RISCOS 3.5+

; TEQ     R0, #0
; BNE     _exit
; MOV     R1, #0			;return 8bit only for RO3.5+
; B       hv_vector_handler_trap
;
; ._exit
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XSound_Mode
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
B       hv_exit_SWI_veneer




;hv_Sound_InstallVoice (PRM4-13 / PRM4-29)
;---------------------
;Changes Voice Generators to be in JIT space
;
;Entry:
; R0     - pointer to Voice Generator or <4 for reason code
; R1     - voice slot
; R2     - pointer to Voice Generator if R0=1
; R12    - pointer to CPSR block
; hv_R14 - +4 = codelet
;
;Exit:
; as per PRM

.hv_Sound_InstallVoice				;PRM4-29
 STMFD   R13!, {R5-R9}			;preserve registers

 CMP     R0, #4				;is it a reason code?
 MOVHI   R7, R0				;NO, R7=pointer to Voice Generator
 MOVHI   R8, #0				; |  R8=register to update
 BHI     _hypervise			; |+ must be a Voice Generator address

	;(0,0 used by COPS / 0,n used by Alien Invasion)
 TEQ     R0, #1				;Sound_InstallVoice 1
 BNE     _exit				;NO, pass on

 MOV     R7, R2				;R7=pointer to Voice Generator
 MOV     R8, #2				;R8=register to update

 ._hypervise
 CMP     R7, #jit_code_start		;is it within App Space
 BHI     _exit				;NO

 TEQ     R1, #0				;do we know the slot?
 BNE     _know_slot			;YES

					;find a free slot
 ADR     R0, our_temp_voice_generator	;use our temp VG
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XSound_InstallVoice		;PRM4-29
 BL      post_SWI_veneer

 TEQ     R1, #0				;is there a free slot?
 BNE     _P1				;YES
 BL      dontexit_SWI_veneer
 LDMFD   R13!, {R5-R9}			;NO, preserve registers and exit
 B       hv_exit_SWI_veneer

 ._P1
 BL      pass_SWI_on			;pass next SWI to SWI dispatch
 SWI     XSound_RemoveVoice
 BL      dontexit_SWI_veneer

 ._know_slot
 ADR     R5, hv_voice_generators - sound_voice_handler.Size	;our Voice Generator table
 ADD     R5, R5, R1, LSL #sound_voice_handler_shift	;R5 = our Voice Generator

 TEQ     R8, #0				;point VG to our one
 MOVEQ   R0, R5				;update R0
 MOVNE   R2, R5				;update R2

 STR     R7, [R5, #sound_voice_handler.voicegenerator]
 LDR     R9, [R7, #sound_voice_handler.voicename] ;R9=offset to voicename
 CMP     R9, #&100000			;(fix for 2067BC) sensible value?
 BLO     _P2				;keep
 CMN     R9, #&100000			;(fix for BloodLust Uh Module)
 BGT     _P2				;keep
 LDR     R9, [R7, #sound_voice_handler.install]	; |  NO, try previous word
 CMP     R9, #&100000			; |  sensible value?
 BHI     _exit				; |+ NO..it's missing entry points
 ._P2
 ADD     R9, R9, R7			;R9=address of voicename
 ADD     R6, R5, #sound_voice_handler.name	;R6=address of our voicename

 MOV     R5, #31			;max 31 chars
 ._L2
   LDRB    R14, [R9], #1		;copy voice name
   TEQ     R14, #0
   STRNEB  R14, [R6], #1
   SUBNES  R5, R5, #1			;make sure we don't overrun buffer
 BNE     _L2
 MOV     R14, #0
 STRB    R14, [R6]			;terminate voice name

 ._exit
 LDMFD   R13!, {R5-R9}
					;Sound_InstallVoice can call user code
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XSound_InstallVoice
 BL      post_SWI_veneer
B       hv_exit_SWI_veneer




;hv_Sound_RemoveVoice (PRM4-35)
;---------------------
;Clears our Voice Generator table entry
;
;Entry:
; R1     - voice slot to remove
; R12    - pointer to CPSR block
; hv_R14 - +4 = codelet
;
;Exit:
; as per PRM

.hv_Sound_RemoveVoice				;PRM4-35
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XSound_RemoveVoice
 MOVVS   R1, #0				;ensure R1=0 and V is clear on error
 CMNVS   R1, #0
 CMPVS   R1, #0
 BL      post_SWI_veneer		;does not return an error
 BL      dontexit_SWI_veneer
 TEQ     R1, #0				;did removal succeed?
 BEQ     _exit				;NO, exit

 ADR     R14, hv_voice_generators - sound_voice_handler.Size	;our Voice Generator table
 ADD     R14, R14, R1, LSL #sound_voice_handler_shift	;R14 = our Voice Generator

 LDR     R12, [R14, #sound_voice_handler.voicegenerator]
 TEQ     R12, #0			;is it our voice?
 LDRNE   R0, [R12, #sound_voice_handler.voicename]	;YES, R12=offset to voicename
 ADDNE   R0, R12, R0			; |   R0=original voice name address

 MOVNE   R12, #0			; |   clear voice generator
 STRNE   R12, [R14, #sound_voice_handler.voicegenerator]	; |+
 ._exit
EXITSWI ""




;hv_Sound_QSchedule
;------------------
;Ensures X bit is set if an SWI is scheduled
;
;Entry:
; R1 > 0 if SWI scheduled, R1=SWI

.hv_Sound_QSchedule				;PRM4-48
 CMP     R1, #0
 ORRNE   R1, R1, #swi_X_bit		;ensure X bit is set

 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XSound_QSchedule
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
B       hv_exit_SWI_veneer




;hv_OS_Memory
;------------
;Returns the correct address for VIDC1 or VIDC20
;
;Entry:
; R0 - 9 (Read controller presence)
; R1 - bits 8 - 31  controller type:
;                   2 - VIDC1
;                   3 - VIDC20
;Exit:
; R1 - controller base address

.hv_OS_Memory					;PRM5a-70
 BL      no_such_SWI_below_RO350	;SWI only applicable on RISCOS 3.5+

 TEQ     R0, #9
 BNE     _exit

 AND     R14, R1, #&FF00
 TEQ     R14, #2 << 8			;VIDC1?
 MOVEQ   R1, #0				;YES, doesn't exist on RO3.5
 BEQ     hv_vector_handler_trap		; |+ exit

 TEQ     R14, #3 << 8			;VIDC20?
 MOVEQ   R1, #VIDC20_base_addr		;emulate RO3.5
 BEQ     hv_vector_handler_trap		; |+ exit

 ._exit
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_Memory
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
B       hv_exit_SWI_veneer




;hv_OS_ReadMemMapInfo
;-----------------
;Returns max RAM we support

.hv_OS_ReadMemMapInfo				;PRM1-391
 ADR     R12, VARS
 LDR     R11, [R12, #emulate_RISCOS - VARS]
 CMP     R11, #&350 << 8		;RO 3.50 or newer?
 MOVHS   R0, #4096			;YES, page size
 MOVHS   R1, #jit_appspace_end/4096	; |+ no. of pages
 MOVLO   R0, #32768			;NO, page size
 MOVLO   R1, #256			; |+ no. of pages
EXITSWI ""




;hv_OS_ReadSysInfo
;-----------------
;Return the currect monitor type for OS_ReadSysInfo 1
;
;Entry:
; R0  - reason code
; R12 - pointer to pre_SWI_veneer block

.hv_OS_ReadSysInfo					;PRM1-746
 #if compile_GPU == 1
   TEQ     R0, #1			;read configured Mode
   BEQ     _reason_1
 #endif
 TEQ     R0, #2				;chip info
 BEQ     _reason_2

 TEQ     R0, #6
 BNE     _not_6

 BL      task_page_zero_R11
 TEQ     R2, #78			;CLib requesting CLibCounter
 ADDEQ   R2, R11, #page_zero_CLibCounter	;YES
 BEQ     hv_vector_handler_trap		; |+ point to our address
 TEQ     R2, #79			;CLib requesting RISCOSLibWord (FEC)
 ADDEQ   R2, R11, #page_zero_RISCOSLibWord	;YES
 BEQ     hv_vector_handler_trap		; |+ point to our address
 TEQ     R2, #80			;CLib requesting CLibWord (FF0)
 ADDEQ   R2, R11, #page_zero_CLibWord	;YES
 BEQ     hv_vector_handler_trap		; |+ point to our address
 ._not_6

 CMP     R0, #4				;no reason codes >3 pre RO5
 LDRHS   R11, emulate_RISCOS
 CMPHS   R11, #&500 << 8		;below RISCOS 5.0?
 ADRLO   R0, error_Unknown_OS_ReadSysInfo	;return error
 BLO     hv_exit_SWI_veneer_VS
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_ReadSysInfo
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
B       hv_exit_SWI_veneer

#if compile_GPU == 1
 ._reason_1
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_ReadSysInfo
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
 MOV     R1, #0				;monitor type
 MOV     R2, #0				;sync
B       hv_exit_SWI_veneer
#endif

 ._reason_2
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_ReadSysInfo
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer

 LDR     R0, emulate_RISCOS		;what are we emulating
 CMP     R0, #&350 << 8			;RO3.11 or lower
 MOVLO   R0, #0				;IOEB ASIC
 MOVLO   R1, #0				;82C710
 MOVHS   R0, #&01010100			;IOEB ASIC
 MOVHS   R1, #1				;82C710
 MOV     R2, #0				;LCD ASIC
B       hv_exit_SWI_veneer




;hv_OS_PlatformFeatures
;----------------------
;Not supported pre-RO5 (required for CLib)

.hv_OS_PlatformFeatures
 ADR     R0, error_SWI_not_known	;return error
B       hv_exit_SWI_veneer_VS




;hv_OS_ClaimProcessorVector
;--------------------------
;returns an error on RO3.11
;
;Entry:
; R0 - bit 0-7 Vector no
;      bit 8   0=release  1=claim
; R1 - address of handler
; R2 - address currently on vector (if releasing)
;
;Exit:
; R0 - preserved
; R1 - previous address
; R2 - preserved

.hv_OS_ClaimProcessorVector			;PRM5a-30
 BL      no_such_SWI_below_RO350	;SWI only applicable on RISCOS 3.5+

 AND     R12, R0, #&FF			;R12=vector no
 TEQ     R12, #1			;Unknown Instruction Vector?
 EXITSWIEQ ""				;YES, ignore it

 MOV     R12, #2			;ADFF5002
 B       hv_report_unimplemented	;NO, report it




;hv_OS_ServiceCall
;-----------------
;Handles certain Service calls
;
;Entry:
; R1  - operation

.hv_OS_ServiceCall					;PRM1-254
 TEQ     R1, #11			;Service_ReleaseFIQ
 TEQNE   R1, #12			;Service_ClaimFIQ
 TEQNE   R1, #71			;Service_ClaimFIQinBackground
 MOVEQ   R1, #0				;YES, claim service
 EXITSWIEQ ""				;exit

 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_ServiceCall
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
B       hv_exit_SWI_veneer




#if compile_RO > 400
;hv_OS_ReadLine
;--------------
;diverts calls to OS_ReadLine32

.hv_OS_ReadLine						;PRM1-941
 STR     R4, [R13, #-4]!		;preserve R4

 AND     R14, R0, #%11 << 30		;move flag from R0 to R4
 AND     R4, R4, #&FF
 ORR     R4, R4, R14
 BIC     R0, R0, #%11 << 30

 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_ReadLine32
 BL      post_SWI_veneerC		;retain C
 BL      dontexit_SWI_veneer
EXITSWI "R4"




;hv_OS_Heap
;----------
;ensures heap allocations are multiples of 8 in length (it went to 4 in RO5.18)
;and that returned address is word aligned
;ref. PRM1-361 for heap description

.hv_OS_Heap					;PRM1-375
 STR     R3, [R13, #-4]!		;preserve R3
 TEQ     R0, #2				;claim block?
 ADDEQ   R3, R3, #7 + 4			;YES, ensure length is multiple of 8
 BICEQ   R3, R3, #7			;matching pre-RO5.18 method
 SUBEQ   R3, R3, #4

 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_Heap
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer

 LDR     R3, [R13], #4			;restore R3
B       hv_exit_SWI_veneer
#endif




;hv_OS_HeapSort
;--------------
;Hypervises comparison routine if applicable
;
;Entry:
; R2 - type of object (0-5) or address of comparison routine

.hv_OS_HeapSort					;PRM1-970
 STR     R2, [R13, #-4]!		;preserve R2
 CMP     R2, #5
 BLS     _exit

 CMP     R2, #jit_appspace_end		;is it in application space?
 ADDLO   R2, R2, #jit_code_start	;YES, change to JIT appspace
 STRLO   R2, _entry			; |
 ADRLO   R2, _our_entry			; |+ and use our entry point

 ._exit
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_HeapSort
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
 LDR     R2, [R13], #4			;restore R2
B       hv_exit_SWI_veneer

 ._entry DCD 0
 ._our_entry
 STMFD   R13!, {R0-R1, R14}		;stack return
 LDR     R14, jit_managed_ldr_pc_r13	;change to return into appspace
 MRS     R0, CPSR
 AND     R1, R0, #&F0000003		;flags and CPU mode
 AND     R0, R0, #%11 << 6
 ORR     R14, R14, R1
 ORR     R14, R14, R0, LSL #20		;FIQ/IRQ
 LDMFD   R13!, {R0-R1}
 LDR     PC, _entry			;call handler




;hv_Wimp_StartTask
;-----------------
;Tracks Wimp task ID's

.hv_Filter_RegisterPre_PostFilter
.hv_Wimp_StartTask				;PRM3-174
 MOV     R12, #2			;NO, ADFF5002
 B       hv_report_unimplemented	; |+ report




;hv_Wimp_Initialise
;------------------
;Installs Pre/Post filters after task is initialised

.hv_Wimp_Initialise				;PRM3-85
 STMFD   R13!, {R2-R7}
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XADFFS_DoNothing

 BL      wimp_delink_application	;delink as we're about to be paged

 STMFD   R13!, {R0-R3}
 MOV     R0, #CAOPointer		;set CAO
 MOV     R1, #&8000			;to prevent memory shrinkage
 SWI     XOS_ChangeEnvironment		;PRM1-320
 MOV     R7, R1				;previous CAO
 LDMFD   R13!, {R0-R3}

 TEQ     R2, #0				;does it have a description
 ADREQ   R2, _ADFFS_Filter		;NO

 SWI     XWimp_Initialise
 BL      post_SWI_veneer
 MOV     R5, R0
 MOV     R3, R1				;R3=task handle
 MOVVS   R6, #1
 MOVVC   R6, #0
 BLVC    set_domain_WimpID		;link Wimp ID to domain

 MOV     R0, #CAOPointer		;set CAO
 MOV     R1, R7				;back to previous value
 SWI     XOS_ChangeEnvironment		;PRM1-320

 BL      wimp_relink_application	;relink as we're back

 TEQ     R6, #0
 BNE     _exit

 ADR     R0, _ADFFS_Filter		;filter name
 ADR     R1, _PreFilter			;filter code
 MOV     R2, #0				;value of R12
 SWI     XFilter_RegisterPreFilter	;PRM3-304
 ADR     R1, _PostFilter		;filter code
 MOV     R4, #0				;capture all events
 SWI     XFilter_RegisterPostFilter	;PRM3-306
 MOV     R1, R3

 ._exit
 MOV     R0, R5
 BL      dontexit_SWI_veneer
 TEQ     R6, #0
 LDMFD   R13!, {R2-R7}
 BNE     hv_exit_SWI_veneer_VS
B       hv_exit_SWI_veneer


 ._ADFFS_Filter	DCB "26bit_task", 0
 ALIGN


 ._PreFilter
 STMFD   R13!, {R14}
 BL      wimp_delink_application
 BL      unmap_screen_memory
; ORR     R0, R0, #1			;ignore NULL (breaks E-Type 2)
LDMFD   R13!, {PC}


 ._PostFilter
 STMFD   R13!, {R14}
 BL      map_screen_memory		;re-map the RO3.1 screen memory
 BL      wimp_relink_application
LDMFD   R13!, {PC}




;Remove_Wimp_Filters
;-------------------
;removes Wimp task filters
;
;Entry:
; R0 - task ID
 
 ._RemoveFilters
 STMFD   R13!, {R0-R4, R14}
 BL      clear_domain_WimpID		;unlink Wimp ID from domain
 MOV     R3, R0				;task ID
 ADR     R0, _ADFFS_Filter		;filter name
 ADR     R1, _PreFilter			;filter code
 MOV     R2, #0				;value of R12
 SWI     XFilter_DeRegisterPreFilter	;PRM3-308
 ADR     R0, _ADFFS_Filter		;filter name
 ADR     R1, _PostFilter		;filter code
 MOV     R4, #0				;capture all events
 SWI     XFilter_DeRegisterPostFilter	;PRM3-309
LDMFD   R13!, {R0-R4, PC}
#set Remove_Wimp_Filters = _RemoveFilters




.wimp_delink_application
 STMFD   R13!, {R0-R2, R7-R8, R12, R14}
 LDR     R12, jit_claimed_vectors
 MOV     R8, #max_vectors_to_track
 ._L1
   LDR     R14, [R12, #vector_table.entry_code]	;get the managed entry
   TEQ     R14, #0				;is it being used?
   BEQ     _P1					;NO

   LDR     R7, [R12, #vector_table.counter]	;claim counter
   LDR     R14, [R12, #vector_table.type]
   TEQ     R14, #&3B << 12			;OS_CallAfter
   TEQNE   R14, #&3C << 12			;OS_CallEvery
   BNE     _not_ticker
   ._ticker_L1
     LDR     R0, [R12, #vector_table.entry_code]	;get the managed entry
     LDR     R1, [R12, #vector_table.private]
     SWI     XOS_RemoveTickerEvent
     SUBS    R7, R7, #1
   BGT     _ticker_L1
   B       _P1

   ._not_ticker
   TEQ     R14, #&54 << 12			;OS_AddCallBack
   BNE     _not_callback
   ._callback_L1
     LDR     R0, [R12, #vector_table.entry_code]	;get the managed entry
     LDR     R1, [R12, #vector_table.private]
     SWI     XOS_RemoveCallBack
     SUBS    R7, R7, #1
   BGT     _callback_L1
   B       _P1

   ._not_callback
   TEQ     R14, #&1F << 12			;OS_Claim
   TEQNE   R14, #&47 << 12			;OS_AddToVector
   BNE     _P1
   ._claim_L1
     LDR     R1, [R12, #vector_table.entry_code]	;get the managed entry
     LDR     R0, [R12, #vector_table.parameter]
     LDR     R2, [R12, #vector_table.private]
     SWI     XOS_Release
     SUBS    R7, R7, #1
   BGT     _claim_L1

   ._P1
   ADD     R12, R12, #vector_table.size
   SUBS    R8, R8, #1
 BNE     _L1
LDMFD    R13!, {R0-R2, R7-R8, R12, PC}




.wimp_relink_application
 STMFD   R13!, {R0-R2, R4, R8, R12, R14}

 LDR     R12, jit_claimed_vectors
 MOV     R8, #max_vectors_to_track
 ._L1
   LDR     R14, [R12, #vector_table.entry_code]	;get the managed entry
   TEQ     R14, #0				;is it being used?
   BEQ     _P1					;NO

   LDR     R14, [R12, #vector_table.type]
   TEQ     R14, #&1F << 12			;OS_Claim
   TEQNE   R14, #&3B << 12			;OS_CallAfter
   TEQNE   R14, #&3C << 12			;OS_CallEvery
   TEQNE   R14, #&47 << 12			;OS_AddToVector
   LDREQ   R0, [R12, #vector_table.parameter]
   LDREQ   R1, [R12, #vector_table.entry_code]	;get the managed entry
   LDREQ   R2, [R12, #vector_table.private]
   TEQ     R14, #&1F << 12			;OS_Claim
   TEQNE   R14, #&47 << 12			;OS_AddToVector
   SWIEQ   XOS_AddToVector
   TEQ     R14, #&3B << 12			;OS_CallAfter
   SWIEQ   XOS_CallAfter
   TEQ     R14, #&3C << 12			;OS_CallEvery
   SWIEQ   XOS_CallEvery
   TEQ     R14, #&54 << 12			;OS_AddCallBack
   LDREQ   R0, [R12, #vector_table.entry_code]	;get the managed entry
   LDREQ   R1, [R12, #vector_table.private]
   SWIEQ   XOS_AddCallBack

   MOV     R0, #1				;now only claimed once
   STR     R0, [R12, #vector_table.counter]	;claim counter

   ._P1
   ADD     R12, R12, #vector_table.size
   SUBS    R8, R8, #1
 BNE     _L1
LDMFD    R13!, {R0-R2, R4, R8, R12, PC}




;hv_OS_FSControl
;---------------
;corrects the entry points for OS_FSControl 12
;ref. PRM2-532 for the FileSystem Information Block
;
;Entry:
; R0 - 12 (add FS)
; R1 - Pointer to Module base
; R2 - Offset of FileSystem Information Block
; R3 - Pointer to private word

.hv_OS_FSControl				;PRM2-96
 TEQ     R0, #12			;add FS
 TEQNE   R0, #35			;add ImageFS
 BNE     _pass_on

 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XADFFS_DoNothing

 STMFD   R13!, {R1, R2}			;preserve around call
 STMFD   R13!, {R0-R11}
 ADD     R11, R1, R2			;R11=Filing system info block
 LDR     R3, Module_being_inserted
 TEQ     R3, #0
 BNE     _module_init_in_progress
 LDR     R3, [R1, #Module_Header.Title]	;get the Module name
 ADD     R1, R1, R3			;module name
 MOV     R0, #18			;PRM1-249
 SWI     XOS_Module			;find our stub Module base
 MOVVS   R12, #&1B			;ADFF501B
 BVS     _imageFS_unsupported		; |+ can't find stub
					;R3 points to stub Module base
 ._module_init_in_progress
 LDR     R0, [R3, #Module_Header.FS_name]
 TEQ     R0, #0				;FS or ImageFS already in this Module?
 MOVNE   R12, #&18			;YES,
 BNE     _imageFS_unsupported		; |+ ADFF5018

 MOV     R0, #Module_Header.FS_system_name
 STR     R0, [R3, #Module_Header.FS_name]	;FS name pointer
 MOV     R0, #Module_Header.FS_startup_text
 STR     R0, [R3, #Module_Header.FS_startup]	;FS startup text pointer

 ADD     R10, R3, #Module_Header.FS_system_name
 LDR     R1, [R13, #4]			;R1=original Module base
 MOV     R4, #2				;copy Filing system name and startup text
 ._L1
   LDR     R9, [R11], #4		;get offset
   ADD     R9, R9, R1			;add Module base
   ._L2					;copy filing system name
     LDRB    R0, [R9], #1
     STRB    R0, [R10], #1
     TEQ     R0, #0
   BNE     _L2

   ADD     R10, R3, #Module_Header.FS_startup_text	;next entry
   SUBS    R4, R4, #1
 BNE     _L1

 MOV     R2, #Module_Header.FSEntry_Open
 BL      _create_FS_entry
 MOV     R2, #Module_Header.FSEntry_GetBytes
 BL      _create_FS_entry
 MOV     R2, #Module_Header.FSEntry_PutBytes
 BL      _create_FS_entry
 MOV     R2, #Module_Header.FSEntry_Args
 BL      _create_FS_entry
 MOV     R2, #Module_Header.FSEntry_Close
 BL      _create_FS_entry
 MOV     R2, #Module_Header.FSEntry_File
 BL      _create_FS_entry
 LDR     R2, [R11], #4
 STR     R2, [R3, #Module_Header.FS_info_word]
 MOV     R2, #Module_Header.FSEntry_Func
 BL      _create_FS_entry
 MOV     R2, #Module_Header.FSEntry_GBPB
 BL      _create_FS_entry
 LDR     R2, [R11], #4
 STR     R2, [R3, #Module_Header.FS_extra_info_word]

 MOV     R2, #Module_Header.FS_name
 STR     R3, [R13, #4]			;new Module base
 STR     R2, [R13, #8]			;new FSControl block offset
 LDMFD   R13!, {R0-R11}
 SWI     XOS_FSControl
 BL      post_SWI_veneer
 LDMFD   R13!, {R1, R2}
B       hv_exit_SWI_veneer

 ._pass_on
 BL      hv_pre_SWI_veneer		;call SWI that follows
 SWI     XOS_FSControl
 BL      hv_post_SWI_veneer
B       hv_exit_SWI_veneer

 ;Entry:
 ; R1 - original Module pointer
 ; R2 - entry to create
 ; R3 - our stub Module pointer
 ; R11 - FSControl block pointer (increased on exit)

 ._create_FS_entry
 LDR     R4, [R3, R2]			;our entry offset
 ADD     R4, R4, R3			;R4=our entry pointer
 LDR     R2, [R11], #4			;FSEntry_xxx
 ADD     R0, R1, R2			;actual entry point
 ADD     R0, R0, #jit_code_start	;JIT entry point
 STR     R0, [R4, #-4]			;store entry in codelet
 MOV     PC, R14


 ._imageFS_unsupported
 LDMFD   R13!, {R0-R11}
 LDMFD   R13!, {R1, R2}			;pull registers from stack
 MOV     R12, #2			;ADFF5002
 B       hv_report_unimplemented




;hv_Squash_Decompress
;--------------------
;flush memory overwritten during decompression
;
;Entry:
; R0 - if bit 3 is clear, output pointer will have been updated
; R4 - output pointer

.hv_Squash_Decompress				;PRM4-106
 TST     R0, #%1000			;are we decompressing?
 BNE     _pass_on			;NO

 CMP     R4, #jit_appspace_end		;is it in application space?
 BHI     _pass_on			;NO

 STR     R4, [R13, #-4]!
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XSquash_Decompress
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer

 STMFD   R13!, {R2, R4}			;preserve R2, R4
 LDR     R2, [R13, #8]			;R2=R4 from entry
 SUBS    R4, R4, R2			;R4=size
 BLGT    hv_reset_memory_block		;reset JIT appspace
 LDMFD   R13!, {R2, R4, R14}		;preserve R2, R4 and drop old R4
B       hv_exit_SWI_veneer

 ._pass_on
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XSquash_Decompress
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
B       hv_exit_SWI_veneer




;hv_OS_ScreenMode
;----------------
;Returns the legacy screen mode list for OS_ScreenMode 2

.hv_OS_ScreenMode				;PRM5a-133
 TEQ     R0, #2
 BNE     _pass_on

 ; R2 = number of modes to skip
 ; R6 = pointer to block or 0 to return number of modes
 ; R7 = size of block if R6<>0

 STMFD   R13!, {R0-R1, R3-R5}
 ADR     R0, mode_translation_table
 ._L2
   LDMIA   R0!, {R3, R4, R5, R11}	;R3=mode R4=x R5=y R11=bpp
   CMN     R3, #1			;last entry?
   BEQ     _exit			;YES
   TEQ     R6, #0			;are we just counting?
   BNE     _no

   SUB     R2, R2, #1			;increase count
   SUB     R7, R7, #7 * 4		;reduce free space
   B       _L2				;exit

   ._no
   SUBS    R7, R7, #7 * 4		;reduce free space
   ADDMI   R7, R7, #7 * 4
   BMI     _finished

   SUB     R2, R2, #1			;increase count
   MOV     R1, #7 * 4
   STR     R1, [R6], #4			;size of entry
   MOV     R1, #1
   STMIA   R6!, {R1, R4, R5, R11}	;mode flags, x, y, bpp
   MOV     R4, #50
   MOV     R5, #0
   STMIA   R6!, {R4, R5}		;hz, name
 B       _L2

 ._finished
 LDR      R1, [R0, #0]			;get next entry
 CMN      R1, #1			;last one?
 MOVNE    R1, #0			;NO, claim as we ran out of space
 STRNE    R1, [R13, #4]
 ._exit
 LDMFD   R13!, {R0-R1, R3-R5}
B        hv_vector_handler_trap

 ._pass_on
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_ScreenMode
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
B       hv_exit_SWI_veneer





.hv_OS_CallASWI
 BIC     R12, R10, #swi_X_bit		;R12 contains SWI being called
 BL      hv_OS_CallASWI_check_SWI	;do we need to pass to the OS?
 MOV     R14, R10
B       hv_OS_CallASWI_handle



.hv_OS_CallASWIR12
 LDR     R12, [R13, #SWI_stack.R12]
 BIC     R12, R12, #swi_X_bit		;R12 contains SWI being called
 BL      hv_OS_CallASWI_check_SWI	;do we need to pass to the OS?
 LDR     R14, [R13, #SWI_stack.R12]
.hv_OS_CallASWI_handle
 ORR     R14, R14, #&EF << 24
 BNE     hypervised_SWI			;NO,  handle internally
;B       hv_OS_CallASWI_pass_to_OS	;YES




;hv_OS_CallASWI_pass_to_OS
;-------------------------
;SWI being called needs passing to the OS

;Entry:
; R14 - SWI instruction

.hv_OS_CallASWI_pass_to_OS
 LDR     R11, jit_managed_swi
 LDR     R12, [R13, #SWI_stack.R14]
 STR     R14, [R11, #0]
 STR     R12, [R11, #8]			;store return in codelet
 MOV     R14, R11
 PULLnoR14SWI
B       pass_SWI_on2			;will return via codelet to caller




;hv_OS_CallASWI_check_SWI
;------------------------
;checks if an SWI is supported via CallASWI under the JIT
;NOTE: These must be mirrored in i_SWI
;
;Entry:
; R0 - SWI with X flag cleared
;
;Exit:
; EQ set if it needs to be passed directly to the OS
; R12 - SWI # without X flag

.hv_OS_CallASWI_check_SWI
 TEQ     R12, #&16			;OS_EnterOS
 TEQNE   R12, #&7C			;OS_LeaveOS
 MOVEQ   R12, #2			;ADFF5002
 BEQ     hv_report_unimplemented

 STR     R14, [R13, #-4]!
 TEMP    R14
 TEQ     R12, #&5			;OS_CLI
 TEQNE   R12, #&13			;OS_IntOn
 TEQNE   R12, #&14			;OS_IntOff
 TEQNE   R12, #&400C7			;Wimp_Poll
 TEQNE   R12, #&400E1			;Wimp_PollIdle
 LOCK    R14
LDR     PC, [R13], #4