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