/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *   Mupen64plus - linkage_arm.s                                           *
 *   Copyright (C) 2009-2011 Ari64                                         *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
	.cpu arm9tdmi
#ifndef __ARM_NEON__
#if (defined(__VFP_FP__) && !defined(__SOFTFP__) && defined(__ARM_PCS_VFP))
 	.fpu vfp
#else
	.fpu softvfp
#endif
#else
    	.fpu neon
#endif
	.eabi_attribute 20, 1
	.eabi_attribute 21, 1
#ifndef __ARM_NEON__
	.eabi_attribute 23, 3
#endif
	.eabi_attribute 24, 1
	.eabi_attribute 25, 1
	.eabi_attribute 26, 2
#ifndef __ARM_NEON__
#if (defined(__VFP_FP__) && !defined(__SOFTFP__) && defined(__ARM_PCS_VFP))
	.eabi_attribute 28, 1
#endif
#endif
	.eabi_attribute 30, 6
	.eabi_attribute 18, 4
	.file	"linkage_arm.S"
	.global extra_memory
	.hidden extra_memory
	.global	dynarec_local
	.hidden dynarec_local
	.global	reg
	.hidden reg
	.global	hi
	.hidden hi
	.global	lo
	.hidden lo
	.global	reg_cop1_simple
	.hidden reg_cop1_simple
	.global	reg_cop1_double
	.hidden reg_cop1_double
	.global g_cp0_regs
	.hidden g_cp0_regs
	.global	FCR0
	.hidden FCR0
	.global	FCR31
	.hidden FCR31
	.global	rounding_modes
	.hidden rounding_modes
	.global	next_interupt
	.hidden next_interupt
	.global	cycle_count
	.hidden cycle_count
	.global	last_count
	.hidden last_count
	.global	pending_exception
	.hidden pending_exception
	.global	pcaddr
	.hidden pcaddr
	.global	stop
	.hidden stop
	.global	invc_ptr
	.hidden invc_ptr
	.global	address
	.hidden address
	.global	readmem_dword
	.hidden readmem_dword
	.global	cpu_dword
	.hidden cpu_dword
	.global	cpu_word
	.hidden cpu_word
	.global	cpu_hword
	.hidden cpu_hword
	.global	cpu_byte
	.hidden cpu_byte
	.global	branch_target
	.hidden branch_target
	.global	PC
	.hidden PC
	.global	fake_pc
	.hidden fake_pc
	.global	mini_ht
	.hidden mini_ht
	.global	restore_candidate
	.hidden restore_candidate
	.global	ram_offset
	.hidden ram_offset
	.global	memory_map
	.hidden memory_map
	.bss
	.align	12
	.type	extra_memory, %object
	.size	extra_memory, 33554432
extra_memory:
	.space	33554432+64+16+16+8+8+8+8+256+8+8+128+128+128+16+8+132+4+256+512+4194304
dynarec_local = extra_memory + 33554432
	.type	dynarec_local, %object
	.size	dynarec_local, 64
next_interupt = dynarec_local + 64
	.type	next_interupt, %object
	.size	next_interupt, 4
cycle_count = next_interupt + 4
	.type	cycle_count, %object
	.size	cycle_count, 4
last_count = cycle_count + 4
	.type	last_count, %object
	.size	last_count, 4
pending_exception = last_count + 4
	.type	pending_exception, %object
	.size	pending_exception, 4
pcaddr = pending_exception + 4
	.type	pcaddr, %object
	.size	pcaddr, 4
stop = pcaddr + 4
	.type	stop, %object
	.size	stop, 4
invc_ptr = stop + 4
	.type	invc_ptr, %object
	.size	invc_ptr, 4
address = invc_ptr + 4
	.type	address, %object
	.size	address, 4
readmem_dword = address + 4
	.type	readmem_dword, %object
	.size	readmem_dword, 8
cpu_dword = readmem_dword + 8
	.type	cpu_dword, %object
	.size	cpu_dword, 8
cpu_word = cpu_dword + 8
	.type	cpu_word, %object
	.size	cpu_word, 4
cpu_hword = cpu_word + 4
	.type	cpu_hword, %object
	.size	cpu_hword, 2
cpu_byte = cpu_hword + 2
	.type	cpu_byte, %object
	.size	cpu_byte, 1 /* 1 byte free */
FCR0 = cpu_hword + 4
	.type	FCR0, %object
	.size	FCR0, 4
FCR31 = FCR0 + 4
	.type	FCR31, %object
	.size	FCR31, 4
reg = FCR31 + 4
	.type	reg, %object
	.size	reg, 256
hi = reg + 256
	.type	hi, %object
	.size	hi, 8
lo = hi + 8
	.type	lo, %object
	.size	lo, 8
g_cp0_regs = lo + 8
	.type	g_cp0_regs, %object
	.size	g_cp0_regs, 128
reg_cop1_simple = g_cp0_regs + 128
	.type	reg_cop1_simple, %object
	.size	reg_cop1_simple, 128
reg_cop1_double = reg_cop1_simple + 128
	.type	reg_cop1_double, %object
	.size	reg_cop1_double, 128
rounding_modes = reg_cop1_double + 128
	.type	rounding_modes, %object
	.size	rounding_modes, 16
branch_target = rounding_modes + 16
	.type	branch_target, %object
	.size	branch_target, 4
PC = branch_target + 4
	.type	PC, %object
	.size	PC, 4
fake_pc = PC + 4
	.type	fake_pc, %object
	.size	fake_pc, 132
