#set Module_Validation = &000ADFF5

STRUCT Module_Header
{
 .Start			DCD 0
 .Init			DCD 0
 .Finalise		DCD 0
 .Service		DCD 0
 .Title			DCD 0
 .Help			DCD 0
 .Commands		DCD 0
 .SWI_chunk		DCD 0
 .SWI_handler		DCD 0
 .SWI_table		DCD 0
 .SWI_decode		DCD 0
 .MsgFilename		DCD 0
 .Flags			DCD 0
 .Address		DCD 0
 .Size			DCD 0
 .ADFFS			DCD 0
 .taskID		DCD 0
 .bit32			DCD 0
 .FS_name		DCD 0
 .FS_startup		DCD 0
 .FSEntry_Open		DCD 0
 .FSEntry_GetBytes	DCD 0
 .FSEntry_PutBytes	DCD 0
 .FSEntry_Args		DCD 0
 .FSEntry_Close		DCD 0
 .FSEntry_File		DCD 0
 .FS_info_word		DCD 0
 .FSEntry_Func		DCD 0
 .FSEntry_GBPB		DCD 0
 .FS_extra_info_word	DCD 0
 .FS_system_name	DBB 32
 .FS_startup_text	DBB 256
 .End
}


;Entry:
; stack  = {SWI stack}
; R0     - reason code
; R1, R2 - depending on reason code
; R12    - pointer to pre_SWI_veneer block

