/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* 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