#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

.load_26bit_module
 STMFD   R13!, {R0-R10}

 MOV     R7, R0				;R7=entry R0
 SUB     R13, R13, #SWI_veneer.size	;space for veneer
 MOV     R12, R13			;state needs to be local
 BL      hv_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
 BNE     _skip_swi_handler		;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_swi_handler
					;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, emulate_RISCOS
 CMP     R1, #&360 << 8			;are we emulating RISC OS 3.6+
 BLO     _skip_optional_entries		;YES, there's no message file
 LDR     R1, [R10, #Module_Header.MsgFilename]
 BL      _check_R1a			;valid?
 BVS     _skip_optional_entries		;NO
 TEQ     R1, #0				;does a Message file exist?
 BEQ     _check_for_32bit		;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

 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}			; |
 BNE     vector_handler_trap_VS		; |+ report error
B       vector_handler_trap


._illegal_header
 ADR     R8, Error_illegal_header
 TEQ     R8, #0				;ensure NE
 B       _discard_Module

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

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

 BL      dontexit_SWI_veneer
 ADD     R13, R13, #SWI_veneer.size	;drop space for veneer
 LDMFD   R13!, {R0-R10}
B       vector_handler_forward		;pass to OS




;_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-R3, 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-R3, 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, R8				;R2=size
 BL      MemCopy
 SUBS    R1, R1, R1			;clear V
 LDMFD   R13!, {R1-R3, 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
 CMP     R0, #1<<31			;R1 appears to be good
 CMNVS   R0, #1<<31			;clear V
MOV     PC, R14

 ._check_R1_invalid
 CMP    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?
 LDMVSFD R13!, {R1-R5, R12, PC}		;NO
 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 << 20)
 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 << 20)
;#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 << 20)
 SWI     ADFFS_CallModuleEntryInitEnd + (JIT_SWI_OS_Flag << 20)
 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 << 20)
 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>,<SWI veneer>,{R0-R10}
;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
 ADD     R13, R13, #SWI_veneer.size
 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     OS_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
 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, SVC26 on 26bit
