;padding to work around compiler bug



#if JIT_instruction_trace == 1
.instruction_trace_codelet
 ._codelet
 STR     R0, _codelet-12		;R0
 STR     R1, _codelet-8
 STR     R2, _codelet-4
 MOV     R0,     #&1000000
 LDR     R1, [R0, #-4]
 BIC     R1, R1, #&0F00000		;R5
 LDR     R2, _codelet-codelet_PC	;R14
 SUB     R2, R2, #8			;R0
 STR     R2, [R1], #4
 STR     R1, [R0, #-4]
 ADR     R0, _codelet-12
 LDMIA   R0, {R0-R2}
 ADD     PC, PC, #codelet_struct.codelet-codelet_struct.source - 4		;R5
 ._codelet_end
					;13 + 5 instructions
 #set JIT_IT_codelet_size = _codelet_end-_codelet + codelet_struct.codelet-codelet_struct.source
#endif




;DID_JIT_ENTER_HERE
;------------------
;checks if the JIT was entered on this instruction
;
;Exit:
; R4, R5 - Corrupted
; EQ if true

MACRO DID_JIT_ENTER_HERE$cc
{
 LDR$cc  R4, [R13, #UND_exit_PC]	;read JIT entry address
 SUB$cc  R5, R14, #8
 TEQ$cc  R4, R5				;was the JIT entered on this instr?
}




;PREDICT_BRANCH
;--------------
;Adds a JIT appspace address to the branch prediction table
;
;Entry:
; Rx - address in JIT appspace to follow
;
;Exit:
; R1, R5 - corrupted

MACRO PREDICT_BRANCH Rx:R
{
 LDR     R5, branch_to_jit_no_condition	;JIT entry instruction
 LDR     R1, [Rx]			;get instruction at Branch
 TEQ     R5, R1, LSL #4			;is it a Hypercall?
 BNE     _ignore			;NO, ignore it then

 ADR     R5, JIT_branch_prediction_table
 LDR     R1, [R5, #-4]			;get index
 TEQ     R1, #JIT_branch_prediction_max	;is the BPT full?
 STRNE   Rx, [R5, R1, LSL #2]		;NO, store in BPT
 ADDNE   R1, R1, #1			; |   go to next table entry
 STRNE   R1, [R5, #-4]			; |+  store back
 ._ignore
}




;CACHEOP_CLEAN_APPSPACE_TO_HERE
;------------------------------
;cleans the D cache from the start of the current code block being processed
;
;Exit:
; R0-R4 - corrupted

MACRO CACHEOP_CLEAN_APPSPACE_TO_HERE
{
 ADR     R2, JIT_processed_counter
 LDR     R0, JIT_started_at		;start address to clean
 LDR     R3, [R2, #0]			;R3=instruction counter
 SUB     R4, R14, R0			;size
 ADD     R3, R3, R4, LSR #2		;increase instruction counter
 MOV     R1, R14			;last address to clean
 STR     R3, [R2, #0]			;update instruction counter
 BL      CACHEOP_CLEAN_D_INVALIDATE_I	;clean range
}




;CACHEOP_INVALIDATE_TLB_ENTRY
;----------------------------
;Invalidated a TLB entry

MACRO CACHEOP_INVALIDATE_TLB_ENTRY$cc Rx:R
{
 #if MMUControl2_support == 1		;corrupts R0, R14, PSR
   LDR$cc  R14, DA_mask
   BIC$cc  R0, Rx, R14
   MOV$cc  R14, PC			;return to us
   LDR$cc  PC, MMUControl_ARMop5
 #endif
 #if MMUControl2_support == 0 AND compile_RO > 400
   MCR$cc  P15, 0, Rx, C8, C6, 1	;invalidate D TLB entry
 #endif
 #if MMUControl2_support == 0 AND compile_RO == 400
   B$cc    _keepTLB
   B       _skipTLB
   ._keepTLB
   LDR     R14, cpu_id
   CMP     R14, #CPUID_StrongARM	;below StrongARM?
   MCRLO   P15, 0, R0, C6, C0, 0	;invalidate complete TLB
   MCRHS   P15, 0, Rx, C8, C6, 1	;invalidate D TLB entry
   ._skipTLB
 #endif
}




;CACHEOP_INVALIDATE_I_CACHE_ABT
;------------------------------
;Invalidated the I cache on StrongARM

MACRO CACHEOP_INVALIDATE_I_CACHE_ABT$cc
{
   MCR$cc  P15, 0, R0, C7, C5, 0	;invalidate I cache
}




;CACHEOP_DRAIN_WRITE_BUFFER_ABT
;------------------------------
;Drains the write buffer.  ie writes pending cache writebacks

MACRO CACHEOP_DRAIN_WRITE_BUFFER_ABT$cc
{
   MCR$cc  P15, 0, R0, C7, C10, 4	;drain write buffer
}




#if MMUControl2_support == 0
;CACHEOP_INVALIDATE_I_ENTRY_ABT
;------------------------------
;Invalidates one instruction cache entry

MACRO CACHEOP_INVALIDATE_I_ENTRY_ABT$cc Rx:R		;80321+ only
{
   MCR$cc  P15, 0, Rx, C7, C5, 1	;invalidate I-cache entry
}




;CACHEOP_CLEAN_D_ENTRY_ABT
;-------------------------
;Cleans a single data cache entry

MACRO CACHEOP_CLEAN_D_ENTRY_ABT$cc Rx:R
{
   MCR$cc  P15, 0, Rx, C7, C10, 1	;clean D-cache entry
}
#endif




;CACHEOP_CLEAN_D_RANGE_ABT
;-------------------------
;Cleans a range in the data cache
;
;Entry: R0=start R1=end exclusive
;
;Exit: R14 corrupted

MACRO CACHEOP_CLEAN_D_RANGE_ABT$cc
{
  MOV$cc  R14, PC			;return to us
  LDR$cc  PC, MMUControl_ARMop8
}



;CACHEOP_PRECACHE_I
;------------------
;Pre-caches instructions

MACRO CACHEOP_PRECACHE_I Rx:R				;ARM11+ only
{
 MCR$cc  P15, 0, Rx, C7, C13, 1		;pre-cache instructions
}




;CACHEOP_CLEAN_CODELET
;---------------------
;Ensures the D cache entries are cleaned from the last codelet created
;
;Exit:
; R0-R5 - Corrupted

MACRO CACHEOP_CLEAN_CODELET
{
 ADR     R0, codelet_cache_flush
 LDMIA   R0, {R0, R1}
 TEQ     R0, #0
 ADD     R1, R1, R0			;R1=end address
 MOV     R5, R14			;preserve R14
 BLNE    CACHEOP_CLEAN_D_RANGE
 MOV     R14, R5			;preserve R14
}




;CODELET_BL <size in words>
;
;Exit:
; R1, R4 - corrupted
; R6     - codelet address

MACRO CODELET_BL size:I
{
 #if JIT_codelet_reuse == 1
   MOV     R1, #0			;codelet cant be reused
 #endif

 ADR     R4, codelet_cache_flush
 MOV     R6, #size << 2
 STR     R6, [R4, #4]			;store size for cache clean

 #if JIT_instruction_trace == 1
   STMFD   R13!, {R0, R2-R3, R5, R7-R9, R14}

   MOV     R6, #(codelet_struct.codelet + (size << 2) + JIT_IT_codelet_size + (codelet_alignment - 1)) AND (&FFFFF-codelet_alignment+1)
   BL      allocate_codelet
   MOV     R9, R6
   ADR     R8, instruction_trace_codelet
   LDMIA   R8!, {R0-R5, R14}
   STMIA   R9!, {R0-R5, R14}
   LDMIA   R8!, {R0-R5}
   STMIA   R9!, {R0-R5, R7}
   LDMFD   R13!, {R0, R2-R3, R5, R7-R9, R14}
 #endif
 #if JIT_instruction_trace == 0
   MOV     R4, R14			;preserve R14
   MOV     R6, #(codelet_struct.codelet + (size << 2) + (codelet_alignment - 1)) AND (&FFFFF-codelet_alignment+1)
   BL      allocate_codelet
   MOV     R14, R4			;preserve R14
 #endif
					;---------------------------------
 AND     R4, R0, #%11111111 << 24	;R4=BLxx 0
 SUB     R1, R6, R14			;R5=offset from instruction to codelet
 BIC     R1, R1, #%111111 << 26
 ORR     R4, R4, R1, LSR #2		;BL <codelet>
 STR     R4, [R14, #-8]			;change original instruction

 #if JIT_instruction_trace == 1
   ADD     R6, R6, #JIT_IT_codelet_size
 #endif
}




;CODELET <size in words>
;
;Exit:
; R1, R4 - corrupted
; R6     - codelet address

MACRO CODELET size:I
{
 #if JIT_codelet_reuse == 1
   MOV     R1, #0			;codelet cant be reused
 #endif

 ADR     R4, codelet_cache_flush
 MOV     R6, #size << 2
 STR     R6, [R4, #4]			;store size for cache clean

 #if JIT_instruction_trace == 1
   STMFD   R13!, {R0, R2-R3, R5, R7-R9, R14}

   MOV     R6, #(codelet_struct.codelet + ((size << 2) + JIT_IT_codelet_size + (codelet_alignment - 1))) AND (&FFFFF-codelet_alignment+1)
   BL      allocate_codelet
   MOV     R9, R6
   ADR     R8, instruction_trace_codelet
   LDMIA   R8!, {R0-R5, R14}
   STMIA   R9!, {R0-R5, R14}
   LDMIA   R8!, {R0-R5}
   STMIA   R9!, {R0-R5, R7}
   LDMFD   R13!, {R0, R2-R3, R5, R7-R9, R14}
 #endif
 #if JIT_instruction_trace == 0
   MOV     R4, R14			;preserve R14
   MOV     R6, #(codelet_struct.codelet + (size << 2) + (codelet_alignment - 1)) AND (&FFFFF-codelet_alignment+1)
   BL      allocate_codelet
   MOV     R14, R4			;preserve R14
 #endif
					;---------------------------------
 AND     R4, R0, #%1111 << 28		;get condition
 ORR     R4, R4, #%1010 << 24		;R4=Bxx 0
 SUB     R1, R6, R14			;R5=offset from instruction to codelet
 BIC     R1, R1, #%111111 << 26
 ORR     R4, R4, R1, LSR #2		;B <codelet>
 STR     R4, [R14, #-8]			;change original instruction
 #if JIT_instruction_trace == 1
   ADD     R6, R6, #JIT_IT_codelet_size
 #endif
}



;CODELET_REUSE <size in words>
;
;Exit:
; R1, R4 - corrupted
; R6     - codelet address

MACRO CODELET_REUSE size:I
{
 #if JIT_codelet_reuse == 1
   MOV     R1, #1			;codelet can be reused
 #endif

 ADR     R4, codelet_cache_flush
 MOV     R6, #size << 2
 STR     R6, [R4, #4]			;store size for cache clean

 #if JIT_instruction_trace == 1
   MOV     R6, #(codelet_struct.codelet + (size << 2) + JIT_IT_codelet_size + (codelet_alignment - 1)) AND (&FFFFF-codelet_alignment+1)
   MOV     R4, R14			;preserve R14
   BL      allocate_codelet
   MOV     R14, R4			;preserve R14
   TEQ     R1, #0			;are we reusing an existing codelet?
   BEQ     _using_existing		; |+  skip codelet setup

   STMFD   R13!, {R0, R2-R3, R5, R7-R9, R14}
   MOV     R9, R6
   ADR     R8, instruction_trace_codelet
   LDMIA   R8!, {R0-R5, R14}
   STMIA   R9!, {R0-R5, R14}
   LDMIA   R8!, {R0-R5}
   STMIA   R9!, {R0-R5, R7}
   LDMFD   R13!, {R0, R2-R3, R5, R7-R9, R14}
 #endif
 #if JIT_instruction_trace == 0
   MOV     R6, #(codelet_struct.codelet + (size << 2) + (codelet_alignment - 1)) AND (&FFFFF-codelet_alignment+1)
   MOV     R4, R14			;preserve R14
   BL      allocate_codelet
   MOV     R14, R4			;preserve R14
   TEQ     R1, #0			;are we reusing an existing codelet?
 #endif
					;---------------------------------
 ._using_existing			;EQ set if using existing codelet
 AND     R4, R0, #OP_condition		;get condition
 #if JIT_codelet_reuse == 1
   BIC     R0, R0, #OP_condition	;clear condition
   ORR     R0, R0, #OP_AL		;change to AL
 #endif
 ORR     R4, R4, #%1010 << 24		;R4=Bxx 0
 SUB     R1, R6, R14			;R5=offset from instruction to codelet
 BIC     R1, R1, #%111111 << 26
 ORR     R4, R4, R1, LSR #2		;B <codelet>
 STR     R4, [R14, #-8]			;change original instruction
 BEQ     i_und_exit_no_codelet		;using an existing codelet, exit JIT

 #if JIT_instruction_trace == 1
   ADD     R6, R6, #JIT_IT_codelet_size
 #endif
}



;CODELET_CALLASWI <size in words>

MACRO CODELET_CALLASWI size:I
{
 #if JIT_codelet_reuse == 1
   MOV     R1, #0			;codelet cant be reused
 #endif

 ADR     R4, codelet_cache_flush
 MOV     R6, #size << 2
 STR     R6, [R4, #4]			;store size for cache clean

 MOV     R6, #(codelet_struct.codelet + (size * 4) + (codelet_alignment - 1)) AND (&FFFFF-codelet_alignment+1)
 MOV     R4, R14			;preserve R14
 BL      allocate_codelet
 MOV     R14, R4			;preserve R14

 CMN     R14, #1			;is it CallASWI calling us?
					;NO, replace original instruction with
					;a branch to the codelet
					;---------------------------------
 ANDNE   R4, R0, #%1111 << 28		;get condition
 ORRNE   R4, R4, #%1010 << 24		;R4=Bxx 0
 SUBNE   R1, R6, R14			;R5=offset from instruction to codelet
 BICNE   R1, R1, #%111111 << 26
 ORRNE   R4, R4, R1, LSR #2		;B <codelet>
 STRNE   R4, [R14, #-8]			;change original instruction
}




; Rx = register for result
; size = number of instructions in final STM to the B <return>
;eg the following example would be 2
;MOV R0, #0
;B <return>

;MACRO CORRECT_RETURN Rx:r, size:I
;{
; SUB     R5, R14, R6			;correct for offset and prefetch
; SUB     R5, R5, #8 + (size * 4)
; BIC     R5, R5, #%111111 << 26
; ORR     Rx, Rx, R5, LSR #2		;B <original address + 4>
;}
