drc: do modification check in smaller than page granularity
[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 .if HAVE_ARMV7
25         .cpu cortex-a8
26         .fpu vfp
27 .else
28         .cpu arm9tdmi
29         .fpu softvfp
30 .endif 
31         .global rdram
32 rdram = 0x80000000
33         .global dynarec_local
34         .global reg
35         .global hi
36         .global lo
37         .global reg_cop0
38         .global reg_cop2d
39         .global reg_cop2c
40         .global FCR0
41         .global FCR31
42         .global next_interupt
43         .global cycle_count
44         .global last_count
45         .global pending_exception
46         .global pcaddr
47         .global stop
48         .global invc_ptr
49         .global address
50         .global readmem_dword
51         .global readmem_word
52         .global dword
53         .global word
54         .global hword
55         .global byte
56         .global branch_target
57         .global PC
58         .global mini_ht
59         .global restore_candidate
60         .global memory_map
61         /* psx */
62         .global psxRegs
63         .global nd_pcsx_io
64         .global psxH_ptr
65         .global inv_code_start
66         .global inv_code_end
67
68         .bss
69         .align  4
70         .type   dynarec_local, %object
71         .size   dynarec_local, dynarec_local_end-dynarec_local
72 dynarec_local:
73         .space  dynarec_local_end-dynarec_local /*0x400630*/
74 next_interupt = dynarec_local + 64
75         .type   next_interupt, %object
76         .size   next_interupt, 4
77 cycle_count = next_interupt + 4
78         .type   cycle_count, %object
79         .size   cycle_count, 4
80 last_count = cycle_count + 4
81         .type   last_count, %object
82         .size   last_count, 4
83 pending_exception = last_count + 4
84         .type   pending_exception, %object
85         .size   pending_exception, 4
86 stop = pending_exception + 4
87         .type   stop, %object
88         .size   stop, 4
89 invc_ptr = stop + 4
90         .type   invc_ptr, %object
91         .size   invc_ptr, 4
92 address = invc_ptr + 4
93         .type   address, %object
94         .size   address, 4
95 readmem_dword = address + 4
96 readmem_word = readmem_dword
97         .type   readmem_dword, %object
98         .size   readmem_dword, 8
99 dword = readmem_dword + 8
100         .type   dword, %object
101         .size   dword, 8
102 word = dword + 8
103         .type   word, %object
104         .size   word, 4
105 hword = word + 4
106         .type   hword, %object
107         .size   hword, 2
108 byte = hword + 2
109         .type   byte, %object
110         .size   byte, 1 /* 1 byte free */
111 FCR0 = hword + 4
112         .type   FCR0, %object
113         .size   FCR0, 4
114 FCR31 = FCR0 + 4
115         .type   FCR31, %object
116         .size   FCR31, 4
117 psxRegs = FCR31 + 4
118
119 /* psxRegs */
120         .type   psxRegs, %object
121         .size   psxRegs, psxRegs_end-psxRegs
122 reg = psxRegs
123         .type   reg, %object
124         .size   reg, 128
125 lo = reg + 128
126         .type   lo, %object
127         .size   lo, 4
128 hi = lo + 4
129         .type   hi, %object
130         .size   hi, 4
131 reg_cop0 = hi + 4
132         .type   reg_cop0, %object
133         .size   reg_cop0, 128
134 reg_cop2d = reg_cop0 + 128
135         .type   reg_cop2d, %object
136         .size   reg_cop2d, 128
137 reg_cop2c = reg_cop2d + 128
138         .type   reg_cop2c, %object
139         .size   reg_cop2c, 128
140 PC = reg_cop2c + 128
141 pcaddr = PC
142         .type   PC, %object
143         .size   PC, 4
144 code = PC + 4
145         .type   code, %object
146         .size   code, 4
147 cycle = code + 4
148         .type   cycle, %object
149         .size   cycle, 4
150 interrupt = cycle + 4
151         .type   interrupt, %object
152         .size   interrupt, 4
153 intCycle = interrupt + 4
154         .type   intCycle, %object
155         .size   intCycle, 256
156 psxRegs_end = intCycle + 256
157
158 /* nd_pcsx_io */
159 nd_pcsx_io = psxRegs_end
160         .type   nd_pcsx_io, %object
161         .size   nd_pcsx_io, nd_pcsx_io_end-nd_pcsx_io
162 tab_read8 = nd_pcsx_io
163         .type   tab_read8, %object
164         .size   tab_read8, 4
165 tab_read16 = tab_read8 + 4
166         .type   tab_read16, %object
167         .size   tab_read16, 4
168 tab_read32 = tab_read16 + 4
169         .type   tab_read32, %object
170         .size   tab_read32, 4
171 tab_write8 = tab_read32 + 4
172         .type   tab_write8, %object
173         .size   tab_write8, 4
174 tab_write16 = tab_write8 + 4
175         .type   tab_write16, %object
176         .size   tab_write16, 4
177 tab_write32 = tab_write16 + 4
178         .type   tab_write32, %object
179         .size   tab_write32, 4
180 spu_readf = tab_write32 + 4
181         .type   spu_readf, %object
182         .size   spu_readf, 4
183 spu_writef = spu_readf + 4
184         .type   spu_writef, %object
185         .size   spu_writef, 4
186 nd_pcsx_io_end = spu_writef + 4
187
188 psxH_ptr = nd_pcsx_io_end
189         .type   psxH_ptr, %object
190         .size   psxH_ptr, 4
191 inv_code_start = psxH_ptr + 4
192         .type   inv_code_start, %object
193         .size   inv_code_start, 4
194 inv_code_end = inv_code_start + 4
195         .type   inv_code_end, %object
196         .size   inv_code_end, 4
197 align0 = inv_code_end + 4 /* just for alignment */
198         .type   align0, %object
199         .size   align0, 12
200 branch_target = align0 + 12
201         .type   branch_target, %object
202         .size   branch_target, 4
203 mini_ht = branch_target + 4
204         .type   mini_ht, %object
205         .size   mini_ht, 256
206 restore_candidate = mini_ht + 256
207         .type   restore_candidate, %object
208         .size   restore_candidate, 512
209 memory_map = restore_candidate + 512
210         .type   memory_map, %object
211         .size   memory_map, 4194304
212 dynarec_local_end = memory_map + 4194304
213
214 .macro load_var_adr reg var
215 .if HAVE_ARMV7
216         movw    \reg, #:lower16:\var
217         movt    \reg, #:upper16:\var
218 .else
219         ldr     \reg, =\var
220 .endif
221 .endm
222
223 .macro dyna_linker_main
224         /* r0 = virtual target address */
225         /* r1 = instruction to patch */
226         ldr     r3, .jiptr
227         /* get_page */
228         lsr     r2, r0, #12
229         mov     r6, #4096
230         bic     r2, r2, #0xe0000
231         sub     r6, r6, #1
232         cmp     r2, #0x1000
233         ldr     r7, [r1]
234         biclt   r2, #0x0e00
235         and     r6, r6, r2
236         cmp     r2, #2048
237         add     r12, r7, #2
238         orrcs   r2, r6, #2048
239         ldr     r5, [r3, r2, lsl #2]
240         lsl     r12, r12, #8
241         add     r6, r1, r12, asr #6
242         mov     r8, #0
243         /* jump_in lookup */
244 1:
245         movs    r4, r5
246         beq     2f
247         ldr     r3, [r5]
248         ldr     r5, [r4, #12]
249         teq     r3, r0
250         bne     1b
251         ldr     r3, [r4, #4]
252         ldr     r4, [r4, #8]
253         tst     r3, r3
254         bne     1b
255         teq     r4, r6
256         moveq   pc, r4 /* Stale i-cache */
257         mov     r8, r4
258         b       1b     /* jump_in may have dupes, continue search */
259 2:
260         tst     r8, r8
261         beq     3f     /* r0 not in jump_in */
262
263         mov     r5, r1
264         mov     r1, r6
265         bl      add_link
266         sub     r2, r8, r5
267         and     r1, r7, #0xff000000
268         lsl     r2, r2, #6
269         sub     r1, r1, #2
270         add     r1, r1, r2, lsr #8
271         str     r1, [r5]
272         mov     pc, r8
273 3:
274         /* hash_table lookup */
275         cmp     r2, #2048
276         ldr     r3, .jdptr
277         eor     r4, r0, r0, lsl #16
278         lslcc   r2, r0, #9
279         ldr     r6, .htptr
280         lsr     r4, r4, #12
281         lsrcc   r2, r2, #21
282         bic     r4, r4, #15
283         ldr     r5, [r3, r2, lsl #2]
284         ldr     r7, [r6, r4]!
285         teq     r7, r0
286         ldreq   pc, [r6, #4]
287         ldr     r7, [r6, #8]
288         teq     r7, r0
289         ldreq   pc, [r6, #12]
290         /* jump_dirty lookup */
291 6:
292         movs    r4, r5
293         beq     8f
294         ldr     r3, [r5]
295         ldr     r5, [r4, #12]
296         teq     r3, r0
297         bne     6b
298 7:
299         ldr     r1, [r4, #8]
300         /* hash_table insert */
301         ldr     r2, [r6]
302         ldr     r3, [r6, #4]
303         str     r0, [r6]
304         str     r1, [r6, #4]
305         str     r2, [r6, #8]
306         str     r3, [r6, #12]
307         mov     pc, r1
308 8:
309 .endm
310
311         .text
312         .align  2
313         .global dyna_linker
314         .type   dyna_linker, %function
315 dyna_linker:
316         /* r0 = virtual target address */
317         /* r1 = instruction to patch */
318         dyna_linker_main
319
320         mov     r4, r0
321         mov     r5, r1
322         bl      new_recompile_block
323         tst     r0, r0
324         mov     r0, r4
325         mov     r1, r5
326         beq     dyna_linker
327         /* pagefault */
328         mov     r1, r0
329         mov     r2, #8
330         .size   dyna_linker, .-dyna_linker
331         .global exec_pagefault
332         .type   exec_pagefault, %function
333 exec_pagefault:
334         /* r0 = instruction pointer */
335         /* r1 = fault address */
336         /* r2 = cause */
337         ldr     r3, [fp, #reg_cop0+48-dynarec_local] /* Status */
338         mvn     r6, #0xF000000F
339         ldr     r4, [fp, #reg_cop0+16-dynarec_local] /* Context */
340         bic     r6, r6, #0x0F800000
341         str     r0, [fp, #reg_cop0+56-dynarec_local] /* EPC */
342         orr     r3, r3, #2
343         str     r1, [fp, #reg_cop0+32-dynarec_local] /* BadVAddr */
344         bic     r4, r4, r6
345         str     r3, [fp, #reg_cop0+48-dynarec_local] /* Status */
346         and     r5, r6, r1, lsr #9
347         str     r2, [fp, #reg_cop0+52-dynarec_local] /* Cause */
348         and     r1, r1, r6, lsl #9
349         str     r1, [fp, #reg_cop0+40-dynarec_local] /* EntryHi */
350         orr     r4, r4, r5
351         str     r4, [fp, #reg_cop0+16-dynarec_local] /* Context */
352         mov     r0, #0x80000000
353         bl      get_addr_ht
354         mov     pc, r0
355         .size   exec_pagefault, .-exec_pagefault
356
357 /* Special dynamic linker for the case where a page fault
358    may occur in a branch delay slot */
359         .global dyna_linker_ds
360         .type   dyna_linker_ds, %function
361 dyna_linker_ds:
362         /* r0 = virtual target address */
363         /* r1 = instruction to patch */
364         dyna_linker_main
365
366         mov     r4, r0
367         bic     r0, r0, #7
368         mov     r5, r1
369         orr     r0, r0, #1
370         bl      new_recompile_block
371         tst     r0, r0
372         mov     r0, r4
373         mov     r1, r5
374         beq     dyna_linker_ds
375         /* pagefault */
376         bic     r1, r0, #7
377         mov     r2, #0x80000008 /* High bit set indicates pagefault in delay slot */
378         sub     r0, r1, #4
379         b       exec_pagefault
380         .size   dyna_linker_ds, .-dyna_linker_ds
381 .jiptr:
382         .word   jump_in
383 .jdptr:
384         .word   jump_dirty
385 .htptr:
386         .word   hash_table
387
388         .align  2
389         .global jump_vaddr_r0
390         .type   jump_vaddr_r0, %function
391 jump_vaddr_r0:
392         eor     r2, r0, r0, lsl #16
393         b       jump_vaddr
394         .size   jump_vaddr_r0, .-jump_vaddr_r0
395         .global jump_vaddr_r1
396         .type   jump_vaddr_r1, %function
397 jump_vaddr_r1:
398         eor     r2, r1, r1, lsl #16
399         mov     r0, r1
400         b       jump_vaddr
401         .size   jump_vaddr_r1, .-jump_vaddr_r1
402         .global jump_vaddr_r2
403         .type   jump_vaddr_r2, %function
404 jump_vaddr_r2:
405         mov     r0, r2
406         eor     r2, r2, r2, lsl #16
407         b       jump_vaddr
408         .size   jump_vaddr_r2, .-jump_vaddr_r2
409         .global jump_vaddr_r3
410         .type   jump_vaddr_r3, %function
411 jump_vaddr_r3:
412         eor     r2, r3, r3, lsl #16
413         mov     r0, r3
414         b       jump_vaddr
415         .size   jump_vaddr_r3, .-jump_vaddr_r3
416         .global jump_vaddr_r4
417         .type   jump_vaddr_r4, %function
418 jump_vaddr_r4:
419         eor     r2, r4, r4, lsl #16
420         mov     r0, r4
421         b       jump_vaddr
422         .size   jump_vaddr_r4, .-jump_vaddr_r4
423         .global jump_vaddr_r5
424         .type   jump_vaddr_r5, %function
425 jump_vaddr_r5:
426         eor     r2, r5, r5, lsl #16
427         mov     r0, r5
428         b       jump_vaddr
429         .size   jump_vaddr_r5, .-jump_vaddr_r5
430         .global jump_vaddr_r6
431         .type   jump_vaddr_r6, %function
432 jump_vaddr_r6:
433         eor     r2, r6, r6, lsl #16
434         mov     r0, r6
435         b       jump_vaddr
436         .size   jump_vaddr_r6, .-jump_vaddr_r6
437         .global jump_vaddr_r8
438         .type   jump_vaddr_r8, %function
439 jump_vaddr_r8:
440         eor     r2, r8, r8, lsl #16
441         mov     r0, r8
442         b       jump_vaddr
443         .size   jump_vaddr_r8, .-jump_vaddr_r8
444         .global jump_vaddr_r9
445         .type   jump_vaddr_r9, %function
446 jump_vaddr_r9:
447         eor     r2, r9, r9, lsl #16
448         mov     r0, r9
449         b       jump_vaddr
450         .size   jump_vaddr_r9, .-jump_vaddr_r9
451         .global jump_vaddr_r10
452         .type   jump_vaddr_r10, %function
453 jump_vaddr_r10:
454         eor     r2, r10, r10, lsl #16
455         mov     r0, r10
456         b       jump_vaddr
457         .size   jump_vaddr_r10, .-jump_vaddr_r10
458         .global jump_vaddr_r12
459         .type   jump_vaddr_r12, %function
460 jump_vaddr_r12:
461         eor     r2, r12, r12, lsl #16
462         mov     r0, r12
463         b       jump_vaddr
464         .size   jump_vaddr_r12, .-jump_vaddr_r12
465         .global jump_vaddr_r7
466         .type   jump_vaddr_r7, %function
467 jump_vaddr_r7:
468         eor     r2, r7, r7, lsl #16
469         add     r0, r7, #0
470         .size   jump_vaddr_r7, .-jump_vaddr_r7
471         .global jump_vaddr
472         .type   jump_vaddr, %function
473 jump_vaddr:
474         ldr     r1, .htptr
475         mvn     r3, #15
476         and     r2, r3, r2, lsr #12
477         ldr     r2, [r1, r2]!
478         teq     r2, r0
479         ldreq   pc, [r1, #4]
480         ldr     r2, [r1, #8]
481         teq     r2, r0
482         ldreq   pc, [r1, #12]
483         str     r10, [fp, #cycle_count-dynarec_local]
484         bl      get_addr
485         ldr     r10, [fp, #cycle_count-dynarec_local]
486         mov     pc, r0
487         .size   jump_vaddr, .-jump_vaddr
488
489         .align  2
490         .global verify_code_ds
491         .type   verify_code_ds, %function
492 verify_code_ds:
493         str     r8, [fp, #branch_target-dynarec_local]
494         .size   verify_code_ds, .-verify_code_ds
495         .global verify_code_vm
496         .type   verify_code_vm, %function
497 verify_code_vm:
498         .global verify_code
499         .type   verify_code, %function
500 verify_code:
501         /* r1 = source */
502         /* r2 = target */
503         /* r3 = length */
504         tst     r3, #4
505         mov     r4, #0
506         add     r3, r1, r3
507         mov     r5, #0
508         ldrne   r4, [r1], #4
509         mov     r12, #0
510         ldrne   r5, [r2], #4
511         teq     r1, r3
512         beq     .D3
513 .D2:
514         ldr     r7, [r1], #4
515         eor     r9, r4, r5
516         ldr     r8, [r2], #4
517         orrs    r9, r9, r12
518         bne     .D4
519         ldr     r4, [r1], #4
520         eor     r12, r7, r8
521         ldr     r5, [r2], #4
522         cmp     r1, r3
523         bcc     .D2
524         teq     r7, r8
525 .D3:
526         teqeq   r4, r5
527 .D4:
528         ldr     r8, [fp, #branch_target-dynarec_local]
529         moveq   pc, lr
530 .D5:
531         bl      get_addr
532         mov     pc, r0
533         .size   verify_code, .-verify_code
534         .size   verify_code_vm, .-verify_code_vm
535
536         .align  2
537         .global cc_interrupt
538         .type   cc_interrupt, %function
539 cc_interrupt:
540         ldr     r0, [fp, #last_count-dynarec_local]
541         mov     r1, #0
542         mov     r2, #0x1fc
543         add     r10, r0, r10
544         str     r1, [fp, #pending_exception-dynarec_local]
545         and     r2, r2, r10, lsr #17
546         add     r3, fp, #restore_candidate-dynarec_local
547         str     r10, [fp, #cycle-dynarec_local] /* PCSX cycles */
548 @@      str     r10, [fp, #reg_cop0+36-dynarec_local] /* Count */
549         ldr     r4, [r2, r3]
550         mov     r10, lr
551         tst     r4, r4
552         bne     .E4
553 .E1:
554         bl      gen_interupt
555         mov     lr, r10
556         ldr     r10, [fp, #cycle-dynarec_local]
557         ldr     r0, [fp, #next_interupt-dynarec_local]
558         ldr     r1, [fp, #pending_exception-dynarec_local]
559         ldr     r2, [fp, #stop-dynarec_local]
560         str     r0, [fp, #last_count-dynarec_local]
561         sub     r10, r10, r0
562         tst     r2, r2
563         ldmnefd sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, pc}
564         tst     r1, r1
565         moveq   pc, lr
566 .E2:
567         ldr     r0, [fp, #pcaddr-dynarec_local]
568         bl      get_addr_ht
569         mov     pc, r0
570 .E4:
571         /* Move 'dirty' blocks to the 'clean' list */
572         lsl     r5, r2, #3
573         str     r1, [r2, r3]
574 .E5:
575         lsrs    r4, r4, #1
576         mov     r0, r5
577         add     r5, r5, #1
578         blcs    clean_blocks
579         tst     r5, #31
580         bne     .E5
581         b       .E1
582         .size   cc_interrupt, .-cc_interrupt
583
584         .align  2
585         .global do_interrupt
586         .type   do_interrupt, %function
587 do_interrupt:
588         ldr     r0, [fp, #pcaddr-dynarec_local]
589         bl      get_addr_ht
590         add     r10, r10, #2
591         mov     pc, r0
592         .size   do_interrupt, .-do_interrupt
593
594         .align  2
595         .global fp_exception
596         .type   fp_exception, %function
597 fp_exception:
598         mov     r2, #0x10000000
599 .E7:
600         ldr     r1, [fp, #reg_cop0+48-dynarec_local] /* Status */
601         mov     r3, #0x80000000
602         str     r0, [fp, #reg_cop0+56-dynarec_local] /* EPC */
603         orr     r1, #2
604         add     r2, r2, #0x2c
605         str     r1, [fp, #reg_cop0+48-dynarec_local] /* Status */
606         str     r2, [fp, #reg_cop0+52-dynarec_local] /* Cause */
607         add     r0, r3, #0x80
608         bl      get_addr_ht
609         mov     pc, r0
610         .size   fp_exception, .-fp_exception
611         .align  2
612         .global fp_exception_ds
613         .type   fp_exception_ds, %function
614 fp_exception_ds:
615         mov     r2, #0x90000000 /* Set high bit if delay slot */
616         b       .E7
617         .size   fp_exception_ds, .-fp_exception_ds
618
619         .align  2
620         .global jump_syscall
621         .type   jump_syscall, %function
622 jump_syscall:
623         ldr     r1, [fp, #reg_cop0+48-dynarec_local] /* Status */
624         mov     r3, #0x80000000
625         str     r0, [fp, #reg_cop0+56-dynarec_local] /* EPC */
626         orr     r1, #2
627         mov     r2, #0x20
628         str     r1, [fp, #reg_cop0+48-dynarec_local] /* Status */
629         str     r2, [fp, #reg_cop0+52-dynarec_local] /* Cause */
630         add     r0, r3, #0x80
631         bl      get_addr_ht
632         mov     pc, r0
633         .size   jump_syscall, .-jump_syscall
634         .align  2
635
636         .align  2
637         .global jump_syscall_hle
638         .type   jump_syscall_hle, %function
639 jump_syscall_hle:
640         str     r0, [fp, #pcaddr-dynarec_local] /* PC must be set to EPC for psxException */
641         ldr     r2, [fp, #last_count-dynarec_local]
642         mov     r1, #0    /* in delay slot */
643         add     r2, r2, r10
644         mov     r0, #0x20 /* cause */
645         str     r2, [fp, #cycle-dynarec_local] /* PCSX cycle counter */
646         bl      psxException
647
648         /* note: psxException might do recorsive recompiler call from it's HLE code,
649          * so be ready for this */
650 pcsx_return:
651         ldr     r1, [fp, #next_interupt-dynarec_local]
652         ldr     r10, [fp, #cycle-dynarec_local]
653         ldr     r0, [fp, #pcaddr-dynarec_local]
654         sub     r10, r10, r1
655         str     r1, [fp, #last_count-dynarec_local]
656         bl      get_addr_ht
657         mov     pc, r0
658         .size   jump_syscall_hle, .-jump_syscall_hle
659
660         .align  2
661         .global jump_hlecall
662         .type   jump_hlecall, %function
663 jump_hlecall:
664         ldr     r2, [fp, #last_count-dynarec_local]
665         str     r0, [fp, #pcaddr-dynarec_local]
666         add     r2, r2, r10
667         adr     lr, pcsx_return
668         str     r2, [fp, #cycle-dynarec_local] /* PCSX cycle counter */
669         bx      r1
670         .size   jump_hlecall, .-jump_hlecall
671
672         .align  2
673         .global jump_intcall
674         .type   jump_intcall, %function
675 jump_intcall:
676         ldr     r2, [fp, #last_count-dynarec_local]
677         str     r0, [fp, #pcaddr-dynarec_local]
678         add     r2, r2, r10
679         adr     lr, pcsx_return
680         str     r2, [fp, #cycle-dynarec_local] /* PCSX cycle counter */
681         b       execI
682         .size   jump_hlecall, .-jump_hlecall
683
684 new_dyna_leave:
685         .align  2
686         .global new_dyna_leave
687         .type   new_dyna_leave, %function
688         ldr     r0, [fp, #last_count-dynarec_local]
689         add     r12, fp, #28
690         add     r10, r0, r10
691         str     r10, [fp, #cycle-dynarec_local]
692         ldmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, pc}
693         .size   new_dyna_leave, .-new_dyna_leave
694
695         /* these are used to call memhandlers */
696         .align  2
697         .global indirect_jump_indexed
698         .type   indirect_jump_indexed, %function
699 indirect_jump_indexed:
700         ldr     r0, [r0, r1, lsl #2]
701         .global indirect_jump
702         .type   indirect_jump, %function
703 indirect_jump:
704         ldr     r12, [fp, #last_count-dynarec_local]
705         add     r2, r2, r12 
706         str     r2, [fp, #cycle-dynarec_local]
707         mov     pc, r0
708         .size   indirect_jump, .-indirect_jump
709         .size   indirect_jump_indexed, .-indirect_jump_indexed
710
711         .align  2
712         .global invalidate_addr_r0
713         .type   invalidate_addr_r0, %function
714 invalidate_addr_r0:
715         stmia   fp, {r0, r1, r2, r3, r12, lr}
716         b       invalidate_addr_call
717         .size   invalidate_addr_r0, .-invalidate_addr_r0
718         .align  2
719         .global invalidate_addr_r1
720         .type   invalidate_addr_r1, %function
721 invalidate_addr_r1:
722         stmia   fp, {r0, r1, r2, r3, r12, lr}
723         mov     r0, r1
724         b       invalidate_addr_call
725         .size   invalidate_addr_r1, .-invalidate_addr_r1
726         .align  2
727         .global invalidate_addr_r2
728         .type   invalidate_addr_r2, %function
729 invalidate_addr_r2:
730         stmia   fp, {r0, r1, r2, r3, r12, lr}
731         mov     r0, r2
732         b       invalidate_addr_call
733         .size   invalidate_addr_r2, .-invalidate_addr_r2
734         .align  2
735         .global invalidate_addr_r3
736         .type   invalidate_addr_r3, %function
737 invalidate_addr_r3:
738         stmia   fp, {r0, r1, r2, r3, r12, lr}
739         mov     r0, r3
740         b       invalidate_addr_call
741         .size   invalidate_addr_r3, .-invalidate_addr_r3
742         .align  2
743         .global invalidate_addr_r4
744         .type   invalidate_addr_r4, %function
745 invalidate_addr_r4:
746         stmia   fp, {r0, r1, r2, r3, r12, lr}
747         mov     r0, r4
748         b       invalidate_addr_call
749         .size   invalidate_addr_r4, .-invalidate_addr_r4
750         .align  2
751         .global invalidate_addr_r5
752         .type   invalidate_addr_r5, %function
753 invalidate_addr_r5:
754         stmia   fp, {r0, r1, r2, r3, r12, lr}
755         mov     r0, r5
756         b       invalidate_addr_call
757         .size   invalidate_addr_r5, .-invalidate_addr_r5
758         .align  2
759         .global invalidate_addr_r6
760         .type   invalidate_addr_r6, %function
761 invalidate_addr_r6:
762         stmia   fp, {r0, r1, r2, r3, r12, lr}
763         mov     r0, r6
764         b       invalidate_addr_call
765         .size   invalidate_addr_r6, .-invalidate_addr_r6
766         .align  2
767         .global invalidate_addr_r7
768         .type   invalidate_addr_r7, %function
769 invalidate_addr_r7:
770         stmia   fp, {r0, r1, r2, r3, r12, lr}
771         mov     r0, r7
772         b       invalidate_addr_call
773         .size   invalidate_addr_r7, .-invalidate_addr_r7
774         .align  2
775         .global invalidate_addr_r8
776         .type   invalidate_addr_r8, %function
777 invalidate_addr_r8:
778         stmia   fp, {r0, r1, r2, r3, r12, lr}
779         mov     r0, r8
780         b       invalidate_addr_call
781         .size   invalidate_addr_r8, .-invalidate_addr_r8
782         .align  2
783         .global invalidate_addr_r9
784         .type   invalidate_addr_r9, %function
785 invalidate_addr_r9:
786         stmia   fp, {r0, r1, r2, r3, r12, lr}
787         mov     r0, r9
788         b       invalidate_addr_call
789         .size   invalidate_addr_r9, .-invalidate_addr_r9
790         .align  2
791         .global invalidate_addr_r10
792         .type   invalidate_addr_r10, %function
793 invalidate_addr_r10:
794         stmia   fp, {r0, r1, r2, r3, r12, lr}
795         mov     r0, r10
796         b       invalidate_addr_call
797         .size   invalidate_addr_r10, .-invalidate_addr_r10
798         .align  2
799         .global invalidate_addr_r12
800         .type   invalidate_addr_r12, %function
801 invalidate_addr_r12:
802         stmia   fp, {r0, r1, r2, r3, r12, lr}
803         mov     r0, r12
804         .size   invalidate_addr_r12, .-invalidate_addr_r12
805         .align  2
806         .global invalidate_addr_call
807         .type   invalidate_addr_call, %function
808 invalidate_addr_call:
809         ldr     r12, [fp, #inv_code_start-dynarec_local]
810         ldr     lr, [fp, #inv_code_end-dynarec_local]
811         cmp     r0, r12
812         cmpcs   lr, r0
813         blcc    invalidate_addr
814         ldmia   fp, {r0, r1, r2, r3, r12, pc}
815         .size   invalidate_addr_call, .-invalidate_addr_call
816
817         .align  2
818         .global new_dyna_start
819         .type   new_dyna_start, %function
820 new_dyna_start:
821         /* ip is stored to conform EABI alignment */
822         stmfd   sp!, {r4, r5, r6, r7, r8, r9, sl, fp, ip, lr}
823         load_var_adr fp, dynarec_local
824         ldr     r0, [fp, #pcaddr-dynarec_local]
825         bl      get_addr_ht
826         ldr     r1, [fp, #next_interupt-dynarec_local]
827         ldr     r10, [fp, #cycle-dynarec_local]
828         str     r1, [fp, #last_count-dynarec_local]
829         sub     r10, r10, r1
830         mov     pc, r0
831         .size   new_dyna_start, .-new_dyna_start
832
833 /* --------------------------------------- */
834
835 .align  2
836 .global ari_read_ram8
837 .global ari_read_ram16
838 .global ari_read_ram32
839 .global ari_read_ram_mirror8
840 .global ari_read_ram_mirror16
841 .global ari_read_ram_mirror32
842 .global ari_write_ram8
843 .global ari_write_ram16
844 .global ari_write_ram32
845 .global ari_write_ram_mirror8
846 .global ari_write_ram_mirror16
847 .global ari_write_ram_mirror32
848 .global ari_write_ram_mirror_ro32
849 .global ari_read_bios8
850 .global ari_read_bios16
851 .global ari_read_bios32
852 .global ari_read_io8
853 .global ari_read_io16
854 .global ari_read_io32
855 .global ari_write_io8
856 .global ari_write_io16
857 .global ari_write_io32
858
859 .macro ari_read_ram bic_const op
860         ldr     r0, [fp, #address-dynarec_local]
861 .if \bic_const
862         bic     r0, r0, #\bic_const
863 .endif
864         \op     r0, [r0]
865         str     r0, [fp, #readmem_dword-dynarec_local]
866         mov     pc, lr
867 .endm
868
869 ari_read_ram8:
870         ari_read_ram 0, ldrb
871
872 ari_read_ram16:
873         ari_read_ram 1, ldrh
874
875 ari_read_ram32:
876         ari_read_ram 3, ldr
877
878 .macro ari_read_ram_mirror mvn_const, op
879         ldr     r0, [fp, #address-dynarec_local]
880         mvn     r1, #\mvn_const
881         and     r0, r1, lsr #11
882         orr     r0, r0, #1<<31
883         \op     r0, [r0]
884         str     r0, [fp, #readmem_dword-dynarec_local]
885         mov     pc, lr
886 .endm
887
888 ari_read_ram_mirror8:
889         ari_read_ram_mirror 0, ldrb
890
891 ari_read_ram_mirror16:
892         ari_read_ram_mirror (1<<11), ldrh
893
894 ari_read_ram_mirror32:
895         ari_read_ram_mirror (3<<11), ldr
896
897 /* invalidation is already taken care of by the caller */
898 .macro ari_write_ram bic_const var pf
899         ldr     r0, [fp, #address-dynarec_local]
900         ldr\pf  r1, [fp, #\var-dynarec_local]
901 .if \bic_const
902         bic     r0, r0, #\bic_const
903 .endif
904         str\pf  r1, [r0]
905         mov     pc, lr
906 .endm
907
908 ari_write_ram8:
909         ari_write_ram 0, byte, b
910
911 ari_write_ram16:
912         ari_write_ram 1, hword, h
913
914 ari_write_ram32:
915         ari_write_ram 3, word,
916
917 .macro ari_write_ram_mirror mvn_const var pf
918         ldr     r0, [fp, #address-dynarec_local]
919         mvn     r3, #\mvn_const
920         ldr\pf  r1, [fp, #\var-dynarec_local]
921         and     r0, r3, lsr #11
922         ldr     r2, [fp, #invc_ptr-dynarec_local]
923         orr     r0, r0, #1<<31
924         ldrb    r2, [r2, r0, lsr #12]
925         str\pf  r1, [r0]
926         tst     r2, r2
927         movne   pc, lr
928         ldr     r1, [fp, #inv_code_start-dynarec_local]
929         ldr     r2, [fp, #inv_code_end-dynarec_local]
930         cmp     r0, r1
931         cmpcs   r2, r0
932         movcs   pc, lr
933         nop
934         b       invalidate_addr
935 .endm
936
937 ari_write_ram_mirror8:
938         ari_write_ram_mirror 0, byte, b
939
940 ari_write_ram_mirror16:
941         ari_write_ram_mirror (1<<11), hword, h
942
943 ari_write_ram_mirror32:
944         ari_write_ram_mirror (3<<11), word,
945
946 ari_write_ram_mirror_ro32:
947         load_var_adr r0, pcsx_ram_is_ro
948         ldr     r0, [r0]
949         tst     r0, r0
950         movne   pc, lr
951         nop
952         b       ari_write_ram_mirror32
953
954
955 .macro ari_read_bios_mirror bic_const op
956         ldr     r0, [fp, #address-dynarec_local]
957         orr     r0, r0, #0x80000000
958         bic     r0, r0, #(0x20000000|\bic_const)        @ map to 0x9fc...
959         \op     r0, [r0]
960         str     r0, [fp, #readmem_dword-dynarec_local]
961         mov     pc, lr
962 .endm
963
964 ari_read_bios8:
965         ari_read_bios_mirror 0, ldrb
966
967 ari_read_bios16:
968         ari_read_bios_mirror 1, ldrh
969
970 ari_read_bios32:
971         ari_read_bios_mirror 3, ldr
972
973
974 @ for testing
975 .macro ari_read_io_old tab_shift
976         str     lr, [sp, #-8]! @ EABI alignment..
977 .if \tab_shift == 0
978         bl      psxHwRead32
979 .endif
980 .if \tab_shift == 1
981         bl      psxHwRead16
982 .endif
983 .if \tab_shift == 2
984         bl      psxHwRead8
985 .endif
986         str     r0, [fp, #readmem_dword-dynarec_local]
987         ldr     pc, [sp], #8
988 .endm
989
990 .macro ari_read_io readop mem_tab tab_shift
991         ldr     r0, [fp, #address-dynarec_local]
992         ldr     r1, [fp, #psxH_ptr-dynarec_local]
993 .if \tab_shift == 0
994         bic     r0, r0, #3
995 .endif
996 .if \tab_shift == 1
997         bic     r0, r0, #1
998 .endif
999         bic     r2, r0, #0x1f800000
1000         ldr     r12,[fp, #\mem_tab-dynarec_local]
1001         subs    r3, r2, #0x1000
1002         blo     2f
1003 @       ari_read_io_old \tab_shift
1004         cmp     r3, #0x880
1005         bhs     1f
1006         ldr     r12,[r12, r3, lsl #\tab_shift]
1007         tst     r12,r12
1008         beq     2f
1009 0:
1010         str     lr, [sp, #-8]! @ EABI alignment..
1011         blx     r12
1012         str     r0, [fp, #readmem_dword-dynarec_local]
1013         ldr     pc, [sp], #8
1014
1015 1:
1016 .if \tab_shift == 1 @ read16
1017         cmp     r2, #0x1c00
1018         blo     2f
1019         cmp     r2, #0x1e00
1020         bhs     2f
1021         ldr     r12,[fp, #spu_readf-dynarec_local]
1022         b       0b
1023 .endif
1024 2:
1025         @ no handler, just read psxH
1026         \readop r0, [r1, r2]
1027         str     r0, [fp, #readmem_dword-dynarec_local]
1028         mov     pc, lr
1029 .endm
1030
1031 ari_read_io8:
1032         ari_read_io ldrb, tab_read8, 2
1033
1034 ari_read_io16:
1035         ari_read_io ldrh, tab_read16, 1
1036
1037 ari_read_io32:
1038         ari_read_io ldr, tab_read32, 0
1039
1040 .macro ari_write_io_old tab_shift
1041 .if \tab_shift == 0
1042         b       psxHwWrite32
1043 .endif
1044 .if \tab_shift == 1
1045         b       psxHwWrite16
1046 .endif
1047 .if \tab_shift == 2
1048         b       psxHwWrite8
1049 .endif
1050 .endm
1051
1052 .macro ari_write_io pf var mem_tab tab_shift
1053         ldr     r0, [fp, #address-dynarec_local]
1054         ldr\pf  r1, [fp, #\var-dynarec_local]
1055 .if \tab_shift == 0
1056         bic     r0, r0, #3
1057 .endif
1058 .if \tab_shift == 1
1059         bic     r0, r0, #1
1060 .endif
1061         bic     r2, r0, #0x1f800000
1062         ldr     r12,[fp, #\mem_tab-dynarec_local]
1063         subs    r3, r2, #0x1000
1064         blo     0f
1065 @       ari_write_io_old \tab_shift
1066         cmp     r3, #0x880
1067         bhs     1f
1068         ldr     r12,[r12, r3, lsl #\tab_shift]
1069         mov     r0, r1
1070         tst     r12,r12
1071         bxne    r12
1072 0:
1073         ldr     r3, [fp, #psxH_ptr-dynarec_local]
1074         str\pf  r1, [r2, r3]
1075         mov     pc, lr
1076 1:
1077         cmp     r2, #0x1c00
1078         blo     0b
1079         cmp     r2, #0x1e00
1080 .if \tab_shift != 0
1081         ldrlo   pc, [fp, #spu_writef-dynarec_local]
1082 .else
1083         @ write32 to SPU - very rare case (is this correct?)
1084         bhs     0b
1085         add     r2, r0, #2
1086         mov     r3, r1, lsr #16
1087         push    {r2,r3,lr}
1088         mov     lr, pc
1089         ldr     pc, [fp, #spu_writef-dynarec_local]
1090         pop     {r0,r1,lr}
1091         ldr     pc, [fp, #spu_writef-dynarec_local]
1092 .endif
1093         nop
1094         b       0b
1095 .endm
1096
1097 ari_write_io8:
1098         @ PCSX always writes to psxH, so do we for consistency
1099         ldr     r0, [fp, #address-dynarec_local]
1100         ldr     r3, [fp, #psxH_ptr-dynarec_local]
1101         ldrb    r1, [fp, #byte-dynarec_local]
1102         bic     r2, r0, #0x1f800000
1103         ldr     r12,[fp, #tab_write8-dynarec_local]
1104         strb    r1, [r2, r3]
1105         subs    r3, r2, #0x1000
1106         movlo   pc, lr
1107 @       ari_write_io_old 2
1108         cmp     r3, #0x880
1109         movhs   pc, lr
1110         ldr     r12,[r12, r3, lsl #2]
1111         mov     r0, r1
1112         tst     r12,r12
1113         bxne    r12
1114         mov     pc, lr
1115
1116 ari_write_io16:
1117         ari_write_io h, hword, tab_write16, 1
1118
1119 ari_write_io32:
1120         ari_write_io , word, tab_write32, 0
1121
1122 @ vim:filetype=armasm