STRUCT Error_Exit_Handler
{
 .error_buffer	DBB 260
 .use_count	DCD 0
 .ADFFS_alive	DCD 0
 .error_handler	DBB FSControl_Exit_handler - FSControl_Error_handler
 .exit_handler	DBB FSControl_Exit_handler_end - FSControl_Exit_handler
 .size
}


;setup_error_handler
;-------------------
;allocation space in RMA setup error handler for the JIT

;Entry:
; R12 - pointer to VARS

.setup_error_handler
 STMFD   R13!, {R1-R3, R14}
 MOV     R0, #Module_Claim
 MOV     R3, #Error_Exit_Handler.size
 SWI     XOS_Module
 LDMVSFD R13!, {R1-R3, PC}
 STR     R2, [R12, #Error_handler_buffer - VARS]
 MOV     R0, #0
 STR     R0, [R2, #Error_Exit_Handler.use_count]
 MOV     R0, #1
 STR     R0, [R2, #Error_Exit_Handler.ADFFS_alive]

 ADD     R1, R2, #Error_Exit_Handler.error_handler
 ADR     R0, FSControl_Error_handler
 MOV     R2, #Error_Exit_Handler.size - Error_Exit_Handler.error_handler
 BL      MemCopy
LDMFD   R13!, {R1-R3, PC}




.FSControl_Error_handler
 MOV     R6, R0
 MRS     R7, CPSR
 SWI     XOS_EnterOS
 MOV     R8, R14
 SWI     XADFFS_ShutdownThisTask	;shutdown task if being managed
 LDMIA   R6, {R1-R3, R4-R5}
 MOV     R0, #6				;release Error handler
 SWI     XOS_ChangeEnvironment
 MOV     R0, #11			;release Exit handler
 MOV     R1, R4
 MOV     R2, R5
 SWI     XOS_ChangeEnvironment

 MOV     R0, #Module_Free
 MOV     R2, R6
 SWI     XOS_Module

 LDR     R0, FSControl_Error_handler - (Error_Exit_Handler.error_handler - Error_Exit_Handler.use_count)
 SUBS    R0, R0, #1			;decrease use count
 STR     R0, FSControl_Error_handler - (Error_Exit_Handler.error_handler - Error_Exit_Handler.use_count)
 LDREQ   R0, FSControl_Error_handler - (Error_Exit_Handler.error_handler - Error_Exit_Handler.ADFFS_alive)
 TEQEQ   R0, #0				;is ADFFS still loaded?
 MOVEQ   R0, #Module_Free
 ADREQ   R2, FSControl_Error_handler - (Error_Exit_Handler.error_handler - Error_Exit_Handler.error_buffer)
 SWIEQ   XOS_Module

 MOV     R14, R8
 MSR     CPSR_all, R7
 NOP
 ADR     R0, FSControl_Error_handler - (Error_Exit_Handler.error_handler - Error_Exit_Handler.error_buffer) + 4
SWI     OS_GenerateError


.FSControl_Exit_handler
 MOV     R9, R0
 MOV     R10, R1
 MOV     R11, R2
 MRS     R7, CPSR
 SWI     XOS_EnterOS
 MOV     R8, R14
 SWI     XADFFS_ShutdownThisTask	;shutdown task if being managed
 LDMIA   R12, {R1-R3, R4-R5}
 MOV     R0, #6				;release Error handler
 SWI     XOS_ChangeEnvironment
 MOV     R0, #11			;release Exit handler
 MOV     R1, R4
 MOV     R2, R5
 SWI     XOS_ChangeEnvironment

 MOV     R0, #Module_Free
 MOV     R2, R12
 SWI     XOS_Module

 LDR     R0, FSControl_Exit_handler - (Error_Exit_Handler.exit_handler - Error_Exit_Handler.use_count)
 SUBS    R0, R0, #1			;decrease use count
 STR     R0, FSControl_Exit_handler - (Error_Exit_Handler.exit_handler - Error_Exit_Handler.use_count)
 LDREQ   R0, FSControl_Exit_handler - (Error_Exit_Handler.exit_handler - Error_Exit_Handler.ADFFS_alive)
 TEQEQ   R0, #0				;is ADFFS still loaded?
 MOVEQ   R0, #Module_Free		;NO, free if last use
 ADREQ   R2, FSControl_Exit_handler - (Error_Exit_Handler.exit_handler - Error_Exit_Handler.error_buffer)
 SWIEQ   XOS_Module

 MOV     R14, R8
 MSR     CPSR_all, R7
 NOP
 MOV     R0, R9
 MOV     R1, R10
 MOV     R2, R11
SWI     OS_Exit
.FSControl_Exit_handler_end




;claim_Error_handler
;------------------
;handle crashes returning to the desktop
;
;NOTE: The exit handler can be in several places:
;      WindowManager	- Wimp task
;      ShellCLI		- shelled Wimp task (SHIFT-F12)
;      UtilityModule	- Supervisor prompt with no active Wimp
;      3rd party Module or Obey
;      Obey can be determined by the Error handler R1,R2,R3 being the same value

.claim_Error_handler
 STMFD   R13!, {R0-R5, R14}

 ADR     R1, _WindowManager		;is it within a Module we know about?
 BL      _check_for_Module
; ADRLO   R1, _ShellCLI
; BLLO    _check_for_Module
; ADRLO   R1, _UtilityModule
; BLLO    _check_for_Module
 LDMLOFD R13!, {R0-R5, PC}		;NO

 LDR     R5, Error_handler_buffer	;Error_Exit_Handler struct
 ADD     R0, R5, #Error_Exit_Handler.exit_handler
 TEQ     R1, R0				;have we already claimed the handler?
 LDMEQFD R13!, {R0-R5, PC}		;YES

 MOV     R0, #Module_Claim
 MOV     R3, #5*4
 SWI     XOS_Module
 LDMVSFD R13!, {R0-R5, PC}		;@@@ needs to report failure
 MOV     R4, R2

 LDR     R0, [R5, #Error_Exit_Handler.use_count]
 ADD     R0, R0, #1			;increase use count
 STR     R0, [R5, #Error_Exit_Handler.use_count]

 MOV     R0, #6
 ADD     R1, R5, #Error_Exit_Handler.error_handler
 MOV     R3, R5
 SWI     XOS_ChangeEnvironment
 STMIA   R4!, {R1-R3}
 SUB     R2, R4, #3*4

 MOV     R0, #11
 ADD     R1, R5, #Error_Exit_Handler.exit_handler
 SWI     XOS_ChangeEnvironment
 STMIA   R4!, {R1-R2}

LDMFD   R13!, {R0-R5, PC}

 ._WindowManager	DCB "WindowManager", 0
; ._ShellCLI		DCB "ShellCLI", 0
; ._UtilityModule	DCB "UtilityModule", 0
			ALIGN

; Exit:
;  HS if inside Module
;  LO if outside Module
;  VS if the Module wasn't found
;  R1 - current Exit handler address

 ._check_for_Module
 STMFD   R13!, {R14}
 MOV     R0, #Module_Lookup		;find WIMP module
 SWI     XOS_Module			;PRM1-249
 LDMVSFD R13!, {PC}			;WindowManager missing
 LDR     R4, [R3, #-4]			;R4=size, R3=module base
 ADD     R4, R4, R3			;R4=end of module

 MOV     R0, #11			;Exit handler
 MOV     R1, #0
 MOV     R2, #0
 STR     R3, [R13, #-4]!		;preserve R3
 MOV     R3, #0
 SWI     XOS_ChangeEnvironment
 LDR     R3, [R13], #4			;preserve R3
 CMP     R1, R3
 CMPHI   R4, R1				;is Exit handler in the Wimp?
LDMFD   R13!, {PC}




;vector_handler_29
;-----------------
;Takes over running a file if the JIT is running
;
;Reference PRM1-288 for actions to take depending on filetype
;          PRM1-197 for OS_UpCall 256 - new application starting
;          PRM1-266 for Service_NewApplication (not much use)
;          PRM2-85  for OS_FSControl 2 (*GO)
;          PRM2-87  for OS_FSControl 4
;
;Entry:
; R0 = reason code
; stack: {SWI stack}
; R12 = buffer for state

.vector_handler_29
 TEQ     R0, #FSControl_StartApplication	;PRM2-85 *GO?
 TEQNE   R0, #FSControl_Run			;PRM2-87 *Run file?
 BNE     vector_handler_forward			;NO, hand to OS
 BL      check_JIT_and_taskID			;is the task supported?
 BEQ     _dont_claim_handlers			;YES
 BL      pre_SWI_veneer				;NO, 
 SWI     XADFFS_DoNothing
 BL      claim_Error_handler			;install Error/Exit handlers
 SUBS    R14, R14, R14				;clear V
 BL      dontexit_SWI_veneer
B       vector_handler_forward

._dont_claim_handlers
 TEQ     R0, #FSControl_StartApplication	;PRM2-85 *GO?
 BEQ     _star_go				;YES

;FSControl 4
;
;Entry:
; R1 = pointer to command tail
;
;NOTE: Reference /RiscOs/Sources/FileSys/FileSwitch/s/FSControl RunEntry

 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XADFFS_DoNothing

 TEMP    R14
 STMFD   R13!, {R0-R11}			;preserve registers
 ADD     R0, R11, #fscontrol_filename - VARS
 BL      allocate_copy_filename
 BVS     _exit_with_error		;R10=filename, R11=filename end

 MOV     R0, #15			;R4 is path variable
 MOV     R1, R10
 ADR     R4, _run_path
 SWI     XOS_File			;PRM2-38 read file info
 BVS     _pass_to_RO			;pass to RISCOS on error
 TEQ     R0, #2				;directory?
 BLEQ     _directory			;Yes
 TEQ     R0, #1				;did we find the file?
 BNE     _pass_to_RO			;NO, hand to RISCOS

 MOV     R9, R3				;R9=execution address (if applicable)
 MOV     R6, R0				;object type
 MOV     R7, R2				;preserve load address
 MOV     R0, #FSControl_GetFileType	;get filetype
 SWI     XOS_FSControl			;PRM2-123
 BVS     _pass_to_RO			;pass to RISCOS on error

 CMN     R2, #1				;-1 no filetype?
 MOVEQ   R2, R7				;YES, use load address
 BEQ     _load_and_run			; |+  and load it

 TEQ     R2, #&FF8			;Absolute
 BEQ     _load_and_run_absolute

 TEQ     R2, #&FFA			;Module
 BEQ     _run_module

 TEQ     R2, #&FFC			;Utility
 BEQ     _utility

 LOCK    R14
 ._pass_to_RO
 ADR     R0, fscontrol_filename
 BL      release_RMA
 LDMFD   R13!, {R0-R11}			;preserve registers
 BL      dontexit_SWI_veneer
B       vector_handler_forward		;hand to OS


 ._run_module
 ADR     R0, fscontrol_filename
 BL      release_RMA
 MOV     R0, #Module_Run
 ADD     R13, R13, #4
 LDMFD   R13!, {R1-R11}			;preserve registers
 BL      dontexit_SWI_veneer
B       load_26bit_module		;run module


 ._run_path	DCB "Run$Path", 0
 ._plingrun	DCB ".!Run", 0
 		ALIGN

 ._directory				;check if !Run exists
 STR     R14, [R13, #-4]!
 ADR     R2, _plingrun
 ._directory_L1
   LDRB    R0, [R2], #1
   STRB    R0, [R11], #1
   TEQ     R0, #0
 BNE     _directory_L1

 MOV     R0, #15			;R4 is path variable
 ADR     R4, _run_path
 SWI     XOS_File			;PRM2-38 read file info
LDR     PC, [R13], #4


;Entry:
;R1 = filename
;R4 = filesize

._utility
 ADD     R4, R4, #8			;extra words for alignment
 MOV     R11, R1			;preserve R1
 MOV     R0, #Heap_Claim		;claim JIT RMA space for file
 MOV     R1, #jit_RMA_heap
 ADD     R3, R4, #&1100			;R3=file size + 1K stack
 SWI     XOS_Heap			;PRM1-379
 ADRVS   R0, Error_no_room_in_RMA	;the claim failed
 BVS     _exit_with_error		; |+ exit with error

 MOV     R1, R2
 ADD     R2, R2, #3			;ensure allocation is word aligned
 BIC     R2, R2, #%11			;R2=start of our temp stack
 STR     R1, [R2], #4			;store allocation start
 MOV     R1, R11			;preserve R1

 ADD     R3, R2, #&100			;R3=start of workspace for utility
 STR     R4, [R2], #4			;stack file size

 LDMFD   R13!, {R6-R11}			;pull R0-R5 from stack
 STMIA   R2!, {R6-R11}			;stack into buffer
 LDMFD   R13!, {R6-R11}			;pull R6-R11 from stack
 STMIA   R2!, {R6-R11}			;stack into buffer
 #if compile_IOMD == 1
   STR    R2, [R2, #0]			;fix for errata on SA-110 rev.2
 #endif
 STMIA   R2, {R13-R14}^			;stack USER R13, R14 into buffer
 #if compile_IOMD == 1
   NOP
 #endif
 ADD     R2, R2, #8
 LDMIA   R12, {R6-R8}			;get SWI_veneer.*
 STMIA   R2!, {R6-R8}			;stack SWI_veneer.* into buffer
 STR     R2, [R13, #-4]!		;preserve R2 so we can free RMA later
					;stack: <Heap alloc>,{SWI stack},{SWI veneer}
 STR     R3, [R2, #2 * 4]		;stack new value for R12
 ADD     R3, R3, #&1000			;needs 1K workspace

 ADR     R14, _utility_return
 STR     R14, [R3, #-4]!		;stack return

 STR     R3, [R2, #3 * 4]		;stack R13
 ADD     R3, R3, #4
 ADD     R14, R3, #jit_code_start
 STR     R14, [R2, #4 * 4]		;stack PC

 STR     R1, [R13, #-4]!
 MOV     R0, #CAOPointer		;set CAO
 MOV     R1, R3				;to prevent memory shrinkage
 SWI     XOS_ChangeEnvironment		;PRM1-320
 LDR     R1, [R13], #4

 MOV     R0, #14			;R4 is path variable
 MOV     R2, R3				;load address
 MOV     R3, #0
 ADR     R4, _run_path
 SWI     XOS_File			;PRM2-43 load file hypervised
 LDR     R2, [R13]			;preserve R2

 ADR     R0, fscontrol_filename
 BL      release_RMA

 STMFD   R13!, {R1-R2}
 SWI     XOS_GetEnv			;PRM1-301 get the environment string
 LDMFD   R13!, {R1-R2}
 STR     R0, [R2, #0 * 4]		;stack R0

 ._utility_L1
   LDRB    R14, [R1], #1		;copy command line
   STRB    R14, [R0], #1
   TEQ     R14, #0
   TEQNE   R14, #13
   TEQNE   R14, #32
 BNE     _utility_L1

 ._utility_L2				;copy any spaces
   TEQ     R14, #32
   STREQB  R14, [R0], #1
   LDREQB  R14, [R1], #1
 BEQ     _utility_L2

 SUB     R0, R0, #1			;R14=command tail
 STR     R0, [R2, #1 * 4]		;stack R1

 ._utility_L3				;copy arguments
   STRB    R14, [R0], #1
   LDRB    R14, [R1], #1
   TEQ     R14, #13
   TEQNE   R14, #0
 BNE     _utility_L3
 MOV     R14, #0
 STRB    R14, [R0]			;terminate string

 LDR     R0, [R12, #SWI_veneer.SPSR]
 AND     R0, R0, #%10000		;correct USER mode
 MSR     CPSR_all, R0			;switch to USER with flags cleared
 #if compile_IOMD == 1
   NOP
 #endif

 LDR     R14, jit_managed_ldr_pc_r13	;return in 26bit space
LDMIA   R2, {R0-R1, R12-R13, PC}	;load USER registers and call utility

 ._utility_return
 MRS     R1, CPSR			;need to track V status
 SWI     XOS_EnterOS

 LDR     R14, [R13], #4			;pull RMA allocation from SVC stack
 ADD     R12, R13, #SWI_stack.size	;buffer used by pre_swi_veneer
 LDMDB   R14!, {R6-R8}			;pull preserved SWI_veneer.*
 TST     R1, #1 << 28			;did it exit with V set?
 ORRNE   R6, R6, #1 << 28		;YES, set V in exit CPSR
 STMIA   R12, {R6-R8}			;preserve SWI_veneer.*
 LDMEQDB R14, {R0-R11, R13-R14}^	;preserve USER registers
 #if compile_IOMD == 1
   NOP					;fix for errata on ARM6/7 macrocells, StrongARM
 #endif
 LDMNEDB R14, {R1-R11, R13-R14}^	;V set, preserve USER registers
 #if compile_IOMD == 1
   NOP					;fix for errata on ARM6/7 macrocells, StrongARM
 #endif
 SUB     R14, R14, #14 * 4		;drop registers we just restored
 STMFD   R13!, {R0-R4}			;preserve R0-R4
 LDR     R4, [R14, #-4]!		;R4=file size
 ADD     R4, R4, #&1100

 MOV     R0, #Heap_Free			;release claimed JIT RMA space
 MOV     R1, #jit_RMA_heap
 LDR     R2, [R14, #-4]			;get address of allocation
 MOV     R3, R2
 SWI     XOS_Heap			;PRM1-380
 BL      hv_reset_memory_block		;release block in JIT space
 LDMFD   R13!, {R0-R4}
B       exit_SWI_veneer




;Entry:
; R1,R10 - filename
; R9     - execution address

._load_and_run
 ;check R2 is within application space
 CMP     R2, #page_zero_Scratch_Space	;valid load address?
 BLO     _pass_to_RO			;NO
 ADD     R5, R2, R4			;R5=start+size
 SUB     R14, R5, #1
 CMP     R3, R2				;is exec above load address?
 RSBGES  R14, R3, R14			;YES, is it below end address
 BLT     _pass_to_RO			;NO

 MOV     R3, #1				;use file load address
 B       _not_absolute


;Entry:
; R1,R10 - filename

._load_and_run_absolute
 MOV     R9, #&8000			;R9=execution address
 MOV     R3, #0				;use address in R2
 MOV     R2, #&8000

 ._not_absolute
 BL      _pre_application_starting	;may not return
 ADR     R4, _run_path
 MOV     R0, #14			;R4 is path variable
 SWI     XOS_File			;PRM2-43 load file hypervised
 BVS     _exit_with_error		;exit on error
 BL      _application_starting

 TEQ     R9, #&8000			;Absolute needs a Squeeze check
 BNE     _CAO_setup
 LDR     R0, [R9]			;get first instruction
 TEQ     R0, #&FB000000			;BLNV 0?  (Acorn C pre v5)
 EORNES  R0, R0, #&E1A00000		;MOV R0, R0?

; At this point, we're supposed to do the following, but can't as UnSqzAIF will
; branch back to the wrong address
; BEQ     _CAO_setup			;NO, not a compressed AIF
; MOV     R0, #0			;file is a compressed AIF
; MOV     R5, R1			;R5=filename
; MOV     R1, #Service_UKCompression
; MOV     R2, #&8000			;R2=load address
; MOV     R3, R4			;R3=size
; MOV     R4, R9			;R4=execute address
; SWI     XOS_ServiceCall
; MOV     R9, R3			;R3=updated execution address
;
; MOV     R0, #1			;file is a compressed AIF
; MOV     R1, #Service_UKCompression
; MOV     R2, #&8000			;R2=load address
; SWI     XOS_ServiceCall
;
; instead, we'll mirror the UnSqzAIF code
 MOVNE   R2, #&8000
 BLNE    UnSqzAIF			;NO, might be an AIF

 ._CAO_setup
 BL      dontexit_SWI_veneer
 BL      get_taskID
 LDR     R14, [R12, #SWI_veneer.SPSR]	;get entry SPSR
 BIC     R14, R14, #%1111 << 28		;clear flags (fixes Pipe Mania)
 BIC     R14, R14, #%11001111		;switch to USER, IRQ/FIQ enabled
 LDR     R13, SVC_stack_init		;collapse the SVC stack

 MSR     CPSR_all, R14			;now in USER
 #if compile_IOMD == 1
   NOP
 #endif
 LDR     R14, jit_managed_os_exit 	;return via an OS_Exit
 MOV     R13, #jit_allocate_memory	;put stack at end of user space
 MOV     R12, #jit_allocate_memory
ADD     PC, R9, #jit_code_start




;FSControl 2
;
;Entry:
; R1=command tail
; R2=address to *GO
; R3=command line
; R7=R2 if called from *GO, R7 is the address *GO uses
; stack: {SWI stack}
;
;Exit:
; R9  - address to call (in original appspace)
; R10 - command line
; NOTE: Dependent on /RiscOs/Sources/Kernel/s/SysComms GO_Code using R7
;       RO5 doesn't clear flags before calling code (causes Pipe Mania
;       to fail)

._star_go
 LDRB    R14, [R3, #0]			;is it *GO?
 TEQ     R14, #ASC("G")
 LDREQB  R14, [R3, #1]
 TEQEQ   R14, #ASC("O")
 LDREQB  R14, [R3, #2]
 TEQEQ   R14, #ASC(" ")
 LDREQB  R14, [R3, #3]
 TEQEQ   R14, #0
 BNE     vector_handler_forward		;NO, pass on

 CMP     R2, #jit_appspace_end		;is it in appspace?
 BHI     vector_handler_forward		;NO

 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XADFFS_DoNothing

 STMFD   R13!, {R0-R11}
 LDRB    R9, [R1, #0]			;get first character of command tail
 TEQ     R9, #0				;is an environment specified
 MOVNE   R10, R1			;YES
 MOVEQ   R10, R3			;command line
 MOV     R9, R2				;address to call
 BL      _application_starting		;may not return
B       _CAO_setup



;Entry:
; R1  - command tail
; R9  - CAO
; R10 - command line

._application_starting
 STMFD   R13!, {R0-R4, R14}
 LDR     R4, pre_JIT_wimp_slot_size
 ADD     R4, R4, #&8000				;correct the value
 ADD     R4, R4, #jit_code_start

 MOV     R0, #11				;Exit handler
 MOV     R1, #0
 MOV     R2, #0
 MOV     R3, #0
 SWI     XOS_ChangeEnvironment
 CMP     R1, #jit_code_start
 CMPHI   R4, R1
 BHI     _shelling				;application shelling

 MOV     R0, #16				;UpCall
 MOV     R1, #0
 MOV     R2, #0
 MOV     R3, #0
 SWI     XOS_ChangeEnvironment
 CMP     R1, #jit_code_start
 CMPHI   R4, R1
 BHI     _shelling
 SWI     XOS_ReadDefaultHandler
 SWI     XOS_ChangeEnvironment			;reset UpCall handler
 ._shelling
 MOV     R0, #FSControl_StartApplication	;setup environment
 LDR     R1, [R13, #4]				;get R1 from stack
 MOV     R2, R9					;CAO
 MOV     R3, R10				;command line
 BL      pass_SWI_on
 SWI     XOS_FSControl				;PRM2-85
 BVS     _rejected

 SWI     XOS_GetEnv				;PRM1-301
 MOV     R1, R2					;R1=time
 MOV     R0, R10				;filename to become environment
 SWI     XOS_WriteEnv				;PRM1-322
 LDMFD   R13!, {R0-R4, PC}

 ._rejected
 ADD     R13, R13, #4				;drop R0
 LDMFD   R13!, {R1-R4, R14}
B       _exit_with_error			;exit on error


;Entry:
; R9  - CAO
;
;stack: {R0-R11}, {SWI stack}

._pre_application_starting
 STMFD   R13!, {R0-R3, R14}
 MOV     R0, #UpCall_NewApplication
 MOV     R2, R9					;CAO
 SWI     XOS_UpCall
 TEQ     R0, #0					;was it rejected
 MOVEQ   R1, #0					;YES
 MOVNE   R1, #Service_NewApplication		;NO
 SWINE   XOS_ServiceCall
 TEQ     R1, #0					;was it rejected
 LDMNEFD R13!, {R0-R3, PC}			;NO

 ADR     R0, error_unable_to_start
B       _rejected				;exit on error




._exit_with_error
 STR     R0, [R13, #0]
 ADR     R0, fscontrol_filename
 BL      release_RMA

 MOV     R1, #1<<31
 ADDS    R1, R1, R1			;set V
 LDMFD   R13!, {R0-R11}			;preserve registers
B      exit_SWI_veneer			;exit with error




;UnSqzAIF
;--------
;replicates the UnSqzAIF Module in a JIT friendly way

;Entry:
; R2=load address
; R4=size

.UnSqzAIF
 STMFD   R13!, {R0-R8, R14}

 LDR     R0, [R2]			;get first word
 AND     R1, R0, #&FE000000
 TEQ     R1, #&EA000000			;B or BL?
 LDMNEFD R13!, {R0-R8, PC}		;not a compressed AIF, exit

 MOVS    R0, R0, LSL #8			;remove instruction
 LDMMIFD R13!, {R0-R8, PC}		;exit if negative address
 ADD     R5, R2, R4
 ADD     R5, R5, #3
 BIC     R5, R5, #3			;R5=end of file
 ADD     R2, R2, R0, LSR #6		;add branch offset
 ADD     R2, R2, #8			;R2=UnSqz code start

 ADR     R1, _UnSqzSignature
 LDR     R3, [R1], #4			;get the word we're looking for
 ._L1
   LDR     R0, [R2], #4			;get word from source address
   TEQ     R0, R3			;does it match
   BEQ     _found_1st_word

   CMP     R2, R5			;have we hit the end of the file?
 BLO     _L1
 LDMFD   R13!, {R0-R8, PC}		;not a compressed AIF, exit

 ._found_1st_word
 ADR     R14, _UnSqzSignature_end	;find copy sequence

 ._L2
   LDR     R3, [R1], #4			;get sig word
   LDR     R0, [R2], #4			;get source word
   TEQ     R0, R3			;do they match?
   LDMNEFD R13!, {R0-R8, PC}		;NO, exit
   TEQ     R1, R14
 BNE     _L2

 LDR     R3, _UnSqzSignature503
 LDR     R0, [R2]			;get the next source word
 TEQ     R0, R3				;is it v5.03 UnSqueeze code?
 BEQ     _needs_SA_patching		;YES
 LDR     R3, _UnSqzSignature500
 TEQ     R0, R3				;is it v5.00 UnSqueeze code?
 LDMNEFD R13!, {R0-R8, PC}		;NO

 ADD     R4, R2, #20			;check for v5.11+ UnSqueeze code
 CMP     R4, R5				;beyond end of file?
 LDMHSFD R13!, {R0-R8, PC}		;YES, exit

 ADR     R1, _UnSqzSignature
 ._L3
   LDR     R3, [R1], #4			;get sig word
   LDR     R0, [R4], #4			;get source word
   TEQ     R0, R3			;do they match?
   BNE     _needs_SA_patching		;NO, must be v5.00 UnSqueeze code
   TEQ     R1, R14
 BNE     _L3
LDMFD    R13!, {R0-R8, PC}


 ._needs_SA_patching
 LDR      R0, _UnSqzFix1
 STR      R0, [R2]			;patch UnSqzSignature500 / 503 instruction

 ADR      R14, _UnSqzFix2
 LDR      R1, _UnSqzFinalInst
 ._L4
   LDR      R0, [R5, #-4]!		;step back from end to find final branch
   TEQ      R0, R1			;final branch?
   LDMEQIA  R14, {R0, R1, R3, R4, R6}	;YES, replace
   STMEQIA  R5, {R0, R1, R3, R4, R6}
   TEQNE    R5, R2			;have we checked all the code
 BNE      _L4
LDMFD    R13!, {R0-R8, PC}


 ._UnSqzSignature			;1st block of code to find
 LDMIA   R5!, {R0-R3}
 STMIA   R7!, {R0-R3}
 CMP     R5, R6
 BLT     _UnSqzSignature
 ._UnSqzSignature_end

 ._UnSqzSignature500	MOV     PC, R4
 ._UnSqzSignature503	MOV     R1, R7
 ._UnSqzFinalInst	MOV     PC, R8

 ._UnSqzFix1		SWI     ADFFS_UnSqueeze

 ._UnSqzFix2
 MOV     R0, #1
 MOV     R1, #&8000
 ADR     R2, _UnSqzFix2
 SWI     XOS_SynchroniseCodeAreas
 MOV     PC, R8


.swi_ADFFS_UnSqueeze
 PULLSWI				;clear stack
 LDMIA   R5!, {R0-R3}			;need to copy more instructions
 STMIA   R7!, {R0-R3}
 MOV     R2, #&8000			;start of code
 ADD     R4, R4, #jit_code_start
 STR     R4, [R13, #-4]!
 SUB     R4, R7, R2			;size
 BL      hv_reset_memory_block		;perform an OS_SynchroniseCodeAreas
LDMFD    R13!, {PC}^			;exit to UnSqueeze code
