1a16aa04da6ff8b08cae51104ea1a8946b9fbab2
[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_jump_out            ESYM(add_jump_out)
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 invalidate_addr         ESYM(invalidate_addr)
36 #define gteCheckStallRaw        ESYM(gteCheckStallRaw)
37 #define psxException            ESYM(psxException)
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(hack_addr, 4)
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(ram_offset, 4)
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  /* old target */
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_jump_out
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, #(4<<2)  /* Address error (fetch) */
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         str     r0, [fp, #LO_reg_cop0+56] /* EPC */
276         orr     r3, r3, #2
277         str     r1, [fp, #LO_reg_cop0+32] /* BadVAddr */
278         str     r3, [fp, #LO_reg_cop0+48] /* Status */
279         str     r2, [fp, #LO_reg_cop0+52] /* Cause */
280         mov     r0, #0x80000000
281         orr     r0, r0, #0x80
282         bl      get_addr_ht
283         mov     pc, r0
284         .size   exec_pagefault, .-exec_pagefault
285
286 /* Special dynamic linker for the case where a page fault
287    may occur in a branch delay slot */
288 FUNCTION(dyna_linker_ds):
289         /* r0 = virtual target address */
290         /* r1 = instruction to patch */
291         dyna_linker_main
292
293         mov     r4, r0
294         bic     r0, r0, #7
295         mov     r5, r1
296         orr     r0, r0, #1
297         bl      new_recompile_block
298         tst     r0, r0
299         mov     r0, r4
300         mov     r1, r5
301         beq     dyna_linker_ds
302         /* pagefault */
303         bic     r1, r0, #7
304         mov     r2, #0x80000008 /* High bit set indicates pagefault in delay slot */
305         sub     r0, r1, #4
306         b       exec_pagefault
307         .size   dyna_linker_ds, .-dyna_linker_ds
308
309         .align  2
310
311 FUNCTION(jump_vaddr_r0):
312         eor     r2, r0, r0, lsl #16
313         b       jump_vaddr
314         .size   jump_vaddr_r0, .-jump_vaddr_r0
315 FUNCTION(jump_vaddr_r1):
316         eor     r2, r1, r1, lsl #16
317         mov     r0, r1
318         b       jump_vaddr
319         .size   jump_vaddr_r1, .-jump_vaddr_r1
320 FUNCTION(jump_vaddr_r2):
321         mov     r0, r2
322         eor     r2, r2, r2, lsl #16
323         b       jump_vaddr
324         .size   jump_vaddr_r2, .-jump_vaddr_r2
325 FUNCTION(jump_vaddr_r3):
326         eor     r2, r3, r3, lsl #16
327         mov     r0, r3
328         b       jump_vaddr
329         .size   jump_vaddr_r3, .-jump_vaddr_r3
330 FUNCTION(jump_vaddr_r4):
331         eor     r2, r4, r4, lsl #16
332         mov     r0, r4
333         b       jump_vaddr
334         .size   jump_vaddr_r4, .-jump_vaddr_r4
335 FUNCTION(jump_vaddr_r5):
336         eor     r2, r5, r5, lsl #16
337         mov     r0, r5
338         b       jump_vaddr
339         .size   jump_vaddr_r5, .-jump_vaddr_r5
340 FUNCTION(jump_vaddr_r6):
341         eor     r2, r6, r6, lsl #16
342         mov     r0, r6
343         b       jump_vaddr
344         .size   jump_vaddr_r6, .-jump_vaddr_r6
345 FUNCTION(jump_vaddr_r8):
346         eor     r2, r8, r8, lsl #16
347         mov     r0, r8
348         b       jump_vaddr
349         .size   jump_vaddr_r8, .-jump_vaddr_r8
350 FUNCTION(jump_vaddr_r9):
351         eor     r2, r9, r9, lsl #16
352         mov     r0, r9
353         b       jump_vaddr
354         .size   jump_vaddr_r9, .-jump_vaddr_r9
355 FUNCTION(jump_vaddr_r10):
356         eor     r2, r10, r10, lsl #16
357         mov     r0, r10
358         b       jump_vaddr
359         .size   jump_vaddr_r10, .-jump_vaddr_r10
360 FUNCTION(jump_vaddr_r12):
361         eor     r2, r12, r12, lsl #16
362         mov     r0, r12
363         b       jump_vaddr
364         .size   jump_vaddr_r12, .-jump_vaddr_r12
365 FUNCTION(jump_vaddr_r7):
366         eor     r2, r7, r7, lsl #16
367         add     r0, r7, #0
368         .size   jump_vaddr_r7, .-jump_vaddr_r7
369 FUNCTION(jump_vaddr):
370         load_varadr_ext r1, hash_table
371         mvn     r3, #15
372         and     r2, r3, r2, lsr #12
373         ldr     r2, [r1, r2]!
374         teq     r2, r0
375         ldreq   pc, [r1, #8]
376         ldr     r2, [r1, #4]
377         teq     r2, r0
378         ldreq   pc, [r1, #12]
379         str     r10, [fp, #LO_cycle_count]
380         bl      get_addr
381         ldr     r10, [fp, #LO_cycle_count]
382         mov     pc, r0
383         .size   jump_vaddr, .-jump_vaddr
384
385         .align  2
386
387 FUNCTION(verify_code_ds):
388         str     r8, [fp, #LO_branch_target]  @ preserve HOST_BTREG?
389 FUNCTION(verify_code):
390         /* r1 = source */
391         /* r2 = target */
392         /* r3 = length */
393         tst     r3, #4
394         mov     r4, #0
395         add     r3, r1, r3
396         mov     r5, #0
397         ldrne   r4, [r1], #4
398         mov     r12, #0
399         ldrne   r5, [r2], #4
400         teq     r1, r3
401         beq     .D3
402 .D2:
403         ldr     r7, [r1], #4
404         eor     r9, r4, r5
405         ldr     r8, [r2], #4
406         orrs    r9, r9, r12
407         bne     .D4
408         ldr     r4, [r1], #4
409         eor     r12, r7, r8
410         ldr     r5, [r2], #4
411         cmp     r1, r3
412         bcc     .D2
413         teq     r7, r8
414 .D3:
415         teqeq   r4, r5
416 .D4:
417         ldr     r8, [fp, #LO_branch_target]
418         moveq   pc, lr
419 .D5:
420         bl      get_addr
421         mov     pc, r0
422         .size   verify_code, .-verify_code
423         .size   verify_code_ds, .-verify_code_ds
424
425         .align  2
426 FUNCTION(cc_interrupt):
427         ldr     r0, [fp, #LO_last_count]
428         mov     r1, #0
429         mov     r2, #0x1fc
430         add     r10, r0, r10
431         str     r1, [fp, #LO_pending_exception]
432         and     r2, r2, r10, lsr #17
433         add     r3, fp, #LO_restore_candidate
434         str     r10, [fp, #LO_cycle]            /* PCSX cycles */
435 @@      str     r10, [fp, #LO_reg_cop0+36]      /* Count - not on PSX */
436         ldr     r4, [r2, r3]
437         mov     r10, lr
438         tst     r4, r4
439         bne     .E4
440 .E1:
441         bl      gen_interupt
442         mov     lr, r10
443         ldr     r10, [fp, #LO_cycle]
444         ldr     r0, [fp, #LO_next_interupt]
445         ldr     r1, [fp, #LO_pending_exception]
446         ldr     r2, [fp, #LO_stop]
447         str     r0, [fp, #LO_last_count]
448         sub     r10, r10, r0
449         tst     r2, r2
450         ldmfdne sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, pc}
451         tst     r1, r1
452         moveq   pc, lr
453 .E2:
454         ldr     r0, [fp, #LO_pcaddr]
455         bl      get_addr_ht
456         mov     pc, r0
457 .E4:
458         /* Move 'dirty' blocks to the 'clean' list */
459         lsl     r5, r2, #3
460         str     r1, [r2, r3]
461 .E5:
462         lsrs    r4, r4, #1
463         mov     r0, r5
464         add     r5, r5, #1
465         blcs    clean_blocks
466         tst     r5, #31
467         bne     .E5
468         b       .E1
469         .size   cc_interrupt, .-cc_interrupt
470
471         .align  2
472 FUNCTION(fp_exception):
473         mov     r2, #0x10000000
474 .E7:
475         ldr     r1, [fp, #LO_reg_cop0+48] /* Status */
476         mov     r3, #0x80000000
477         str     r0, [fp, #LO_reg_cop0+56] /* EPC */
478         orr     r1, #2
479         add     r2, r2, #0x2c
480         str     r1, [fp, #LO_reg_cop0+48] /* Status */
481         str     r2, [fp, #LO_reg_cop0+52] /* Cause */
482         add     r0, r3, #0x80
483         bl      get_addr_ht
484         mov     pc, r0
485         .size   fp_exception, .-fp_exception
486         .align  2
487 FUNCTION(fp_exception_ds):
488         mov     r2, #0x90000000 /* Set high bit if delay slot */
489         b       .E7
490         .size   fp_exception_ds, .-fp_exception_ds
491
492         .align  2
493 FUNCTION(jump_break_ds):
494         mov     r0, #0x24
495         mov     r1, #1
496         b       call_psxException
497 FUNCTION(jump_break):
498         mov     r0, #0x24
499         mov     r1, #0
500         b       call_psxException
501 FUNCTION(jump_syscall_ds):
502         mov     r0, #0x20
503         mov     r1, #1
504         b       call_psxException
505 FUNCTION(jump_syscall):
506         mov     r0, #0x20
507         mov     r1, #0
508
509 call_psxException:
510         ldr     r3, [fp, #LO_last_count]
511         str     r2, [fp, #LO_pcaddr]
512         add     r10, r3, r10
513         str     r10, [fp, #LO_cycle]            /* PCSX cycles */
514         bl      psxException
515
516         /* note: psxException might do recursive recompiler call from it's HLE code,
517          * so be ready for this */
518 FUNCTION(jump_to_new_pc):
519         ldr     r1, [fp, #LO_next_interupt]
520         ldr     r10, [fp, #LO_cycle]
521         ldr     r0, [fp, #LO_pcaddr]
522         sub     r10, r10, r1
523         str     r1, [fp, #LO_last_count]
524         bl      get_addr_ht
525         mov     pc, r0
526         .size   jump_to_new_pc, .-jump_to_new_pc
527
528         .align  2
529 FUNCTION(new_dyna_leave):
530         ldr     r0, [fp, #LO_last_count]
531         add     r12, fp, #28
532         add     r10, r0, r10
533         str     r10, [fp, #LO_cycle]
534         ldmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, pc}
535         .size   new_dyna_leave, .-new_dyna_leave
536
537         .align  2
538 FUNCTION(invalidate_addr_r0):
539         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
540         b       invalidate_addr_call
541         .size   invalidate_addr_r0, .-invalidate_addr_r0
542         .align  2
543 FUNCTION(invalidate_addr_r1):
544         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
545         mov     r0, r1
546         b       invalidate_addr_call
547         .size   invalidate_addr_r1, .-invalidate_addr_r1
548         .align  2
549 FUNCTION(invalidate_addr_r2):
550         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
551         mov     r0, r2
552         b       invalidate_addr_call
553         .size   invalidate_addr_r2, .-invalidate_addr_r2
554         .align  2
555 FUNCTION(invalidate_addr_r3):
556         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
557         mov     r0, r3
558         b       invalidate_addr_call
559         .size   invalidate_addr_r3, .-invalidate_addr_r3
560         .align  2
561 FUNCTION(invalidate_addr_r4):
562         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
563         mov     r0, r4
564         b       invalidate_addr_call
565         .size   invalidate_addr_r4, .-invalidate_addr_r4
566         .align  2
567 FUNCTION(invalidate_addr_r5):
568         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
569         mov     r0, r5
570         b       invalidate_addr_call
571         .size   invalidate_addr_r5, .-invalidate_addr_r5
572         .align  2
573 FUNCTION(invalidate_addr_r6):
574         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
575         mov     r0, r6
576         b       invalidate_addr_call
577         .size   invalidate_addr_r6, .-invalidate_addr_r6
578         .align  2
579 FUNCTION(invalidate_addr_r7):
580         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
581         mov     r0, r7
582         b       invalidate_addr_call
583         .size   invalidate_addr_r7, .-invalidate_addr_r7
584         .align  2
585 FUNCTION(invalidate_addr_r8):
586         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
587         mov     r0, r8
588         b       invalidate_addr_call
589         .size   invalidate_addr_r8, .-invalidate_addr_r8
590         .align  2
591 FUNCTION(invalidate_addr_r9):
592         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
593         mov     r0, r9
594         b       invalidate_addr_call
595         .size   invalidate_addr_r9, .-invalidate_addr_r9
596         .align  2
597 FUNCTION(invalidate_addr_r10):
598         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
599         mov     r0, r10
600         b       invalidate_addr_call
601         .size   invalidate_addr_r10, .-invalidate_addr_r10
602         .align  2
603 FUNCTION(invalidate_addr_r12):
604         stmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, lr}
605         mov     r0, r12
606         .size   invalidate_addr_r12, .-invalidate_addr_r12
607         .align  2
608 invalidate_addr_call:
609         ldr     r12, [fp, #LO_inv_code_start]
610         ldr     lr, [fp, #LO_inv_code_end]
611         cmp     r0, r12
612         cmpcs   lr, r0
613         blcc    invalidate_addr
614         ldmia   fp, {r0, r1, r2, r3, EXTRA_UNSAVED_REGS r12, pc}
615         .size   invalidate_addr_call, .-invalidate_addr_call
616
617         .align  2
618 FUNCTION(new_dyna_start):
619         /* ip is stored to conform EABI alignment */
620         stmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, lr}
621         mov     fp, r0 /* dynarec_local */
622         ldr     r0, [fp, #LO_pcaddr]
623         bl      get_addr_ht
624         ldr     r1, [fp, #LO_next_interupt]
625         ldr     r10, [fp, #LO_cycle]
626         str     r1, [fp, #LO_last_count]
627         sub     r10, r10, r1
628         mov     pc, r0
629         .size   new_dyna_start, .-new_dyna_start
630
631 /* --------------------------------------- */
632
633 .align  2
634
635 .macro pcsx_read_mem readop tab_shift
636         /* r0 = address, r1 = handler_tab, r2 = cycles */
637         lsl     r3, r0, #20
638         lsr     r3, #(20+\tab_shift)
639         ldr     r12, [fp, #LO_last_count]
640         ldr     r1, [r1, r3, lsl #2]
641         add     r2, r2, r12
642         lsls    r1, #1
643 .if \tab_shift == 1
644         lsl     r3, #1
645         \readop r0, [r1, r3]
646 .else
647         \readop r0, [r1, r3, lsl #\tab_shift]
648 .endif
649         movcc   pc, lr
650         str     r2, [fp, #LO_cycle]
651         bx      r1
652 .endm
653
654 FUNCTION(jump_handler_read8):
655         add     r1, #0x1000/4*4 + 0x1000/2*4 @ shift to r8 part
656         pcsx_read_mem ldrbcc, 0
657
658 FUNCTION(jump_handler_read16):
659         add     r1, #0x1000/4*4              @ shift to r16 part
660         pcsx_read_mem ldrhcc, 1
661
662 FUNCTION(jump_handler_read32):
663         pcsx_read_mem ldrcc, 2
664
665
666 .macro memhandler_post
667         ldr     r0, [fp, #LO_next_interupt]
668         ldr     r2, [fp, #LO_cycle]        @ memhandlers can modify cc, like dma
669         str     r0, [fp, #LO_last_count]
670         sub     r0, r2, r0
671 .endm
672
673 .macro pcsx_write_mem wrtop tab_shift
674         /* r0 = address, r1 = data, r2 = cycles, r3 = handler_tab */
675         lsl     r12,r0, #20
676         lsr     r12, #(20+\tab_shift)
677         ldr     r3, [r3, r12, lsl #2]
678         str     r0, [fp, #LO_address]      @ some handlers still need it..
679         lsls    r3, #1
680         mov     r0, r2                     @ cycle return in case of direct store
681 .if \tab_shift == 1
682         lsl     r12, #1
683         \wrtop  r1, [r3, r12]
684 .else
685         \wrtop  r1, [r3, r12, lsl #\tab_shift]
686 .endif
687         movcc   pc, lr
688         ldr     r12, [fp, #LO_last_count]
689         mov     r0, r1
690         add     r2, r2, r12
691         str     r2, [fp, #LO_cycle]
692
693         str     lr, [fp, #LO_saved_lr]
694         blx     r3
695         ldr     lr, [fp, #LO_saved_lr]
696
697         memhandler_post
698         bx      lr
699 .endm
700
701 FUNCTION(jump_handler_write8):
702         add     r3, #0x1000/4*4 + 0x1000/2*4 @ shift to r8 part
703         pcsx_write_mem strbcc, 0
704
705 FUNCTION(jump_handler_write16):
706         add     r3, #0x1000/4*4              @ shift to r16 part
707         pcsx_write_mem strhcc, 1
708
709 FUNCTION(jump_handler_write32):
710         pcsx_write_mem strcc, 2
711
712 FUNCTION(jump_handler_write_h):
713         /* r0 = address, r1 = data, r2 = cycles, r3 = handler */
714         ldr     r12, [fp, #LO_last_count]
715         str     r0, [fp, #LO_address]      @ some handlers still need it..
716         add     r2, r2, r12
717         mov     r0, r1
718         str     r2, [fp, #LO_cycle]
719
720         str     lr, [fp, #LO_saved_lr]
721         blx     r3
722         ldr     lr, [fp, #LO_saved_lr]
723
724         memhandler_post
725         bx      lr
726
727 FUNCTION(jump_handle_swl):
728         /* r0 = address, r1 = data, r2 = cycles */
729         ldr     r3, [fp, #LO_mem_wtab]
730         mov     r12,r0,lsr #12
731         ldr     r3, [r3, r12, lsl #2]
732         lsls    r3, #1
733         bcs     4f
734         add     r3, r0, r3
735         mov     r0, r2
736         tst     r3, #2
737         beq     101f
738         tst     r3, #1
739         beq     2f
740 3:
741         str     r1, [r3, #-3]
742         bx      lr
743 2:
744         lsr     r2, r1, #8
745         lsr     r1, #24
746         strh    r2, [r3, #-2]
747         strb    r1, [r3]
748         bx      lr
749 101:
750         tst     r3, #1
751         lsrne   r1, #16         @ 1
752         lsreq   r12, r1, #24    @ 0
753         strhne  r1, [r3, #-1]
754         strbeq  r12, [r3]
755         bx      lr
756 4:
757         mov     r0, r2
758 @       b       abort
759         bx      lr              @ TODO?
760
761
762 FUNCTION(jump_handle_swr):
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         and     r12,r3, #3
771         mov     r0, r2
772         cmp     r12,#2
773         strbgt  r1, [r3]        @ 3
774         strheq  r1, [r3]        @ 2
775         cmp     r12,#1
776         strlt   r1, [r3]        @ 0
777         bxne    lr
778         lsr     r2, r1, #8      @ 1
779         strb    r1, [r3]
780         strh    r2, [r3, #1]
781         bx      lr
782 4:
783         mov     r0, r2
784 @       b       abort
785         bx      lr              @ TODO?
786
787
788 .macro rcntx_read_mode0 num
789         /* r0 = address, r2 = cycles */
790         ldr     r3, [fp, #LO_rcnts+6*4+7*4*\num] @ cycleStart
791         mov     r0, r2, lsl #16
792         sub     r0, r0, r3, lsl #16
793         lsr     r0, #16
794         bx      lr
795 .endm
796
797 FUNCTION(rcnt0_read_count_m0):
798         rcntx_read_mode0 0
799
800 FUNCTION(rcnt1_read_count_m0):
801         rcntx_read_mode0 1
802
803 FUNCTION(rcnt2_read_count_m0):
804         rcntx_read_mode0 2
805
806 FUNCTION(rcnt0_read_count_m1):
807         /* r0 = address, r2 = cycles */
808         ldr     r3, [fp, #LO_rcnts+6*4+7*4*0] @ cycleStart
809         mov_16  r1, 0x3334
810         sub     r2, r2, r3
811         mul     r0, r1, r2              @ /= 5
812         lsr     r0, #16
813         bx      lr
814
815 FUNCTION(rcnt1_read_count_m1):
816         /* r0 = address, r2 = cycles */
817         ldr     r3, [fp, #LO_rcnts+6*4+7*4*1]
818         mov_24  r1, 0x1e6cde
819         sub     r2, r2, r3
820         umull   r3, r0, r1, r2          @ ~ /= hsync_cycles, max ~0x1e6cdd
821         bx      lr
822
823 FUNCTION(rcnt2_read_count_m1):
824         /* r0 = address, r2 = cycles */
825         ldr     r3, [fp, #LO_rcnts+6*4+7*4*2]
826         mov     r0, r2, lsl #16-3
827         sub     r0, r0, r3, lsl #16-3
828         lsr     r0, #16                 @ /= 8
829         bx      lr
830
831 FUNCTION(call_gteStall):
832         /* r0 = op_cycles, r1 = cycles */
833         ldr     r2, [fp, #LO_last_count]
834         str     lr, [fp, #LO_saved_lr]
835         add     r1, r1, r2
836         str     r1, [fp, #LO_cycle]
837         add     r1, fp, #LO_psxRegs
838         bl      gteCheckStallRaw
839         ldr     lr, [fp, #LO_saved_lr]
840         add     r10, r10, r0
841         bx      lr
842
843 #ifdef HAVE_ARMV6
844
845 FUNCTION(get_reg):
846         ldr     r12, [r0]
847         and     r1, r1, #0xff
848         ldr     r2, [r0, #4]
849         orr     r1, r1, r1, lsl #8
850         ldr     r3, [r0, #8]
851         orr     r1, r1, r1, lsl #16   @ searched char in every byte
852         ldrb    r0, [r0, #12]         @ last byte
853         eor     r12, r12, r1
854         eor     r2, r2, r1
855         eor     r3, r3, r1
856         cmp     r0, r1, lsr #24
857         mov     r0, #12
858         mvn     r1, #0                @ r1=~0
859         bxeq    lr
860         orr     r3, r3, #0xff000000   @ EXCLUDE_REG
861         uadd8   r0, r12, r1           @ add and set GE bits when not 0 (match)
862         mov     r12, #0
863         sel     r0, r12, r1           @ 0 if no match, else ff in some byte
864         uadd8   r2, r2, r1
865         sel     r2, r12, r1
866         uadd8   r3, r3, r1
867         sel     r3, r12, r1
868         mov     r12, #3
869         clz     r0, r0                @ 0, 8, 16, 24 or 32
870         clz     r2, r2
871         clz     r3, r3
872         sub     r0, r12, r0, lsr #3   @ 3, 2, 1, 0 or -1
873         sub     r2, r12, r2, lsr #3
874         sub     r3, r12, r3, lsr #3
875         orr     r2, r2, #4
876         orr     r3, r3, #8
877         and     r0, r0, r2
878         and     r0, r0, r3
879         bx      lr
880
881 #endif /* HAVE_ARMV6 */
882
883 @ vim:filetype=armasm