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