1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 *   Mupen64plus - linkage_arm.S                                           *
3 *   Copyright (C) 2009-2011 Ari64                                         *
4 *                                                                         *
5 *   This program is free software; you can redistribute it and/or modify  *
6 *   it under the terms of the GNU General Public License as published by  *
7 *   the Free Software Foundation; either version 2 of the License, or     *
8 *   (at your option) any later version.                                   *
9 *                                                                         *
10 *   This program is distributed in the hope that it will be useful,       *
11 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13 *   GNU General Public License for more details.                          *
14 *                                                                         *
15 *   You should have received a copy of the GNU General Public License     *
16 *   along with this program; if not, write to the                         *
17 *   Free Software Foundation, Inc.,                                       *
18 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
19 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
20
21#define GLOBAL_FUNCTION(name)  \
22    .align 2;                  \
23    .globl name;               \
24    .hidden name;              \
25    .type name, %function;     \
26    name
27
28#define LOCAL_FUNCTION(name)  \
29    .align 2;                 \
30    .hidden name;             \
31    .type name, %function;    \
32    name
33
34#define GLOBAL_VARIABLE(name, size_) \
35    .global name;                    \
36    .hidden name;                    \
37    .type   name, %object;           \
38    .size   name, size_
39
40#define BSS_SECTION  .bss
41#define TEXT_SECTION .text
42#define END_SECTION
43
44#ifndef __ARM_NEON__
45#if (defined(__VFP_FP__) && !defined(__SOFTFP__) && defined(__ARM_PCS_VFP))
46    .fpu vfp
47#else
48    .fpu softvfp
49#endif
50#else
51    .fpu neon
52#endif
53    .eabi_attribute 20, 1
54    .eabi_attribute 21, 1
55#ifndef __ARM_NEON__
56    .eabi_attribute 23, 3
57#endif
58    .eabi_attribute 24, 1
59    .eabi_attribute 25, 1
60    .eabi_attribute 26, 2
61#ifndef __ARM_NEON__
62#if (defined(__VFP_FP__) && !defined(__SOFTFP__) && defined(__ARM_PCS_VFP))
63    .eabi_attribute 28, 1
64#endif
65#endif
66    .eabi_attribute 30, 6
67    .eabi_attribute 18, 4
68    .file    "linkage_arm.S"
69
70BSS_SECTION
71
72    .align   12
73    GLOBAL_VARIABLE(extra_memory, 33554432)
74    GLOBAL_VARIABLE(dynarec_local, 64)
75    GLOBAL_VARIABLE(next_interrupt, 4)
76    GLOBAL_VARIABLE(cycle_count, 4)
77    GLOBAL_VARIABLE(last_count, 4)
78    GLOBAL_VARIABLE(pending_exception, 4)
79    GLOBAL_VARIABLE(pcaddr, 4)
80    GLOBAL_VARIABLE(stop, 4)
81    GLOBAL_VARIABLE(invc_ptr, 4)
82    GLOBAL_VARIABLE(address, 4)
83    GLOBAL_VARIABLE(readmem_dword, 8)
84    GLOBAL_VARIABLE(cpu_dword, 8)
85    GLOBAL_VARIABLE(cpu_word, 4)
86    GLOBAL_VARIABLE(cpu_hword, 2)
87    GLOBAL_VARIABLE(cpu_byte, 1)
88    GLOBAL_VARIABLE(FCR0, 4)
89    GLOBAL_VARIABLE(FCR31, 4)
90    GLOBAL_VARIABLE(reg, 256)
91    GLOBAL_VARIABLE(hi, 8)
92    GLOBAL_VARIABLE(lo, 8)
93    GLOBAL_VARIABLE(g_cp0_regs, 128)
94    GLOBAL_VARIABLE(reg_cop1_simple, 128)
95    GLOBAL_VARIABLE(reg_cop1_double, 128)
96    GLOBAL_VARIABLE(rounding_modes, 16)
97    GLOBAL_VARIABLE(branch_target, 4)
98    GLOBAL_VARIABLE(PC, 4)
99    GLOBAL_VARIABLE(fake_pc, 132)
100    GLOBAL_VARIABLE(ram_offset, 4)
101    GLOBAL_VARIABLE(mini_ht, 256)
102    GLOBAL_VARIABLE(restore_candidate, 512)
103    GLOBAL_VARIABLE(memory_map, 4194304)
104
105extra_memory:
106    .space    33554432+64+4+4+4+4+4+4+4+4+8+8+4+2+2+4+4+256+8+8+128+128+128+16+4+4+132+4+256+512+4194304
107
108    dynarec_local     = extra_memory      + 33554432
109    next_interrupt     = dynarec_local     + 64
110    cycle_count       = next_interrupt     + 4
111    last_count        = cycle_count       + 4
112    pending_exception = last_count        + 4
113    pcaddr            = pending_exception + 4
114    stop              = pcaddr            + 4
115    invc_ptr          = stop              + 4
116    address           = invc_ptr          + 4
117    readmem_dword     = address           + 4
118    cpu_dword         = readmem_dword     + 8
119    cpu_word          = cpu_dword         + 8
120    cpu_hword         = cpu_word          + 4
121    cpu_byte          = cpu_hword         + 2 /* 1 byte free */
122    FCR0              = cpu_hword         + 4
123    FCR31             = FCR0              + 4
124    reg               = FCR31             + 4
125    hi                = reg               + 256
126    lo                = hi                + 8
127    g_cp0_regs        = lo                + 8
128    reg_cop1_simple   = g_cp0_regs        + 128
129    reg_cop1_double   = reg_cop1_simple   + 128
130    rounding_modes    = reg_cop1_double   + 128
131    branch_target     = rounding_modes    + 16
132    PC                = branch_target     + 4
133    fake_pc           = PC                + 4
134    ram_offset        = fake_pc           + 132
135    mini_ht           = ram_offset        + 4
136    restore_candidate = mini_ht           + 256
137    memory_map        = restore_candidate + 512
138
139END_SECTION
140
141TEXT_SECTION
142
143    .align   2
144    .jiptr_offset1  : .word jump_in-(.jiptr_pic1+8)
145    .jiptr_offset2  : .word jump_in-(.jiptr_pic2+8)
146    .jdptr_offset1  : .word jump_dirty-(.jdptr_pic1+8)
147    .jdptr_offset2  : .word jump_dirty-(.jdptr_pic2+8)
148    .tlbptr_offset1 : .word tlb_LUT_r-(.tlbptr_pic1+8)
149    .tlbptr_offset2 : .word tlb_LUT_r-(.tlbptr_pic2+8)
150    .htptr_offset1  : .word hash_table-(.htptr_pic1+8)
151    .htptr_offset2  : .word hash_table-(.htptr_pic2+8)
152    .htptr_offset3  : .word hash_table-(.htptr_pic3+8)
153    .dlptr_offset   : .word dynarec_local+28-(.dlptr_pic+8)
154    .outptr_offset  : .word out-(.outptr_pic+8)
155
156GLOBAL_FUNCTION(dyna_linker):
157    /* r0 = virtual target address */
158    /* r1 = instruction to patch */
159    ldr    r4, .tlbptr_offset1
160.tlbptr_pic1:
161    add    r4, pc, r4
162    lsr    r5, r0, #12
163    mov    r12, r0
164    cmp    r0, #0xC0000000
165    mov    r6, #4096
166    ldrge  r12, [r4, r5, lsl #2]
167    mov    r2, #0x80000
168    ldr    r3, .jiptr_offset1
169.jiptr_pic1:
170    add    r3, pc, r3
171    tst    r12, r12
172    sub    r6, r6, #1
173    moveq  r12, r0
174    ldr    r7, [r1]
175    eor    r2, r2, r12, lsr #12
176    and    r6, r6, r12, lsr #12
177    cmp    r2, #2048
178    add    r12, r7, #2
179    orrcs  r2, r6, #2048
180    ldr    r5, [r3, r2, lsl #2]
181    lsl    r12, r12, #8
182    /* jump_in lookup */
183.A1:
184    movs   r4, r5
185    beq    .A3
186    ldr    r3, [r5]
187    ldr    r5, [r4, #12]
188    teq    r3, r0
189    bne    .A1
190    ldr    r3, [r4, #4]
191    ldr    r4, [r4, #8]
192    tst    r3, r3
193    bne    .A1
194.A2:
195    mov    r5, r1
196    add    r1, r1, r12, asr #6
197    teq    r1, r4
198    moveq  pc, r4 /* Stale i-cache */
199    bl     add_link
200    sub    r2, r4, r5
201    and    r1, r7, #0xff000000
202    lsl    r2, r2, #6
203    sub    r1, r1, #2
204    add    r1, r1, r2, lsr #8
205    str    r1, [r5]
206    mov    pc, r4
207.A3:
208    /* hash_table lookup */
209    cmp    r2, #2048
210    ldr    r3, .jdptr_offset1
211.jdptr_pic1:
212    add    r3, pc, r3
213    eor    r4, r0, r0, lsl #16
214    lslcc  r2, r0, #9
215    ldr    r6, .htptr_offset1
216.htptr_pic1:
217    add    r6, pc, r6
218    lsr    r4, r4, #12
219    lsrcc  r2, r2, #21
220    bic    r4, r4, #15
221    ldr    r5, [r3, r2, lsl #2]
222    ldr    r7, [r6, r4]!
223    teq    r7, r0
224    ldreq  pc, [r6, #4]
225    ldr    r7, [r6, #8]
226    teq    r7, r0
227    ldreq  pc, [r6, #12]
228    /* jump_dirty lookup */
229.A6:
230    movs   r4, r5
231    beq    .A8
232    ldr    r3, [r5]
233    ldr    r5, [r4, #12]
234    teq    r3, r0
235    bne    .A6
236.A7:
237    ldr    r1, [r4, #8]
238    /* hash_table insert */
239    ldr    r2, [r6]
240    ldr    r3, [r6, #4]
241    str    r0, [r6]
242    str    r1, [r6, #4]
243    str    r2, [r6, #8]
244    str    r3, [r6, #12]
245    mov    pc, r1
246.A8:
247    mov    r4, r0
248    mov    r5, r1
249    bl     new_recompile_block
250    tst    r0, r0
251    mov    r0, r4
252    mov    r1, r5
253    beq    dyna_linker
254    /* pagefault */
255    mov    r1, r0
256    mov    r2, #8
257
258LOCAL_FUNCTION(exec_pagefault):
259    /* r0 = instruction pointer */
260    /* r1 = fault address */
261    /* r2 = cause */
262    ldr    r3, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
263    mvn    r6, #0xF000000F
264    ldr    r4, [fp, #g_cp0_regs+16-dynarec_local] /* Context */
265    bic    r6, r6, #0x0F800000
266    str    r0, [fp, #g_cp0_regs+56-dynarec_local] /* EPC */
267    orr    r3, r3, #2
268    str    r1, [fp, #g_cp0_regs+32-dynarec_local] /* BadVAddr */
269    bic    r4, r4, r6
270    str    r3, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
271    and    r5, r6, r1, lsr #9
272    str    r2, [fp, #g_cp0_regs+52-dynarec_local] /* Cause */
273    and    r1, r1, r6, lsl #9
274    str    r1, [fp, #g_cp0_regs+40-dynarec_local] /* EntryHi */
275    orr    r4, r4, r5
276    str    r4, [fp, #g_cp0_regs+16-dynarec_local] /* Context */
277    mov    r0, #0x80000000
278    bl     get_addr_ht
279    mov    pc, r0
280
281/* Special dynamic linker for the case where a page fault
282   may occur in a branch delay slot */
283GLOBAL_FUNCTION(dyna_linker_ds):
284    /* r0 = virtual target address */
285    /* r1 = instruction to patch */
286    ldr    r4, .tlbptr_offset2
287.tlbptr_pic2:
288    add    r4, pc, r4
289    lsr    r5, r0, #12
290    mov    r12, r0
291    cmp    r0, #0xC0000000
292    mov    r6, #4096
293    ldrge  r12, [r4, r5, lsl #2]
294    mov    r2, #0x80000
295    ldr    r3, .jiptr_offset2
296.jiptr_pic2:
297    add    r3, pc, r3
298    tst    r12, r12
299    sub    r6, r6, #1
300    moveq  r12, r0
301    ldr    r7, [r1]
302    eor    r2, r2, r12, lsr #12
303    and    r6, r6, r12, lsr #12
304    cmp    r2, #2048
305    add    r12, r7, #2
306    orrcs  r2, r6, #2048
307    ldr    r5, [r3, r2, lsl #2]
308    lsl    r12, r12, #8
309    /* jump_in lookup */
310.B1:
311    movs   r4, r5
312    beq    .B3
313    ldr    r3, [r5]
314    ldr    r5, [r4, #12]
315    teq    r3, r0
316    bne    .B1
317    ldr    r3, [r4, #4]
318    ldr    r4, [r4, #8]
319    tst    r3, r3
320    bne    .B1
321.B2:
322    mov    r5, r1
323    add    r1, r1, r12, asr #6
324    teq    r1, r4
325    moveq  pc, r4 /* Stale i-cache */
326    bl     add_link
327    sub    r2, r4, r5
328    and    r1, r7, #0xff000000
329    lsl    r2, r2, #6
330    sub    r1, r1, #2
331    add    r1, r1, r2, lsr #8
332    str    r1, [r5]
333    mov    pc, r4
334.B3:
335    /* hash_table lookup */
336    cmp    r2, #2048
337    ldr    r3, .jdptr_offset2
338.jdptr_pic2:
339    add    r3, pc, r3
340    eor    r4, r0, r0, lsl #16
341    lslcc  r2, r0, #9
342    ldr    r6, .htptr_offset2
343.htptr_pic2:
344    add    r6, pc, r6
345    lsr    r4, r4, #12
346    lsrcc  r2, r2, #21
347    bic    r4, r4, #15
348    ldr    r5, [r3, r2, lsl #2]
349    ldr    r7, [r6, r4]!
350    teq    r7, r0
351    ldreq  pc, [r6, #4]
352    ldr    r7, [r6, #8]
353    teq    r7, r0
354    ldreq  pc, [r6, #12]
355    /* jump_dirty lookup */
356.B6:
357    movs   r4, r5
358    beq    .B8
359    ldr    r3, [r5]
360    ldr    r5, [r4, #12]
361    teq    r3, r0
362    bne    .B6
363.B7:
364    ldr    r1, [r4, #8]
365    /* hash_table insert */
366    ldr    r2, [r6]
367    ldr    r3, [r6, #4]
368    str    r0, [r6]
369    str    r1, [r6, #4]
370    str    r2, [r6, #8]
371    str    r3, [r6, #12]
372    mov    pc, r1
373.B8:
374    mov    r4, r0
375    bic    r0, r0, #7
376    mov    r5, r1
377    orr    r0, r0, #1
378    bl     new_recompile_block
379    tst    r0, r0
380    mov    r0, r4
381    mov    r1, r5
382    beq    dyna_linker_ds
383    /* pagefault */
384    bic    r1, r0, #7
385    mov    r2, #0x80000008 /* High bit set indicates pagefault in delay slot */
386    sub    r0, r1, #4
387    b      exec_pagefault
388
389GLOBAL_FUNCTION(jump_vaddr_r0):
390    eor    r2, r0, r0, lsl #16
391    b      jump_vaddr
392
393GLOBAL_FUNCTION(jump_vaddr_r1):
394    eor    r2, r1, r1, lsl #16
395    mov    r0, r1
396    b      jump_vaddr
397
398GLOBAL_FUNCTION(jump_vaddr_r2):
399    mov    r0, r2
400    eor    r2, r2, r2, lsl #16
401    b      jump_vaddr
402
403GLOBAL_FUNCTION(jump_vaddr_r3):
404    eor    r2, r3, r3, lsl #16
405    mov    r0, r3
406    b      jump_vaddr
407
408GLOBAL_FUNCTION(jump_vaddr_r4):
409    eor    r2, r4, r4, lsl #16
410    mov    r0, r4
411    b      jump_vaddr
412
413GLOBAL_FUNCTION(jump_vaddr_r5):
414    eor    r2, r5, r5, lsl #16
415    mov    r0, r5
416    b      jump_vaddr
417
418GLOBAL_FUNCTION(jump_vaddr_r6):
419    eor    r2, r6, r6, lsl #16
420    mov    r0, r6
421    b      jump_vaddr
422
423GLOBAL_FUNCTION(jump_vaddr_r8):
424    eor    r2, r8, r8, lsl #16
425    mov    r0, r8
426    b      jump_vaddr
427
428GLOBAL_FUNCTION(jump_vaddr_r9):
429    eor    r2, r9, r9, lsl #16
430    mov    r0, r9
431    b      jump_vaddr
432
433GLOBAL_FUNCTION(jump_vaddr_r10):
434    eor    r2, r10, r10, lsl #16
435    mov    r0, r10
436    b      jump_vaddr
437
438GLOBAL_FUNCTION(jump_vaddr_r12):
439    eor    r2, r12, r12, lsl #16
440    mov    r0, r12
441    b      jump_vaddr
442
443GLOBAL_FUNCTION(jump_vaddr_r7):
444    eor    r2, r7, r7, lsl #16
445    add    r0, r7, #0
446
447GLOBAL_FUNCTION(jump_vaddr):
448    ldr    r1, .htptr_offset3
449.htptr_pic3:
450    add    r1, pc, r1
451    mvn    r3, #15
452    and    r2, r3, r2, lsr #12
453    ldr    r2, [r1, r2]!
454    teq    r2, r0
455    ldreq  pc, [r1, #4]
456    ldr    r2, [r1, #8]
457    teq    r2, r0
458    ldreq  pc, [r1, #12]
459    str    r10, [fp, #cycle_count-dynarec_local]
460    bl     get_addr
461    ldr    r10, [fp, #cycle_count-dynarec_local]
462    mov    pc, r0
463
464GLOBAL_FUNCTION(verify_code_ds):
465    str    r8, [fp, #branch_target-dynarec_local]
466
467GLOBAL_FUNCTION(verify_code_vm):
468    /* r0 = instruction pointer (virtual address) */
469    /* r1 = source (virtual address) */
470    /* r2 = target */
471    /* r3 = length */
472    cmp    r1, #0xC0000000
473    blt    verify_code
474    add    r12, fp, #memory_map-dynarec_local
475    lsr    r4, r1, #12
476    add    r5, r1, r3
477    sub    r5, #1
478    ldr    r6, [r12, r4, lsl #2]
479    lsr    r5, r5, #12
480    movs   r7, r6
481    bmi    .D5
482    add    r1, r1, r6, lsl #2
483    lsl    r6, r6, #2
484.D1:
485    add    r4, r4, #1
486    teq    r6, r7, lsl #2
487    bne    .D5
488    ldr    r7, [r12, r4, lsl #2]
489    cmp    r4, r5
490    bls    .D1
491
492GLOBAL_FUNCTION(verify_code):
493    /* r1 = source */
494    /* r2 = target */
495    /* r3 = length */
496    tst    r3, #4
497    mov    r4, #0
498    add    r3, r1, r3
499    mov    r5, #0
500    ldrne  r4, [r1], #4
501    mov    r12, #0
502    ldrne  r5, [r2], #4
503    teq    r1, r3
504    beq    .D3
505.D2:
506    ldr    r7, [r1], #4
507    eor    r9, r4, r5
508    ldr    r8, [r2], #4
509    orrs   r9, r9, r12
510    bne    .D4
511    ldr    r4, [r1], #4
512    eor    r12, r7, r8
513    ldr    r5, [r2], #4
514    cmp    r1, r3
515    bcc    .D2
516    teq    r7, r8
517.D3:
518    teqeq  r4, r5
519.D4:
520    ldr    r8, [fp, #branch_target-dynarec_local]
521    moveq  pc, lr
522.D5:
523    bl     get_addr
524    mov    pc, r0
525
526GLOBAL_FUNCTION(cc_interrupt):
527    ldr    r0, [fp, #last_count-dynarec_local]
528    mov    r1, #0
529    mov    r2, #0x1fc
530    add    r10, r0, r10
531    str    r1, [fp, #pending_exception-dynarec_local]
532    and    r2, r2, r10, lsr #19
533    add    r3, fp, #restore_candidate-dynarec_local
534    str    r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */
535    ldr    r4, [r2, r3]
536    mov    r10, lr
537    tst    r4, r4
538    bne    .E4
539.E1:
540    bl     gen_interrupt
541    mov    lr, r10
542    ldr    r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */
543    ldr    r0, [fp, #next_interrupt-dynarec_local]
544    ldr    r1, [fp, #pending_exception-dynarec_local]
545    ldr    r2, [fp, #stop-dynarec_local]
546    str    r0, [fp, #last_count-dynarec_local]
547    sub    r10, r10, r0
548    tst    r2, r2
549    bne    .E3
550    tst    r1, r1
551    moveq  pc, lr
552.E2:
553    ldr    r0, [fp, #pcaddr-dynarec_local]
554    bl     get_addr_ht
555    mov    pc, r0
556.E3:
557    add    r12, fp, #28
558    ldmia  r12, {r4, r5, r6, r7, r8, r9, sl, fp, pc}
559.E4:
560    /* Move 'dirty' blocks to the 'clean' list */
561    lsl    r5, r2, #3
562    str    r1, [r2, r3]
563    mov    r6,    #0
564.E5:
565    lsrs   r4, r4, #1
566    add    r0, r5, r6
567    blcs   clean_blocks
568    add    r6, r6, #1
569    tst    r6, #31
570    bne    .E5
571    b      .E1
572
573GLOBAL_FUNCTION(do_interrupt):
574    ldr    r0, [fp, #pcaddr-dynarec_local]
575    bl     get_addr_ht
576    ldr    r1, [fp, #next_interrupt-dynarec_local]
577    ldr    r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */
578    str    r1, [fp, #last_count-dynarec_local]
579    sub    r10, r10, r1
580    add    r10, r10, #2
581    mov    pc, r0
582
583GLOBAL_FUNCTION(fp_exception):
584    mov    r2, #0x10000000
585.E7:
586    ldr    r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
587    mov    r3, #0x80000000
588    str    r0, [fp, #g_cp0_regs+56-dynarec_local] /* EPC */
589    orr    r1, #2
590    add    r2, r2, #0x2c
591    str    r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
592    str    r2, [fp, #g_cp0_regs+52-dynarec_local] /* Cause */
593    add    r0, r3, #0x180
594    bl     get_addr_ht
595    mov    pc, r0
596
597GLOBAL_FUNCTION(fp_exception_ds):
598    mov    r2, #0x90000000 /* Set high bit if delay slot */
599    b      .E7
600
601GLOBAL_FUNCTION(jump_syscall):
602    ldr    r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
603    mov    r3, #0x80000000
604    str    r0, [fp, #g_cp0_regs+56-dynarec_local] /* EPC */
605    orr    r1, #2
606    mov    r2, #0x20
607    str    r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
608    str    r2, [fp, #g_cp0_regs+52-dynarec_local] /* Cause */
609    add    r0, r3, #0x180
610    bl     get_addr_ht
611    mov    pc, r0
612
613GLOBAL_FUNCTION(indirect_jump_indexed):
614    ldr    r0, [r0, r1, lsl #2]
615
616GLOBAL_FUNCTION(indirect_jump):
617    ldr    r12, [fp, #last_count-dynarec_local]
618    add    r2, r2, r12
619    str    r2, [fp, #g_cp0_regs+36-dynarec_local] /* Count */
620    mov    pc, r0
621
622GLOBAL_FUNCTION(jump_eret):
623    ldr    r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
624    ldr    r0, [fp, #last_count-dynarec_local]
625    bic    r1, r1, #2
626    add    r10, r0, r10
627    str    r1, [fp, #g_cp0_regs+48-dynarec_local] /* Status */
628    str    r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */
629    bl     check_interrupt
630    ldr    r1, [fp, #next_interrupt-dynarec_local]
631    ldr    r0, [fp, #g_cp0_regs+56-dynarec_local] /* EPC */
632    str    r1, [fp, #last_count-dynarec_local]
633    subs   r10, r10, r1
634    bpl    .E11
635.E8:
636    add    r6, fp, #reg+256-dynarec_local
637    mov    r5, #248
638    mov    r1, #0
639.E9:
640    ldr    r2, [r6, #-8]!
641    ldr    r3, [r6, #4]
642    eor    r3, r3, r2, asr #31
643    subs   r3, r3, #1
644    adc    r1, r1, r1
645    subs   r5, r5, #8
646    bne    .E9
647    ldr    r2, [fp, #hi-dynarec_local]
648    ldr    r3, [fp, #hi+4-dynarec_local]
649    eors   r3, r3, r2, asr #31
650    ldr    r2, [fp, #lo-dynarec_local]
651    ldreq  r3, [fp, #lo+4-dynarec_local]
652    eoreq  r3, r3, r2, asr #31
653    subs   r3, r3, #1
654    adc    r1, r1, r1
655    bl     get_addr_32
656    mov    pc, r0
657.E11:
658    str    r0, [fp, #pcaddr-dynarec_local]
659    bl     cc_interrupt
660    ldr    r0, [fp, #pcaddr-dynarec_local]
661    b      .E8
662
663GLOBAL_FUNCTION(new_dyna_start):
664    ldr    r12, .dlptr_offset
665.dlptr_pic:
666    add    r12, pc, r12
667    ldr    r1, .outptr_offset
668.outptr_pic:
669    add    r1, pc, r1
670    mov    r0, #0xa4000000
671    stmia  r12, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
672    sub    fp, r12, #28
673    ldr    r4, [r1]
674    add    r0, r0, #0x40
675    bl     new_recompile_block
676    ldr    r0, [fp, #next_interrupt-dynarec_local]
677    ldr    r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */
678    str    r0, [fp, #last_count-dynarec_local]
679    sub    r10, r10, r0
680    mov    pc, r4
681
682GLOBAL_FUNCTION(invalidate_addr_r0):
683    stmia  fp, {r0, r1, r2, r3, r12, lr}
684    lsr    r0, r0, #12
685    b      invalidate_addr_call
686
687GLOBAL_FUNCTION(invalidate_addr_r1):
688    stmia  fp, {r0, r1, r2, r3, r12, lr}
689    lsr    r0, r1, #12
690    b      invalidate_addr_call
691
692GLOBAL_FUNCTION(invalidate_addr_r2):
693    stmia  fp, {r0, r1, r2, r3, r12, lr}
694    lsr    r0, r2, #12
695    b      invalidate_addr_call
696
697GLOBAL_FUNCTION(invalidate_addr_r3):
698    stmia  fp, {r0, r1, r2, r3, r12, lr}
699    lsr    r0, r3, #12
700    b      invalidate_addr_call
701
702GLOBAL_FUNCTION(invalidate_addr_r4):
703    stmia  fp, {r0, r1, r2, r3, r12, lr}
704    lsr    r0, r4, #12
705    b      invalidate_addr_call
706
707GLOBAL_FUNCTION(invalidate_addr_r5):
708    stmia  fp, {r0, r1, r2, r3, r12, lr}
709    lsr    r0, r5, #12
710    b      invalidate_addr_call
711
712GLOBAL_FUNCTION(invalidate_addr_r6):
713    stmia  fp, {r0, r1, r2, r3, r12, lr}
714    lsr    r0, r6, #12
715    b      invalidate_addr_call
716
717GLOBAL_FUNCTION(invalidate_addr_r7):
718    stmia  fp, {r0, r1, r2, r3, r12, lr}
719    lsr    r0, r7, #12
720    b      invalidate_addr_call
721
722GLOBAL_FUNCTION(invalidate_addr_r8):
723    stmia  fp, {r0, r1, r2, r3, r12, lr}
724    lsr    r0, r8, #12
725    b      invalidate_addr_call
726
727GLOBAL_FUNCTION(invalidate_addr_r9):
728    stmia  fp, {r0, r1, r2, r3, r12, lr}
729    lsr    r0, r9, #12
730    b      invalidate_addr_call
731
732GLOBAL_FUNCTION(invalidate_addr_r10):
733    stmia  fp, {r0, r1, r2, r3, r12, lr}
734    lsr    r0, r10, #12
735    b      invalidate_addr_call
736
737GLOBAL_FUNCTION(invalidate_addr_r12):
738    stmia  fp, {r0, r1, r2, r3, r12, lr}
739    lsr    r0, r12, #12
740
741LOCAL_FUNCTION(invalidate_addr_call):
742    bl     invalidate_block
743    ldmia  fp, {r0, r1, r2, r3, r12, pc}
744
745GLOBAL_FUNCTION(write_rdram_new):
746    ldr    r3, [fp, #ram_offset-dynarec_local]
747    ldr    r2, [fp, #address-dynarec_local]
748    ldr    r0, [fp, #cpu_word-dynarec_local]
749    str    r0, [r2, r3, lsl #2]
750    b      .E12
751
752GLOBAL_FUNCTION(write_rdramb_new):
753    ldr    r3, [fp, #ram_offset-dynarec_local]
754    ldr    r2, [fp, #address-dynarec_local]
755    ldrb   r0, [fp, #cpu_byte-dynarec_local]
756    eor    r2, r2, #3
757    strb   r0, [r2, r3, lsl #2]
758    b      .E12
759
760GLOBAL_FUNCTION(write_rdramh_new):
761    ldr    r3, [fp, #ram_offset-dynarec_local]
762    ldr    r2, [fp, #address-dynarec_local]
763    ldrh   r0, [fp, #cpu_hword-dynarec_local]
764    eor    r2, r2, #2
765    lsl    r3, r3, #2
766    strh   r0, [r2, r3]
767    b      .E12
768
769GLOBAL_FUNCTION(write_rdramd_new):
770    ldr    r3, [fp, #ram_offset-dynarec_local]
771    ldr    r2, [fp, #address-dynarec_local]
772/*    ldrd    r0, [fp, #cpu_dword-dynarec_local]*/
773    ldr    r0, [fp, #cpu_dword-dynarec_local]
774    ldr    r1, [fp, #cpu_dword+4-dynarec_local]
775    add    r3, r2, r3, lsl #2
776    str    r0, [r3, #4]
777    str    r1, [r3]
778    b      .E12
779
780LOCAL_FUNCTION(do_invalidate):
781    ldr    r2, [fp, #address-dynarec_local]
782.E12:
783    ldr    r1, [fp, #invc_ptr-dynarec_local]
784    lsr    r0, r2, #12
785    ldrb   r2, [r1, r0]
786    tst    r2, r2
787    beq    invalidate_block
788    mov    pc, lr
789
790GLOBAL_FUNCTION(read_nomem_new):
791    ldr    r1, [fp, #address-dynarec_local]
792    add    r12, fp, #memory_map-dynarec_local
793    lsr    r0, r1, #12
794    ldr    r12, [r12, r0, lsl #2]
795    mov    r2, #0
796    tst    r12, r12
797    bmi    tlb_exception
798    ldr    r0, [r1, r12, lsl #2]
799    str    r0, [fp, #readmem_dword-dynarec_local]
800    mov    pc, lr
801
802GLOBAL_FUNCTION(read_nomemb_new):
803    ldr    r1, [fp, #address-dynarec_local]
804    add    r12, fp, #memory_map-dynarec_local
805    lsr    r0, r1, #12
806    ldr    r12, [r12, r0, lsl #2]
807    mov    r2, #0
808    tst    r12, r12
809    bmi    tlb_exception
810    eor    r1, r1, #3
811    ldrb   r0, [r1, r12, lsl #2]
812    str    r0, [fp, #readmem_dword-dynarec_local]
813    mov    pc, lr
814
815GLOBAL_FUNCTION(read_nomemh_new):
816    ldr    r1, [fp, #address-dynarec_local]
817    add    r12, fp, #memory_map-dynarec_local
818    lsr    r0, r1, #12
819    ldr    r12, [r12, r0, lsl #2]
820    mov    r2, #0
821    tst    r12, r12
822    bmi    tlb_exception
823    lsl    r12, r12, #2
824    eor    r1, r1, #2
825    ldrh   r0, [r1, r12]
826    str    r0, [fp, #readmem_dword-dynarec_local]
827    mov    pc, lr
828
829GLOBAL_FUNCTION(read_nomemd_new):
830    ldr    r1, [fp, #address-dynarec_local]
831    add    r12, fp, #memory_map-dynarec_local
832    lsr    r0, r1, #12
833    ldr    r12, [r12, r0, lsl #2]
834    mov    r2, #0
835    tst    r12, r12
836    bmi    tlb_exception
837    lsl    r12, r12, #2
838/*    ldrd    r0, [r1, r12]*/
839    add    r3, r1, #4
840    ldr    r0, [r1, r12]
841    ldr    r1, [r3, r12]
842    str    r0, [fp, #readmem_dword+4-dynarec_local]
843    str    r1, [fp, #readmem_dword-dynarec_local]
844    mov    pc, lr
845
846GLOBAL_FUNCTION(write_nomem_new):
847    str    r3, [fp, #24]
848    str    lr, [fp, #28]
849    bl     do_invalidate
850    ldr    r1, [fp, #address-dynarec_local]
851    add    r12, fp, #memory_map-dynarec_local
852    ldr    lr, [fp, #28]
853    lsr    r0, r1, #12
854    ldr    r3, [fp, #24]
855    ldr    r12, [r12, r0, lsl #2]
856    mov    r2, #1
857    tst    r12, #0x40000000
858    bne    tlb_exception
859    ldr    r0, [fp, #cpu_word-dynarec_local]
860    str    r0, [r1, r12, lsl #2]
861    mov    pc, lr
862
863GLOBAL_FUNCTION(write_nomemb_new):
864    str    r3, [fp, #24]
865    str    lr, [fp, #28]
866    bl     do_invalidate
867    ldr    r1, [fp, #address-dynarec_local]
868    add    r12, fp, #memory_map-dynarec_local
869    ldr    lr, [fp, #28]
870    lsr    r0, r1, #12
871    ldr    r3, [fp, #24]
872    ldr    r12, [r12, r0, lsl #2]
873    mov    r2, #1
874    tst    r12, #0x40000000
875    bne    tlb_exception
876    eor    r1, r1, #3
877    ldrb   r0, [fp, #cpu_byte-dynarec_local]
878    strb   r0, [r1, r12, lsl #2]
879    mov    pc, lr
880
881GLOBAL_FUNCTION(write_nomemh_new):
882    str    r3, [fp, #24]
883    str    lr, [fp, #28]
884    bl     do_invalidate
885    ldr    r1, [fp, #address-dynarec_local]
886    add    r12, fp, #memory_map-dynarec_local
887    ldr    lr, [fp, #28]
888    lsr    r0, r1, #12
889    ldr    r3, [fp, #24]
890    ldr    r12, [r12, r0, lsl #2]
891    mov    r2, #1
892    lsls   r12, #2
893    bcs    tlb_exception
894    eor    r1, r1, #2
895    ldrh   r0, [fp, #cpu_hword-dynarec_local]
896    strh   r0, [r1, r12]
897    mov    pc, lr
898
899GLOBAL_FUNCTION(write_nomemd_new):
900    str    r3, [fp, #24]
901    str    lr, [fp, #28]
902    bl     do_invalidate
903    ldr    r1, [fp, #address-dynarec_local]
904    add    r12, fp, #memory_map-dynarec_local
905    ldr    lr, [fp, #28]
906    lsr    r0, r1, #12
907    ldr    r3, [fp, #24]
908    ldr    r12, [r12, r0, lsl #2]
909    mov    r2, #1
910    lsls   r12, #2
911    bcs    tlb_exception
912    add    r3, r1, #4
913    ldr    r0, [fp, #cpu_dword+4-dynarec_local]
914    ldr    r1, [fp, #cpu_dword-dynarec_local]
915/*    strd    r0, [r1, r12]*/
916    str    r0, [r1, r12]
917    str    r1, [r3, r12]
918    mov    pc, lr
919
920GLOBAL_FUNCTION(write_mi_new):
921    str    r3, [fp, #24]
922    str    lr, [fp, #28]
923    add    r3, #4
924    str    r3, [fp, #pcaddr-dynarec_local]
925    mov    r1, #0
926    str    r1, [fp, #pending_exception-dynarec_local]
927    bl     write_mi
928    ldr    lr, [fp, #28]
929    ldr    r3, [fp, #24]
930    ldr    r1, [fp, #pending_exception-dynarec_local]
931    tst    r1, r1
932    bne    mi_exception
933    mov    pc, lr
934
935GLOBAL_FUNCTION(write_mib_new):
936    str    r3, [fp, #24]
937    str    lr, [fp, #28]
938    add    r3, #4
939    str    r3, [fp, #pcaddr-dynarec_local]
940    mov    r1, #0
941    str    r1, [fp, #pending_exception-dynarec_local]
942    bl     write_mib
943    ldr    lr, [fp, #28]
944    ldr    r3, [fp, #24]
945    ldr    r1, [fp, #pending_exception-dynarec_local]
946    tst    r1, r1
947    bne    mi_exception
948    mov    pc, lr
949
950GLOBAL_FUNCTION(write_mih_new):
951    str    r3, [fp, #24]
952    str    lr, [fp, #28]
953    add    r3, #4
954    str    r3, [fp, #pcaddr-dynarec_local]
955    mov    r1, #0
956    str    r1, [fp, #pending_exception-dynarec_local]
957    bl     write_mih
958    ldr    lr, [fp, #28]
959    ldr    r3, [fp, #24]
960    ldr    r1, [fp, #pending_exception-dynarec_local]
961    tst    r1, r1
962    bne    mi_exception
963    mov    pc, lr
964
965GLOBAL_FUNCTION(write_mid_new):
966    str    r3, [fp, #24]
967    str    lr, [fp, #28]
968    add    r3, #4
969    str    r3, [fp, #pcaddr-dynarec_local]
970    mov    r1, #0
971    str    r1, [fp, #pending_exception-dynarec_local]
972    bl     write_mid
973    ldr    lr, [fp, #28]
974    ldr    r3, [fp, #24]
975    ldr    r1, [fp, #pending_exception-dynarec_local]
976    tst    r1, r1
977    bne    mi_exception
978    mov    pc, lr
979
980LOCAL_FUNCTION(mi_exception):
981    /* r1 = mem addr */
982    /* r3 = instr addr/flags */
983    ldr    r1, [fp, #address-dynarec_local]
984    bl     wb_base_reg
985    b      do_interrupt
986
987LOCAL_FUNCTION(tlb_exception):
988    /* r1 = mem addr */
989    /* r2 = r/w */
990    /* r3 = instr addr/flags */
991    bl     wb_base_reg
992    mov    r0, r3
993    bl     TLB_refill_exception_new
994    ldr    r1, [fp, #next_interrupt-dynarec_local]
995    ldr    r10, [fp, #g_cp0_regs+36-dynarec_local] /* Count */
996    str    r1, [fp, #last_count-dynarec_local]
997    sub    r10, r10, r1
998    mov    pc, r0
999
1000LOCAL_FUNCTION(wb_base_reg):
1001    /* r1 = mem addr */
1002    /* r3 = instr addr/flags */
1003    add    r5, fp, #memory_map-dynarec_local
1004    lsr    r6, r3, #12
1005    ldr    r7, [r5, r6, lsl #2]
1006    bic    r8, r3, #3
1007    mov    r6, #0x6000000
1008    orr    r6, r6, #0x22
1009    ldr    r0, [r8, r7, lsl #2]
1010    add    r5, fp, #reg-dynarec_local
1011    mov    r7, #0xf8
1012    lsl    r8, r0, #16
1013    lsr    r4, r0, #26
1014    and    r7, r7, r0, lsr #18
1015    sub    r9, r1, r8, asr #16
1016    rors   r6, r6, r4
1017    ldrcs  r9, [r5, r7]
1018    tst    r3, #2
1019    str    r9, [r5, r7]
1020    add    r6, fp, #reg+4-dynarec_local
1021    asr    r5, r9, #31
1022    strne  r5, [r6, r7]
1023    mov    pc, lr
1024
1025GLOBAL_FUNCTION(breakpoint):
1026    /* Set breakpoint here for debugging */
1027    mov    pc, lr
1028
1029GLOBAL_FUNCTION(__clear_cache_bugfix):
1030    /*  The following bug-fix implements __clear_cache (missing in Android)  */
1031    push   {r7, lr}
1032    mov    r2, #0
1033    mov    r7, #0x2
1034    add    r7, r7, #0xf0000
1035    svc    0x00000000
1036    pop    {r7, pc}
1037
1038END_SECTION
1039