.load_26bit_module
 STMFD   R13!, {R0-R10}

 MOV     R7, R0				;R7=entry R0
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XADFFS_DoNothing

 TEQ     R0, #Module_Run
 TEQNE   R0, #Module_Load
 BEQ     _P2

 TEQ     R0, #Module_InsertFromMemory	;RAM based Module?
 MOVEQ   R8, #0				;YES, no RMA space needed
 MOVEQ   R10, R1			; |   R1=module address in RAM
 BEQ     _P1				; |+  skip copying to the RMA
					;Module_InsertFromMemoryToRAM
 MOV     R8, R2				;R8=module size
 BL      _copy_to_RMA			;R10=module address (unaligned)
 BVS     _exit				;exit on error
 B       _P1

 ._P2					;must be Load or Run
 BL      _load_module			;R10=module address (unaligned)
 BVS     _exit				;exit on error

 ._P1
 MOV     R0, #Heap_Claim		;claim JIT RMA space for stub
 MOV     R1, #jit_RMA_heap
 MOVS    R3, R8				;RAM based?
 BNE     _not_RAM_based			;NO, we know the size
 LDR     R3, [R10, #-4]			;YES, get Module size
 CMP     R3, #512 * 1024		;is it a sensible size? (Raw Power Sqsh
 MOVHI   R3, #32 * 1024			;Module doesn't have a size, so guess)
 ._not_RAM_based
 ADD     R3, R3, #4 + Module_Header.End + ((_codelet_end - _codelet + 4) * 8)
					;stub Module size=Module size + Stub header
					; + FS entries + word for alignment
 SWI     XOS_Heap			;PRM1-379
 BVS     _free_initial_heap		;exit with error
 STR     R2, [R13, #-4]!		;store temp stub block for release later
 STR     R7, [R13, #-4]!		;store entry R0 for later
 ADD     R2, R2, #3			;ensure allocation is word aligned
 BIC     R11, R2, #%11			;R11=temp space for stub header
 ADD     R9, R11, #Module_Header.End	;R9=start of dynamic code
 STR     R8, [R11, #Module_Header.Size]	;NO, store size so we can kill it later
 STR     R10, [R11, #Module_Header.Address]	;store our address
 TEQ     R8, #0				;RAM based?
 ADDNE   R10, R10, #3			;NO, ensure allocation is word aligned
 BICNE   R10, R10, #%11			; |
 BNE     _not_RAM_based2		; |+ we know the size
 LDR     R8, [R10, #-4]			;YES, get Module size
 CMP     R8, #512 * 1024		;is it a sensible size? (Raw Power Sqsh
 MOVHI   R8, #32 * 1024			;Module doesn't have a size, so guess)
 ._not_RAM_based2

 MOV     R0, #Module_Header.Start
 BL      _create_entry_USER
 BVS     _illegal_header		;invalid entry
 MOV     R0, #Module_Header.Init
 BL      _create_entry_INIT
 BVS     _illegal_header		;invalid entry
 MOV     R0, #Module_Header.Finalise
 BL      _create_entry
 BVS     _illegal_header		;invalid entry
 MOV     R0, #Module_Header.Service
 BL      _create_entry
 BVS     _illegal_header		;invalid entry

 LDR     R1, [R10, #Module_Header.Title]
 BL      _check_R1			;valid?
 BVS     _illegal_header		;NO
 ADD     R1, R1, R10			;R1=title start
 BL      check_essential_modules	;is the Module essential?
 MOVNE   R8, #0				;YES
 STRNE   R11, [R13, #0]			; |  overwrite R0, so we can't RMRun
 BNE     _discard_Module		; |+ discard the Module
 SUB     R0, R9, R11			;R0=offset to title
 STR     R0, [R11, #Module_Header.Title]
 MOV     R0, R1
 BL      _strcpy			;copy text

 LDR     R1, [R10, #Module_Header.Help]
 BL      _check_R1			;valid?
 BVS     _illegal_header		;NO
 TEQ     R1, #0				;does entry exist?
 STREQ   R1, [R11, #Module_Header.Help]
 SUBNE   R0, R9, R11			;R0=offset to help
 STRNE   R0, [R11, #Module_Header.Help]
 ADDNE   R0, R10, R1			;R0=help start
 BLNE    _strcpy			;copy text
 ADD     R9, R9, #3
 BIC     R9, R9, #%11			;word align R9

					;**************************
					;Copy command table
 LDR     R1, [R10, #Module_Header.Commands]
 BL      _check_R1			;valid?
 BVS     _illegal_header		;NO
 TEQ     R1, #0				;does a table exist?
 MOVEQ   R0, #0				;NO
 LDRNEB  R0, [R10, R1]			;YES,
 TEQNE   R0, #0				; |+  is the first command entry valid?
 SUBNE   R0, R9, R11			;new offset to table
 STR     R0, [R11, #Module_Header.Commands]
 BEQ     _skip_command_table_copy	;no commands

 ADD     R0, R10, R1			;R0=address of Command table
					;work out command table size
 MOV     R3, R0				;preserve R0
 ._L1
     LDRB    R1, [R0], #1		;skip *command title
     TEQ     R1, #0			;terminator
   BNE     _L1
   ADD     R0, R0, #3
   BIC     R0, R0, #%11			;word align R0
   LDRB    R1, [R0, #4 * 4]!		;skip entry points
   TEQ     R1, #0			;terminator?
 BNE     _L1				;NO

 ADD     R2, R0, #4			;skip 0 terminator
 SUB     R2, R2, R3			;R2=table size
 ADD     R2, R2, #3			;word align (for non-aligned table starts)
 BIC     R2, R2, #%11
 MOV     R6, R9				;R6=our Command table start
 ADD     R9, R9, R2			;R9=syntax / help start
 MOV     R0, R3				;preserve R0

 ._copy_command_table
   MOV     R7, R9
   MOV     R9, R6			;R9=command table
   BL      _strcpy
   ADD     R0, R0, #3
   BIC     R0, R0, #%11			;word align R0
   ADD     R6, R9, #3
   BIC     R6, R6, #%11			;word align R6
   MOV     R9, R7			;R9=syntax / help start

   BL      _create_command_entry	;create managed entry
   LDR     R1, [R0], #4
   STR     R1, [R6], #4			;store flags

   LDR     R2, [R0], #4			;Command Syntax
   CMP     R2, R8			;is it valid?
   MOVHS   R2, #0			;NO
   TEQ     R2, #0			;does text exist?
   MOVEQ   R1, #0			;NO
   SUBNE   R1, R9, R11			;YES, R1=new offset
   STR     R1, [R6], #4
   BEQ     _no_command_syntax		;NO
   MOV     R3, R0			;YES, preserve R0
   ADD     R0, R2, R10			; |  R0=text pointer
   BL      _strcpy			; |  copy text
   MOV     R0, R3			; |+ preserve R0

   ._no_command_syntax
   LDR     R2, [R0], #4			;Command Help
   CMP     R2, R8			;is it valid?
   MOVHS   R2, #0			;NO
   TEQ     R2, #0			;does text exist?
   MOVEQ   R1, #0			;NO
   SUBNE   R1, R9, R11			;YES, R1=new offset
   STR     R1, [R6], #4
   BEQ     _no_command_help		;NO
   MOV     R3, R0			;YES, preserve R0
   ADD     R0, R2, R10			; |  R0=text pointer
   BL      _strcpy			; |  copy text
   MOV     R0, R3			; |+ preserve R0

   ._no_command_help
   ADD     R9, R9, #3
   BIC     R9, R9, #%11			;word align R9

   LDRB    R1, [R0]
   TEQ     R1, #0			;last entry?
 BNE     _copy_command_table
 STR     R1, [R6], #4

					;**************************
 ._skip_command_table_copy
 MOV     R1, #0				;clear optional entries
 STR     R1, [R11, #Module_Header.SWI_chunk]
 STR     R1, [R11, #Module_Header.SWI_handler]
 STR     R1, [R11, #Module_Header.SWI_table]
 STR     R1, [R11, #Module_Header.SWI_decode]
 STR     R1, [R11, #Module_Header.MsgFilename]
					;**************************
					;validate optional SWI entries
 LDR     R1, [R10, #Module_Header.SWI_handler]
 TEQ     R1, #0				;does entry exist?
 BEQ     _skip_swi_handler		;NO
 BL      _check_R1a			;valid?
 BVS     _skip_optional_entries		;NO
					;**************************
 LDR     R1, [R10, #Module_Header.SWI_chunk]
 TST     R1, #%11111			;these must be blank
 TSTEQ   R1, #%11111111 << 24		;  instruction
 BNE     _skip_optional_entries		;invalid
 STR     R1, [R11, #Module_Header.SWI_chunk]

 MOV     R0, #Module_Header.SWI_handler
 BL      _create_entry
 MOVVS   R1, #0				;invalid entry
 STR     R1, [R11, #Module_Header.SWI_chunk]
 BVS     _skip_optional_entries
					;Copy SWI table
 LDR     R1, [R10, #Module_Header.SWI_table]
 BL      _check_R1			;valid?
 BVS     _skip_swi_handler		;NO
 TEQ     R1, #0				;does entry exist?
 BEQ     _skip_swi_handler		;NO
 SUB     R0, R9, R11			;new offset to table
 STR     R0, [R11, #Module_Header.SWI_table]

 ADD     R0, R10, R1			;R0=address of SWI table
 ._copy_swi_table
   BL      _strcpy			;copy SWI entry
   LDRB    R1, [R0]			;get char
   TEQ     R1, #0			;last SWI entry?
 BNE     _copy_swi_table
 STRB    R1, [R9], #1			;terminate SWI table

 ADD     R9, R9, #3
 BIC     R9, R9, #%11			;word align R9
					;**************************
 MOV     R0, #Module_Header.SWI_decode
 BL      _create_entry

 ._skip_swi_handler
 LDR     R1, [R10, #Module_Header.MsgFilename]
 TEQ     R1, #0				;does a Message file exist?
 BEQ     _check_for_32bit		;NO

 BL      _check_R1a			;valid? must be word aligned
 BLVC    _check_msgfilename		;is the filename valid (fix for TEK 1608 sound Modules)
 BVS     _skip_optional_entries		;NO

 SUB     R0, R9, R11			;new offset
 STR     R0, [R11, #Module_Header.MsgFilename]
 ADD     R0, R1, R10			;R0=text pointer
 BL      _strcpy			;copy text
 ADD     R9, R9, #3
 BIC     R9, R9, #%11			;word align R9

 ._check_for_32bit
 LDR     R1, [R10, #Module_Header.Flags]	;check for 32bit module
 TEQ     R1, #0				;does flags exist?
 BEQ     _skip_optional_entries		;NO
 BL      _check_R1a			;valid?
 BVS     _skip_optional_entries		;NO
 LDR     R0, [R10, R1]
 TST     R0, #1				;is the 32bit flag set?
 BNE     _loading_32bit_module

 ._skip_optional_entries
 STMFD   R13!, {R10}
 BL      return_taskID			;R10=taskID
 STR     R10, [R11, #Module_Header.taskID]
 LDMFD   R13!, {R10}
 MOV     R0, #Module_Header.bit32
 STR     R0, [R11, #Module_Header.Flags]
 MOV     R0, #1				;Module is 32bit
 STR     R0, [R11, #Module_Header.bit32]
 MOV     R0, #Module_Validation		;mark as an ADFFS module
 STR     R0, [R11, #Module_Header.ADFFS]
 MOV     R0, #0
 STR     R0, [R11, #Module_Header.FS_name]	;no FS or ImageFS currently
					;****************************************
					;create FS/ImageFS entry points
 MOV     R0, #Module_Header.FSEntry_Open
 BL      _create_FS_entry
 MOV     R0, #Module_Header.FSEntry_GetBytes
 BL      _create_FS_entry
 MOV     R0, #Module_Header.FSEntry_PutBytes
 BL      _create_FS_entry
 MOV     R0, #Module_Header.FSEntry_Args
 BL      _create_FS_entry
 MOV     R0, #Module_Header.FSEntry_Close
 BL      _create_FS_entry
 MOV     R0, #Module_Header.FSEntry_File
 BL      _create_FS_entry
 MOV     R0, #Module_Header.FSEntry_Func
 BL      _create_FS_entry
 MOV     R0, #Module_Header.FSEntry_GBPB
 BL      _create_FS_entry
					;****************************************
 BL      _check_for_jitmemorya

 MOV     R1, R11			;R1=Module start
 SUB     R2, R9, R11			;R2=Module size
 MOV     R0, #Module_InsertFromMemoryToRMA
 BL      pass_SWI_on
 SWI     XOS_Module			;insert into RMA
 MOVVS   R8, R0
 MOVVC   R8, #0				;R8=exit error
 BL      post_SWI_veneer

._discard_Module2
 TEQ     R8, #0				;did an error occur?
._discard_Module
 MOV     R1, #jit_RMA_heap
 LDRNE   R0, [R11, #Module_Header.Size]	;YES, get Module size
 TEQNE   R0, #0				; |   did we allocate heap space
 MOVNE   R0, #Heap_Free			; |
 MOVNE   R2, R10			; |   discard loaded Module
 SWINE   XOS_Heap			; |+  PRM1-380

 LDR     R0, [R13], #4			;get entry R0 from stack
 TEQ     R8, #0				;did an error occur
 BNE     _skip_Enter_check		;YES
 TEQ     R0, #Module_Run		;was it RMRun?
 BNE     _skip_Enter_check		;NO
 LDR     R0, [R11, #Module_Header.Start]	;get the Start entry for later
 TEQ     R0, #0				;does an Entry exist?
 BNE     Enter_module			;YES

 ._skip_Enter_check
 MOV     R0, #Heap_Free
 LDR     R2, [R13], #4			;free temp stub block
 SWI     XOS_Heap			;PRM1-380

 TEQ     R8, #0				;did an error occur
 MOVNE   R0, R8				;YES, the insert failed
 SUBEQS  R0, R0, R0			;NO, clear V and set R0 to 0
 ._exit
 BL      dontexit_SWI_veneer
 TEQ     R0, #0				;did an error occur?
; ADD     R13, R13, #SWI_veneer.size
 STRNE   R0, [R13, #0]			;YES, overwrite R0
 LDMFD   R13!, {R0-R10}			; |
; ADD     R12, R13, #SWI_stack.size	;R12=address for state
 BNE     vector_handler_trap_VS		; |+ report error
B       vector_handler_trap


._illegal_header
 ADR     R8, Error_illegal_header
 B       _discard_Module2

._loading_32bit_module
 MOV     R1, #jit_RMA_heap
 LDR     R0, [R11, #Module_Header.Size]	;get Module size
 TEQ     R0, #0				;did we allocate heap space
 MOVNE   R0, #Heap_Free
 MOVNE   R2, R10			;discard Module space
 SWINE   XOS_Heap			;PRM1-380

 LDMFD   R13!, {R0, R2}			;get entry R0 and stub block address
 MOV     R0, #Heap_Free
 SWI     XOS_Heap			;PRM1-380

 BL      dontexit_SWI_veneer
 LDMFD   R13!, {R0-R10}

; need to see if VProtect is trying to load a 32bit Module
 LDR     R14, VProtect_Module
 TEQ     R14, #0
 BEQ     _not_vprotect
 LDR     R11, [R13, #SWI_stack.R14]
 #if compile_RO == 400
   BIC     R11, R11, #&FC000003		;clear PSR
 #endif
 SUB     R11, R11, R14
 LDR     R14, VProtect_Module + 4
 CMP     R11, R14			;is it within VProtect?
 BHI     _not_vprotect			;NO
 TEQ     R0, #Module_InsertFromMemory
 BNE     _not_vprotect

 STMFD   R13!, {R0, R2}			;VProtect is loading a Module
 MOV     R0, #Module_InsertFromMemoryToRMA
 LDR     R2, [R1, #-4]			;get the Module size
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_Module
 STRVS   R0, [R13, #0]
 LDMVSFD R13!, {R0, R2}
 BVS     _error

;need to release the block R7 points to
 STMFD   R13!, {R1}
 MOV     R0, #Heap_Free
 MOV     R1, #jit_RMA_heap
 MOV     R2, R7
 SWI     XOS_Heap
 LDMFD   R13!, {R1}
 SUBS    R0, R0, R0			;clear V...just in case
 LDMFD   R13!, {R0, R2}
B       exit_SWI_veneer

 ._not_vprotect
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_Module
 ._error
 BL      post_SWI_veneer
B       exit_SWI_veneer




 ;R1 =Message file offset
 ;R8 =Module length
 ;R10=Module
._check_msgfilename
 MOV     R2, #1024			;max filename length
 ADD     R3, R10, R1
 ADD     R4, R10, R8
 ._check_msgfilename_L1
   LDRB    R0, [R3], #1
   TEQ     R0, #0
   BEQ     _valid_string		;valid

   CMP     R0, #32
   BLO     _invalid_string		;fails on name
   CMP     R0, #&A0
   BHI     _invalid_string		;fails on name
   CMP     R3, R4			;have we hit the Module end?
   BHS     _invalid_string		;YES

   SUBS    R2, R2, #1			;fails on length
 BNE     _check_msgfilename_L1

 ._invalid_string
 CMPVC    R0, #1<<31
 CMNVC    R0, #1<<31
 MOV      PC, R14

 ._valid_string
 CMPVS    R0, #1<<31
 CMNVS    R0, #1<<31
 MOV      PC, R14





;_check_for_jitmemorya
;---------------------
;checks for JITMEMORYA module entries and adds them to the JITMEMORYA table
;
;Entry:
; R10 - Module
;
;Exit:
; R0 - corrupted

._check_for_jitmemorya
 LDR     R0, JIT_module_fixups
 TEQ     R0, #0				;are there Module fixups?
 MOVEQ   PC, R14			;NO

 STMFD   R13!, {R1-R4, R9, R11-R12, R14}
 ADD     R2, R0, #4			;R2=JITMEMORYA table
 LDR     R3, [R10, #Module_Header.Title]
 ADD     R3, R3, R10			;R3=Module title

 MOV     R12, #jit_max_fixups
 ._check_for_jitmemorya_L1
   LDR     R0, [R2, #jit_module_fixup_table.offset]
   TEQ     R0, #0
   BNE     _found_jitmemorya

   ._check_for_jitmemorya_L1_return
   ADD     R2, R2, #jit_module_fixup_table.size
   SUBS    R12, R12, #1
 BNE     _check_for_jitmemorya_L1
 LDMFD   R13!, {R1-R4, R9, R11-R12, PC}


 ._found_jitmemorya			;check Module Title matches
 MOV     R9, R2				;R9=JITMEMORYA Module title
 MOV     R11, R3			;R11=Module title
 MOV     R14, #jit_module_fixup_table.offset	;max length
 ._found_jitmemorya_L1
   LDRB    R0, [R9], #1
   LDRB    R1, [R11], #1
   SUBS    R14, R14, #1			;hit limit?
   ADDNES  R4, R0, R1			;NO, CHR(0) hit?
   TEQNE   R1, #&0D			;  NO, CR?
   BEQ     _add_jitmemorya		;    YES, Module matches

   TEQ     R0, R1			;does the char match?
 BEQ     _found_jitmemorya_L1		;YES
 B       _check_for_jitmemorya_L1_return	;NO


 ._add_jitmemorya
 ADD     R0, R2, #jit_module_fixup_table.offset
 MOV     R1, R10			;preserve R10
 LDMIA   R0, {R9, R10, R11}
 ADD     R9, R9, R1			;absolute address
 BL      add_JITMEMORYA
 MOV     R10, R1			;preserve R10
 B       _check_for_jitmemorya_L1_return




;_copy_to_RMA
;------------
;Copy Module from R1 to JIT RMA space
;
;Entry:
; R1 - Module address in RAM
; R8 - Module size
;
;Exit:
; R0 - corrupted
; R10 - address in RMA of Module (unaligned)

._copy_to_RMA
 STMFD   R13!, {R1-R4, R14}

 MOV     R0, #Heap_Claim		;claim JIT RMA space for Module
 MOV     R1, #jit_RMA_heap
 ADD     R3, R8, #4			;R3=Module size + word for alignment
 SWI     XOS_Heap			;PRM1-379
 LDMVSFD R13!, {R1-R4, PC}		; |+ exit on error
 MOV     R10, R2			;R10=allocated space in our RMA

 LDR     R0, [R13, #0]			;R0=from address
 ADD     R1, R10, #3			;ensure allocation is word aligned
 BIC     R1, R1, #%11			;R1=to address

 MOV     R2, R1
 MOV     R4, R8
 BL      hv_reset_memory_block		;release block in JIT space

 MOV     R2, R8				;R2=size
 BL      MemCopy

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




;_load_module
;------------
;load a Module into JIT RMA
;
;Entry:
;R1 - module filename
;
;Exit:
; R0 - corrupted
; R8 - Module size
; R10 - address in JIT RMA of Module (unaligned)

._load_module
 STMFD   R13!, {R1-R5, R7, R14}

 MOV     R0, #5				;read file info
 SWI     XOS_File			;PRM2-38
 LDMVSFD R13!, {R1-R5, R7, PC}		;exit on error
 TEQ     R0, #1				;did we find a file?
 MOVNE   R0, #19			;NO, generate an error
 MOVNE   R2, #0				; |  File 'xxx' not found
 SWINE   XOS_File			; |+ PRM2-45
 LDMVSFD R13!, {R1-R5, R7, PC}		;exit on error
 MOV     R8, R4				;R8=module size

 MOV     R0, #Heap_Claim		;claim JIT RMA space for Module
 MOV     R1, #jit_RMA_heap
 ADD     R3, R8, #4			;R3=Module size + a word for alignment
 SWI     XOS_Heap			;PRM1-379
 LDMVSFD R13!, {R1-R5, R7, PC}		;exit on error
 MOV     R10, R2

 MOV     R0, #255
 LDR     R1, [R13, #0]			;preserve R1
 ADD     R2, R10, #3			;ensure allocation is word aligned
 BIC     R2, R2, #%11
 MOV     R3, #0				;load at R2
 SWI     XOS_File			;PRM2-43
 LDMVCFD R13!, {R1-R5, R7, PC}
 LDMFD   R13!, {R1-R5, R7, R14}		;error occured loading
					;fall-thru to _free_initial_heap
._free_initial_heap
 STMFD   R13!, {R0-R3}
 MOV     R0, #Heap_Free			;error loading, free heap block
 MOV     R1, #jit_RMA_heap
 MOV     R2, R10
 SWI     XOS_Heap			;PRM1-380
 LDMFD   R13!, {R0-R3}
B       _exit



;_strcpy
;--------
;Copy zero terminated string in memory
;
;Entry:
; R0 - string to copy
; R9 - address to copy too
;
;Exit:
; R0 - incremented by string size
; R1 - corrupted
; R9 - incremented by string size

._strcpy
   LDRB    R1, [R0], #1
   STRB    R1, [R9], #1			;copy one char
   TEQ     R1, #0			;until terminator hit
 BNE     _strcpy
MOV     PC, R14




;_check_R1 /_check_R1a
;---------------------
;checks if R1 points with the Module and _check_R1a also checks its word aligned

;Entry:
; R1 - address
; R8 - Module size

;Exit: EQ if OK

._check_R1a
 TST     R1, #%11			;is it word aligned?
 BNE     _check_R1_invalid		;NO, must be invalid
._check_R1
 CMP     R1, R8				;is pointer within Module size?
 BHS     _check_R1_invalid		;NO
 CMPVS   R0, #1<<31			;R1 appears to be good
 CMNVS   R0, #1<<31			;clear V
MOV     PC, R14

 ._check_R1_invalid
 CMPVC  R0, #1<<31
 CMNVC  R0, #1<<31			;set V
MOV    PC, R14



;_create_entry
;-------------
;Create Module entry point
;
;Entry:
; R0 - Module Header entry to create
; R8 - Size of Module
; R9 - Address to put managed entry code
; R10 - Module address
; R11 - Stub Module address
;
;Exit:
; R9 - incremented by code size

._create_entry
 STMFD   R13!, {R1-R5, R12, R14}
 ADR     R12, _codelet
 MOV     R2, #_codelet_end - _codelet

 LDR     R1, [R10, R0]
 BL      _check_R1a			;valid?
 LDMVSFD R13!, {R1-R5, R12, PC}		;NO
 ._create_entry_P1
 TEQ     R1, #0				;does the entry exist?
 BEQ     _create_entry_exit		;NO
 ADD     R1, R10, R1			;YES,
 ADD     R1, R1, #jit_code_start	;R1=actual entry address
 ._create_entry_P2
 STR     R1, [R9], #4			;copy codelet
 SUB     R1, R9, R11			;R0=offset in stub Module

 ._create_entry_L1
   LDR     R3, [R12], #4
   STR     R3, [R9], #4
   SUBS    R2, R2, #4
 BNE     _create_entry_L1

 ._create_entry_exit
 STR     R1, [R11, R0]			;new entry point
LDMFD   R13!, {R1-R5, R12, PC}




;_create_entry_USER
;------------------
;Create Module entry point that's entered in USER mode
;
;Entry:
; R0 - Module Header entry to create
; R8 - Size of Module
; R9 - Address to put managed entry code
; R10 - Module address
; R11 - Stub Module address
;
;Exit:
; R9 - incremented by code size

._create_entry_USER
 STMFD   R13!, {R1-R5, R12, R14}
 LDR     R1, [R10, R0]			;get entry
 MOV     R2, R1, LSR #24
 TEQ     R2, #&EA			;check for B &xxx
 BICEQ   R1, R1, #&FF << 24		;clear the instruction
 ADDEQ   R1, R1, #2			;correct offset
 MOVEQ   R1, R1, LSL #2			;convert to Module offset
 BL      _check_R1a			;valid?
 MOVVS   R0, #0				;NO, zero it match RO behaviour
 ADR     R12, _codelet_USER
 MOV     R2, #_codelet_end_USER - _codelet_USER
 B       _create_entry_P1




;_create_entry_INIT
;------------------
;Create Module entry point that's entered in USER mode
;
;Entry:
; R0 - Module Header entry to create
; R8 - Size of Module
; R9 - Address to put managed entry code
; R10 - Module address
; R11 - Stub Module address
;
;Exit:
; R9 - incremented by code size

._create_entry_INIT
 STMFD   R13!, {R1-R5, R12, R14}
 LDR     R1, [R10, R0]			;get entry
 BL      _check_R1a			;valid?
 LDMVSFD R13!, {R1-R5, R12, PC}		;NO
 SUB     R2, R9, R11			;get offset to base of stub Module
 ADD     R2, R2, #stub_module_base_offset	;return address of ADFFS_CallModuleEntryInit
 STR     R2, [R9], #4			;store in stub Module
 ADR     R12, _codelet_INIT
 MOV     R2, #_codelet_end_INIT - _codelet_INIT
 B       _create_entry_P1



;_create_FS_entry
;----------------
;Create Module entry point that's entered in USER mode
;
;Entry:
; R0 - FS entry to create
; R8 - Size of Module
; R9 - Address to put managed entry code
; R10 - Module address
; R11 - Stub Module address
;
;Exit:
; R9 - incremented by code size

._create_FS_entry
 STMFD   R13!, {R1-R5, R12, R14}
 ADR     R12, _codelet
 MOV     R2, #_codelet_end - _codelet
 MOV     R1, #0					;entry set by OS_FSControl
 B       _create_entry_P2




;_create_command_entry
;---------------------
;Create Module entry point for a command
;
;Entry:
; R0 - Module Header entry to create
; R6 - Address of Command entry
; R8 - Size of Module
; R9 - Address to put managed entry code
; R10 - Module address
; R11 - Stub Module address
;
;Exit:
; R0 - incremented by 4
; R6 - incremented by 4
; R9 - incremented by code size

._create_command_entry
 STMFD   R13!, {R1-R5, R12, R14}
 LDR     R1, [R0], #4
 CMP     R1, R8				;valid?
 MOVHS   R1, #0				;NO
 TEQ     R1, #0				;does the entry exist?
 STREQ   R1, [R6], #4			;NO
 LDMEQFD R13!, {R1-R5, R12, PC}		; |+ exit
 ADD     R1, R10, R1			;YES,
 ADD     R1, R1, #jit_code_start	;R1=actual entry address
 STR     R1, [R9], #4			;store entry in codelet
 SUB     R1, R9, R11			;R0=offset in stub Module
 STR     R1, [R6], #4			;new entry point

 ADR     R12, _codeletR0
 MOV     R2, #_codeletR0_end - _codeletR0
 ._create_command_entry_L1
   LDR     R3, [R12], #4
   STR     R3, [R9], #4
   SUBS    R2, R2, #4
 BNE     _create_command_entry_L1
LDMFD   R13!, {R1-R5, R12, PC}


; DCD    <Module entry point>
._codeletR0
 STR     R14, [R13, #-4]!
 SWI     ADFFS_CallModuleEntryR0 + JIT_SWI_OS_Flag
 LDR     PC, [R13], #4
 ._codeletR0_end


; DCD    <Module entry point>
._codelet_USER
;#if JIT_WIMP_modules == 1  ;***NEEDS TO MAP MODULE IN***
; SWI     ADFFS_MapModulesIn + JIT_SWI_OS_Flag
;#endif
 LDR     PC, _codelet_USER - 4
 ._codelet_end_USER


; DCD    <Offset>			;offset to start of Module from
					;ADFFS_CallModuleEntryInit call address + 4
; DCD    <Module entry point>
._codelet_INIT
 STR     R14, [R13, #-4]!
 ._codelet_INIT_call
 SWI     ADFFS_CallModuleEntryInit + JIT_SWI_OS_Flag
 SWI     ADFFS_CallModuleEntryInitEnd + JIT_SWI_OS_Flag
 LDR     PC, [R13], #4
 ._codelet_end_INIT


; DCD    <Module entry point>
._codelet
 STR     R14, [R13, #-4]!
 ._codelet_swi SWI     ADFFS_CallModuleEntry + JIT_SWI_OS_Flag
 LDR     PC, [R13], #4
 ._codelet_end


 #set module_entry_ptr = 4 + (_codelet_swi - _codelet) + 4
 #set stub_module_base_offset = 16 ; _codelet_INIT_call + 4 - _codelet_INIT + 8


;Stack: <heap block to free>,{R0-R10},<SWI veneer>
;R11 - Stub Module pointer
.Enter_module
 MOV     R0, #Module_Lookup
 LDR     R1, [R11, #Module_Header.Title]
 ADD     R1, R11, R1			;R1 points to Module name
 SWI     XOS_Module
 LDR     R11, [R3, #Module_Header.Title]
 ADD     R11, R3, R11			;R11=module title

 MOV     R0, #Heap_Free
 LDR     R2, [R13], #4			;free temp stub block
 SWI     XOS_Heap			;PRM1-380
 BL      dontexit_SWI_veneer
 LDMFD   R13!, {R0-R10}

 MOV     R2, R1				;find parameters on commandline
 ._run_params
   LDRB    R14, [R2], #1
   TEQ     R14, #0
   TEQNE   R14, #13
   SUBEQ   R2, R2, #1			;no commandline parameters
   TEQNE   R14, #32
 BNE     _run_params

 MOV     R0, #Module_Enter		;YES
 MOV     R1, R11
 PULLSWI				;clear stack
 BL      pass_SWI_on2			;pass next SWI to OS
 SWI     XOS_Module			;Enter Module
B       call_OS_Exit			;should never reach here




;call_module_entry_INIT_END
;--------------------------
;26bit Module init has completed
;
;Entry: CPU in SVC32 on 32bit, SVC26 on 26bit
; stack: {SWI stack}, [Module_being_inserted]
; [R14, #-module_entry_ptr] = ptr to Module entry

.call_module_entry_INIT_END
 LDR     R14, [R13, #SWI_stack.size + SWI_veneer.size]	;get Module_being_inserted old value
 TEMP    R12
 STR     R14, Module_being_inserted
 LOCK    R12
 PULLSWI
 ADD     R13, R13, #4			;drop Module_being_inserted from stack
MOVS     PC, R14




;call_module_entry_INIT
;----------------------
;Init a 26bit Module
;
;Entry: CPU in SVC32 on 32bit, SVC26 on 26bit
; [R14, #-module_entry_ptr] = ptr to Module entry

.call_module_entry_INIT
 PULLSWI
 SUB     R13, R13, #4				;space for Module_being_inserted
 PPUSHSWI
 #if compile_RO == 400
   BIC     R14, R14, #&FC000003
 #endif
 LDR     R12, Module_being_inserted
 STR     R12, [R13, #SWI_stack.size + SWI_veneer.size]	;store current value
 LDR     R12, [R14, #-stub_module_base_offset]	;get offset to Stub Module base
 SUB     R14, R14, R12				;Module base address
 TEMP    R12
 STR     R14, Module_being_inserted
 LOCK    R12
;fall-thru to call_module_entry_R0



.call_module_entry_R0
 #if compile_RO > 400
   TEMP    R14
   STR     R0, page_zero_module_cmdline	;store commandline to handle Aborts
   LOCK    R14				;(fixes Stunt Racer 2000)
 #endif




;call_module_entry
;-----------------
;Enters a 26bit Module
;
;Entry: CPU in SVC32 on 32bit
; stack: {SWI stack}, [Module_being_inserted]
; [R14, #-module_entry_ptr] = ptr to Module entry

.call_module_entry
 PULLSWI				;clear stack
 STR     R14, [R13, #-4]!		;restack return address
 #if JIT_WIMP_modules == 1
   BL      check_JIT_and_taskID		;is the task supported?
   LDMNEFD R13!, {PC}^			;NO, exit
   LDR     R14, [R13]
 #endif
 LDR     R14, [R14, #-module_entry_ptr]	;get Module entry address
 TEQ     R14, #0			;does the entry exist?
 LDMEQFD R13!, {PC}^			;NO, exit

 MRS     R14, CPSR
 ORR     R14, R14, #%11 << 6		;disable IRQ/FIQ
 MSR     CPSR_c, R14
 #if compile_IOMD == 1
   NOP
 #endif

;KKK needs to page task in

 MRS     R14, SPSR
 STR     R14, [R13, #-4]!		;stack return SPSR
 ;SVC32 STACK: SPSR, R14

 #if compile_RO == 400
   SUB     R13, R13, #4 * 4
   STMFD   R13!, {R0-R2}
   ;SVC32 STACK: R0, R1, R2, <spare>, <spare>, <spare>, <spare>, SPSR, R14
   ADD     R0, R13, #3 * 4
   BIC     R2, R14, #%10000
   MSR     CPSR_c, R2			;SVC26
   NOP
   STR    R0, [R0, #0]			;fix for errata on SA-110 rev.2
   STMIA   R0, {R13, R14}^		;store USR26_R13, USR26_R14
   ;SVC32 STACK: R0, R1, R2, USR26_R13, USR26_R14, <spare>, <spare>, SPSR, R14
   NOP					;fix for errata on ARM6/7 macrocells, StrongARM
   MRS     R0, SPSR
   MOV     R1, R14
   ORR     R2, R2, #%10000
   MSR     CPSR_c, R2			;SVC32
   NOP
   STR     R1, [R13, #6 * 4]		;stack SVC26 R14
   ;SVC32 STACK: R0, R1, R2, USR26_R13, USR26_R14, <spare>, SVC26_R14, SPSR, R14
   STR     R0, [R13, #5 * 4]		;stack SVC26 SPSR
   ;SVC32 STACK: R0, R1, R2, USR26_R13, USR26_R14, SVC26_SPSR, SVC26_R14, SPSR, R14
   LDMFD   R13!, {R0-R2}
 #endif
 #if compile_RO > 400
   SUB     R13, R13, #8
   STMIA   R13, {R13, R14}^		;stack USR R13, R14
 #endif
 ;SVC32 STACK: USR_R13, USR_R14, [SVC26_SPSR, SVC26_R14], SPSR, R14

 SUB     R13, R13, #8
 STMFD   R13!, {R0-R1}
 ;SVC32 STACK: R0, R1, <spare>, <spare>, USR_R13, USR_R14, [SVC26_SPSR, SVC26_R14], SPSR, R14

 #if compile_RO == 400
   LDR     R14, [R13, #9 * 4]
 #endif
 #if compile_RO > 400
   LDR     R14, [R13, #7 * 4]
 #endif
 LDR     R14, [R14, #-module_entry_ptr]	;get Module entry address
 STR     R14, [R13, #2 * 4]		;store Module entry point
 ;SVC32 STACK: R0, R1, Module entry, <spare>, USR_R13, USR_R14, [SVC26_SPSR, SVC26_R14], SPSR, R14

 BL      Allocate_Transient_Stack	;R0=stack pointer, R1=stack number
 SUB     R0, R0, #2 * 4			;space for Module entry and return
 STR     R1, [R13, #3 * 4]		;store Transient stack being used
 ;SVC32 STACK: R0, R1, Module entry, Transient stack#, USR_R13, USR_R14, [SVC26_SPSR, SVC26_R14], SPSR, R14

 #if compile_RO == 400
   STR     R2, [R13, #-4]!
   MRS     R2, CPSR
   BIC     R14, R2, #%10000
   MSR     CPSR_c, R14			;SVC26
   NOP
 #endif
 STR     R0, [R13, #-4]!
 LDMIA   R13, {R13}^			;set USR stack
 #if compile_IOMD == 1
   NOP
 #endif
 ADD     R13, R13, #4
 #if compile_RO == 400
   MSR     CPSR_c, R2			;SVC32
   NOP
   LDR     R2, [R13], #4
 #endif

 ADR     R14, _return
 LDR     R1, [R13, #2 * 4]		;get Module entry
 STMIA   R0, {R1, R14}			;store on USR stack
 ;USR[32] STACK: <entry>, <return>

 LDMFD   R13!, {R0-R1}
 ADD     R13, R13, #4			;drop Module entry
 ;SVC32 STACK: Transient stack#, USR_R13, USR_R14, [SVC26_SPSR, SVC26_R14], SPSR, R14

 MRS     R14, SPSR			;get entry flags/CPU mode
 #if compile_RO == 400
   BIC     R14, R14, #%10011 + (%1111 << 28)	;USR26 / clear flags
 #endif
 #if compile_RO > 400
   BIC     R14, R14, #%11 + (%1111 << 28)	;USR32 / clear flags
 #endif
 MSR     CPSR_all, R14			;switch to USR[32] mode
 #if compile_IOMD == 1
   NOP
 #endif

 LDR     R14, jit_managed_ldr_pc_r13
 LDMFD   R13!, {PC}			;call module entry
 ;USR[32] STACK: <return>

 ._return				;returns in USR[32]
 MRS     R14, CPSR			;get flags
 STR     R14, [R13, #-4]!		;stack them
 ;USR[32] STACK: USR_CPSR
 SWI     XOS_IntOff			;prevent IRQ's
 SWI     XOS_EnterOS			;switch back to SVC[32]

 #if compile_RO == 400			;entered in SVC26
   ;SVC32 STACK: Transient stack#, USR_R13, USR_R14, SVC26_SPSR, SVC26_R14, SPSR, R14
   MSR     CPSR_c, #%11010011		;SVC32 IRQ/FIQ disabled
   NOP
   STR     R0, [R13, #-8]!
   ;SVC32 STACK: R0, <spare>, Transient stack#, USR_R13, USR_R14, SVC26_SPSR, SVC26_R14, SPSR, R14
   ADD     R0, R13, #4
   MSR     CPSR_c, #%11000011		;SVC26 IRQ/FIQ disabled
   NOP
   STR     R0, [R0, #0]			;fix for errata on SA-110 rev.2
   STMIA   R0, {R13}^			;store USR R13
   NOP					;fix for errata on ARM6/7 macrocells, StrongARM
   ;SVC32 STACK: R0, USR26_R13, Transient stack#, USR_R13, USR_R14, SVC26_SPSR, SVC26_R14, SPSR, R14
   ADD     R0, R0, #2 * 4
   LDMIA   R0, {R13, R14}^		;restore USR26_R13, USR26_R14
   ;SVC32 STACK: R0, USR26_R13, Transient stack#, <spare>, <spare>, SVC26_SPSR, SVC26_R14, SPSR, R14
   NOP					;fix for errata on ARM6/7 macrocells, StrongARM
   ADD     R0, R0, #2 * 4
   LDMIA   R0, {R0, R14}		;restore SVC26_SPSR, SVC26_R14
   ;SVC32 STACK: R0, USR26_R13, Transient stack#, <spare>, <spare>, <spare>, <spare>, SPSR, R14
   MSR     SPSR_all, R0
   MSR     CPSR_c, #%11010011		;SVC32 IRQ/FIQ disabled
   NOP
 #endif					;now in SVC32 with SVC26 state restored
 #if compile_RO > 400
   ;SVC32 STACK: Transient stack#, USR_R13, USR_R14, SPSR, R14
   MSR     CPSR_c, #%11010011		;SVC32 IRQ/FIQ disabled
   #if compile_RO > 400 AND compile_IOMD == 1
     NOP
   #endif
   SUB     R13, R13, #8
   STMIA   R13, {R0, R13}^		;store USR R13
   #if compile_RO > 400 AND compile_IOMD == 1
     NOP				;fix for errata on ARM6/7 macrocells, StrongARM
   #endif
   ;SVC32 STACK: R0, USR32_R13, Transient stack#, USR_R13, USR_R14, SPSR, R14
   ADD     R0, R13, #3 * 4
   LDMIA   R0, {R13, R14}^		;restore USR_R13, USR_R14
   #if compile_RO > 400 AND compile_IOMD == 1
     NOP				;fix for errata on ARM6/7 macrocells, StrongARM
   #endif
   ;SVC32 STACK: R0, USR32_R13, Transient stack#, <spare>, <spare>, SPSR, R14
 #endif

 LDR     R0, [R13, #4]
 LDR     R0, [R0, #0]			;USR_CPSR
 STR     R0, [R13, #4]
 ;SVC32 STACK: R0, USR_CPSR, Transient stack#, <spare>, <spare>, [<spare>, <spare>], SPSR, R14

 LDR     R0, [R13, #2 * 4]		;get the stack we used
 BL      Free_Transient_Stack		;and free it
 ;SVC32 STACK: R0, USR_CPSR, <spare>, <spare>, <spare>, [<spare>, <spare>], SPSR, R14

 #if compile_RO == 400
   ;SVC STACK: R0, USR_CPSR, <spare>, <spare>, <spare>, <spare>, <spare>, SPSR, R14
   LDR     R14, [R13, #7 * 4]
 #endif
 #if compile_RO > 400
   TEMP    R14
   MOV     R0, #0
   STR     R0, page_zero_module_cmdline
   LOCK    R14
   ;SVC STACK: R0, USR_CPSR, <spare>, <spare>, <spare>, SPSR, R14
   LDR     R14, [R13, #5 * 4]
 #endif					;R14=entry SPSR
 ;SVC STACK: R0, USR_CPSR, <spare>, <spare>, <spare>, [<spare>, <spare>], <spare>, R14

 LDR     R0, [R13, #4]			;USR_CPSR
 ;SVC STACK: R0, <spare>, <spare>, <spare>, <spare>, [<spare>, <spare>], <spare>, R14
 MSR     CPSR_f, R0			;set SVC32_f to match USR flags
 AND     R0, R0, #%1111 << 28		;R0=return flags
 BIC     R14, R14, #%1111 << 28
 ORR     R14, R14, R0

 LDR     R0, [R13]
 ;SVC STACK: <spare>, <spare>, <spare>, <spare>, <spare>, [<spare>, <spare>], <spare>, R14
 #if compile_RO == 400
   ADD     R13, R13, #8 * 4
 #endif
 #if compile_RO > 400
   ADD     R13, R13, #6 * 4
 #endif
 ;SVC STACK: R14

 MSR     SPSR_all, R14
LDMFD   R13!, {PC}^			;exit

#set handle_finalise_error=_return




;kill_26bit_modules
;------------------
;RMKills all 26bit Modules

;Entry:
; in either SVC32 or SVC26

.kill_26bit_modules
 STMFD   R13!, {R0-R12, R14}
 ADR     R12, VARS

 MOV     R0, #FSControl_StartApplication	;setup environment
 ADR     R1, ADFFS_Title
 MOV     R2, #&8000				;set CAO to ensure Modules are killed
 MOV     R3, R1
 BL      pass_SWI_on
 SWI     XOS_FSControl				;PRM2-85

 BL      return_taskID				;R10=taskID
 ._recheck
 MOV     R1, #0
 MOV     R2, #0					;instantiation number
 ._next_module
   #if compile_RO > 311 AND compile_RO < 500
     SUB     R9, R13, #4			;ref001 R9=ptr to Module Private word
     MOV     R0, #Module_ExtractInfo		;          (R4 on stack)
     SWI     XOS_Module				;PRM1-243
     LDMVSFD R13!, {R0-R12, PC}			;no more Modules
   #endif
   #if compile_RO == 500
     MOV     R0, #Module_Enumerate		;try new method first
     SWI     XOS_Module				;which returns Module Private Word
     MOVVC   R9, R4
     SUBVS   R9, R13, #4			;ref001 R9=ptr to Module Private word
     MOVVS   R0, #Module_ExtractInfo		;          (R4 on stack)
     SWIVS   XOS_Module				;PRM1-243
     LDMVSFD R13!, {R0-R12, PC}			;no more Modules
   #endif

   LDRB    R0, [R12, #soundDMA_restarting - VARS]
   TEQ     R0, #0				;is SoundDMA restarting?
   BEQ     _ok					;NO

   MRS     R1, CPSR
   #if compile_RO > 400
     BIC     R0, R1, #%1111			;switch to USR to trigger CallBacks
   #endif
   #if compile_RO == 400
     BIC     R0, R1, #%11111
   #endif
   MSR     CPSR_c, R0
   #if compile_IOMD == 1
     NOP
   #endif
   ._L1
     SWI     XOS_SetCallBack			;trigger CallBacks
     LDRB    R0, [R12, #soundDMA_restarting - VARS]
     CMP     R0, #1				;has it finished?
   BNE     _L1					;NO

   SWI     OS_EnterOS
   MSR     CPSR_c, R1
   #if compile_IOMD == 1
     NOP
   #endif
   MOV     R1, #0
   STRB    R1, [R12, #soundDMA_restarting - VARS]
   B       _recheck

   ._ok
   LDR     R0, [R3, #Module_Header.ADFFS]	;check it's one of ours
   EORS    R0, R0, #Module_Validation
   LDREQ   R8, [R3, #Module_Header.taskID]
   TEQEQ   R8, R10				;is it in the current domain?
   BNE     _next_module

   STMFD   R13!, {R1, R2, R4}			;ref001 store next Module/instance, Module Private word
   LDR     R0, [R5]				;get instance name
   EORS    R0, R0, #&65736142			;="Base"
   LDREQB  R0, [R5, #4]
   TEQEQ   R0, #0				;does it have a postfix?

   LDR     R1, [R3, #Module_Header.Title]	;pointer to Module name
   ADD     R1, R1, R3
   BNE     _kill_instantiation			;YES

   ._kill_module
   LDR     R2, [R3, #Module_Header.Address]	;get start and size
   LDR     R4, [R3, #Module_Header.Size]	;so we can kill vector claims

   #if compile_DEBUG == 1 AND JIT_debug == 1
     MOV     R6, #0
     STR     R6, [R3, #Module_Header.Service]	;prevent code running
     STR     R6, [R3, #Module_Header.Finalise]
     STR     R6, [R3, #Module_Header.Service]
     STR     R6, [R3, #Module_Header.Commands]
     STR     R6, [R3, #Module_Header.SWI_handler]
   #endif
   #if (compile_DEBUG == 0 OR JIT_debug == 0) AND compile_RO > 311
     STMFD   R13!, {R1-R4, R12}
     STR     R13, [R12, #trap_aborts_in_Finalise - VARS]
     ADR     R0, DAV_ABT_resume
     MRS     R2, CPSR
     ADR     R1, _trap_aborts
     STMIA   R0, {R1, R2}
 
     LDR     R0, [R3, #Module_Header.Finalise]
     TEQ     R0, #0
     MOVNE   R1, #0
     STRNE   R1, [R3, #Module_Header.Finalise]	;clear Finalise entry point
     ADRNE   R14, _trap_aborts_return
     MOVNE   R12, R9
     ADDNE   PC, R3, R0				;call finalise entry directly to trap errors
     ._trap_aborts_return
     LDMFD   R13!, {R1-R4, R12}

     MOV     R0, #Module_Delete
     BL      pass_SWI_on
     SWI     XOS_Module
     LDRVC   R0, [R13, #0]
     SUBVC   R0, R0, #1				;move back for next Module
     STRVC   R0, [R13, #0]
     TEMP    R1
     MOV     R0, #0
     STR     R0, [R12, #trap_aborts_in_Finalise - VARS]
     STR     R0, DAV_ABT_resume
     LOCK    R1
   #endif

   MOV     R8, R2				;start of Module
   ADD     R9, R4, R2				;end of Module
   #if compile_DEBUG == 0 OR JIT_debug == 0
     MOV     R0, #0				;allow clean voice shutdown
   #endif
   #if compile_DEBUG == 1 AND JIT_debug == 1
     MOV     R0, #1				;forcibly kill voices
   #endif
   BL      kill_voices_in_range			;kill any rogue voices
   BL      kill_vectors_in_range		;kill any rogue vectors

   #if JIT_debug == 0 AND JIT_instruction_trace == 0
     MOV     R0, R2				;R0=start R4=size
     BL      hv_reset_memory_block		;free codelets
   #endif
   ._nothing_to_kill
   LDMFD   R13!, {R1, R2, R3}			;restore R1,R2 and drop Module Private word
 B       _next_module

 ._kill_instantiation
;@@@ needs to create string: <Module_Header.Title>%<R5>
;@@@ then jump to: _kill_module
MOV R0, R1
SWI OS_Write0
SWI OS_WriteS
DCB " - instanced", 0
ALIGN
SWI OS_NewLine
 B        _nothing_to_kill


#if (compile_DEBUG == 0 OR JIT_debug == 0) AND compile_RO > 311
 ._trap_aborts
 SWI     XOS_WriteS
 DCB     "Module aborted", 0
 ALIGN
 SWI     XOS_NewLine
 ADR     R12, VARS
 LDR     R13, [R12, #trap_aborts_in_Finalise - VARS]
 B       _trap_aborts_return

 ;Entered in USR
 .handle_module_error
 SWI     XOS_WriteS
 DCB     "Module Error: ", 0
 ALIGN
 ADD     R0, R0, #4
 SWI     XOS_Write0
 SWI     XOS_NewLine
 SUBS    R0, R0, R0			;clear V
B       handle_finalise_error
#endif
