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