; 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
 #if compile_RO == 400
   BIC     R14, R14, #&FC000003
 #endif
 LDR     R14, [R14, #-module_entry_ptr]	;get Module entry address
 TEQ     R14, #0			;does the entry exist?
 LDMEQFD R13!, {PC}^			;NO, exit
 STR     R14, _entry + 4		;store entry
;KKK needs to page task in

 LDR     R14, jit_managed_ldr_pc_r13
 STR     R14, _entry			;store return

 MRS     R14, SPSR
 STR     R14, [R13, #-4]!		;stack return SPSR
					;stack: {SPSR, R14}
 #if compile_RO == 400
   BIC     R14, R14, #%10000
   MSR     CPSR_all, R14		;SVC26
   NOP
   STR     R14, [R13, #-4]!		;stack SVC26 R14
   MRS     R14, SPSR
   STR     R14, [R13, #-4]!		;stack SVC26 SPSR
 #endif

 SUB     R13, R13, #5 * 4		;space on stack for USER regs
 STMIA   R13, {R0-R1, R12, R13, R14}^	;stack: {R0, R1, <free>, USER_R13, USER_R14,
					;:[SVC26_SPSR, SVC26_R14], SPSR, R14}

 BL      Allocate_Transient_Stack	;R0=stack pointer, R1=stack number
 STR     R0, [R13, #-4]!
 LDMIA   R13, {R13}^			;set USER stack
 #if compile_IOMD == 1
   NOP					;fix for errata on ARM6/7 macrocells, StrongARM
 #endif
 ADD     R13, R13, #4
 STR     R1, [R13, #2 * 4]		;store stack being used (over R12)
 LDMFD   R13!, {R0-R1}
 MRS     R14, SPSR			;get entry flags/CPU mode
 BIC     R14, R14, #%11 + (%1111 << 28)	;USER[32] flags clear
 MSR     CPSR_all, R14			;switch to USER[32] mode
 #if compile_IOMD == 1
   NOP
 #endif

 ADR     R14, _return
 STR     R14, [R13, #-4]!		;stack our return address
 ADR     R14, _entry
 LDMIA   R14, {R14, PC}			;call module entry

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

 SUB     R13, R13, #8
 STMIA   R13, {R0, R13}^		;get USER R13
 LDR     R0, [R13, #4]
 LDR     R0, [R0, #0]			;get USER flags
 STR     R0, [R13, #4]
			;stack: {R0, <USER flags>, <stack>, USER_R13, USER_R14,
			;:       [SVC26_SPSR, SVC26_R14], SPSR, R14}
 LDR     R0, [R13, #2 * 4]		;get the stack we used
 BL      Free_Transient_Stack		;and free it
 LDR     R0, [R13, #4]			;get returned USER flags
 MSR     CPSR_f, R0			;set SVC flags to match USER flags
 LDR     R0, [R13], #4
 STR     R12, [R13, #4]!
			;stack: {R12, USER_R13, USER_R14,
			;:       [SVC26_SPSR, SVC26_R14], SPSR, R14}

 #if compile_RO == 400			;get return SPSR from stack
   MOV     R12, #%10010011		;SVC32, IRQ disabled
   MSR     CPSR_all, R12
   NOP
   LDR     R14, [R13, #0]		;stack: {SPSR, R14}
 #endif
 #if compile_RO > 400
   LDR     R14, [R13, #3 * 4]		;stack: {R12, USER_R13, USER_R14, SPSR, R14}
 #endif
 MRS     R12, CPSR
 AND     R12, R12, #%1111 << 28		;R12=return flags
 BIC     R14, R14, #%1111 << 28
 ORR     R14, R14, R12
 #if compile_RO == 400
   STR     R14, [R13, #0]		;update return SPSR
   MOV     R12, #%10000011		;SVC26, IRQ disabled
   MSR     CPSR_all, R12		;SVC26
   NOP
 #endif
 #if compile_RO > 400
   STR     R14, [R13, #3 * 4]		;update return SPSR
 #endif
 LDR     R12, [R13], #4			;preserve R12
					;stack: {USER_R13, USER_R14,
					;:[SVC26_SPSR, SVC26_R14], SPSR, R14}
 LDMIA   R13, {R13, R14}^		;restore USER R13, R14
 #if compile_IOMD == 1
   NOP					;fix for errata on ARM6/7 macrocells, StrongARM
 #endif
 ADD     R13, R13, #8			;stack: {[SVC26_SPSR, SVC26_R14], SPSR, R14}

 #if compile_RO == 400
   LDR     R14, [R13], #4		;restore SVC26 SPSR
   MSR     SPSR_all, R14
   LDR     R14, [R13], #4		;restore SVC26 R14

   STR     R0, _entry			;preserve R0
   MOV     R0, #%10010011		;SVC32
   MSR     CPSR_all, R0			;preserve R0
   NOP
   LDR     R0, _entry
 #endif
 #if compile_RO > 400
   STR     R0, [R13, #-4]!
   MOV     R0, #0
   TEMP    R14
   STR     R0, page_zero_module_cmdline
   LOCK    R14
   LDR     R0, [R13], #4
 #endif
					;stack: {SPSR, R14}
 LDR     R14, [R13], #4			;pull return SPSR
 MSR     SPSR_all, R14
LDMFD   R13!, {PC}^			;exit

 ._entry	DCD 0
		DCD 0



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

.kill_26bit_modules
 STMFD   R13!, {R0-R10, R14}

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

 BL      return_taskID				;R10=taskID
#if JIT_debug == 1
 MOV     R6, #0					;don't allow code to run
#endif
 MOV     R0, #Module_ExtractInfo
 MOV     R1, #0
 ._L1
   MOV     R2, #0				;instantiation number
   ._L2
     SWI     XOS_Module				;PRM1-243
     LDMVSFD R13!, {R0-R10, PC}			;no more Modules

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

#if JIT_debug == 1
     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

     TEQ     R2, #0				;does it have a postfix?
     BNE     _kill_instantiation		;YES

#if JIT_debug == 0
     SUB     R1, R1, #1				;reduce module no.
#endif
     STMFD   R13!, {R0-R2}

     LDR     R1, [R3, #Module_Header.Title]	;pointer to Module name
     ADD     R1, R1, R3
     ._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 JIT_debug == 0
     MOV     R0, #Module_Delete
     SWI     XOS_Module
     LDRVS   R1, [R13, #4]			;failed
     ADDVS   R1, R1, #1
     STRVS   R1, [R13, #4]			;move to next Module
#endif

     TEQ     R4, #0				;is the Module Appspace based?
     BEQ     _nothing_to_kill			;YES
     MOV     R8, R2				;start of Module
     ADD     R9, R4, R8				;end of Module
#if JIT_debug == 0
     MOV     R0, #0				;allow clean voice shutdown
#endif
#if 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!, {R0-R2}

     ._not_26bit
     TEQ     R2, #0				;last instantiation
   BNE     _L2
 B       _L1

 ._kill_instantiation
;@@@ needs to create string: <Module_Header.Title>%<R5>
;@@@ then jump to: _kill_module
 B        _not_26bit
