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