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