ram_offset = fake_pc + 132
	.type	ram_offset, %object
	.size	ram_offset, 4
mini_ht = ram_offset + 4
	.type	mini_ht, %object
	.size	mini_ht, 256
restore_candidate = mini_ht + 256
	.type	restore_candidate, %object
	.size	restore_candidate, 512
memory_map = restore_candidate + 512
	.type	memory_map, %object
	.size	memory_map, 4194304

	.text
	.align	2
	.global	dyna_linker
	.hidden dyna_linker
	.type	dyna_linker, %function
dyna_linker:
	/* r0 = virtual target address */
	/* r1 = instruction to patch */
	ldr	r4, .tlbptr
	lsr	r5, r0, #12
	mov	r12, r0
	cmp	r0, #0xC0000000
	mov	r6, #4096
	ldrge	r12, [r4, r5, lsl #2]
	mov	r2, #0x80000
	ldr	r3, .jiptr
	tst	r12, r12
	sub	r6, r6, #1
	moveq	r12, r0
	ldr	r7, [r1]
	eor	r2, r2, r12, lsr #12
	and	r6, r6, r12, lsr #12
	cmp	r2, #2048
	add	r12, r7, #2
	orrcs	r2, r6, #2048
	ldr	r5, [r3, r2, lsl #2]
	lsl	r12, r12, #8
	/* jump_in lookup */
.A1:
	movs	r4, r5
	beq	.A3
	ldr	r3, [r5]
	ldr	r5, [r4, #12]
	teq	r3, r0
	bne	.A1
	ldr	r3, [r4, #4]
	ldr	r4, [r4, #8]
	tst	r3, r3
	bne	.A1
.A2:
	mov	r5, r1
	add	r1, r1, r12, asr #6
	teq	r1, r4
	moveq	pc, r4 /* Stale i-cache */
	bl	add_link
	sub	r2, r4, r5
	and	r1, r7, #0xff000000
	lsl	r2, r2, #6
	sub	r1, r1, #2
	add	r1, r1, r2, lsr #8
	str	r1, [r5]
	mov	pc, r4
.A3:
	/* hash_table lookup */
	cmp	r2, #2048
	ldr	r3, .jdptr
	eor	r4, r0, r0, lsl #16
	lslcc	r2, r0, #9
	ldr	r6, .htptr
	lsr	r4, r4, #12
	lsrcc	r2, r2, #21
	bic	r4, r4, #15
	ldr	r5, [r3, r2, lsl #2]
	ldr	r7, [r6, r4]!
	teq	r7, r0
	ldreq	pc, [r6, #4]
	ldr	r7, [r6, #8]
	teq	r7, r0
	ldreq	pc, [r6, #12]
	/* jump_dirty lookup */
.A6:
	movs	r4, r5
	beq	.A8
	ldr	r3, [r5]
	ldr	r5, [r4, #12]
	teq	r3, r0
	bne	.A6
.A7:
	ldr	r1, [r4, #8]
	/* hash_table insert */
	ldr	r2, [r6]
	ldr	r3, [r6, #4]
	str	r0, [r6]
	str	r1, [r6, #4]
	str	r2, [r6, #8]
	str	r3, [r6, #12]
	mov	pc, r1
.A8:
	mov	r4, r0
	mov	r5, r1
	bl	new_recompile_block
	tst	r0, r0
	mov	r0, r4
	mov	r1, r5
	beq	dyna_linker
	/* pagefault */
	mov	r1, r0
	mov	r2, #8
	.size	dyna_linker, .-dyna_linker
	.type	exec_pagefault, %function
exec_pagefault:
	/* r0 = instruction pointer */
	/* r1 = fault address */
	/* r2 = cause */
	ldr	r3, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
	mvn	r6, #0xF000000F
	ldr	r4, [fp, #g_cp0_regs+16-dynarec_local] /* Context */
	bic	r6, r6, #0x0F800000
	str	r0, [fp, #g_cp0_regs+56-dynarec_local] /* EPC */
	orr	r3, r3, #2
	str	r1, [fp, #g_cp0_regs+32-dynarec_local] /* BadVAddr */
	bic	r4, r4, r6
	str	r3, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
	and	r5, r6, r1, lsr #9
	str	r2, [fp, #g_cp0_regs+52-dynarec_local] /* Cause */
	and	r1, r1, r6, lsl #9
	str	r1, [fp, #g_cp0_regs+40-dynarec_local] /* EntryHi */
	orr	r4, r4, r5
	str	r4, [fp, #g_cp0_regs+16-dynarec_local] /* Context */
	mov	r0, #0x80000000
	bl	get_addr_ht
	mov	pc, r0
	.size	exec_pagefault, .-exec_pagefault
/* Special dynamic linker for the case where a page fault
   may occur in a branch delay slot */
	.global	dyna_linker_ds
	.hidden dyna_linker_ds
	.type	dyna_linker_ds, %function
dyna_linker_ds:
	/* r0 = virtual target address */
	/* r1 = instruction to patch */
	ldr	r4, .tlbptr
	lsr	r5, r0, #12
	mov	r12, r0
	cmp	r0, #0xC0000000
	mov	r6, #4096
	ldrge	r12, [r4, r5, lsl #2]
	mov	r2, #0x80000
	ldr	r3, .jiptr
	tst	r12, r12
	sub	r6, r6, #1
	moveq	r12, r0
	ldr	r7, [r1]
	eor	r2, r2, r12, lsr #12
	and	r6, r6, r12, lsr #12
	cmp	r2, #2048
	add	r12, r7, #2
	orrcs	r2, r6, #2048
	ldr	r5, [r3, r2, lsl #2]
	lsl	r12, r12, #8
	/* jump_in lookup */
.B1:
	movs	r4, r5
	beq	.B3
	ldr	r3, [r5]
	ldr	r5, [r4, #12]
	teq	r3, r0
	bne	.B1
	ldr	r3, [r4, #4]
	ldr	r4, [r4, #8]
	tst	r3, r3
	bne	.B1
.B2:
	mov	r5, r1
	add	r1, r1, r12, asr #6
	teq	r1, r4
	moveq	pc, r4 /* Stale i-cache */
	bl	add_link
	sub	r2, r4, r5
	and	r1, r7, #0xff000000
	lsl	r2, r2, #6
	sub	r1, r1, #2
	add	r1, r1, r2, lsr #8
	str	r1, [r5]
	mov	pc, r4
.B3:
	/* hash_table lookup */
	cmp	r2, #2048
	ldr	r3, .jdptr
	eor	r4, r0, r0, lsl #16
	lslcc	r2, r0, #9
	ldr	r6, .htptr
	lsr	r4, r4, #12
	lsrcc	r2, r2, #21
	bic	r4, r4, #15
	ldr	r5, [r3, r2, lsl #2]
	ldr	r7, [r6, r4]!
	teq	r7, r0
	ldreq	pc, [r6, #4]
	ldr	r7, [r6, #8]
	teq	r7, r0
	ldreq	pc, [r6, #12]
	/* jump_dirty lookup */
.B6:
	movs	r4, r5
	beq	.B8
	ldr	r3, [r5]
	ldr	r5, [r4, #12]
	teq	r3, r0
	bne	.B6
.B7:
	ldr	r1, [r4, #8]
	/* hash_table insert */
	ldr	r2, [r6]
	ldr	r3, [r6, #4]
	str	r0, [r6]
	str	r1, [r6, #4]
	str	r2, [r6, #8]
	str	r3, [r6, #12]
	mov	pc, r1
.B8:
	mov	r4, r0
	bic	r0, r0, #7
	mov	r5, r1
	orr	r0, r0, #1
	bl	new_recompile_block
	tst	r0, r0
	mov	r0, r4
	mov	r1, r5
	beq	dyna_linker_ds
	/* pagefault */
	bic	r1, r0, #7
	mov	r2, #0x80000008 /* High bit set indicates pagefault in delay slot */
	sub	r0, r1, #4
	b	exec_pagefault
	.size	dyna_linker_ds, .-dyna_linker_ds
.jiptr:
	.word	jump_in
.jdptr:
	.word	jump_dirty
.tlbptr:
	.word	tlb_LUT_r
.htptr:
	.word	hash_table
	.align	2
	.global	jump_vaddr_r0
	.hidden jump_vaddr_r0
	.type	jump_vaddr_r0, %function
jump_vaddr_r0:
	eor	r2, r0, r0, lsl #16
	b	jump_vaddr
	.size	jump_vaddr_r0, .-jump_vaddr_r0
	.global	jump_vaddr_r1
	.hidden jump_vaddr_r1
	.type	jump_vaddr_r1, %function
jump_vaddr_r1:
	eor	r2, r1, r1, lsl #16
	mov	r0, r1
	b	jump_vaddr
	.size	jump_vaddr_r1, .-jump_vaddr_r1
	.global	jump_vaddr_r2
	.hidden jump_vaddr_r2
	.type	jump_vaddr_r2, %function
jump_vaddr_r2:
	mov	r0, r2
	eor	r2, r2, r2, lsl #16
	b	jump_vaddr
	.size	jump_vaddr_r2, .-jump_vaddr_r2
	.global	jump_vaddr_r3
	.hidden jump_vaddr_r3
	.type	jump_vaddr_r3, %function
jump_vaddr_r3:
	eor	r2, r3, r3, lsl #16
	mov	r0, r3
	b	jump_vaddr
	.size	jump_vaddr_r3, .-jump_vaddr_r3
	.global	jump_vaddr_r4
	.hidden jump_vaddr_r4
	.type	jump_vaddr_r4, %function
jump_vaddr_r4:
	eor	r2, r4, r4, lsl #16
	mov	r0, r4
	b	jump_vaddr
	.size	jump_vaddr_r4, .-jump_vaddr_r4
	.global	jump_vaddr_r5
	.hidden jump_vaddr_r5
	.type	jump_vaddr_r5, %function
jump_vaddr_r5:
	eor	r2, r5, r5, lsl #16
	mov	r0, r5
	b	jump_vaddr
	.size	jump_vaddr_r5, .-jump_vaddr_r5
	.global	jump_vaddr_r6
	.hidden jump_vaddr_r6
	.type	jump_vaddr_r6, %function
jump_vaddr_r6:
	eor	r2, r6, r6, lsl #16
	mov	r0, r6
	b	jump_vaddr
	.size	jump_vaddr_r6, .-jump_vaddr_r6
	.global	jump_vaddr_r8
	.hidden jump_vaddr_r8
	.type	jump_vaddr_r8, %function
jump_vaddr_r8:
	eor	r2, r8, r8, lsl #16
	mov	r0, r8
	b	jump_vaddr
	.size	jump_vaddr_r8, .-jump_vaddr_r8
	.global	jump_vaddr_r9
	.hidden jump_vaddr_r9
	.type	jump_vaddr_r9, %function
jump_vaddr_r9:
	eor	r2, r9, r9, lsl #16
	mov	r0, r9
	b	jump_vaddr
	.size	jump_vaddr_r9, .-jump_vaddr_r9
	.global	jump_vaddr_r10
	.hidden jump_vaddr_r10
	.type	jump_vaddr_r10, %function
jump_vaddr_r10:
	eor	r2, r10, r10, lsl #16
	mov	r0, r10
	b	jump_vaddr
	.size	jump_vaddr_r10, .-jump_vaddr_r10
	.global	jump_vaddr_r12
	.hidden jump_vaddr_r12
	.type	jump_vaddr_r12, %function
jump_vaddr_r12:
	eor	r2, r12, r12, lsl #16
	mov	r0, r12
	b	jump_vaddr
	.size	jump_vaddr_r12, .-jump_vaddr_r12
	.global	jump_vaddr_r7
	.hidden jump_vaddr_r7
	.type	jump_vaddr_r7, %function
jump_vaddr_r7:
	eor	r2, r7, r7, lsl #16
	add	r0, r7, #0
	.size	jump_vaddr_r7, .-jump_vaddr_r7
	.global	jump_vaddr
	.hidden jump_vaddr
	.type	jump_vaddr, %function
jump_vaddr:
	ldr	r1, .htptr
	mvn	r3, #15
	and	r2, r3, r2, lsr #12
	ldr	r2, [r1, r2]!
	teq	r2, r0
	ldreq	pc, [r1, #4]
	ldr	r2, [r1, #8]
	teq	r2, r0
	ldreq	pc, [r1, #12]
	str	r10, [fp, #cycle_count-dynarec_local]
	bl	get_addr
	ldr	r10, [fp, #cycle_count-dynarec_local]
	mov	pc, r0
	.size	jump_vaddr, .-jump_vaddr
	.align	2
	.global	verify_code_ds
	.hidden verify_code_ds
	.type	verify_code_ds, %function
verify_code_ds:
	str	r8, [fp, #branch_target-dynarec_local]
	.size	verify_code_ds, .-verify_code_ds
	.global	verify_code_vm
	.hidden verify_code_vm
	.type	verify_code_vm, %function
verify_code_vm:
	/* r0 = instruction pointer (virtual address) */
	/* r1 = source (virtual address) */
	/* r2 = target */
	/* r3 = length */
	cmp	r1, #0xC0000000
	blt	verify_code
	add	r12, fp, #memory_map-dynarec_local
	lsr	r4, r1, #12
	add	r5, r1, r3
	sub	r5, #1
	ldr	r6, [r12, r4, lsl #2]
	lsr	r5, r5, #12
	movs	r7, r6
	bmi	.D5
	add	r1, r1, r6, lsl #2
	lsl	r6, r6, #2
.D1:
	add	r4, r4, #1
	teq	r6, r7, lsl #2
	bne	.D5
	ldr	r7, [r12, r4, lsl #2]
	cmp	r4, r5
	bls	.D1
	.size	verify_code_vm, .-verify_code_vm
	.global	verify_code
	.hidden verify_code
	.type	verify_code, %function
verify_code:
	/* r1 = source */
	/* r2 = target */
	/* r3 = length */
	tst	r3, #4
	mov	r4, #0
	add	r3, r1, r3
	mov	r5, #0
	ldrne	r4, [r1], #4
	mov	r12, #0
	ldrne	r5, [r2], #4
	teq	r1, r3
	beq	.D3
.D2:
	ldr	r7, [r1], #4
	eor	r9, r4, r5
	ldr	r8, [r2], #4
	orrs	r9, r9, r12
	bne	.D4
	ldr	r4, [r1], #4
	eor	r12, r7, r8
	ldr	r5, [r2], #4
	cmp	r1, r3
	bcc	.D2
	teq	r7, r8
.D3:
	teqeq	r4, r5
.D4:
	ldr	r8, [fp, #branch_target-dynarec_local]
	moveq	pc, lr
.D5:
	bl	get_addr
	mov	pc, r0
	.size	verify_code, .-verify_code
	.align	2
	.global	cc_interrupt
	.hidden cc_interrupt
	.type	cc_interrupt, %function
cc_interrupt:
	ldr	r0, [fp, #last_count-dynarec_local]
	mov	r1, #0
	mov	r2, #0x1fc
	add	r10, r0, r10
	str	r1, [fp, #pending_exception-dynarec_local]
	and	r2, r2, r10, lsr #17
	add	r3, fp, #restore_candidate-dynarec_local
	str	r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */
	ldr	r4, [r2, r3]
	mov	r10, lr
	tst	r4, r4
	bne	.E4
.E1:
	bl	gen_interupt
	mov	lr, r10
	ldr	r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */
	ldr	r0, [fp, #next_interupt-dynarec_local]
	ldr	r1, [fp, #pending_exception-dynarec_local]
	ldr	r2, [fp, #stop-dynarec_local]
	str	r0, [fp, #last_count-dynarec_local]
	sub	r10, r10, r0
	tst	r2, r2
	bne	.E3
	tst	r1, r1
	moveq	pc, lr
.E2:
	ldr	r0, [fp, #pcaddr-dynarec_local]
	bl	get_addr_ht
	mov	pc, r0
.E3:
	add	r12, fp, #28
	ldmia	r12, {r4, r5, r6, r7, r8, r9, sl, fp, pc}
.E4:
	/* Move 'dirty' blocks to the 'clean' list */
	lsl	r5, r2, #3
	str	r1, [r2, r3]
.E5:
	lsrs	r4, r4, #1
	mov	r0, r5
	add	r5, r5, #1
	blcs	clean_blocks
	tst	r5, #31
	bne	.E5
	b	.E1

	.size	cc_interrupt, .-cc_interrupt
	.align	2
	.global	do_interrupt
	.hidden do_interrupt
	.type	do_interrupt, %function
do_interrupt:
	ldr	r0, [fp, #pcaddr-dynarec_local]
	bl	get_addr_ht
	ldr	r1, [fp, #next_interupt-dynarec_local]
	ldr	r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */
	str	r1, [fp, #last_count-dynarec_local]
	sub	r10, r10, r1
	add	r10, r10, #2
	mov	pc, r0
	.size	do_interrupt, .-do_interrupt
	.align	2
	.global	fp_exception
	.hidden fp_exception
	.type	fp_exception, %function
fp_exception:
	mov	r2, #0x10000000
.E7:
	ldr	r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
	mov	r3, #0x80000000
	str	r0, [fp, #g_cp0_regs+56-dynarec_local] /* EPC */
	orr	r1, #2
	add	r2, r2, #0x2c
	str	r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
	str	r2, [fp, #g_cp0_regs+52-dynarec_local] /* Cause */
	add	r0, r3, #0x180
	bl	get_addr_ht
	mov	pc, r0
	.size	fp_exception, .-fp_exception
	.align	2
	.global	fp_exception_ds
	.hidden fp_exception_ds
	.type	fp_exception_ds, %function
fp_exception_ds:
	mov	r2, #0x90000000 /* Set high bit if delay slot */
	b	.E7
	.size	fp_exception_ds, .-fp_exception_ds
	.align	2
	.global	jump_syscall
	.hidden jump_syscall
	.type	jump_syscall, %function
jump_syscall:
	ldr	r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
	mov	r3, #0x80000000
	str	r0, [fp, #g_cp0_regs+56-dynarec_local] /* EPC */
	orr	r1, #2
	mov	r2, #0x20
	str	r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
	str	r2, [fp, #g_cp0_regs+52-dynarec_local] /* Cause */
	add	r0, r3, #0x180
	bl	get_addr_ht
	mov	pc, r0
	.size	jump_syscall, .-jump_syscall
	.align	2
	.global	indirect_jump_indexed
	.hidden indirect_jump_indexed
	.type	indirect_jump_indexed, %function
indirect_jump_indexed:
	ldr	r0, [r0, r1, lsl #2]
	.size	indirect_jump_indexed, .-indirect_jump_indexed
	.align	2
	.global	indirect_jump
	.hidden indirect_jump
	.type	indirect_jump, %function
indirect_jump:
	ldr	r12, [fp, #last_count-dynarec_local]
	add	r2, r2, r12 
	str	r2, [fp, #g_cp0_regs+36-dynarec_local] /* Count */
	mov	pc, r0
	.size	indirect_jump, .-indirect_jump
	.align	2
	.global	jump_eret
	.hidden jump_eret
	.type	jump_eret, %function
jump_eret:
	ldr	r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
	ldr	r0, [fp, #last_count-dynarec_local]
	bic	r1, r1, #2
	add	r10, r0, r10
	str	r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
	str	r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */
	bl	check_interupt
	ldr	r1, [fp, #next_interupt-dynarec_local]
	ldr	r0, [fp, #g_cp0_regs+56-dynarec_local] /* EPC */
	str	r1, [fp, #last_count-dynarec_local]
	subs	r10, r10, r1
	bpl	.E11
.E8:
	add	r6, fp, #reg+256-dynarec_local
	mov	r5, #248
	mov	r1, #0
.E9:
	ldr	r2, [r6, #-8]!
	ldr	r3, [r6, #4]
	eor	r3, r3, r2, asr #31
	subs	r3, r3, #1
	adc	r1, r1, r1
	subs	r5, r5, #8
	bne	.E9
	ldr	r2, [fp, #hi-dynarec_local]
	ldr	r3, [fp, #hi+4-dynarec_local]
	eors	r3, r3, r2, asr #31
	ldr	r2, [fp, #lo-dynarec_local]
	ldreq	r3, [fp, #lo+4-dynarec_local]
	eoreq	r3, r3, r2, asr #31
	subs	r3, r3, #1
	adc	r1, r1, r1
	bl	get_addr_32
	mov	pc, r0
.E11:
	str	r0, [fp, #pcaddr-dynarec_local]
	bl	cc_interrupt
	ldr	r0, [fp, #pcaddr-dynarec_local]
	b	.E8
	.size	jump_eret, .-jump_eret
	.align	2
	.global	new_dyna_start
	.hidden new_dyna_start
	.type	new_dyna_start, %function
new_dyna_start:
	ldr	r12, .dlptr
	ldr	r1, .tgtptr
	mov	r0, #0xa4000000
	stmia	r12, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
	sub	fp, r12, #28
	ldr	r4, [r1]
	add	r0, r0, #0x40
	bl	new_recompile_block
	ldr	r0, [fp, #next_interupt-dynarec_local]
	ldr	r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */
	str	r0, [fp, #last_count-dynarec_local]
	sub	r10, r10, r0
	mov	pc, r4
.dlptr:
	.word	dynarec_local+28
.tgtptr:
	.word	out
	.size	new_dyna_start, .-new_dyna_start
	.align	2
	.global	invalidate_addr_r0
	.hidden invalidate_addr_r0
	.type	invalidate_addr_r0, %function
invalidate_addr_r0:
	stmia	fp, {r0, r1, r2, r3, r12, lr}
	lsr	r0, r0, #12	
	b	invalidate_addr_call
	.size	invalidate_addr_r0, .-invalidate_addr_r0
	.align	2
	.global	invalidate_addr_r1
	.hidden invalidate_addr_r1
	.type	invalidate_addr_r1, %function
invalidate_addr_r1:
	stmia	fp, {r0, r1, r2, r3, r12, lr}
	lsr	r0, r1, #12	
	b	invalidate_addr_call
	.size	invalidate_addr_r1, .-invalidate_addr_r1
	.align	2
	.global	invalidate_addr_r2
	.hidden invalidate_addr_r2
	.type	invalidate_addr_r2, %function
invalidate_addr_r2:
	stmia	fp, {r0, r1, r2, r3, r12, lr}
	lsr	r0, r2, #12	
	b	invalidate_addr_call
	.size	invalidate_addr_r2, .-invalidate_addr_r2
	.align	2
	.global	invalidate_addr_r3
	.hidden invalidate_addr_r3
	.type	invalidate_addr_r3, %function
invalidate_addr_r3:
	stmia	fp, {r0, r1, r2, r3, r12, lr}
	lsr	r0, r3, #12	
	b	invalidate_addr_call
	.size	invalidate_addr_r3, .-invalidate_addr_r3
	.align	2
	.global	invalidate_addr_r4
	.hidden invalidate_addr_r4
	.type	invalidate_addr_r4, %function
invalidate_addr_r4:
	stmia	fp, {r0, r1, r2, r3, r12, lr}
	lsr	r0, r4, #12	
	b	invalidate_addr_call
	.size	invalidate_addr_r4, .-invalidate_addr_r4
	.align	2
	.global	invalidate_addr_r5
	.hidden invalidate_addr_r5
	.type	invalidate_addr_r5, %function
invalidate_addr_r5:
	stmia	fp, {r0, r1, r2, r3, r12, lr}
	lsr	r0, r5, #12	
	b	invalidate_addr_call
	.size	invalidate_addr_r5, .-invalidate_addr_r5
	.align	2
	.global	invalidate_addr_r6
	.hidden invalidate_addr_r6
	.type	invalidate_addr_r6, %function
invalidate_addr_r6:
	stmia	fp, {r0, r1, r2, r3, r12, lr}
	lsr	r0, r6, #12	
	b	invalidate_addr_call
	.size	invalidate_addr_r6, .-invalidate_addr_r6
	.align	2
	.global	invalidate_addr_r7
	.hidden invalidate_addr_r7
	.type	invalidate_addr_r7, %function
invalidate_addr_r7:
	stmia	fp, {r0, r1, r2, r3, r12, lr}
	lsr	r0, r7, #12	
	b	invalidate_addr_call
	.size	invalidate_addr_r7, .-invalidate_addr_r7
	.align	2
	.global	invalidate_addr_r8
	.hidden invalidate_addr_r8
	.type	invalidate_addr_r8, %function
invalidate_addr_r8:
	stmia	fp, {r0, r1, r2, r3, r12, lr}
	lsr	r0, r8, #12	
	b	invalidate_addr_call
	.size	invalidate_addr_r8, .-invalidate_addr_r8
	.align	2
	.global	invalidate_addr_r9
	.hidden invalidate_addr_r9
	.type	invalidate_addr_r9, %function
invalidate_addr_r9:
	stmia	fp, {r0, r1, r2, r3, r12, lr}
	lsr	r0, r9, #12	
	b	invalidate_addr_call
	.size	invalidate_addr_r9, .-invalidate_addr_r9
	.align	2
	.global	invalidate_addr_r10
	.hidden invalidate_addr_r10
	.type	invalidate_addr_r10, %function
invalidate_addr_r10:
	stmia	fp, {r0, r1, r2, r3, r12, lr}
	lsr	r0, r10, #12	
	b	invalidate_addr_call
	.size	invalidate_addr_r10, .-invalidate_addr_r10
	.align	2
	.global	invalidate_addr_r12
	.hidden invalidate_addr_r12
	.type	invalidate_addr_r12, %function
invalidate_addr_r12:
	stmia	fp, {r0, r1, r2, r3, r12, lr}
	lsr	r0, r12, #12	
	.size	invalidate_addr_r12, .-invalidate_addr_r12
	.align	2
	.type	invalidate_addr_call, %function
invalidate_addr_call:
	bl	invalidate_block
	ldmia	fp, {r0, r1, r2, r3, r12, pc}
	.size	invalidate_addr_call, .-invalidate_addr_call
	.align	2
	.global	write_rdram_new
	.hidden write_rdram_new
	.type	write_rdram_new, %function
write_rdram_new:
	ldr	r3, [fp, #ram_offset-dynarec_local]
	ldr	r2, [fp, #address-dynarec_local]
	ldr	r0, [fp, #cpu_word-dynarec_local]
	str	r0, [r2, r3, lsl #2]
	b	.E12
	.size	write_rdram_new, .-write_rdram_new
	.align	2
	.global	write_rdramb_new
	.hidden write_rdramb_new
	.type	write_rdramb_new, %function
write_rdramb_new:
	ldr	r3, [fp, #ram_offset-dynarec_local]
	ldr	r2, [fp, #address-dynarec_local]
	ldrb	r0, [fp, #cpu_byte-dynarec_local]
	eor	r2, r2, #3
	strb	r0, [r2, r3, lsl #2]
	b	.E12
	.size	write_rdramb_new, .-write_rdramb_new
	.align	2
	.global	write_rdramh_new
	.hidden write_rdramh_new
	.type	write_rdramh_new, %function
write_rdramh_new:
	ldr	r3, [fp, #ram_offset-dynarec_local]
	ldr	r2, [fp, #address-dynarec_local]
	ldrh	r0, [fp, #cpu_hword-dynarec_local]
	eor	r2, r2, #2
	lsl	r3, r3, #2
	strh	r0, [r2, r3]
	b	.E12
	.size	write_rdramh_new, .-write_rdramh_new
	.align	2
	.global	write_rdramd_new
	.hidden write_rdramd_new
	.type	write_rdramd_new, %function
write_rdramd_new:
	ldr	r3, [fp, #ram_offset-dynarec_local]
	ldr	r2, [fp, #address-dynarec_local]
/*	ldrd	r0, [fp, #cpu_dword-dynarec_local]*/
	ldr	r0, [fp, #cpu_dword-dynarec_local]
	ldr	r1, [fp, #cpu_dword+4-dynarec_local]
	add	r3, r2, r3, lsl #2
	str	r0, [r3, #4]
	str	r1, [r3]
	b	.E12
	.size	write_rdramd_new, .-write_rdramd_new
	.align	2
	.type	do_invalidate, %function
do_invalidate:
	ldr	r2, [fp, #address-dynarec_local]
.E12:
	ldr	r1, [fp, #invc_ptr-dynarec_local]
	lsr	r0, r2, #12
	ldrb	r2, [r1, r0]
	tst	r2, r2
	beq	invalidate_block
	mov	pc, lr
	.size	do_invalidate, .-do_invalidate
	.align	2
	.global	read_nomem_new
	.hidden read_nomem_new
	.type	read_nomem_new, %function
read_nomem_new:
	ldr	r2, [fp, #address-dynarec_local]
	add	r12, fp, #memory_map-dynarec_local
	lsr	r0, r2, #12
	ldr	r12, [r12, r0, lsl #2]
	mov	r1, #8
	tst	r12, r12
	bmi	tlb_exception
	ldr	r0, [r2, r12, lsl #2]
	str	r0, [fp, #readmem_dword-dynarec_local]
	mov	pc, lr
	.size	read_nomem_new, .-read_nomem_new
	.align	2
	.global	read_nomemb_new
	.hidden read_nomemb_new
	.type	read_nomemb_new, %function
read_nomemb_new:
	ldr	r2, [fp, #address-dynarec_local]
	add	r12, fp, #memory_map-dynarec_local
	lsr	r0, r2, #12
	ldr	r12, [r12, r0, lsl #2]
	mov	r1, #8
	tst	r12, r12
	bmi	tlb_exception
	eor	r2, r2, #3
	ldrb	r0, [r2, r12, lsl #2]
	str	r0, [fp, #readmem_dword-dynarec_local]
	mov	pc, lr
	.size	read_nomemb_new, .-read_nomemb_new
	.align	2
	.global	read_nomemh_new
	.hidden read_nomemh_new
	.type	read_nomemh_new, %function
read_nomemh_new:
	ldr	r2, [fp, #address-dynarec_local]
	add	r12, fp, #memory_map-dynarec_local
	lsr	r0, r2, #12
	ldr	r12, [r12, r0, lsl #2]
	mov	r1, #8
	tst	r12, r12
	bmi	tlb_exception
	lsl	r12, r12, #2
	eor	r2, r2, #2
	ldrh	r0, [r2, r12]
	str	r0, [fp, #readmem_dword-dynarec_local]
	mov	pc, lr
	.size	read_nomemh_new, .-read_nomemh_new
	.align	2
	.global	read_nomemd_new
	.hidden read_nomemd_new
	.type	read_nomemd_new, %function
read_nomemd_new:
	ldr	r2, [fp, #address-dynarec_local]
	add	r12, fp, #memory_map-dynarec_local
	lsr	r0, r2, #12
	ldr	r12, [r12, r0, lsl #2]
	mov	r1, #8
	tst	r12, r12
	bmi	tlb_exception
	lsl	r12, r12, #2
/*	ldrd	r0, [r2, r12]*/
	add	r3, r2, #4
	ldr	r0, [r2, r12]
	ldr	r1, [r3, r12]
	str	r0, [fp, #readmem_dword+4-dynarec_local]
	str	r1, [fp, #readmem_dword-dynarec_local]
	mov	pc, lr
	.size	read_nomemd_new, .-read_nomemd_new
	.align	2
	.global	write_nomem_new
	.hidden write_nomem_new
	.type	write_nomem_new, %function
write_nomem_new:
	str	r3, [fp, #24]
	str	lr, [fp, #28]
	bl	do_invalidate
	ldr	r2, [fp, #address-dynarec_local]
	add	r12, fp, #memory_map-dynarec_local
	ldr	lr, [fp, #28]
	lsr	r0, r2, #12
	ldr	r3, [fp, #24]
	ldr	r12, [r12, r0, lsl #2]
	mov	r1, #0xc
	tst	r12, #0x40000000
	bne	tlb_exception
	ldr	r0, [fp, #cpu_word-dynarec_local]
	str	r0, [r2, r12, lsl #2]
	mov	pc, lr
	.size	write_nomem_new, .-write_nomem_new
	.align	2
	.global	write_nomemb_new
	.hidden write_nomemb_new
	.type	write_nomemb_new, %function
write_nomemb_new:
	str	r3, [fp, #24]
	str	lr, [fp, #28]
	bl	do_invalidate
	ldr	r2, [fp, #address-dynarec_local]
	add	r12, fp, #memory_map-dynarec_local
	ldr	lr, [fp, #28]
	lsr	r0, r2, #12
	ldr	r3, [fp, #24]
	ldr	r12, [r12, r0, lsl #2]
	mov	r1, #0xc
	tst	r12, #0x40000000
	bne	tlb_exception
	eor	r2, r2, #3
	ldrb	r0, [fp, #cpu_byte-dynarec_local]
	strb	r0, [r2, r12, lsl #2]
	mov	pc, lr
	.size	write_nomemb_new, .-write_nomemb_new
	.align	2
	.global	write_nomemh_new
	.hidden write_nomemh_new
	.type	write_nomemh_new, %function
write_nomemh_new:
	str	r3, [fp, #24]
	str	lr, [fp, #28]
	bl	do_invalidate
	ldr	r2, [fp, #address-dynarec_local]
	add	r12, fp, #memory_map-dynarec_local
	ldr	lr, [fp, #28]
	lsr	r0, r2, #12
	ldr	r3, [fp, #24]
	ldr	r12, [r12, r0, lsl #2]
	mov	r1, #0xc
	lsls	r12, #2
	bcs	tlb_exception
	eor	r2, r2, #2
	ldrh	r0, [fp, #cpu_hword-dynarec_local]
	strh	r0, [r2, r12]
	mov	pc, lr
	.size	write_nomemh_new, .-write_nomemh_new
	.align	2
	.global	write_nomemd_new
	.hidden write_nomemd_new
	.type	write_nomemd_new, %function
write_nomemd_new:
	str	r3, [fp, #24]
	str	lr, [fp, #28]
	bl	do_invalidate
	ldr	r2, [fp, #address-dynarec_local]
	add	r12, fp, #memory_map-dynarec_local
	ldr	lr, [fp, #28]
	lsr	r0, r2, #12
	ldr	r3, [fp, #24]
	ldr	r12, [r12, r0, lsl #2]
	mov	r1, #0xc
	lsls	r12, #2
	bcs	tlb_exception
	add	r3, r2, #4
	ldr	r0, [fp, #cpu_dword+4-dynarec_local]
	ldr	r1, [fp, #cpu_dword-dynarec_local]
/*	strd	r0, [r2, r12]*/
	str	r0, [r2, r12]
	str	r1, [r3, r12]
	mov	pc, lr
	.size	write_nomemd_new, .-write_nomemd_new
	.align	2
	.type	tlb_exception, %function
tlb_exception:
	/* r1 = cause */
	/* r2 = address */
	/* r3 = instr addr/flags */
	ldr	r4, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
	add	r5, fp, #memory_map-dynarec_local
	lsr	r6, r3, #12
	orr	r1, r1, r3, lsl #31
	orr	r4, r4, #2
	ldr	r7, [r5, r6, lsl #2]
	bic	r8, r3, #3
	str	r4, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
	mov	r6, #0x6000000
	str	r1, [fp, #g_cp0_regs+52-dynarec_local] /* Cause */
	orr	r6, r6, #0x22
	ldr	r0, [r8, r7, lsl #2]
	add	r4, r8, r1, asr #29
	add	r5, fp, #reg-dynarec_local
	str	r4, [fp, #g_cp0_regs+56-dynarec_local] /* EPC */
	mov	r7, #0xf8
	ldr	r8, [fp, #g_cp0_regs+16-dynarec_local] /* Context */
	lsl	r1, r0, #16
	lsr	r4, r0,	#26
	and	r7, r7, r0, lsr #18
	mvn	r9, #0xF000000F
	sub	r2, r2, r1, asr #16
	bic	r9, r9, #0x0F800000
	rors	r6, r6, r4
	mov	r0, #0x80000000
	ldrcs	r2, [r5, r7]
	bic	r8, r8, r9
	tst	r3, #2
	str	r2, [r5, r7]
	add	r4, r2, r1, asr #16
	add	r6, fp, #reg+4-dynarec_local
	asr	r3, r2, #31
	str	r4, [fp, #g_cp0_regs+32-dynarec_local] /* BadVAddr */
	add	r0, r0, #0x180
	and	r4, r9, r4, lsr #9
	strne	r3, [r6, r7]
	orr	r8, r8, r4
	str	r8, [fp, #g_cp0_regs+16-dynarec_local] /* Context */
	bl	get_addr_ht
	ldr	r1, [fp, #next_interupt-dynarec_local]
	ldr	r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */
	str	r1, [fp, #last_count-dynarec_local]
	sub	r10, r10, r1
	mov	pc, r0	
	.size	tlb_exception, .-tlb_exception
	.align	2
	.global	breakpoint
	.hidden breakpoint
	.type	breakpoint, %function
breakpoint:
	/* Set breakpoint here for debugging */
	mov	pc, lr
	.size	breakpoint, .-breakpoint
/*  The following bug-fix implements __clear_cache (missing in Android)  */
	.align	2
	.global	__clear_cache_bugfix
	.hidden __clear_cache_bugfix
	.type	__clear_cache_bugfix, %function
__clear_cache_bugfix:
	push    {r7, lr}
	mov     r2, #0
	mov     r7, #0x2
	add     r7, r7, #0xf0000
	svc     0x00000000
	pop     {r7, pc}
	.size	__clear_cache_bugfix, .-__clear_cache_bugfix
/*  End of bug-fix	*/
	.section	.note.GNU-stack,"",%progbits
