;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


#set max_vectors_to_track = 32			;max number of vectors we allow
#set last_device_to_track = IOC_SSBC		;last IOC device to track

#if Private_BASIC == 0
  #set ADFFS_BASICCall = ADFFS_SWI_Base		;used to trap BASIC CALL / USR
  #set ADFFS_BASICSys  = ADFFS_SWI_Base + 4	;used to trap BASIC SYS
#endif



STRUCT vector_table
{
  .entry_code		DCD 0
  .original_code	DCD 0
  .type			DCD 0
  .parameter		DCD 0
  .private		DCD 0
  .counter		DCD 0	;track number of claims
  .size
}




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




;hypervised_SWI
;--------------
;handles an OS SWI that we need to manage
;
;Entry:
;R12, R14 - stacked

.hypervised_SWI
 LDR     R14, [R14, #-4]		;get instruction

.hypervised_BASIC_SYS
.hypervised_CallASWI
 BIC     R14, R14, #%1111 << 20		;clear OS value
 STR     R14, swi_to_pass_to_OS
 MOV     R12, #ADFFS_CallModuleEntry << 12
 BIC     R14, R14, #1 << 17		;clear X bit
 MOV     R14, R14, LSL #12		;shift SWI# to top bits
 TEQ     R14, R12			;our Module entry call?
 BEQ     call_module_entry		;YES
 ADD     R12, R12, #1 << 12
 TEQ     R14, R12			;our Module init entry call?
 BEQ     call_module_entry_INIT		;YES
 ADD     R12, R12, #1 << 12
 TEQ     R14, R12			;our Module init end entry call?
 BEQ     call_module_entry_INIT_END	;YES

 ADR     R12, hv_SPSR			;buffer for C/SPSR (pre_swi_veneer)
 STR     R14, hv_SWI			;store SWI # for later use

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

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

 TEQ     R14, #&71 << 12		;OS_CallASWIR12
 BEQ     hv_OS_CallASWIR12

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

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

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

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

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

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

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

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

 #if compile_GPU == 1
   TEQ     R14, #&35 << 12		;OS_ReadModeVariable	PRM1-736
   BEQ     hv_OS_ReadModeVariable
 #endif

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

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

 TEQ     R14, #&42 << 12		;OS_ReadMonotonicTime	PRM1-446
 BEQ     hv_OS_ReadMonotonicTime

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 TEQ     R14, #6 << 12			;OS_Byte
 TEQEQ   R1, #11			;key transition?
 BNE     _skip_ok_byte_1314_check
 TEQ     R0, #13			;Disable event?
 TEQNE   R0, #14			;Enable event?
 BNE     _skip_ok_byte_1314_check	;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
   LDMFD   R13!, {R12, PC}^		;exit
 ._skip_ok_byte_1314_check

 SUB     R14, R14, #&40000 << 12
 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, #(&42700 - &40144) << 12
 TEQ     R14, #(&42701 - &42700) << 12	;Squash_Decompress	PRM4-106
 BEQ     hv_Squash_Decompress

 SUB     R14, R14, #(&59000 - &42700) << 12
#if Private_BASIC == 0
 TEQ     R14, #(ADFFS_BASICCall - &59000) << 12	;ADFFS_BASICCall
 BEQ     hv_ADFFS_BASICCall

 TEQ     R14, #(ADFFS_BASICSys - &59000) << 12	;ADFFS_BASICSys
 BEQ     hv_ADFFS_BASICSys
#endif

#if Private_CLib == 0
 SUB     R14, R14, #(&80680 - &59000) << 12
 TEQ     R14, #(&80681 - &80680) << 12		;SharedCLibrary_LibInitAPCS_R
 BEQ     hv_SharedCLibrary_LibInitAPCS_R
#endif
#if Private_CLib == 1
 SUBS    R14, R14, #((&80680+(1<<18)) - &59000) << 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
#endif

#if swi_flag_preservation == 1
					;****** CHECK SWI FOR FLAGS TO RETAIN *****
 LDR     R14, swi_to_pass_to_OS
 MVN     R12, #%0001 << 28		;retain V
 BIC     R14, R14, #&FF << 24		;clear instruction
 BIC     R14, R14, #1 << 17		;clear X bit
 TST     R14, #1 << 19			;3rd party / user SWI?
 BNE     _preserve_flags		;YES, assume NZC need preserving

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

 TEQ     R14, #&57			;OS_SerialOp
 TEQEQ   R0, #3				;OS_SerialOp 3?
 BEQ     _retain_C

 TEQ     R14, #6			;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   R14, SPSR			;OS_Byte doesn't actually preserve C
 BICEQ   R14, R14, #%0010 << 28
 MSREQ   SPSR_all, R14
 B       _preserve_flags

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

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

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

 ._preserve_flags
 MRS     R14, SPSR
 AND     R14, R14, R12			;R14=flags to preserve
 AND     R12, R12, #%1111 << 28
 EOR     R12, R12, #%1111 << 28		;R12=flag mask to retain from SWI
 STMFD   R13!, {R12, R14}		;store mask and flags
#endif
 SUB     R13, R13, #4 * 4
 MOV     R12, R13			;use stack for temp area

 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
 ADD     R13, R13, #4 * 4		;drop temp area from stack
#if swi_flag_preservation == 1
 MRS     R14, SPSR			;get flags returned from SWI
 LDR     R12, [R13], #4			;pull flag mask
 AND     R14, R14, R12			;R14=flags to keep
 LDR     R12, [R13], #4			;pull flags to preserve
 ORR     R14, R14, R12
 MSR     SPSR_all, R14			;preserve flags
#endif
LDMFD   R13!, {R12, PC}^





;hv_report_unimplemented
;-----------------------
;aborts on an SWI that's not been implemented
;
;Entry:
; R12, R14 stacked
; 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
 LDR     R12, [R13], #4			;pull R12 from stack
 STMIA   R14!, {R0-R7}
 LDR     R0, [R13], #4			;pull PC from stack
 SUB     R0, R0, #4
 SUB     R0, R0, #jit_code_start	;correct PC
 STR     R0, [R14, #(15-8) * 4]
 MOV     R0, R14

 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_SWI	DCD 0
 .hv_SPSR	DBD 4




;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, #0]			;entry PSR
 BIC     R0, R0, #%1111 << 28		;clear flags
 #if compile_RO > 400
   MRS     R14, CPSR			;32bit
 #endif
 AND     R14, R14, #%1111 << 28		;keep flags
 ORR     R0, R0, R14
 STR     R0, [R12, #0]			;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 return from stack
 MRS     R12, SPSR			;emulate RO3.1 behaviour
 ORR     R12, R12, #1 << 28		; | set V
 MSR     SPSR_all, R12			; |
 ADR     R0, error_SWI_not_known	; | return error
LDMFD   R13!, {R12, PC}^		; |+ exit




;hv_ADFFS_BASICSys
;-----------------
;Hypervise OS SWI's issued through BASIC's SYS command

.hv_ADFFS_BASICSys
 LDR     R14, [R11]			;load BASIC's SYS SWI
 BIC     R12, R14, #1 << 17		;clear X bit
 MOV     R12, R12, LSL #12		;shift SWI# to top bits
 SUB     R12, R12, #&400C0 << 12
 TEQ     R12, #(&400EC - &400C0) << 12	;Wimp_SlotSize?
 BEQ     _retain			;YES, must be hypervised
 CMP     R12, #(&40100 - &400C0) << 12	;Wimp_?
 BLO     _pass_on			;YES, leave to exec as normal
 ._retain
 ANDS    R12, R14, #%11 << 18		;R12=SWI type, OS?
 TEQNE   R12, #%01 << 18		;NO, OS extension Module?
 BEQ     hypervised_BASIC_SYS		;YES, retain it

 ._pass_on
 ADD     R14, R11, #4			;NO, correct R14
 STR     R14, [R13, #4]			; |+ and pass to RISCOS
B       vector_handler_forward




;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
 STMFD   R13!, {R10, R11}		;preserve R10, R11
 MRS     R10, SPSR			;preserve SPSR for reentry via GBPBV vector
 MOV     R11, R2			;R11=load address
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_GBPB
 STR     R10, [R12, #0]			;overwrite exit SPSR
 BL      post_SWI_veneerC
 BL      dontexit_SWI_veneer
 LDMVSFD R13!, {R10-R12, PC}^		;exit on error

 TEQ     R0, #3				;is it a load operation?
 TEQNE   R0, #4				;PRM2-69
 LDMNEFD R13!, {R10-R12, PC}^		;NO, exit

 CMP     R2, #jit_appspace_end		;is it in application space?
 LDMHIFD R13!, {R10-R12, PC}^		;NO, exit

 STMFD   R13!, {R2, R4}			;preserve R2, R4
 SUB     R4, R2, R11			;R4=size
 MOV     R2, R11			;R2=start address
 BL      hv_reset_memory_block		;reset JIT appspace
LDMFD   R13!, {R2, R4, R10-R12, PC}^




;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, #2 * 4]		;get PC from stack
 BIC     R0, R0, #&FC000003
 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, #2 * 4]		;restack PC
LDMFD   R13!, {R0, R12, PC}^		;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:
; R12    - pointer to pre_SWI_veneer block
; hv_R14 - +4 = codelet

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

 LDR     R9, hv_SWI				;R9=SWI# used to claim
 TEQ     R9, #&3B << 12				;OS_CallAfter	PRM1-441
 TEQNE   R9, #&3C << 12				;OS_CallEvery	PRM1-443
 MVNEQ   R6, #0					;YES, no parameter
 MOVNE   R6, R0					;NO, R6=vector

 ADR     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.type]	; |
   TEQEQ   R14, R9				; |+ does the claim type 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

 ADR     R7, jit_claimed_vectors - 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
 BEQ     hv_report_unimplemented		; |+ report

 STR     R1, [R7, #vector_table.original_code]	;original entry point
 ADR     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     R9, [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

 ._already_exists
 TEQ     R9, #&1F << 12				;OS_Claim	PRM1-66
 BEQ     _OS_Claim
 TEQ     R9, #&3B << 12				;OS_CallAfter	PRM1-441
 BEQ     _OS_CallAfter
 TEQ     R9, #&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
 LDRVC   R1, [R7, #vector_table.counter]	;increase the claim counter
 ADDVC   R1, R1, #1
 STRVC   R1, [R7, #vector_table.counter]
 BL      post_SWI_veneer
 LDR     R1, [R7, #vector_table.original_code]	;restore original address

 BL      dontexit_SWI_veneer
LDMFD   R13!, {R6-R9, R12, PC}^			;return to original caller


.Vector_Claim_Handlers
#if call_vectors_in_USER == 0
 #set loop = 0
 #rept max_vectors_to_track
   STMFD   R13!, {R0, R1, R7, R12, R14}	;R0,R1,PC,26bit return,32bit return
   MOV     R0, #loop
   B       call_vector_claim
   NOP
   #set loop = loop + 1
 #endr

 .call_vector_claim
 ADR     R14, jit_claimed_vectors
 MOV     R1, #vector_table.size
 MLA     R0, R1, R0, R14		;R0=vector info
 LDR     R1, [R0, #vector_table.type]	;need to clear CallAfter/CallBack's
 TEQ     R1, #&3B << 12			;was claim via OS_CallAfter?
 TEQNE   R1, #&54 << 12			;was claim via OS_AddCallBack?
 BNE     _not_callafter			;NO
 LDR     R1, [R0, #vector_table.counter]	;decrease the claim counter
 SUBS    R1, R1, #1
 STRPL   R1, [R0, #vector_table.counter]
 STREQ   R1, [R0, #vector_table.entry_code]	;allow the slot to be used
 STREQ   R1, [R0, #vector_table.type]		;allow the slot to be used
 ._not_callafter
 LDR     R1, [R0, #vector_table.original_code]
 ADD     R1, R1, #jit_code_start	;R0=new vector entry
 STR     R1, [R13, #2 * 4]		;overwrite R7 on stack
 LDR     R14, jit_managed_ldr_pc_r13_2
 MRS     R1, CPSR
 AND     R0, R1, #&F0000003
 AND     R1, R1, #%11000000		;FIQ / IRQ
 ORR     R14, R14, R0
 ORR     R14, R14, R1, LSL #20
 STR     R14, [R13, #3 * 4]		;overwrite R12 on stack
 LDMFD   R13!, {R0, R1, PC}		;call vector
#endif

#if call_vectors_in_USER == 1
; call vector claims in USER
 #set loop = 0
 #rept max_vectors_to_track
   STMFD   R13!, {R4-R7, R14}
   MOV     R6, #loop
   B       call_vector_claim
   NOP
   #set loop = loop + 1
 #endr

 .call_vector_claim
 ADR     R14, jit_claimed_vectors
 MOV     R7, #vector_table.size
 MLA     R6, R7, R6, R14		;R0=vector info
 MRS     R5, CPSR			;R5=entry CPU mode
 LDR     R7, [R6, #vector_table.type]	;need to clear CallAfter's
 TEQ     R7, #&3B << 12			;was claim via OS_CallAfter?
 TEQNE   R7, #&54 << 12			;was claim via OS_AddCallBack?
 BNE     _not_callafter			;NO
 LDR     R7, [R6, #vector_table.counter]	;decrease the claim counter
 SUBS    R7, R7, #1
 STRPL   R7, [R6, #vector_table.counter]
 STREQ   R7, [R6, #vector_table.entry_code]	;allow the slot to be used
 STREQ   R7, [R6, #vector_table.type]		;allow the slot to be used
 ._not_callafter
 LDR     R7, [R6, #vector_table.original_code]
 #if call_vectors_in_USER == 1 AND compile_IOMD == 1
   #if call_vectors_in_USER == 1 AND compile_RO == 400
     MOV     R14, #%10000011		;SVC26, IRQ disabled
   #endif
   #if call_vectors_in_USER == 1 AND compile_RO == 450
     MOV     R14, #%10010011		;SVC32, IRQ disabled
   #endif
   MSR     CPSR_all, R14
   NOP
 #endif
 #if call_vectors_in_USER == 1 AND compile_RO == 500
   MSR     CPSR_c, #%10010011		;SVC32, IRQ disabled
 #endif
 MRS     R6, SPSR
 STMFD   R13!, {R6, R14}		;preserve SVC SPSR and R14

 BIC     R6, R5, #%1111			;switch to USER
 ORR     R6, R6, #%10 << 6		;with IRQ disabled
 MSR     CPSR_all, R6
 #if call_vectors_in_USER == 1 AND compile_IOMD == 1
   NOP
 #endif

 MOV     R4, R13			;R4=user R13
 MOV     R6, R14			;R6=user R14
 LDR     R13, IRQ_vector_stack		;temp stack
 ADR     R14, _return_claimed
 STR     R14, [R13, #-4]!
 ADR     R14, _return
 STR     R14, [R13, #-4]!

 LDR     R14, jit_managed_ldr_pc_r13_2	;hypervised LDR PC, [R13+4], #4
 ORR     R14, R14, #%10 << 26		;return in USER with IRQ disabled
 STR     R14, [R13, #-4]!		;stack IRQ return address
 ADD     PC, R7, #jit_code_start	;call claimant

 ._return
 MOV     R13, R4			;restore user R13
 MOV     R14, R6			;restore user R14
 SWI     XOS_EnterOS			;PRM1-141
 LDMFD   R13!, {R6, R14}		;preserve SVC SPSR and R14
 MSR     SPSR_all, R6
 MSR     CPSR_all, R5			;back into entry CPU mode
 #if call_vectors_in_USER == 1 AND compile_IOMD == 1
   NOP
 #endif
 LDMFD   R13!, {R4-R7, PC}

 ._return_claimed
 MOV     R13, R4			;restore user R13
 MOV     R14, R6			;restore user R14
 SWI     XOS_EnterOS			;PRM1-141
 LDMFD   R13!, {R6, R14}		;preserve SVC SPSR and R14
 MSR     SPSR_all, R6
 MSR     CPSR_all, R5			;back into entry CPU mode
 #if call_vectors_in_USER == 1 AND compile_IOMD == 1
   NOP
 #endif
 LDMFD   R13!, {R4-R7, R14, PC}
#endif




;hv_OS_AddCallBack
;-----------------
;Hypervize OS_AddCallBack
;
;Entry:
; R12 - pointer to pre_SWI_veneer block
; R0  - Address to call
; R1  - R12 value

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

 ADR     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   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

 ADR     R7, jit_claimed_vectors - 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
 BEQ     hv_report_unimplemented		; |+ report

 LDR     R14, hv_SWI				;SWI that triggered us
 STR     R14, [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
 ADR     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

 ._already_exists
 BL      pre_SWI_veneer				;call SWI that follows
 SWI     XOS_AddCallBack
 BL      post_SWI_veneer
 LDRVC   R0, [R7, #vector_table.original_code]	;restore original address
 LDRVC   R8, [R7, #vector_table.counter]	;increase the claim counter
 ADDVC   R8, R8, #1
 STRVC   R8, [R7, #vector_table.counter]

 BL      dontexit_SWI_veneer
LDMFD   R13!, {R7-R8, R12, PC}^			;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}			;preserve R1, R7-R8
 ADR     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
   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
 #if JIT_debug == 1
   LDMEQFD R13!, {R7-R8}			;NO, clear down stack
   MOVEQ   R12, #4				; | ADFF5004
   BEQ     hv_report_unimplemented		; |+ report
 #endif
 MOVEQ   R1, #0
 BEQ     _trigger_error

 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]
 STREQ   R1, [R7, #vector_table.entry_code]	;allow the slot to be reused
 STREQ   R1, [R7, #vector_table.type]		;allow the slot to be used

 MOV     R1, R8					;get our entry address
 BL      pre_SWI_veneer				;call SWI that follows
 ._trigger_error
 SWI     XOS_Release
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
LDMFD   R13!, {R1, R7-R8, R12, PC}^		;return to original caller

 ._bad_vector_release	DCD 417
			DCB "Bad vector release", 0
			ALIGN



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

.hv_OS_RemoveTickerEvent			;PRM1-445
 STMFD   R13!, {R7-R8}				;preserve R7-R8
 ADR     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?
   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
 LDMEQFD R13!, {R7-R8, R12, PC}^		;NO, exit silently

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

 BL      pre_SWI_veneer				;call SWI that follows
 SWI     XOS_RemoveTickerEvent
 BL      post_SWI_veneer
 LDRVC   R0, [R7, #vector_table.original_code]	;restore original address

 BL      dontexit_SWI_veneer
LDMFD   R13!, {R7-R8, R12, PC}^			;return to original caller




;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}				;preserve R7-R8
 ADR     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?
   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
 LDMEQFD R13!, {R7-R8, R12, PC}^		;NO, exit silently

 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]		;allow the slot to be used

 BL      pre_SWI_veneer				;call SWI that follows
 SWI     XOS_RemoveCallBack
 BL      post_SWI_veneer
 LDRVC   R0, [R7, #vector_table.original_code]	;restore original address

 BL      dontexit_SWI_veneer
LDMFD   R13!, {R7-R8, R12, PC}^			;return to original caller




;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
 LDR     R1, pre_JIT_wimp_slot_size	;new end of appspace
 ADD     R1, R1, #&8000			;correct value
B       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
 STR     R2, [R13, #-4]!
 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
 MOV     R0, R1				;old handler

 LDR     R1, pre_JIT_wimp_slot_size	;return correct slotsize
 ADD     R1, R1, #&8000			;correct value

 STMFD   R13!, {R0-R1}			;stack now: R0-R2, R12, PC
 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
LDMFD   R13!, {R0-R2, R12, PC}^




;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
LDMFD   R13!, {R12, PC}^




;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
LDMFD   R13!, {R2-R3, R12, PC}^




;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
LDMFD   R13!, {R2-R3, R12, PC}^




;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, #8]			;overwrite R4, R5 on stack
 STR     R3, [R13, #12]

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

 LDR     R1, [R13], #4			;pull R3 from stack
 MOV     R2, #0
 MOV     R3, #0
 MOV     R0, #10			;Event handler
 BL      change_environment_handler
 MOV     R3, R1
LDMFD   R13!, {R0-R2, R12, PC}^




;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

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

 ADR     R12, _SPSR			;state needs to be local as
					;Sound_InstallVoice calls user code
 BL      hv_pre_SWI_veneer		;call SWI that follows
 SWI     XOS_Module			;PRM1-228
 BL      post_SWI_veneer
B       exit_SWI_veneer

 ._SPSR	DBD 4


;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
 ._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
LDMFD   R13!, {R0-R1, R12, PC}^


;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
 ._free_error
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
 BLVC    hv_reset_memory_block		;flush any instructions in it
LDMFD   R13!, {R0-R4, R12, PC}^


;Entry:
; R1 - pointer to Module name

 ._lookup
 BL      pre_SWI_veneer				;call SWI that follows
 SWI     XOS_Module
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer
 LDMVSFD R13!, {R12, PC}^			;exit on error

 LDR     R0, [R3, #Module_Header.ADFFS]
 EORS    R0, R0, #Module_Validation		;one of ours?
 LDREQ   R3, [R3, #Module_Header.Address]	;YES, get 26bit address
 MOV     R0, #Module_Lookup
LDMFD   R13!, {R12, PC}^




;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

 CMP     R0, #jit_allocate_memory	;cap to our max
 MOVGT   R0, #jit_allocate_memory
 TEMP    R1
 STR     R0, pre_JIT_wimp_slot_size	;set - update slot size
 LOCK    R1

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

 LDR     R0, pre_JIT_wimp_slot_size	;return size app requested
 MOV     R2, #jit_allocate_memory	;cap free pool to our max
 SUB     R2, R2, R0
B       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

 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]
LDMFD   R13!, {R12, PC}^		;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]

 #if compile_IOMD == 1
   LDMFD   R13!, {R12, PC}^		;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]
  LDMFD   R13!, {R0, R12, PC}^		;return to original caller
 #endif




#if Private_BASIC == 0
;hv_ADFFS_BASICCall
;------------------
;Called by BASIC when it processes a CALL or USR instruction
;ensures CALL and USR in BASIC exit in/out of memory below 32mb and that
;the code called is in JIT space if its trying to call something in
;application space
;
;Entry:
; R0-R7 = A%-H%
; USER R14   = return address
; USER [R13] = address to call

.hv_ADFFS_BASICCall
 LDMFD   R13!, {R12, R14}		;clear SVC stack

 MRS     R14, SPSR			;go to BASIC's CPU mode
 MSR     CPSR_all, R14
 #if Private_BASIC == 0 AND compile_IOMD == 1
   NOP
 #endif

 STR     R13, _basic_R13		;preserve R13 on return to BASIC
 STMFD   R13!, {R12, R14}		;now in USER CPU mode

 #if JIT_WIMP_support == 1 AND Private_BASIC == 0
   BL      check_task_ID		;is the task supported?
   LDMNEFD R13!, {R12, R14, PC}		;NO, call directly
   LDR     R14, [R13, #4]		;preserve R14
 #endif

 LDR     R12, [R13, #2 * 4]		;BASIC's stacked call address
 CMP     R12, #jit_appspace_end		;are we jumping into appspace?
 LDMHIFD R13!, {R12, R14, PC}		;NO, call directly

 ADD     R12, R12, #jit_code_start	;YES, correct it
 STR     R12, [R13, #2 * 4]		;overwrite stacked address
 LDR     R12, jit_managed_BASIC_entry	;address of our managed block
 STR     R12, [R13, #4]			;new R14
 STMFD   R13!, {R0-R11}			;stack now: R0-R12, R14, <CALL/USR address>

 ADR     R0, _basic_return
 STR     R0, [R12, #31 * 4]		;return to us to restore stack
 STR     R14, _basic_R14		; (fixes Drifter)
 LDR     R0, [R14, #-4]			;get BASIC's version
 STR     R0, [R12, #-4]			;store in our codelet

 ADD     R14, R14, #4
 ADD     R12, R12, #4

 LDMIA   R14!, {R0-R10}			;copy BASIC's ARGP entries
 STMIA   R12!, {R0-R10}			;STRACC, PAGE, TOP, LOMEM, HIMEM, MEMLIMIT
					;FSA, TALLY, TRACEFILE, ESCWORD, WIDTHLOC

 MOV     R11, #8			;copy the internal BASIC routine jump table
 ADD     R0, R12, #31 * 4
 ADD     R1, R0, #10 * 4
 ADD     R9, R14, #10 * 4
 ._L1
   STR     R14, [R0], #4
   STR     R9, [R1], #4
   ADD     R14, R14, #4
   ADD     R9, R9, #4
   SUBS    R11, R11, #1
 BNE     _L1
 STR     R9, [R1], #4

 ADD     R12, R12, #8 * 4		;copy last entry from internal BASIC
 LDMIA   R14!, {R0-R1}			;routines and first from FPOINT
 STMIA   R12!, {R0-R1}			;eg. 0 and 9 - terminator and entry count perhaps?
LDMFD   R13!, {R0-R12, R14, PC}


 ._basic_R13 DCD 0
 ._basic_R14 DCD 0
 ._basic_return				;CALL/USR returns here first
 LDR     R13, _basic_R13
 ADD     R13, R13, #4			;correct stack
 LDR     PC, _basic_R14			;return to BASIC
#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
 LDMEQFD R13!, {R12, PC}^

 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
LDMFD   R13!, {R12, PC}^		;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
LDMFD   R13!, {R12, PC}^		;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_allocate_memory	;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
B       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+
; LDMFD   R13!, {R12, PC}^
;
; ._exit
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XSound_Mode
 BL      post_SWI_veneer
B       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

 ADDS    R5, R0, R1			;any parameters?
 BEQ     _exit				;NO (used by COPS)

 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

 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     R12, _SPSR2
 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, R12, PC}^		;NO, preserve registers and exit

 ._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}			;preserve registers

 ADR     R12, _SPSR			;state needs to be local as
					;Sound_InstallVoice can call user code
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XSound_InstallVoice
 BL      post_SWI_veneer
B       exit_SWI_veneer

 ._SPSR DBD 4
 ._SPSR2 DBD 4




;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
 ADR     R12, _SPSR			;state needs to be local as
					;Sound_RemoveVoice can call user code
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XSound_RemoveVoice
 BL      post_SWI_veneer
 TEQ     R1, #0				;did removal succeed?
 BEQ     exit_SWI_veneer		;NO, exit
 BL      dontexit_SWI_veneer

 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?
 LDMEQFD R13!, {R12, PC}^		;NO
 LDR     R0, [R12, #sound_voice_handler.voicename] 	;R12=offset to voicename
 ADD     R0, R12, R0			;R0=original voice name address

 MOV     R12, #0			;clear voice generator
 STR     R12, [R14, #sound_voice_handler.voicegenerator]
LDMFD   R13!, {R12, PC}^

 ._SPSR DBD 4




;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, #1 << 17		;ensure X bit is set

 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XSound_QSchedule
 BL      post_SWI_veneer
B       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
 LDMEQFD R13!, {R12, PC}^		; |+ exit

 TEQ     R14, #3 << 8			;VIDC20?
 MOVEQ   R1, #VIDC20_base_addr		;emulate RO3.5
 LDMEQFD R13!, {R12, PC}^		; |+ exit

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




;hv_OS_ReadMemMapInfo
;-----------------
;Returns 8MB of RAM

.hv_OS_ReadMemMapInfo				;PRM1-391
 MOV     R0, #32 * 1024			;page size
 MOV     R1, #256			;no. of pages
LDMFD   R13!, {R12, PC}^




;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
 TEQ     R0, #1				;read configured Mode
 BEQ     _reason_1
 TEQ     R0, #2				;chip info
 BEQ     _reason_2

#if Private_CLib == 1
 TEQ     R0, #6
 TEQEQ   R2, #78			;CLib requesting CLibCounter
 LDREQ   R2, private_CLibCounter	;YES
 LDMEQFD R13!, {R12, PC}^		; |+ point to our address
 TEQ     R0, #6
 TEQEQ   R2, #79			;CLib requesting RISCOSLibWord (FEC)
 LDREQ   R2, private_RISCOSLibWord	;YES
 LDMEQFD R13!, {R12, PC}^		; |+ point to our address
 TEQ     R0, #6
 TEQEQ   R2, #80			;CLib requesting CLibWord (FF0)
 LDREQ   R2, private_CLibWord		;YES
 LDMEQFD R13!, {R12, PC}^		; |+ point to our address
#endif

 STR     R5, [R13, #-4]!		;preserve R5
 CMP     R0, #3				;no reason codes >3 pre RO5
 LDRHI   R5, emulate_RISCOS
 CMPHI   R5, #&500 << 8			;below RISCOS 5.0?
 LDR     R5, [R13], #4
 BHI     _ok

 MRS     R12, SPSR			;emulate RO3.1 behaviour
 ORR     R12, R12, #1 << 28		; | set V
 MSR     SPSR_all, R12			; |
 ADR     R0, error_Unknown_OS_ReadSysInfo	; | return error
 LDMFD   R13!, {R12, PC}^		; |+ exit

 ._ok
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_ReadSysInfo
 BL      post_SWI_veneer
B       exit_SWI_veneer

 ._reason_1
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_ReadSysInfo
 BL      post_SWI_veneer
 MOV     R1, #0				;monitor type
 MOV     R2, #0				;sync
B       exit_SWI_veneer

 ._reason_2
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_ReadSysInfo
 BL      post_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       exit_SWI_veneer




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

.hv_OS_PlatformFeatures
 MRS     R12, SPSR			;emulate RO3.1 behaviour
 ORR     R12, R12, #1 << 28		; | set V
 MSR     SPSR_all, R12			; |
 ADR     R0, error_SWI_not_known	; | return error
 LDMFD   R13!, {R12, PC}^		; |+ exit




;hv_OS_ReadModeVariable
;----------------------
;corrects R2 if R0=7 (bytes per screen buffer)
;
;Entry:
; R0  - screen mode or -1 for current
; R1  - variable no.
; R12 - pointer to pre_SWI_veneer block

;Exit:
; R0, R1 - preserved
; R2  - value

#if compile_GPU == 1
.hv_OS_ReadModeVariable				;PRM1-736
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_ReadModeVariable		;PRM1-736
 BL      post_SWI_veneerC		;C needs retaining

 CMN     R0, #0				;current MODE?
 BNE    exit_SWI_veneer			;NO

 LDR     R2, VIDC20_width		;get actual width
 TEQ     R1, #6				;LineLength
 BEQ     _correct			;YES, correct it

 TEQ     R1, #7				;ScreenSize?
 BNE     exit_SWI_veneer		;NO, exit

 LDR     R14, VIDC20_height
 MUL     R2, R14, R2			;width*height
 ._correct
 LDR     R14, current_mode_bitdepth	;YES, get the MODE bpp
 MOVEQ   R2, R2, LSL #2			;*4 to get 32bpp
 ADDEQ   PC, PC, R14, LSL #2		; |+  jump to bpp correction
B       exit_SWI_veneer
 MOV     R2, R2, LSR #1			;1bpp
 MOV     R2, R2, LSR #1			;2bpp
 MOV     R2, R2, LSR #1			;4bpp
 MOV     R2, R2, LSR #1			;8bpp
 MOV     R2, R2, LSR #1			;/2 for final correction
B       exit_SWI_veneer
#endif




;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?
 LDMEQFD R13!, {R12, PC}^		;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
 LDMEQFD R13!, {R12, PC}^		;exit

 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_ServiceCall
B       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

 ADR     R12, _SPSR			;local SPSR (fixes Master Break)
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_ReadLine32
 BL      post_SWI_veneerC		;retain C
 BL      dontexit_SWI_veneer
LDMFD   R13!, {R4, R12, PC}^

 ._SPSR	DBD 4




;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       exit_SWI_veneer			;exit
#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       exit_SWI_veneer			;exit

 ._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_OS_ReadMonotonicTime
;-----------------------
;Ensures IRQ's are enabled when checking time

.hv_OS_ReadMonotonicTime			;PRM1-446
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_IntOn
 SWI     XOS_ReadMonotonicTime
B       exit_SWI_veneer			;exit




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

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




;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, #&18			;error? ADFF5018
 BVS     hv_report_unimplemented	;YES, report
					;R3 points to stub Module base
 ._module_init_in_progress
 LDR     R0, [R3, #Module_Header.FS_name]
 TEQ     R0, #0				;FS or ImageFS already?
 MOVNE   R12, #&18			;YES, ADFF5018
 BNE     hv_report_unimplemented	; |+  report

 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       exit_SWI_veneer

 ._pass_on
 BL      hv_pre_SWI_veneer		;call SWI that follows
 SWI     XOS_FSControl
 BL      hv_post_SWI_veneer
B       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



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

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




#if Private_CLib == 1
.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
 LDMIA   R12, {R2-R5}			;preserve SPSR and CPU state
 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

 TEMP    R14
 STR     R7, swi_to_pass_to_OS
 LOCK    R14
 MSR     SPSR_all, R6
 STMIA   R12, {R2-R5}
 LDMFD   R13!, {R0-R12, PC}
#endif




#if Private_CLib == 0
;hv_SharedCLibrary_LibInitAPCS_R
;-------------------------------
;Fixes up the branch table to redirect to the 32bit APCS equivelant
;
;Entry:
; R0 - pointer to stub descriptions, terminated with -1
; R1 - pointer to workspace start
; R2 - pointer to workspace end
; R3 - -1
; R4 - 0
; R5 - -1

.hv_SharedCLibrary_LibInitAPCS_R		;PRM4-255
 LDR     R14, [R13, #4]			;get PC from stack
 #if Private_CLib == 0 AND compile_IOMD == 1
   BIC     R14, R14, #&FC000003
 #endif
 STMFD   R13!, {R0, R7-R11}
 #if Private_CLib == 0 AND compile_RO > 400
   ORR     R6, R6, #1			;we're a 32bit client
 #endif
 STMFD   R13!, {R6, R12}		;preserve R6 and R12

 ADD     R11, R14, #4			;R11 = stub chunk 1
 ADD     R12, R11, #5 * 4		;R12 = stub chunk 2
 ._L1
   LDMIA   R0!, {R6-R10}		;load stub values
   CMP     R6, #1			;chunk 1?
   STREQ   R9,  [R11, #12]		;1 - copy static data base
   STREQ   R10, [R11, #16]		;1 - copy static data limit
   STRGT   R9,  [R12, #12]		;2 - copy static data base
   STRGT   R10, [R12, #16]		;2 - copy static data limit
 BPL     _L1				;if negative we've hit the end

 MOV     R0, R11			;R0 = new stub pointer
 ADD     R11, R14, #CLib_chunk_1_vectors ;R11=chunk 1 pointer
 ADD     R12, R14, #CLib_chunk_2_vectors ;R12=chunk 2 pointer

 LDR     R6, [R13, #4]			;get R12 from stack
 STR     R12, [R13, #4]			;store new R12
 MOV     R12, R6
 LDR     R6, [R13], #4			;preserve R6
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XSharedCLibrary_LibInitAPCS_32
 BL      post_SWI_veneer
 BL      dontexit_SWI_veneer

 LDMFD   R13!, {R12, R14}		;pull R12 and original R0 from stack
 STMFD   R13!, {R2, R4-R6}		;preserve R2, R4-R6
 MOV     R5, R14			;R5=our stub table
 ._L2
   LDMIA   R5!, {R6-R10}		;load stub values
   CMN     R6, #1			;-1 terminator?
   BEQ     _exit_L2

   MOV     R2, R7			;start address of chunk
   SUB     R4, R8, R7			;length of chunk
   TEQ     R6, #1			;chunk 1?
   SUBEQ   R9, R11, #8			;use chunk 1 corrected for PC offset
   SUBNE   R9, R12, #8			;use chunk 2 corrected for PC offset
   ._L3					;setup branch table
     SUB     R6, R9, R7			;correct address
     MOV     R6, R6, LSR #2
     BIC     R6, R6, #&FF000000
     ORR     R6, R6, #&EA000000		;change to a B instruction
     ADD     R9, R9, #4 * 3		;go to next entry point
     STR     R6, [R7], #4
     TEQ     R7, R8			;have we reached the limit of this stub
   BNE     _L3

   BL      hv_reset_memory_block
 B       _L2
 ._exit_L2
LDMFD   R13!, {R2, R4-R12, PC}^
#endif




.hv_OS_CallASWI
 STR     R0, [R13, #-4]!		;preserve R0
 BIC     R0, R10, #1 << 17		;R0 contains SWI being called
 BL      hv_OS_CallASWI_check_SWI	;is SWI supported?
 MOV     R14, R0			;R14 = SWI#
 LDR     R0, [R13], #4			;preserve R0
 BEQ     hv_OS_CallASWI_codelet_required

 CMP     R14, #JIT_SWI_OS_Flag << 20	;does it need hypervising?
 BHI     hypervised_CallASWI		;YES
					;NO, pass on
 ADR     R12, _SPSR
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_CallASWI
 BL      post_SWI_veneer
B      exit_SWI_veneer

 ._SPSR      DBD 4


.hv_OS_CallASWIR12
 STR     R0, [R13, #-4]!		;preserve R0
 LDR     R0, [R13, #4]			;get R12 from stack
 BIC     R0, R0, #1 << 17		;R0 contains SWI being called
 BL      hv_OS_CallASWI_check_SWI	;is SWI supported?
 MOV     R14, R0			;R14 = SWI#
 LDR     R0, [R13], #4			;preserve R0
 BEQ     hv_OS_CallASWI_codelet_required

 CMP     R14, #JIT_SWI_OS_Flag << 20	;does it need hypervising?
 BHI     hypervised_CallASWI		;YES
					;NO, pass on
 ADR     R12, _SPSR
 BL      pre_SWI_veneer_R12		;call SWI that follows
 SWI     XOS_CallASWIR12
 ADR     R12, _SPSR
 BL      post_SWI_veneer
B      exit_SWI_veneer

 ._SPSR      DBD 4




;hv_OS_CallASWI_codelet_required
;-------------------------------
;checks if an SWI requires a codelet and then calls the SWI handler
;to create it
;
;Entry:
; R14 - SWI

.hv_OS_CallASWI_codelet_required
 STMFD   R13!, {R0-R7}			;stack is {R0-R7,R12,R14}
 MOV     R0, R14			;R0=SWI#
 ORR     R0, R0, #&EF << 24		;add in SWI instruction
 LDR     R7, [R13, #9 * 4]		;R7=return address
 ADR     R14, _return
 STR     R14, [R13, #-4]!		;stack return to us
 MVN     R14, #0			;let codelet know its CallASWI
 B       i_SWI				;create codelet
 ._return
 ;stack is : <codelet address>,<_return>,{R0-R7,R12,R14}
 LDR     R12, [R13], #4			;get codelet address
 ADD     R13, R13, #4			;drop our _return address
 LDMFD   R13!, {R0-R7}
 STR     R12, [R13, #4]			;need to return to the codelet
 LDMFD   R13!, {R12, PC}^		;..which will return to caller




;hv_OS_CallASWI_check_SWI
;------------------------
;checks if an SWI is supported via CallASWI under the JIT
;
;Entry:
; R0 - SWI
;
;Exit:
; EQ set if a codelet is required
; R0 - updated SWI # if it needs hypervising

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

 TEMP    R14
 TEQ     R0, #&0C		;OS_GBPB		PRM2-69
 TEQNE   R0, #&0F		;OS_Control
 TEQNE   R0, #&10		;OS_GetEnv
 TEQNE   R0, #&11		;OS_Exit		PRM1-303
 TEQNE   R0, #&12		;OS_SetEnv
 TEQNE   R0, #&15		;OS_CallBack		PRM1-307
 TEQNE   R0, #&18		;OS_BreakCtrl		PRM1-310
 TEQNE   R0, #&1E		;OS_Module
 TEQNE   R0, #&1F		;OS_Claim		PRM1-66
 TEQNE   R0, #&20		;OS_Release
 TEQNE   R0, #&29		;OS_FSControl
 TEQNE   R0, #&30		;OS_ServiceCall
 #if compile_GPU == 1
   TEQNE   R0, #&35		;OS_ReadModeVariable
 #endif
 TEQNE   R0, #&3B		;OS_CallAfter		PRM1-441
 TEQNE   R0, #&3C		;OS_CallEvery		PRM1-443
 TEQNE   R0, #&3D		;OS_RemoveTickerEvent
 TEQNE   R0, #&40		;OS_ChangeEnvironment
 TEQNE   R0, #&41		;OS_ClaimScreenMemory
 TEQNE   R0, #&47		;OS_AddToVector		PRM1-72
 TEQNE   R0, #&4B		;OS_ClaimDeviceVector	PRM1-123
 TEQNE   R0, #&4C		;OS_ReleaseDeviceVector
 TEQNE   R0, #&4F		;OS_HeapSort		PRM1-970
 TEQNE   R0, #&51		;OS_ReadMemMapInfo	PRM-391
 TEQNE   R0, #&54		;OS_AddCallBack		PRM1-324
 TEQNE   R0, #&58		;OS_ReadSysInfo
 TEQNE   R0, #&5F		;OS_RemoveCallBack
 TEQNE   R0, #&68		;OS_Memory
 TEQNE   R0, #&69		;OS_ClaimProcessorVector	PRM5a-30
 TEQNE   R0, #&40240		;ADFS_DiscOp
 TEQNE   R0, #&400DE		;Wimp_StartTask
 TEQNE   R0, #&400EC		;Wimp_SlotSize
 TEQNE   R0, #&40144		;Sound_Mode
 TEQNE   R0, #&40145		;Sound_LinearHandler
 TEQNE   R0, #&40183		;Sound_InstallVoice
 TEQNE   R0, #&40184		;Sound_RemoveVoice
 TEQNE   R0, #&42701		;Squash_Decompress
 BEQ     _hypervise

 LOCK    R14
LDR     PC, [R13], #4

 ._hypervise
 ADDS    R0, R0, #JIT_SWI_OS_Flag << 20	;trigger our SWI handler
LDR     PC, [R13], #4		;return with NE set
