;TODO: Check if Module is already 32bit

#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
 .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  = {R12, PC}
; R0     - reason code
; R1, R2 - depending on reason code

.load_26bit_module
 STMFD   R13!, {R0-R11}

 ADR     R12, _SPSR			;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
 LDREQ   R8, [R1, #-4]
 MOVNE   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
 ADD     R3, R8, #4 + Module_Header.End + ((_codelet_end - _codelet_start + 4) * 8)	;stub Module size=Module size + Stub header + FS entries + word for alignment
 SWI     XOS_Heap			;PRM1-379
 BVS     _exit				;exit with error
 STR     R2, [R13, #-4]!		;store temp stub block for release 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     R10, [R11, #Module_Header.Address]	;store our address
 ADD     R10, R10, #3			;ensure allocation is word aligned
 BIC     R10, R10, #%11
 ADD     R0, R8, #4			;size + word for alignment
 STR     R0, [R11, #Module_Header.Size]	;and size so we can kill it later

 MOV     R0, #Module_Header.Start
 BL      _create_entry_USER
 MOV     R0, #Module_Header.Init
 BL      _create_entry_INIT
 MOV     R0, #Module_Header.Finalise
 BL      _create_entry
 MOV     R0, #Module_Header.Service
 BL      _create_entry

 LDR     R1, [R10, #Module_Header.Title]
 ADD     R1, R1, R10			;R1=title start
 BL      check_essential_modules	;is the Module essential?
 MOVNE   R8, #0				;YES
 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]
 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     R0, [R10, #Module_Header.Commands]
 TEQ     R0, #0				;does a table exist?
 MOVEQ   R1, #0				;NO
 LDRNEB  R1, [R10, R0]			;YES,
 TEQNE   R1, #0				; |+  is the first command entry valid?
 SUBNE   R1, R9, R11			;new offset to table
 STR     R1, [R11, #Module_Header.Commands]
 BEQ     _skip_command_table_copy

 ADD     R0, R10, R0			;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
 CMP     R1, R8				;is table within Module size?
 BHS     _skip_optional_entries		;NO
					;**************************
 LDR     R1, [R10, #Module_Header.SWI_chunk]
 TST     R1, #%11111			;these must be blank
 BNE     _skip_optional_entries		;invalid
 STR     R1, [R11, #Module_Header.SWI_chunk]

 MOV     R0, #Module_Header.SWI_handler
 BL      _create_entry
					;Copy SWI table
 LDR     R0, [R10, #Module_Header.SWI_table]
 TEQ     R0, #0				;does entry exist?
 BEQ     _skip_swi_handler		;NO
 CMP     R0, R8				;is table within Module size?
 BHS     _skip_optional_entries		;NO
 SUB     R1, R9, R11			;new offset to table
 STR     R1, [R11, #Module_Header.SWI_table]

 ADD     R0, R10, R0			;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
 CMP     R1, R8				;is pointer within Module size?
 BHS     _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

 ._check_for_32bit
 LDR     R1, [R10, #Module_Header.Flags]	;check for 32bit module
 TEQ     R1, #0				;does flags exist?
 BEQ     _skip_optional_entries		;NO
 CMP     R1, R8				;is pointer within Module size?
 BHS     _skip_optional_entries		;NO
 TST     R1, #%11			;is it word aligned?
 BNE     _skip_optional_entries		;NO
 LDR     R0, [R10, R1]
 TST     R0, #1				;is the 32bit flag set?
 BNE     _loading_32bit_module

 ._skip_optional_entries
 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

 ADR     R12, _SPSR
 LDMIA   R12, {R3-R6}			;preserve for re-entrancy
 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
 STMIA   R12, {R3-R6}			;preserve for re-entrancy

 TEQ     R8, #0				;did an error occur?
._discard_Module
 MOV     R0, #Heap_Free
 MOV     R1, #jit_RMA_heap
 MOVNE   R2, R10			;YES, discard Module space
 SWINE   XOS_Heap			; |+  PRM1-380
 MOV     R0, #Heap_Free
 LDR     R2, [R13], #4			;free temp stub block
 SWI     XOS_Heap			;PRM1-380

 TEQ     R8, #0				;did an error occur
 ADRNE   R0, Error_no_room_in_RMA	;YES, the claim failed
 SUBEQS  R0, R0, R0			;NO, clear V and set R0 to 0
 ._exit
 ADR     R12, _SPSR
 BL      dontexit_SWI_veneer
 TEQ     R0, #0				;did an error occur?
 MOVNE   R8, #1 << 31			;YES
 ADDNES  R8, R8, R8			; |  set V
 ._exit_error
 ADDVS   R13, R13, #4			; |  drop R0
 LDMVSFD R13!, {R1-R11}			; |
 BVS     exit_SWI_veneer		; |+ report error

 LDMFD   R13!, {R0-R10}
 TEQ     R0, #Module_Run		;was it RMRun?
 LDRNE   R11, [R13], #4			;NO
 BNE     exit_SWI_veneer		;exit

 MOV     R0, #Module_Enter		;YES
 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

 LDR     R1, [R11, #Module_Header.Title]
 ADD     R1, R1, R11			;R1 points to Module name
 LDR     R11, [R13], #4

 ADR     R12, _SPSR			;state needs to be local
 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_Module			;pass to OS
B       exit_SWI_veneer


._loading_32bit_module
 MOV     R0, #Heap_Free
 MOV     R2, R10			;discard Module space
 MOV     R1, #jit_RMA_heap
 SWI     XOS_Heap			;PRM1-380

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

 ADR     R12, _SPSR
 BL      dontexit_SWI_veneer
 LDMFD   R13!, {R0-R11}
B       vector_handler_forward		;pass to OS


 ._SPSR DBD 4



;_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     R7, R1				;preserve R1
 MOV     R0, #5				;info with File$Path
 SWI     XOS_File			;PRM2-38
 TEQ     R0, #1				;did we find a file?
 MOVNE   R0, #19			;NO, generate an error
 MOVNE   R1, R7				; |  preserve R1
 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
 MOV     R1, R7				;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
 LDMFD   R13!, {R1-R5, R7, PC}


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


;_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:
; R0 - preserved
; R9 - incremented by code size
; R1-R5, R12 - corrupted

._create_entry
 ADR     R12, _codelet_start
 MOV     R2, #_codelet_end - _codelet_start

 LDR     R1, [R10, R0]
 CMP     R1, R8				;valid?
 MOVHS   R1, #0				;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
 MOV     PC, R14




;_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:
; R0 - preserved
; R9 - incremented by code size
; R1-R5, R12 - corrupted

._create_entry_USER
 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

 CMP     R1, R8				;valid?
 MOVHS   R1, #0				;NO
 ADR     R12, _codelet_start_USER
 MOV     R2, #_codelet_end_USER - _codelet_start_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:
; R0 - preserved
; R9 - incremented by code size
; R1-R5, R12 - corrupted

._create_entry_INIT
 LDR     R1, [R10, R0]			;get entry
 CMP     R1, R8				;valid?
 MOVHS   R1, #0				;NO
 ADR     R12, _codelet_start_INIT
 MOV     R2, #_codelet_end_INIT - _codelet_start_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:
; R0 - preserved
; R9 - incremented by code size
; R1-R5, R12 - corrupted

._create_FS_entry
 ADR     R12, _codelet_start
 MOV     R2, #_codelet_end - _codelet_start
 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
; R1-R5, R12 - corrupted

._create_command_entry
 LDR     R1, [R0], #4
 CMP     R1, R8				;valid?
 MOVHS   R1, #0				;NO
 TEQ     R1, #0				;does the entry exist?
 STREQ   R1, [R6], #4			;NO
 MOVEQ   PC, R14			; |+ 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, _codelet_start
 MOV     R2, #_codelet_end - _codelet_start
 B       _create_entry_L1


._codelet_start
 STR     R14, [R13, #-4]!
 ._codelet_swi SWI     ADFFS_CallModuleEntry + (JIT_SWI_OS_Flag << 20)
 LDR     PC, [R13], #4
 ._codelet_end


._codelet_start_USER
 LDR     PC, _codelet_start_USER - 4
 ._codelet_end_USER


._codelet_start_INIT
 STR     R14, [R13, #-4]!
 ._codelet_start_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

 #set module_entry_ptr = 4 + (_codelet_swi - _codelet_start) + 4
; #set stub_module_base_offset = 4 + (_codelet_start_INIT_call - _codelet_start_INIT+ 4) + Module_Header.End + (_codelet_end_USER - _codelet_start_USER + 4)
 #set stub_module_base_offset = (4 + 4) + 4 + Module_Header.End + (8 + 4)



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

.call_module_entry_INIT_END
 LDR     R14, [R13, #8]			;get Module_being_inserted old value
 TEMP    R12
 STR     R14, Module_being_inserted
 LOCK    R12
 LDMFD   R13!, {R12, R14}		;exit SWI handler
 ADD     R13, R13, #4
MOVS     PC, R14




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

.call_module_entry_INIT
 LDMFD   R13!, {R12, R14}
 SUB     R13, R13, #4
 STMFD   R13!, {R12, R14}
 #if compile_RO == 400
   BIC     R14, R14, #&FC000003
 #endif
 LDR     R12, Module_being_inserted
 STR     R12, [R13, #8]				;store current value
 SUB     R14, R14, #stub_module_base_offset	;SWI ADFFS_CallModuleEntryInit address
 TEMP    R12
 STR     R14, Module_being_inserted
 LOCK    R12
;fall-thru to call_module_entry




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

.call_module_entry
 LDR     R14, jit_managed_ldr_pc_r13
 STR     R14, _entry			;store return

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

 LDR     R14, [R13, #4]			;entry SWI address
 #if compile_RO == 400
   BIC     R14, R14, #&FC000003
 #endif
 LDR     R14, [R14, #-module_entry_ptr]	;get Module entry address
 STR     R14, _entry + 4		;store entry

 LDR     R12, [R13], #4			;pull R12 from stack
 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, #3 * 4		;space on stack for USER regs
 STMIA   R13, {R12, R13, R14}^		;stack: {R12, USER_R13, USER_R14,
					;:[SVC26_SPSR, SVC26_R14], SPSR, R14}

 LDR     R12, tmp_module_stack		;our temp stack
 LDR     R14, [R13, #4]			;get current USER stack

 ADD     R14, R14, #tmp_irq_stack_size
 SUB     R14, R14, R12
 CMP     R14, #tmp_irq_stack_size	;is USER R13 pointing at our stack

 LDR     R12, [R13], #4			;preserve R12
 MRS     R14, SPSR			;get entry flags/CPU mode
 BIC     R14, R14, #%11			;USER[32]
 BIC     R14, R14, #%1111 << 28		;clear flags
 BLO     _dont_set_stack		;YES

 MSR     CPSR_all, R14			;switch to USER[32] mode
 #if compile_IOMD == 1
   NOP
 #endif
 LDR     R13, tmp_module_stack		;|+ and set temp stack
 B       _stack_ok

 ._dont_set_stack
 MSR     CPSR_all, R14			;switch to USER[32] mode
 #if compile_IOMD == 1
   NOP
 #endif

 ._stack_ok
 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

 STR     R12, [R13, #-4]!		;preserve R12
 ADR     R14, _entry			;stack: {R12, USER_R13, USER_R14,
					;:[SVC26_SPSR, SVC26_R14], SPSR, R14}
 STMIA   R14, {R13}^			;store USER R13 in _entry
 #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
 LDR     R12, _entry			;R12=USER R13
 LDR     R12, [R12, #0]			;get flags from USER stack
 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-R9, R14}

; MOV     R0, #CAOPointer		;set CAO
; MOV     R1, #&8000			;to ensure Modules are killed
; SWI     XOS_ChangeEnvironment		;PRM1-320
 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

 LDR     R6, jit_code				;can't run finalise if =0
 MOV     R0, #Module_ExtractInfo
 MOV     R1, #0
 ._L1
   MOV     R2, #0				;instantiation number
   ._L2
     SWI     XOS_Module				;PRM1-243
     LDMVSFD R13!, {R0-R9, PC}			;no more Modules

     LDR     R4, [R3, #Module_Header.ADFFS]	;check it's one of ours
     EORS    R4, R4, #Module_Validation
     BNE     _not_26bit

     TEQ     R6, #0				;is the JIT running?
     STREQ   R6, [R3, #Module_Header.Finalise]	;NO, prevent Finalise code

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

     SUB     R1, R1, #1				;reduce module no.
     STMFD   R13!, {R0-R2}

     LDR     R1, [R3, #Module_Header.Title]	;pointer to Module name
     ADD     R1, R1, R3
     ._kill_module
     MOV     R0, #Module_Delete
     SWI     XOS_Module

     LDR     R2, [R3, #Module_Header.Address]	;get start and size
     LDR     R4, [R3, #Module_Header.Size]	;so we can kill vector claims
     MOV     R8, R2				;start of Module
     ADD     R9, R4, R8				;end of Module
     BL      kill_voices_in_range		;kill any rogue voices
     BL      kill_vectors_in_range		;kill any rogue vectors

     MOV     R0, R2				;R0=start R4=size
     BL      hv_reset_memory_block		;free codelets
     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
