drc: try to support w^x platforms like iOS
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / linkage_arm.S
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *   linkage_arm.s for PCSX                                                *
3  *   Copyright (C) 2009-2011 Ari64                                         *
4  *   Copyright (C) 2010-2013 GraÅžvydas "notaz" Ignotas                     *
5  *                                                                         *
6  *   This program is free software; you can redistribute it and/or modify  *
7  *   it under the terms of the GNU General Public License as published by  *
8  *   the Free Software Foundation; either version 2 of the License, or     *
9  *   (at your option) any later version.                                   *
10  *                                                                         *
11  *   This program is distributed in the hope that it will be useful,       *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14  *   GNU General Public License for more details.                          *
15  *                                                                         *
16  *   You should have received a copy of the GNU General Public License     *
17  *   along with this program; if not, write to the                         *
18  *   Free Software Foundation, Inc.,                                       *
19  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
20  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21
22 #include "arm_features.h"
23 #include "new_dynarec_config.h"
24 #include "linkage_offsets.h"
25
26
27 #ifdef __MACH__
28 #define dynarec_local           ESYM(dynarec_local)
29 #define add_link                ESYM(add_link)
30 #define new_recompile_block     ESYM(new_recompile_block)
31 #define get_addr                ESYM(get_addr)
32 #define get_addr_ht             ESYM(get_addr_ht)
33 #define clean_blocks            ESYM(clean_blocks)
34 #define gen_interupt            ESYM(gen_interupt)
35 #define psxException            ESYM(psxException)
36 #define execI                   ESYM(execI)
37 #define invalidate_addr         ESYM(invalidate_addr)
38 #endif
39
40         .bss
41         .align  4
42         .global dynarec_local
43         .type   dynarec_local, %object
44         .size   dynarec_local, LO_dynarec_local_size
45 dynarec_local:
46         .space  LO_dynarec_local_size
47
48 #define DRC_VAR_(name, vname, size_) \
49         vname = dynarec_local + LO_##name; \
50         .global vname; \
51         .type   vname, %object; \
52         .size   vname, size_
53
54 #define DRC_VAR(name, size_) \
55         DRC_VAR_(name, ESYM(name), size_)
56
57 DRC_VAR(next_interupt, 4)
58 DRC_VAR(cycle_count, 4)
59 DRC_VAR(last_count, 4)
60 DRC_VAR(pending_exception, 4)
61 DRC_VAR(stop, 4)
62 DRC_VAR(invc_ptr, 4)
63 DRC_VAR(address, 4)
64 DRC_VAR(psxRegs, LO_psxRegs_end - LO_psxRegs)
65
66 /* psxRegs */
67 DRC_VAR(reg, 128)
68 DRC_VAR(lo, 4)
69 DRC_VAR(hi, 4)
70 DRC_VAR(reg_cop0, 128)
71 DRC_VAR(reg_cop2d, 128)
72 DRC_VAR(reg_cop2c, 128)
73 DRC_VAR(pcaddr, 4)
74 @DRC_VAR(code, 4)
75 @DRC_VAR(cycle, 4)
76 @DRC_VAR(interrupt, 4)
77 @DRC_VAR(intCycle, 256)
78
79 DRC_VAR(rcnts, 7*4*4)
80 DRC_VAR(mem_rtab, 4)
81 DRC_VAR(mem_wtab, 4)
82 DRC_VAR(psxH_ptr, 4)
83 DRC_VAR(zeromem_ptr, 4)
84 DRC_VAR(inv_code_start, 4)
85 DRC_VAR(inv_code_end, 4)
86 DRC_VAR(branch_target, 4)
87 DRC_VAR(scratch_buf_ptr, 4)
88 @DRC_VAR(align0, 12) /* unused/alignment */
89 DRC_VAR(mini_ht, 256)
90 DRC_VAR(restore_candidate, 512)
91
92 /* unused */
93 DRC_VAR(FCR0, 4)
94 DRC_VAR(FCR31, 4)
95
96 #ifdef __MACH__
97         .data
98         .align 2
99 ptr_jump_in:
100         .word   ESYM(jump_in)
101 ptr_jump_dirty:
102         .word   ESYM(jump_dirty)
103 ptr_hash_table:
104         .word   ESYM(hash_table)
105 #endif
106
107
108         .syntax unified
109         .text
110         .align  2
111
112 #ifndef HAVE_ARMV5
113 .macro blx rd
114         mov     lr, pc
115         bx      \rd
116 .endm
117 #endif
118
119 .macro load_varadr reg var
120 #if defined(HAVE_ARMV7) && !defined(__PIC__)
121         movw    \reg, #:lower16:\var
122         movt    \reg, #:upper16:\var
123 #elif defined(HAVE_ARMV7) && defined(__MACH__)
124         movw    \reg, #:lower16:(\var-(1678f+8))
125         movt    \reg, #:upper16:(\var-(1678f+8))
126 1678:
127         add     \reg, pc
128 #else
129         ldr     \reg, =\var
130 #endif
131 .endm
132
133 .macro load_varadr_ext reg var
134 #if defined(HAVE_ARMV7) && defined(__MACH__) && defined(__PIC__)
135         movw    \reg, #:lower16:(ptr_\var-(1678f+8))
136         movt    \reg, #:upper16:(ptr_\var-(1678f+8))
137 1678:
138         ldr     \reg, [pc, \reg]
139 #else
140         load_varadr \reg \var
141 #endif
142 .endm
143
144 .macro mov_16 reg imm
145 #ifdef HAVE_ARMV7
146         movw    \reg, #\imm
147 #else
148         mov     \reg, #(\imm & 0x00ff)
149         orr     \reg, #(\imm & 0xff00)
150 #endif
151 .endm
152
153 .macro mov_24 reg imm
154 #ifdef HAVE_ARMV7
155         movw    \reg, #(\imm & 0xffff)
156         movt    \reg, #(\imm >> 16)
157 #else
158         mov     \reg, #(\imm & 0x0000ff)
159         orr     \reg, #(\imm & 0x00ff00)
160         orr     \reg, #(\imm & 0xff0000)
161 #endif
162 .endm
163
164 /* r0 = virtual target address */
165 /* r1 = instruction to patch */
166 .macro dyna_linker_main
167 #ifndef NO_WRITE_EXEC
168         load_varadr_ext r3, jump_in
169         /* get_page */
170         lsr     r2, r0, #12
171         mov     r6, #4096
172         bic     r2, r2, #0xe0000
173         sub     r6, r6, #1
174         cmp     r2, #0x1000
175         ldr     r7, [r1]
176         biclt   r2, #0x0e00
177         and     r6, r6, r2
178         cmp     r2, #2048
179         add     r12, r7, #2
180         orrcs   r2, r6, #2048
181         ldr     r5, [r3, r2, lsl #2]
182         lsl     r12, r12, #8
183         add     r6, r1, r12, asr #6
184         mov     r8, #0
185         /* jump_in lookup */
186 1:
187         movs    r4, r5
188         beq     2f
189         ldr     r3, [r5]         /* ll_entry .vaddr */
190         ldrd    r4, r5, [r4, #8] /* ll_entry .next, .addr */
191         teq     r3, r0
192         bne     1b
193         teq     r4, r6
194         moveq   pc, r4 /* Stale i-cache */
195         mov     r8, r4
196         b       1b     /* jump_in may have dupes, continue search */
197 2:
198         tst     r8, r8
199         beq     3f     /* r0 not in jump_in */
200
201         mov     r5, r1
202         mov     r1, r6
203         bl      add_link
204         sub     r2, r8, r5
205         and     r1, r7, #0xff000000
206         lsl     r2, r2, #6
207         sub     r1, r1, #2
208         add     r1, r1, r2, lsr #8
209         str     r1, [r5]
210         mov     pc, r8
211 3:
212         /* hash_table lookup */
213         cmp     r2, #2048
214         load_varadr_ext r3, jump_dirty
215         eor     r4, r0, r0, lsl #16
216         lslcc   r2, r0, #9
217         load_varadr_ext r6, hash_table
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 6:
230         movs    r4, r5
231         beq     8f
232         ldr     r3, [r5]
233         ldr     r5, [r4, #12]
234         teq     r3, r0
235         bne     6b
236 7:
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 8:
247 #else
248         /* XXX: should be able to do better than this... */
249         bl      get_addr_ht
250         mov     pc, r0
251 #endif
252 .endm
253
254
255 FUNCTION(dyna_linker):
256         /* r0 = virtual target address */
257         /* r1 = instruction to patch */
258         dyna_linker_main
259
260         mov     r4, r0
261         mov     r5, r1
262         bl      new_recompile_block
263         tst     r0, r0
264         mov     r0, r4
265         mov     r1, r5
266         beq     dyna_linker
267         /* pagefault */
268         mov     r1, r0
269         mov     r2, #8
270         .size   dyna_linker, .-dyna_linker
271
272 FUNCTION(exec_pagefault):
273         /* r0 = instruction pointer */
274         /* r1 = fault address */
275         /* r2 = cause */
276         ldr     r3, [fp, #LO_reg_cop0+48] /* Status */
277         mvn     r6, #0xF000000F
278         ldr     r4, [fp, #LO_reg_cop0+16] /* Context */
279         bic     r6, r6, #0x0F800000
280         str     r0, [fp, #LO_reg_cop0+56] /* EPC */
281         orr     r3, r3, #2
282         str     r1, [fp, #LO_reg_cop0+32] /* BadVAddr */
283         bic     r4, r4, r6
284         str     r3, [fp, #LO_reg_cop0+48] /* Status */
285         and     r5, r6, r1, lsr #9
286         str     r2, [fp, #LO_reg_cop0+52] /* Cause */
287         and     r1, r1, r6, lsl #9
288         str     r1, [fp, #LO_reg_cop0+40] /* EntryHi */
289         orr     r4, r4, r5
290         str     r4, [fp, #LO_reg_cop0+16] /* Context */
291         mov     r0, #0x80000000
292         bl      get_addr_ht
293         mov     pc, r0
294         .size   exec_pagefault, .-exec_pagefault
295
296 /* Special dynamic linker for the case where a page fault
297    may occur in a branch delay slot */
298 FUNCTION(dyna_linker_ds):
299         /* r0 = virtual target address */
300         /* r1 = instruction to patch */
301         dyna_linker_main
302
303         mov     r4, r0
304         bic     r0, r0, #7
305         mov     r5, r1
306         orr     r0, r0, #1
307         bl      new_recompile_block
308         tst     r0, r0
309         mov     r0, r4
310         mov     r1, r5
311         beq     dyna_linker_ds
312         /* pagefault */
313         bic     r1, r0, #7
314         mov     r2, #0x80000008 /* High bit set indicates pagefault in delay slot */
315         sub     r0, r1, #4
316         b       exec_pagefault
317         .size   dyna_linker_ds, .-dyna_linker_ds
318
319         .align  2
320
321 FUNCTION(jump_vaddr_r0):
322         eor     r2, r0, r0, lsl #16
323         b       jump_vaddr
324         .size   jump_vaddr_r0, .-jump_vaddr_r0
325 FUNCTION(jump_vaddr_r1):
326         eor     r2, r1, r1, lsl #16
327         mov     r0, r1
328         b       jump_vaddr
329         .size   jump_vaddr_r1, .-jump_vaddr_r1
330 FUNCTION(jump_vaddr_r2):
331         mov     r0, r2
332         eor     r2, r2, r2, lsl #16
333         b       jump_vaddr
334         .size   jump_vaddr_r2, .-jump_vaddr_r2
335 FUNCTION(jump_vaddr_r3):
336         eor     r2, r3, r3, lsl #16
337         mov     r0, r3
338         b       jump_vaddr
339         .size   jump_vaddr_r3, .-jump_vaddr_r3
340 FUNCTION(jump_vaddr_r4):
341         eor     r2, r4, r4, lsl #16
342         mov     r0, r4
343         b       jump_vaddr
344         .size   jump_vaddr_r4, .-jump_vaddr_r4
345 FUNCTION(jump_vaddr_r5):
346         eor     r2, r5, r5, lsl #16
347         mov     r0, r5
348         b       jump_vaddr
349         .size   jump_vaddr_r5, .-jump_vaddr_r5
350 FUNCTION(jump_vaddr_r6):
351         eor     r2, r6, r6, lsl #16
352         mov     r0, r6
353         b       jump_vaddr
354         .size   jump_vaddr_r6, .-jump_vaddr_r6
355 FUNCTION(jump_vaddr_r8):
356         eor     r2, r8, r8, lsl #16
357         mov     r0, r8
358         b       jump_vaddr
359         .size   jump_vaddr_r8, .-jump_vaddr_r8
360 FUNCTION(jump_vaddr_r9):
361         eor     r2, r9, r9, lsl #16
362         mov     r0, r9
363         b       jump_vaddr
364         .size   jump_vaddr_r9, .-jump_vaddr_r9
365 FUNCTION(jump_vaddr_r10):
366         eor     r2, r10, r10, lsl #16
367         mov     r0, r10
368         b       jump_vaddr
369         .size   jump_vaddr_r10, .-jump_vaddr_r10
370 FUNCTION(jump_vaddr_r12):
371         eor     r2, r12, r12, lsl #16
372         mov     r0, r12
373         b       jump_vaddr
374         .size   jump_vaddr_r12, .-jump_vaddr_r12
375 FUNCTION(jump_vaddr_r7):
376         eor     r2, r7, r7, lsl #16
377         add     r0, r7, #0
378         .size   jump_vaddr_r7, .-jump_vaddr_r7
379 FUNCTION(jump_vaddr):
380         load_varadr_ext r1, hash_table
381         mvn     r3, #15
382         and     r2, r3, r2, lsr #12
383         ldr     r2, [r1, r2]!
384         teq     r2, r0
385         ldreq   pc, [r1, #4]
386         ldr     r2, [r1, #8]
387         teq     r2, r0
388         ldreq   pc, [r1, #12]
389         str     r10, [fp, #LO_cycle_count]
390         bl      get_addr
391         ldr     r10, [fp, #LO_cycle_count]
392         mov     pc, r0
393         .size   jump_vaddr, .-jump_vaddr
394
395         .align  2
396
397 FUNCTION(verify_code_ds):
398         str     r8, [fp, #LO_branch_target]
399 FUNCTION(verify_code_vm):
400 FUNCTION(verify_code):
401         /* r1 = source */
402         /* r2 = target */
403         /* r3 = length */
404         tst     r3, #4
405         mov     r4, #0
406         add     r3, r1, r3
407         mov     r5, #0
408         ldrne   r4, [r1], #4
409         mov     r12, #0
410         ldrne   r5, [r2], #4
411         teq     r1, r3
412         beq     .D3
413 .D2:
414         ldr     r7, [r1], #4
415         eor     r9, r4, r5
416         ldr     r8, [r2], #4
417         orrs    r9, r9, r12
418         bne     .D4
419         ldr     r4, [r1], #4
420         eor     r12, r7, r8
421         ldr     r5, [r2], #4
422         cmp     r1, r3
423         bcc     .D2
424         teq     r7, r8
425 .D3:
426         teqeq   r4, r5
427 .D4:
428         ldr     r8, [fp, #LO_branch_target]
429         moveq   pc, lr
430 .D5:
431         bl      get_addr
432         mov     pc, r0
433         .size   verify_code, .-verify_code
434         .size   verify_code_vm, .-verify_code_vm
435
436         .align  2
437 FUNCTION(cc_interrupt):
438         ldr     r0, [fp, #LO_last_count]
439         mov     r1, #0
440         mov     r2, #0x1fc
441         add     r10, r0, r10
442         str     r1, [fp, #LO_pending_exception]
443         and     r2, r2, r10, lsr #17
444         add     r3, fp, #LO_restore_candidate
445         str     r10, [fp, #LO_cycle]            /* PCSX cycles */
446 @@      str     r10, [fp, #LO_reg_cop0+36]      /* Count */
447         ldr     r4, [r2, r3]
448         mov     r10, lr
449         tst     r4, r4
450         bne     .E4
451 .E1:
452         bl      gen_interupt
453         mov     lr, r10
454         ldr     r10, [fp, #LO_cycle]
455         ldr     r0, [fp, #LO_next_interupt]
456         ldr     r1, [fp, #LO_pending_exception]
457         ldr     r2, [fp, #LO_stop]
458         str     r0, [fp, #LO_last_count]
459         sub     r10, r10, r0
460         tst     r2, r2
461         ldmfdne sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, pc}
462         tst     r1, r1
463         moveq   pc, lr
464 .E2:
465         ldr     r0, [fp, #LO_pcaddr]
466         bl      get_addr_ht
467         mov     pc, r0
468 .E4:
469         /* Move 'dirty' blocks to the 'clean' list */
470         lsl     r5, r2, #3
471         str     r1, [r2, r3]
472 .E5:
473         lsrs    r4, r4, #1
474         mov     r0, r5
475         add     r5, r5, #1
476         blcs    clean_blocks
477         tst     r5, #31
478         bne     .E5
479         b       .E1
480         .size   cc_interrupt, .-cc_interrupt
481
482         .align  2
483 FUNCTION(do_interrupt):
484         ldr     r0, [fp, #LO_pcaddr]
485         bl      get_addr_ht
486         add     r10, r10, #2
487         mov     pc, r0
488         .size   do_interrupt, .-do_interrupt
489
490         .align  2
491 FUNCTION(fp_exception):
492         mov     r2, #0x10000000
493 .E7:
494         ldr     r1, [fp, #LO_reg_cop0+48] /* Status */
495         mov     r3, #0x80000000
496         str     r0, [fp, #LO_reg_cop0+56] /* EPC */
497         orr     r1, #2
498         add     r2, r2, #0x2c
499         str     r1, [fp, #LO_reg_cop0+48] /* Status */
500         str     r2, [fp, #LO_reg_cop0+52] /* Cause */
501         add     r0, r3, #0x80
502         bl      get_addr_ht
503         mov     pc, r0
504         .size   fp_exception, .-fp_exception
505         .align  2
506 FUNCTION(fp_exception_ds):
507         mov     r2, #0x90000000 /* Set high bit if delay slot */
508         b       .E7
509         .size   fp_exception_ds, .-fp_exception_ds
510
511         .align  2
512 FUNCTION(jump_syscall):
513         ldr     r1, [fp, #LO_reg_cop0+48] /* Status */
514         mov     r3, #0x80000000
515         str     r0, [fp, #LO_reg_cop0+56] /* EPC */
516         orr     r1, #2
517         mov     r2, #0x20
518         str     r1, [fp, #LO_reg_cop0+48] /* Status */
519         str     r2, [fp, #LO_reg_cop0+52] /* Cause */
520         add     r0, r3, #0x80
521         bl      get_addr_ht
522         mov     pc, r0
523         .size   jump_syscall, .-jump_syscall
524         .align  2
525
526         .align  2
527 FUNCTION(jump_syscall_hle):
528         str     r0, [fp, #LO_pcaddr] /* PC must be set to EPC for psxException */
529         ldr     r2, [fp, #LO_last_count]
530         mov     r1, #0    /* in delay slot */
531         add     r2, r2, r10
532         mov     r0, #0x20 /* cause */
533         str     r2, [fp, #LO_cycle] /* PCSX cycle counter */
534         bl      psxException
535
536         /* note: psxException might do recursive recompiler call from it's HLE code,
537          * so be ready for this */
538 pcsx_return:
539         ldr     r1, [fp, #LO_next_interupt]
540         ldr     r10, [fp, #LO_cycle]
541         ldr     r0, [fp, #LO_pcaddr]
542         sub     r10, r10, r1
543         str     r1, [fp, #LO_last_count]
544         bl      get_addr_ht
545         mov     pc, r0
546         .size   jump_syscall_hle, .-jump_syscall_hle
547
548         .align  2
549 FUNCTION(jump_hlecall):
550         ldr     r2, [fp, #LO_last_count]
551         str     r0, [fp, #LO_pcaddr]
552         add     r2, r2, r10
553         adr     lr, pcsx_return
554         str     r2, [fp, #LO_cycle] /* PCSX cycle counter */
555         bx      r1
556         .size   jump_hlecall, .-jump_hlecall
557
558         .align  2
559 FUNCTION(jump_intcall):
560         ldr     r2, [fp, #LO_last_count]
561         str     r0, [fp, #LO_pcaddr]
562         add     r2, r2, r10
563         adr     lr, pcsx_return
564         str     r2, [fp, #LO_cycle] /* PCSX cycle counter */
565         b       execI
566         .size   jump_hlecall, .-jump_hlecall
567
568         .align  2
569 FUNCTION(new_dyna_leave):
570         ldr     r0, [fp, #LO_last_count]
571         add     r12, fp, #28
572         add     r10, r0, r10
573         str     r10, [fp, #LO_cycle]
574         ldmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, pc}
575         .size   new_dyna_leave, .-new_dyna_leave
576
577         .align  2
578 FUNCTION(invalidate_addr_r0):
579         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
580         b       invalidate_addr_call
581         .size   invalidate_addr_r0, .-invalidate_addr_r0
582         .align  2
583 FUNCTION(invalidate_addr_r1):
584         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
585         mov     r0, r1
586         b       invalidate_addr_call
587         .size   invalidate_addr_r1, .-invalidate_addr_r1
588         .align  2
589 FUNCTION(invalidate_addr_r2):
590         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
591         mov     r0, r2
592         b       invalidate_addr_call
593         .size   invalidate_addr_r2, .-invalidate_addr_r2
594         .align  2
595 FUNCTION(invalidate_addr_r3):
596         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
597         mov     r0, r3
598         b       invalidate_addr_call
599         .size   invalidate_addr_r3, .-invalidate_addr_r3
600         .align  2
601 FUNCTION(invalidate_addr_r4):
602         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
603         mov     r0, r4
604         b       invalidate_addr_call
605         .size   invalidate_addr_r4, .-invalidate_addr_r4
606         .align  2
607 FUNCTION(invalidate_addr_r5):
608         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
609         mov     r0, r5
610         b       invalidate_addr_call
611         .size   invalidate_addr_r5, .-invalidate_addr_r5
612         .align  2
613 FUNCTION(invalidate_addr_r6):
614         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
615         mov     r0, r6
616         b       invalidate_addr_call
617         .size   invalidate_addr_r6, .-invalidate_addr_r6
618         .align  2
619 FUNCTION(invalidate_addr_r7):
620         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
621         mov     r0, r7
622         b       invalidate_addr_call
623         .size   invalidate_addr_r7, .-invalidate_addr_r7
624         .align  2
625 FUNCTION(invalidate_addr_r8):
626         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
627         mov     r0, r8
628         b       invalidate_addr_call
629         .size   invalidate_addr_r8, .-invalidate_addr_r8
630         .align  2
631 FUNCTION(invalidate_addr_r9):
632         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
633         mov     r0, r9
634         b       invalidate_addr_call
635         .size   invalidate_addr_r9, .-invalidate_addr_r9
636         .align  2
637 FUNCTION(invalidate_addr_r10):
638         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
639         mov     r0, r10
640         b       invalidate_addr_call
641         .size   invalidate_addr_r10, .-invalidate_addr_r10
642         .align  2
643 FUNCTION(invalidate_addr_r12):
644         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
645         mov     r0, r12
646         .size   invalidate_addr_r12, .-invalidate_addr_r12
647         .align  2
648 invalidate_addr_call:
649         ldr     r12, [fp, #LO_inv_code_start]
650         ldr     lr, [fp, #LO_inv_code_end]
651         cmp     r0, r12
652         cmpcs   lr, r0
653         blcc    invalidate_addr
654         ldmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, pc}
655         .size   invalidate_addr_call, .-invalidate_addr_call
656
657         .align  2
658 FUNCTION(new_dyna_start):
659         /* ip is stored to conform EABI alignment */
660         stmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, lr}
661         load_varadr fp, dynarec_local
662         ldr     r0, [fp, #LO_pcaddr]
663         bl      get_addr_ht
664         ldr     r1, [fp, #LO_next_interupt]
665         ldr     r10, [fp, #LO_cycle]
666         str     r1, [fp, #LO_last_count]
667         sub     r10, r10, r1
668         mov     pc, r0
669         .size   new_dyna_start, .-new_dyna_start
670
671 /* --------------------------------------- */
672
673 .align  2
674
675 .macro pcsx_read_mem readop tab_shift
676         /* r0 = address, r1 = handler_tab, r2 = cycles */
677         lsl     r3, r0, #20
678         lsr     r3, #(20+\tab_shift)
679         ldr     r12, [fp, #LO_last_count]
680         ldr     r1, [r1, r3, lsl #2]
681         add     r2, r2, r12
682         lsls    r1, #1
683 .if \tab_shift == 1
684         lsl     r3, #1
685         \readop r0, [r1, r3]
686 .else
687         \readop r0, [r1, r3, lsl #\tab_shift]
688 .endif
689         movcc   pc, lr
690         str     r2, [fp, #LO_cycle]
691         bx      r1
692 .endm
693
694 FUNCTION(jump_handler_read8):
695         add     r1, #0x1000/4*4 + 0x1000/2*4 @ shift to r8 part
696         pcsx_read_mem ldrbcc, 0
697
698 FUNCTION(jump_handler_read16):
699         add     r1, #0x1000/4*4              @ shift to r16 part
700         pcsx_read_mem ldrhcc, 1
701
702 FUNCTION(jump_handler_read32):
703         pcsx_read_mem ldrcc, 2
704
705
706 .macro pcsx_write_mem wrtop tab_shift
707         /* r0 = address, r1 = data, r2 = cycles, r3 = handler_tab */
708         lsl     r12,r0, #20
709         lsr     r12, #(20+\tab_shift)
710         ldr     r3, [r3, r12, lsl #2]
711         str     r0, [fp, #LO_address]      @ some handlers still need it..
712         lsls    r3, #1
713         mov     r0, r2                                @ cycle return in case of direct store
714 .if \tab_shift == 1
715         lsl     r12, #1
716         \wrtop  r1, [r3, r12]
717 .else
718         \wrtop  r1, [r3, r12, lsl #\tab_shift]
719 .endif
720         movcc   pc, lr
721         ldr     r12, [fp, #LO_last_count]
722         mov     r0, r1
723         add     r2, r2, r12
724         push    {r2, lr}
725         str     r2, [fp, #LO_cycle]
726         blx     r3
727
728         ldr     r0, [fp, #LO_next_interupt]
729         pop     {r2, r3}
730         str     r0, [fp, #LO_last_count]
731         sub     r0, r2, r0
732         bx      r3
733 .endm
734
735 FUNCTION(jump_handler_write8):
736         add     r3, #0x1000/4*4 + 0x1000/2*4 @ shift to r8 part
737         pcsx_write_mem strbcc, 0
738
739 FUNCTION(jump_handler_write16):
740         add     r3, #0x1000/4*4              @ shift to r16 part
741         pcsx_write_mem strhcc, 1
742
743 FUNCTION(jump_handler_write32):
744         pcsx_write_mem strcc, 2
745
746 FUNCTION(jump_handler_write_h):
747         /* r0 = address, r1 = data, r2 = cycles, r3 = handler */
748         ldr     r12, [fp, #LO_last_count]
749         str     r0, [fp, #LO_address]      @ some handlers still need it..
750         add     r2, r2, r12
751         mov     r0, r1
752         push    {r2, lr}
753         str     r2, [fp, #LO_cycle]
754         blx     r3
755
756         ldr     r0, [fp, #LO_next_interupt]
757         pop     {r2, r3}
758         str     r0, [fp, #LO_last_count]
759         sub     r0, r2, r0
760         bx      r3
761
762 FUNCTION(jump_handle_swl):
763         /* r0 = address, r1 = data, r2 = cycles */
764         ldr     r3, [fp, #LO_mem_wtab]
765         mov     r12,r0,lsr #12
766         ldr     r3, [r3, r12, lsl #2]
767         lsls    r3, #1
768         bcs     4f
769         add     r3, r0, r3
770         mov     r0, r2
771         tst     r3, #2
772         beq     101f
773         tst     r3, #1
774         beq     2f
775 3:
776         str     r1, [r3, #-3]
777         bx      lr
778 2:
779         lsr     r2, r1, #8
780         lsr     r1, #24
781         strh    r2, [r3, #-2]
782         strb    r1, [r3]
783         bx      lr
784 101:
785         tst     r3, #1
786         lsrne   r1, #16         @ 1
787         lsreq   r12, r1, #24    @ 0
788         strhne  r1, [r3, #-1]
789         strbeq  r12, [r3]
790         bx      lr
791 4:
792         mov     r0, r2
793 @       b       abort
794         bx      lr              @ TODO?
795
796
797 FUNCTION(jump_handle_swr):
798         /* r0 = address, r1 = data, r2 = cycles */
799         ldr     r3, [fp, #LO_mem_wtab]
800         mov     r12,r0,lsr #12
801         ldr     r3, [r3, r12, lsl #2]
802         lsls    r3, #1
803         bcs     4f
804         add     r3, r0, r3
805         and     r12,r3, #3
806         mov     r0, r2
807         cmp     r12,#2
808         strbgt  r1, [r3]        @ 3
809         strheq  r1, [r3]        @ 2
810         cmp     r12,#1
811         strlt   r1, [r3]        @ 0
812         bxne    lr
813         lsr     r2, r1, #8      @ 1
814         strb    r1, [r3]
815         strh    r2, [r3, #1]
816         bx      lr
817 4:
818         mov     r0, r2
819 @       b       abort
820         bx      lr              @ TODO?
821
822
823 .macro rcntx_read_mode0 num
824         /* r0 = address, r2 = cycles */
825         ldr     r3, [fp, #LO_rcnts+6*4+7*4*\num] @ cycleStart
826         mov     r0, r2, lsl #16
827         sub     r0, r0, r3, lsl #16
828         lsr     r0, #16
829         bx      lr
830 .endm
831
832 FUNCTION(rcnt0_read_count_m0):
833         rcntx_read_mode0 0
834
835 FUNCTION(rcnt1_read_count_m0):
836         rcntx_read_mode0 1
837
838 FUNCTION(rcnt2_read_count_m0):
839         rcntx_read_mode0 2
840
841 FUNCTION(rcnt0_read_count_m1):
842         /* r0 = address, r2 = cycles */
843         ldr     r3, [fp, #LO_rcnts+6*4+7*4*0] @ cycleStart
844         mov_16  r1, 0x3334
845         sub     r2, r2, r3
846         mul     r0, r1, r2              @ /= 5
847         lsr     r0, #16
848         bx      lr
849
850 FUNCTION(rcnt1_read_count_m1):
851         /* r0 = address, r2 = cycles */
852         ldr     r3, [fp, #LO_rcnts+6*4+7*4*1]
853         mov_24  r1, 0x1e6cde
854         sub     r2, r2, r3
855         umull   r3, r0, r1, r2          @ ~ /= hsync_cycles, max ~0x1e6cdd
856         bx      lr
857
858 FUNCTION(rcnt2_read_count_m1):
859         /* r0 = address, r2 = cycles */
860         ldr     r3, [fp, #LO_rcnts+6*4+7*4*2]
861         mov     r0, r2, lsl #16-3
862         sub     r0, r0, r3, lsl #16-3
863         lsr     r0, #16                 @ /= 8
864         bx      lr
865
866 @ vim:filetype=armasm