;blank line to work around bug in extASM (if on 1st line is ignored)
#if compile_RO == 400
  #set jit_allocate_memory	= &A00000	;total memory for JIT
  #set jit_RMA_size		= &180000	;total memory for JIT RMA
  #set jit_slotsize		= &1880000	;ram to allocate for appspace
  #set jit_code_start		= jit_slotsize - (jit_allocate_memory + jit_RMA_size)
  #set jit_ram			= jit_slotsize	;highest address for WimpSlot
#endif
#if compile_RO > 400
  #set jit_allocate_memory	= &D00000	;total memory for JIT
  #set jit_RMA_size		= &100000	;total memory for JIT RMA
  #set jit_slotsize		= &1F00000	;ram to allocate for appspace
  #set jit_code_start		= jit_slotsize - (jit_allocate_memory + jit_RMA_size)
  #set jit_ram			= &1F08000	;highest address for WimpSlot
						;includes pointer/sound buffers
#endif

#set jit_appspace_end	= jit_allocate_memory + jit_RMA_size
						;max RAM JIT supports
						;16mb is theorical max
#set jit_RMA_heap	= jit_allocate_memory	;start of JIT RMA

#set jit_hardware_vectors= jit_RMA_heap + jit_RMA_size + jit_code_start
#set jit_RMA_size = jit_RMA_size - 16		;reduce by size of code at
						;jit_hardware_vectors

#set lastfree_codelet	= jit_appspace_end	;last free block in codelets

#set jit_trace_buffer_size	= &400000	;size of the trace buffer
						;length must have only 1 bit set
						;for the overrun code to work

