;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, #instruction_trace_ptr
 LDR     R1, [R0, #-4]
 LDR     R2, _codelet-codelet_PC
 SUB     R2, R2, #8			;R14
 STR     R2, [R1], #4			;R0
 BIC     R1, R1, #&80000
 STR     R1, [R0, #-4]
 ADR     R0, _codelet-12
 LDMIA   R0, {R0-R2}
 B       _codelet_end + (codelet_struct.codelet-codelet_struct.source)	;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
;
;Syntax: CACHEOP_INVALIDATE_TLB_ENTRY{NE/EQ/CC/CS/LO/HS} Rx

MACRO CACHEOP_INVALIDATE_TLB_ENTRY$cc Rx:R		;corrupts R0, R14, flags
{
 #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_IOMD == 0
   MCR$cc  P15, 0, Rx, C8, C6, 1	;invalidate D TLB entry
 #endif
 #if MMUControl2_support == 0 AND compile_IOMD == 1
   #if MMUControl2_support == 0 AND compile_IOMD == 1 AND cc==0
     BNE     _skipTLB			;$cc=EQ
   #endif
   #if MMUControl2_support == 0 AND compile_IOMD == 1 AND cc==1
     BEQ     _skipTLB			;$cc=NE
   #endif
   #if MMUControl2_support == 0 AND compile_IOMD == 1 AND cc==2
     BCC     _skipTLB			;$cc=CS / HS
   #endif
   #if MMUControl2_support == 0 AND compile_IOMD == 1 AND cc==3
     BCS     _skipTLB			;$cc=CC / LO
   #endif
   LDR     R14, cpu_id
   CMP     R14, #CPUID_StrongARM	;below StrongARM?
   MCRLO   P15, 0, Rx, C6, C0, 0	;ARM710VE-71 purge TLB entry
   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
}




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




;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_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, R8-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, R8-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, R8-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, R8-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?
   STMNEFD R13!, {R0, R2-R3, R5, R8-R9, R14}
   MOVNE   R9, R6
   ADRNE   R8, instruction_trace_codelet
   LDMNEIA R8!, {R0-R5, R14}
   STMNEIA R9!, {R0-R5, R14}
   LDMNEIA R8!, {R0-R5}
   STMNEIA R9!, {R0-R5, R7}
   LDMNEFD R13!, {R0, R2-R3, R5, R8-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
					;---------------------------------
					;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
}
