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