.Entry_GOARM3JIT
 STMFD   R13!, {R12, R14}

 ADR     R12, VARS
 TEQ     R1, #0				;are we shutting down?
 BEQ     Entry_GOARMxJIT		;YES

 LDR     R14, [R12, #jit_code - VARS]
 TEQ     R14, #0			;is the JIT running?
 LDRNE   R14, [R12, #JIT_ARM4 - VARS]	;YES, is it in ARMv3 mode?
 TEQNE   R14, #0
 BNE     _jit_already_running		;NO, running in ARMv4, report an error

 MOV     R14, #0			;notify JIT to startup in ARMv3 mode
 STR     R14, [R12, #JIT_ARM4 - VARS]
B       Entry_GOARMxJIT			;start the JIT

 ._jit_already_running
 MOV     R0, #1 << 31
 ADDS    R0, R0, R0			;set V
 ADR     R0, Error_JIT_ARM3_or_4	;report error
LDMFD   R13!, {R12, PC}



;Entry:
; R12 - pointer to VARS
; {R12, R14} - stacked

.Entry_GOARMxJIT
 TEQ     R1, #0				;are we initialising?
 MOV     R1, R0
 STMFD   R13!, {R1-R11}
 BNE     _P1				;YES

 LDR     R0, [R12, #jit_code - VARS]	;NO, shutting down
 TEQ     R0, #0				;is the JIT running?
 LDMEQFD R13!, {R1-R12, PC}		;NO, exit

 BL      shutdown_interrupts
 BL      kill_26bit_modules		;kill legacy modules
 BL      remove_this_taskID		;remove this taskID
 LDR     R0, [R12, #jit_task_count - VARS]
 TEQ     R0, #0				;is this the last task
 BNE     _not_last_task			;NO

 #if Managed_ChannelHandler == 1
   BL      reset_sound_configure	;reset audio subsystem
 #endif
 BL      clear_jitmemorya		;remove any buffered code changes

 #if JIT_debug == 1 AND compile_IOMD == 1
   ADR     R0, report_JIT_IOMD
   MOV     R1, #0
   SWI     XOS_RemoveTickerEvent
 #endif

 BL      _release_processor_vectors
 LDMVSFD R13!, {R1-R12, PC}

 LDR     R0, [R12, #BASICTrans_loaded - VARS]
 TEQ     R0, #0
 MOVNE   R0, #Module_Delete		;RMKill BASIC module
 ADRNE   R1, _BASICTrans
 SWINE   XOS_Module			;PRM1-235
 MOV     R0, #0
 STR     R0, [R12, #BASICTrans_loaded - VARS]

 BL      Remove_Transient_DA - 4	;remove transient DA's
 TEMP    R1
 MOV     R0, #0
 STR     R0, [R12, #jit_code - VARS]
 STR     R0, JIT_event11_active		;reset Event 11 counter
 LOCK    R1

 #if JIT_protect_page_zero == 1
   LDR     R0, os_version		;ARM710VE-83 / 85
   CMP     R0, #&380 << 8		;are we below RO3.8?
   LDRLO   R1, page_zero_L2PT		;YES, restore page zero protection
   MOVLO   R0, #0			; |
   BLLO    CACHEOP_INVALIDATE_TLB_R0	; |+ flush TLB
 #endif

 #if compile_RO == 500
   MOV     R1, #0
   LDR     R0, [R12, #Current_Machine_State - VARS + Machine_State.cpu_control_register]
   TEQ     R0, #0			;did we change the CPU CR?
   STRNE   R1, [R12, #Current_Machine_State - VARS + Machine_State.cpu_control_register]
   MCRNE   P15, 0, R0, C1, C0, 0	;YES, set it back

   #if compile_RO == 500 AND High_Vectors == 1
;ref. https://www.riscosopen.org/wiki/documentation/show/OS_Memory%2020
     MOV     R0, #20			;check compatibility page
     LDR     R1, [R12, #Current_Machine_State - VARS + Machine_State.OS_Memory20]
     TEQ     R1, #0			;did we change it?
     SWINE   XOS_Memory			;YES
   #endif
 #endif

 ._not_last_task
 #if JIT_self_modifying_support == 1
   BL      reset_appspace_L2PT
 #endif

 MOV     R0, #WimpSysInfo_CurrentTaskHandle	;get task handle
 SWI     XWimp_ReadSysInfo		;PRM3-216
 TEQ     R0, #0				;do we need to remove Filters
 BLNE    Remove_Wimp_Filters		;YES

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

 ._VProtect DCB "VProtect", 0
 ALIGN

 ._P1
 MOV     R0, #Module_Lookup
 ADR     R1, _VProtect
 SWI     XOS_Module			;check for VProtect
 TEQ     R0, #Module_Lookup		;is VProtect running?
 MOVNE   R3, #0				;NO
 MOVNE   R1, #0
 LDREQ   R1, [R3, #-4]			;YES, get size of VProtect Module
 STR     R3, [R12, #VProtect_Module - VARS]
 STR     R1, [R12, #VProtect_Module + 4 - VARS]

 #if JIT_debug == 1 AND compile_IOMD == 1
   MOV     R0, #dbg_pause_default
   TEMP    R1
   STR     R0, dbg_pause
   LOCK    R1

   MOV     R0, #1
   ADR     R1, report_JIT_IOMD
   MOV     R2, #0
   SWI     XOS_CallEvery
 #endif

 LDR     R0, [R12, #jit_code - VARS]
 TEQ     R0, #0				;is the JIT already setup?
 BNE     _already_setup			; |+ skip initialisation

 BL      store_machine_state		;store key repeat etc
 
 MVN     R0, #0				;read current slotsize
 MVN     R1, #0
 SWI     XWimp_SlotSize			;PRM3-203

 MOV     R1, #jit_allocate_memory - &8000	;RAM limit
 CMP     R0, R1				;do we have enough RAM?
 MOVHS   R3, R1				;cap at jit_ram limit
 MOVLO   R3, R0				;store current slotsize
 MOV     R1, #jit_ram - &8000
 CMP     R0, R1				;do we have enough RAM?
 MOVLO   R0, R1				;NO, allocate more
 MVNLO   R1, #0
 SWILO   XWimp_SlotSize			;PRM3-203
 LDMVSFD R13!, {R1-R12, PC}		;exit on error

 MVN     R0, #0				;read current slotsize
 MVN     R1, #0
 SWI     XWimp_SlotSize			;PRM3-203
 MOV     R1, #jit_ram - &8000
 CMP     R0, R1				;do we have enough RAM?
 MOVLO   R0, #1 << 31			;NO, set V
 ADDLOS  R0, R0, R0
 ADRVS   R0, Error_jit_slotsize
 LDMVSFD R13!, {R1-R12, PC}		;exit on error
 TEMP    R0
 STR     R3, pre_JIT_wimp_slot_size	;store current WimpSlot
 LOCK    R0

 MOV     R0, #Heap_Initialise		;initialise JIT RMA heap
 MOV     R1, #jit_RMA_heap
 MOV     R3, #jit_RMA_size
 SWI     XOS_Heap			;PRM1-377

 ADR     R7, MEMC_registers		;reset MEMC registers
 MOV     R0, #&1F03800
 STR     R0, [R7, #IOC_Cinit << 2]	;Pointer
 MOV     R0, #&36E0D0C
 STR     R0, [R7, #MEMC_CR << 2]

 MOV     R0, #0
 #if compile_GPU == 1
   BL      reset_IOC
 #endif

 TEMP    R1
 STR     R0, linear_handler_entry	;reset sound handler
 STR     R0, Module_being_inserted	;reset
 LOCK    R1

 ADR     R7, DeviceVectors		;initialise Device Vector claims
 MOV     R1, #(last_device_to_track + 1) * device_table.size
 ._device_vectors_L1
   STR     R0, [R7], #4
   SUBS    R1, R1, #4
 BNE     _device_vectors_L1

 ADR     R2, Current_Machine_State
 #if Unaligned_Support == 0
   MRC     P15, 0, R0, C1, C0, 0	;get CPU control register
					;see ARM ARM rev.I B3-12
   BIC     R3, R0, #1 << 1		;disable alignment fault checking
   BIC     R3, R3, #1 << 22		;enable rotated unaligned loads
   TEQ     R0, R3
   TEMP    R1
   STRNE   R0, [R2, #Machine_State.cpu_control_register]
   LOCK    R1
   MCRNE   P15, 0, R3, C1, C0, 0	;update ARM Control Register
 #endif
 #if Unaligned_Support == 1
   MRC     P15, 0, R0, C1, C0, 0	;get CPU control register
					;see ARM ARM rev.I B3-12
   ORR     R3, R0, #1 << 1		;enable alignment fault checking
   TEQ     R0, R3
   TEMP    R1
   STRNE   R0, [R2, #Machine_State.cpu_control_register]
   LOCK    R1
   MCRNE   P15, 0, R3, C1, C0, 0	;update ARM Control Register
 #endif

 #if compile_RO == 500 AND High_Vectors == 1
;ref. https://www.riscosopen.org/wiki/documentation/show/OS_Memory%2020
   MOV     R0, #20			;check compatibility page
   MVN     R1, #0
   SWI     XOS_Memory
   MOVVS   R1, #0
   CMP     R1, #0			;is it available?
   MOVMI   R1, #0			;NO
   STR     R1, [R2, #Machine_State.OS_Memory20]
   TEQ     R1, #1			;is page zero mapped?
   MOVEQ   R1, #0			;YES
   SWIEQ   XOS_Memory			; |+ disable page
 #endif

 #if JIT_protect_page_zero == 1
   LDR     R0, os_version		;ARM710VE-83 / 85
   CMP     R0, #&380 << 8		;are we below RO3.8?
   TEMP    R3
   LDRLO   R0, L2PT_addr		;YES, protect page zero
   LDRLO   R1, [R0]			; |  page zero L2PT
   STRLO   R1, page_zero_L2PT		; |  keep a copy for later
   BICLO   R1, R1, #%11111111 << 4	; |  user is read-only
   ORRLO   R1, R1, #%11101010 << 4	; |  protect 0..&2FFF
   MOVLO   R0, #0			; |
   BLLO    CACHEOP_INVALIDATE_TLB_R0	; |+ flush TLB
   LOCK    R3
 #endif
					;Now setup the JIT space ready for
					;translated code
 MOV     R3, #jit_code_start
 MOV     R4, #0
 MOV     R5, #0
 MOV     R6, #0
 MOV     R7, #0
 ADD     R8, R3, #&4000			;clear page zero
 ._PZ_L1
   STMIA    R3!, {R4-R7}
   STMIA    R3!, {R4-R7}
   TEQ      R3, R8
 BNE     _PZ_L1

 LDR     R1, branch_to_jit		;instruction to enter JIT
 MOV     R2, R1, LSL #4
 TEMP    R7
 STR     R2, branch_to_jit_no_condition	;used to quickly check for Hypercalls
 LOCK    R7
 MOV     R2, R1
 MOV     R4, R1
 MOV     R5, R1
 MOV     R6, R1
 MOV     R7, R1
 MOV     R8, R1
 MOV     R0, R1
 ._L2
   STMIA   R3!, {R0-R2, R4-R8}
   STMIA   R3!, {R0-R2, R4-R8}
   TEQ     R3, #jit_slotsize
 BNE     _L2

 #if compile_DEBUG == 1 OR JIT_instruction_trace == 1	;force chocolate off
   MOV     R0, #5			;turn lazy page mapping off
   MOV     R1, #0
   SWI     XOS_AMBControl

   MOV     R3, #&4000
   LDR     R4, [R12, #current_PageSize - VARS]
   ._L1_chocolate
     LDR     R0, [R3], R4		;force pages to be mapped
     CMP     R3, #jit_code_start
   BLO     _L1_chocolate
 #endif

 BL      Create_Transient_DA - 4	;create transient DA's
 #if JIT_instruction_trace == 1
   LDR     R3, [R12, #IT_DA_address - VARS]	;our DA address
   MOV     R1, #&100000
   ADD     R3, R3, #&100000
   SUB     R1, R1, #1
   BIC     R3, R3, R1				;align to 1MB boundary
   TEMP    R1
   STR     R3, [R12, #instruction_trace_ptr - VARS]
   LOCK    R1
   STR     R3, [R3, #-4]
 #endif

 SWI     XOS_GetEnv			;get EnvString
 STR     R0, [R12, #page_zero_EnvString - VARS]	;used in page_zero_abort handler
 STR     R2, [R12, #page_zero_EnvTime - VARS]	;used in page_zero_abort handler
 MOV     R0, #0				;reset hypervised IRQ handlers
 STR     R0, [R12, #hypervised_IRQ1V - VARS]
 STR     R0, [R12, #hypervised_IRQv - VARS]
 STR     R0, [R12, #transient_stacks_used - VARS]
 TEMP    R3
 STR     R0, terminate_all_voices
 #if JIT_debug == 1
   STR     R0, jit_codelet_count
   STR     R0, jit_joysticks
 #endif
					;setup exit code below 27.5mb
 MOV     R0, #jit_code_start
 LDR     R1, _codelet_os_exit		;OS_Exit for general use
 STR     R1, [R0, #-4]!
 STR     R0, [R12, #jit_managed_os_exit - VARS]
 
 ADR     R5, _codelet3			;LDR PC, [R13], #4 for general use
 LDMIA   R5, {R1-R3}
 STMDB   R0!, {R1-R3}			;entry for us
 ADD     R1, R0, #8			;skip the two NOP's
 STR     R1, [R12, #jit_managed_ldr_pc_r13 - VARS]
 
 ADR     R5, _codelet3_2		;LDR PC, [R13+4], #4 for general use
 LDMIA   R5, {R1-R4}
 STMDB   R0!, {R1-R4}			;entry for us
 ADD     R1, R0, #8			;skip the two NOP's
 STR     R1, [R12, #jit_managed_ldr_pc_r13_2 - VARS]

 MOV     R6, #jit_hardware_vectors
 STMDB   R6!, {R1-R4}			;hardware vectors must jump high
 SUB     R1, R6, #&18 + 8 - 8		;(fixes Lotus Turbo Challenge 2)
					;<address> - <PC offset> + skip two NOP's
 SUB     R1, R1, #jit_code_start	;correct address
 MOV     R1, R1, LSR #2
 ORR     R1, R1, #&EA000000		;B <address>
 STR     R1, [R12, #jit_managed_IRQ_entry - VARS]	;instruction game sees at &18

 SUB     R0, R0, #EnvHandler.size * 17	;space to track environment handlers
 STR     R0, [R12, #environment_handlers - VARS]
 BL      claim_ChangeEnvironmentV	;ensure we've claimed environment handlers
 BL      initialise_vector_table
 BL      get_DA2_size

 MOV     R1, #0
 STR     R1, [R0, #-4]!
 STR     R0, [R12, #private_CLibCounter - VARS]
 STR     R1, [R0, #-4]!
 STR     R0, [R12, #private_RISCOSLibWord - VARS]
 STR     R1, [R0, #-4]!
 STR     R0, [R12, #private_CLibWord - VARS]
					;-----------------------
 SUB     R0, R0, #codelet_struct.codelet	;initialize first codelet
 BIC     R0, R0, #codelet_alignment - 1		;align it
 STR     R0, [R0, #codelet_struct.next]		;next=pointer to itself
 STR     R0, [R0, #codelet_struct.previous]	;previous=pointer to itself
 MOV     R1, #codelet_struct.codelet
 STR     R1, [R0, #codelet_struct.size]		;size=codelet_struct size
 MVN     R1, #0
 STR     R1, [R0, #codelet_struct.source]	;source=-1
 STR     R0, [R12, #first_codelet - VARS]
						;initialize last free codelet
 MOV     R2, #lastfree_codelet			;R2=codelet
 STR     R2, [R2, #codelet_struct.next]		;next=pointer to itself
 STR     R2, [R2, #codelet_struct.previous]	;previous=pointer to itself
 MOV     R1, #0
 STR     R1, [R2, #codelet_struct.source]	;source=0
 SUB     R1, R0, R2				;R1=size
 STR     R1, [R2, #codelet_struct.size]		;size=free space
					;-----------------------
 MOV     R0, #jit_code_start
 STR     R0, [R12, #jit_code - VARS]	;start of translated code

 BL      _claim_processor_vectors	;claim processor vectors
 BVC     _already_setup

 BL      _release_processor_vectors
 MSR     CPSR_f, #1 << 28		;set V
 LDMFD   R13!, {R1-R12, PC}		;exit
 LOCK    R3

 ._already_setup
 BL      get_taskID			;get current task
 BL      load_softFont			;put softFont into our Page Zero

 LDR     R1, [R13, #0]			;command tail
 MOV     R0, #16			;base 16 number with restricted range
 SWI     XOS_ReadUnsigned		;read the value PRM1-460
 LDMVSFD R13!, {R1-R12, PC}		;exit on error
 ADD     R4, R2, #jit_code_start	;R4=start address

 MOV     R3, R1				;do we have an environment string?
 ._find_env_L1
   LDRB    R1, [R3], #1
   TEQ     R1, #ASC(";")		;environment string?
   TEQNE   R1, #0			;terminator?
 BNE     _find_env_L1			;NO

 TEQ     R1, #ASC(";")			;environment string found?
 BNE     _find_env_P1
 SWI     XOS_GetEnv			;PRM1-301
 MOV     R1, R2				;R1=time
 MOV     R0, R3				;string to become environment
 SWI     XOS_WriteEnv			;PRM1-322

 ._find_env_P1
 TEQ     R4, #jit_code_start		;are we simply setting up the JIT?
 LDMEQFD R13!, {R1-R12, PC}		;YES, exit
 MOV     R2, R4				;preserve R2

 LDR     R13, [R12, #SVC_stack_init - VARS]	;collapse the SVC stack

 MRS     R14, CPSR			;go into the correct USER mode
 BIC     R14, R14, #%11001111 + (%1111 << 28)	;USER/USER32 IRQ/FIQ enabled
 MSR     CPSR_all, R14
 #if compile_IOMD == 1
   NOP
 #endif

 MOV     R13, #jit_allocate_memory	;put stack at end of user space
 LDR     R14, [R12, #jit_managed_os_exit - VARS]
 MOV     R12, R13			;set R12 to stack pointer
MOV     PC, R2				;call code, R0=environment string


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

 TEMP    R14
 BL      Claim_DataAbort_Vector			;claim DataAbort vector
 LDRVS   PC, [R13], #4

 MOV     R0, #Vector_UndefinedInstr + (1<<8)	;claim Undefined instruction vector
 LDR     R1, existing_UndefinedInstr
 TEQ     R1, #0					;already claimed
 ADREQ   R1, Undefined_Instruction_Vector
 SWIEQ   XOS_ClaimProcessorVector		;PRM5a-30
 LDRVS   PC, [R13], #4
 STR     R1, existing_UndefinedInstr

 MOV     R0, #Vector_IRQ + (1<<8)		;claim IRQ vector
 LDR     R1, existing_IRQVector
 TEQ     R1, #0					;already claimed
 ADREQ   R1, IRQ_Vector_Handler
 SWIEQ   XOS_ClaimProcessorVector		;PRM5a-30
 LDRVS   PC, [R13], #4
 STR     R1, existing_IRQVector			;store existing

 MOV     R0, #Vector_BranchThruZero + (1<<8)	;claim Reset vector
 LDR     R1, [R12, #existing_Branch_thru_zero - VARS]
 TEQ     R1, #0					;already claimed
 ADREQ   R1, Branch_thru_zero
 SWIEQ   XOS_ClaimProcessorVector		;PRM5a-30
 LDRVS   PC, [R13], #4
 STR     R1, [R12, #existing_Branch_thru_zero - VARS]	;store existing

 #if compile_RO > 400
   MOV     R0, #Vector_SeriousErrorV		;claim SeriousError vector
   ADR     R1, seriousErrorV_handler
   ADR     R2, VARS
   SWI     XOS_Claim
 #endif

 LOCK    R14
LDR     PC, [R13], #4



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

 TEMP    R14
 SUBS    R4, R4, R4			;R4=0 and V clear
 LDR     R0, [R12, #remapping_video_memory - VARS]
 TEQ     R0, #0				;are we remapping video memory
 BLEQ    release_DataAbort_Vector	;NO, we can shutdown the Abort handler
 MOVVS   R4, R0
 MOV     R3, #0
 MOV     R0, #Vector_IRQ		;release IRQ vector
 LDR     R1, existing_IRQVector
 ADR     R2, IRQ_Vector_Handler
 TEQ     R1, #0
 SWINE   XOS_ClaimProcessorVector	;PRM5a-30
 MOVVS   R4, R0
 STRVC   R3, existing_IRQVector
 MOV     R0, #Vector_BranchThruZero	;release branch through zero handler
 LDR     R1, existing_Branch_thru_zero
 ADR     R2, Branch_thru_zero
 TEQ     R1, #0
 SWINE   XOS_ClaimProcessorVector	;PRM5a-30
 MOVVS   R4, R0
 STRVC   R3, [R12, #existing_Branch_thru_zero - VARS]
 MOV     R0, #Vector_UndefinedInstr	;release Undefined Instruction vector
 LDR     R1, existing_UndefinedInstr
 ADR     R2, Undefined_Instruction_Vector
 TEQ     R1, #0
 SWINE   XOS_ClaimProcessorVector	;PRM5a-30
 MOVVS   R4, R0
 STRVC   R3, existing_UndefinedInstr
 #if compile_RO > 400
   MOV     R0, #Vector_SeriousErrorV	;release SeriousError vector
   ADR     R1, seriousErrorV_handler
   ADR     R2, VARS
   SWI     XOS_Release
   MOVVS   R4, R0
 #endif
 LOCK    R14

 MOVS    R0, R4
 MSRNE   CPSR_f, #1 << 28		;set V
LDMFD   R13!, {R1-R4, PC}



 ._BASICTrans		DCB "BASICTrans", 0
			ALIGN

 ._codelet_os_exit	SWI OS_Exit	;hypervised exit back to OS

 ._codelet3
 NOP					;R1 NOP's for processor vector returns
 NOP					;R2
 LDR     PC, [R13], #4			;R3 hypervised exit back to us

 ._codelet3_2
 NOP					;R1 NOP's for processor vector returns
 NOP					;R2
 ADD     R13, R13, #4			;R3
 LDR     PC, [R13], #4			;R4 hypervised exit back to us
