1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus - linkage_arm.s *
3 * Copyright (C) 2009-2010 Ari64 *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
43 .global pending_exception
57 .global restore_candidate
64 .type dynarec_local, %object
65 .size dynarec_local, dynarec_local_end-dynarec_local
67 .space dynarec_local_end-dynarec_local /*0x400630*/
68 next_interupt = dynarec_local + 64
69 .type next_interupt, %object
70 .size next_interupt, 4
71 cycle_count = next_interupt + 4
72 .type cycle_count, %object
74 last_count = cycle_count + 4
75 .type last_count, %object
77 pending_exception = last_count + 4
78 .type pending_exception, %object
79 .size pending_exception, 4
80 pcaddr = pending_exception + 4
87 .type invc_ptr, %object
89 address = invc_ptr + 4
90 .type address, %object
92 readmem_dword = address + 4
93 readmem_word = readmem_dword
94 .type readmem_dword, %object
95 .size readmem_dword, 8
96 dword = readmem_dword + 8
107 .size byte, 1 /* 1 byte free */
120 .size psxRegs, psxRegs_end-psxRegs
128 .type reg_cop0, %object
130 reg_cop2d = reg_cop0 + 128
131 .type reg_cop2d, %object
133 reg_cop2c = reg_cop2d + 128
134 .type reg_cop2c, %object
145 interrupt = cycle + 4
146 .type interrupt, %object
148 intCycle = interrupt + 4
149 .type intCycle, %object
151 psxRegs_end = intCycle + 128
153 align0 = psxRegs_end /* just for alignment */
154 .type align0, %object
156 branch_target = align0 + 4
157 .type branch_target, %object
158 .size branch_target, 4
159 mini_ht = branch_target + 4
160 .type mini_ht, %object
162 restore_candidate = mini_ht + 256
163 .type restore_candidate, %object
164 .size restore_candidate, 512
165 memory_map = restore_candidate + 512
166 .type memory_map, %object
167 .size memory_map, 4194304
168 dynarec_local_end = memory_map + 4194304
173 .type dyna_linker, %function
175 /* r0 = virtual target address */
176 /* r1 = instruction to patch */
183 eor r2, r2, r12, lsr #12
184 and r6, r6, r12, lsr #12
188 ldr r5, [r3, r2, lsl #2]
204 add r1, r1, r12, asr #6
206 moveq pc, r4 /* Stale i-cache */
209 and r1, r7, #0xff000000
212 add r1, r1, r2, lsr #8
216 /* hash_table lookup */
219 eor r4, r0, r0, lsl #16
225 ldr r5, [r3, r2, lsl #2]
232 /* jump_dirty lookup */
242 /* hash_table insert */
253 bl new_recompile_block
261 .size dyna_linker, .-dyna_linker
262 .global exec_pagefault
263 .type exec_pagefault, %function
265 /* r0 = instruction pointer */
266 /* r1 = fault address */
268 ldr r3, [fp, #reg_cop0+48-dynarec_local] /* Status */
270 ldr r4, [fp, #reg_cop0+16-dynarec_local] /* Context */
271 bic r6, r6, #0x0F800000
272 str r0, [fp, #reg_cop0+56-dynarec_local] /* EPC */
274 str r1, [fp, #reg_cop0+32-dynarec_local] /* BadVAddr */
276 str r3, [fp, #reg_cop0+48-dynarec_local] /* Status */
277 and r5, r6, r1, lsr #9
278 str r2, [fp, #reg_cop0+52-dynarec_local] /* Cause */
279 and r1, r1, r6, lsl #9
280 str r1, [fp, #reg_cop0+40-dynarec_local] /* EntryHi */
282 str r4, [fp, #reg_cop0+16-dynarec_local] /* Context */
286 .size exec_pagefault, .-exec_pagefault
287 /* Special dynamic linker for the case where a page fault
288 may occur in a branch delay slot */
289 .global dyna_linker_ds
290 .type dyna_linker_ds, %function
292 /* r0 = virtual target address */
293 /* r1 = instruction to patch */
300 eor r2, r2, r12, lsr #12
301 and r6, r6, r12, lsr #12
305 ldr r5, [r3, r2, lsl #2]
321 add r1, r1, r12, asr #6
323 moveq pc, r4 /* Stale i-cache */
326 and r1, r7, #0xff000000
329 add r1, r1, r2, lsr #8
333 /* hash_table lookup */
336 eor r4, r0, r0, lsl #16
342 ldr r5, [r3, r2, lsl #2]
349 /* jump_dirty lookup */
359 /* hash_table insert */
372 bl new_recompile_block
379 mov r2, #0x80000008 /* High bit set indicates pagefault in delay slot */
382 .size dyna_linker_ds, .-dyna_linker_ds
390 .global jump_vaddr_r0
391 .type jump_vaddr_r0, %function
393 eor r2, r0, r0, lsl #16
395 .size jump_vaddr_r0, .-jump_vaddr_r0
396 .global jump_vaddr_r1
397 .type jump_vaddr_r1, %function
399 eor r2, r1, r1, lsl #16
402 .size jump_vaddr_r1, .-jump_vaddr_r1
403 .global jump_vaddr_r2
404 .type jump_vaddr_r2, %function
407 eor r2, r2, r2, lsl #16
409 .size jump_vaddr_r2, .-jump_vaddr_r2
410 .global jump_vaddr_r3
411 .type jump_vaddr_r3, %function
413 eor r2, r3, r3, lsl #16
416 .size jump_vaddr_r3, .-jump_vaddr_r3
417 .global jump_vaddr_r4
418 .type jump_vaddr_r4, %function
420 eor r2, r4, r4, lsl #16
423 .size jump_vaddr_r4, .-jump_vaddr_r4
424 .global jump_vaddr_r5
425 .type jump_vaddr_r5, %function
427 eor r2, r5, r5, lsl #16
430 .size jump_vaddr_r5, .-jump_vaddr_r5
431 .global jump_vaddr_r6
432 .type jump_vaddr_r6, %function
434 eor r2, r6, r6, lsl #16
437 .size jump_vaddr_r6, .-jump_vaddr_r6
438 .global jump_vaddr_r8
439 .type jump_vaddr_r8, %function
441 eor r2, r8, r8, lsl #16
444 .size jump_vaddr_r8, .-jump_vaddr_r8
445 .global jump_vaddr_r9
446 .type jump_vaddr_r9, %function
448 eor r2, r9, r9, lsl #16
451 .size jump_vaddr_r9, .-jump_vaddr_r9
452 .global jump_vaddr_r10
453 .type jump_vaddr_r10, %function
455 eor r2, r10, r10, lsl #16
458 .size jump_vaddr_r10, .-jump_vaddr_r10
459 .global jump_vaddr_r12
460 .type jump_vaddr_r12, %function
462 eor r2, r12, r12, lsl #16
465 .size jump_vaddr_r12, .-jump_vaddr_r12
466 .global jump_vaddr_r7
467 .type jump_vaddr_r7, %function
469 eor r2, r7, r7, lsl #16
471 .size jump_vaddr_r7, .-jump_vaddr_r7
473 .type jump_vaddr, %function
477 and r2, r3, r2, lsr #12
484 str r10, [fp, #cycle_count-dynarec_local]
486 ldr r10, [fp, #cycle_count-dynarec_local]
488 .size jump_vaddr, .-jump_vaddr
490 .global verify_code_ds
491 .type verify_code_ds, %function
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
498 /* r0 = instruction pointer (virtual address) */
499 /* r1 = source (virtual address) */
504 add r12, fp, #memory_map-dynarec_local
508 ldr r6, [r12, r4, lsl #2]
512 add r1, r1, r6, lsl #2
518 ldr r7, [r12, r4, lsl #2]
521 .size verify_code_vm, .-verify_code_vm
523 .type verify_code, %function
552 ldr r8, [fp, #branch_target-dynarec_local]
557 .size verify_code, .-verify_code
560 .type cc_interrupt, %function
562 ldr r0, [fp, #last_count-dynarec_local]
566 str r1, [fp, #pending_exception-dynarec_local]
567 and r2, r2, r10, lsr #17
568 add r3, fp, #restore_candidate-dynarec_local
569 str r10, [fp, #reg_cop0+36-dynarec_local] /* Count */
577 ldr r10, [fp, #reg_cop0+36-dynarec_local] /* Count */
578 ldr r0, [fp, #next_interupt-dynarec_local]
579 ldr r1, [fp, #pending_exception-dynarec_local]
580 ldr r2, [fp, #stop-dynarec_local]
581 str r0, [fp, #last_count-dynarec_local]
588 ldr r0, [fp, #pcaddr-dynarec_local]
593 ldmia r12, {r4, r5, r6, r7, r8, r9, sl, fp, pc}
595 /* Move 'dirty' blocks to the 'clean' list */
607 .size cc_interrupt, .-cc_interrupt
610 .type do_interrupt, %function
612 ldr r0, [fp, #pcaddr-dynarec_local]
614 ldr r1, [fp, #next_interupt-dynarec_local]
615 ldr r10, [fp, #reg_cop0+36-dynarec_local] /* Count */
616 str r1, [fp, #last_count-dynarec_local]
620 .size do_interrupt, .-do_interrupt
623 .type fp_exception, %function
627 ldr r1, [fp, #reg_cop0+48-dynarec_local] /* Status */
629 str r0, [fp, #reg_cop0+56-dynarec_local] /* EPC */
632 str r1, [fp, #reg_cop0+48-dynarec_local] /* Status */
633 str r2, [fp, #reg_cop0+52-dynarec_local] /* Cause */
637 .size fp_exception, .-fp_exception
639 .global fp_exception_ds
640 .type fp_exception_ds, %function
642 mov r2, #0x90000000 /* Set high bit if delay slot */
644 .size fp_exception_ds, .-fp_exception_ds
647 .type jump_syscall, %function
649 ldr r1, [fp, #reg_cop0+48-dynarec_local] /* Status */
651 str r0, [fp, #reg_cop0+56-dynarec_local] /* EPC */
654 str r1, [fp, #reg_cop0+48-dynarec_local] /* Status */
655 str r2, [fp, #reg_cop0+52-dynarec_local] /* Cause */
659 .size jump_syscall, .-jump_syscall
661 .global indirect_jump_indexed
662 .type indirect_jump_indexed, %function
663 indirect_jump_indexed:
664 ldr r0, [r0, r1, lsl #2]
665 .size indirect_jump_indexed, .-indirect_jump_indexed
667 .global indirect_jump
668 .type indirect_jump, %function
670 ldr r12, [fp, #last_count-dynarec_local]
672 str r2, [fp, #reg_cop0+36-dynarec_local] /* Count */
674 .size indirect_jump, .-indirect_jump
677 .type jump_eret, %function
679 ldr r1, [fp, #reg_cop0+48-dynarec_local] /* Status */
680 ldr r0, [fp, #last_count-dynarec_local]
683 str r1, [fp, #reg_cop0+48-dynarec_local] /* Status */
684 str r10, [fp, #reg_cop0+36-dynarec_local] /* Count */
686 ldr r1, [fp, #next_interupt-dynarec_local]
687 ldr r0, [fp, #reg_cop0+56-dynarec_local] /* EPC */
688 str r1, [fp, #last_count-dynarec_local]
692 add r6, fp, #reg+256-dynarec_local
698 eor r3, r3, r2, asr #31
703 ldr r2, [fp, #hi-dynarec_local]
704 ldr r3, [fp, #hi+4-dynarec_local]
705 eors r3, r3, r2, asr #31
706 ldr r2, [fp, #lo-dynarec_local]
707 ldreq r3, [fp, #lo+4-dynarec_local]
708 eoreq r3, r3, r2, asr #31
714 str r0, [fp, #pcaddr-dynarec_local]
716 ldr r0, [fp, #pcaddr-dynarec_local]
718 .size jump_eret, .-jump_eret
720 .global new_dyna_start
721 .type new_dyna_start, %function
724 stmia r12, {r4, r5, r6, r7, r8, r9, sl, fp, lr}
726 bl new_recompile_block
727 ldr r0, [fp, #next_interupt-dynarec_local]
728 ldr r10, [fp, #reg_cop0+36-dynarec_local] /* Count */
729 str r0, [fp, #last_count-dynarec_local]
733 .word dynarec_local+28
734 .size new_dyna_start, .-new_dyna_start
736 .global write_rdram_new
737 .type write_rdram_new, %function
739 ldr r2, [fp, #address-dynarec_local]
740 ldr r0, [fp, #word-dynarec_local]
743 .size write_rdram_new, .-write_rdram_new
745 .global write_rdramb_new
746 .type write_rdramb_new, %function
748 ldr r2, [fp, #address-dynarec_local]
749 ldrb r0, [fp, #byte-dynarec_local]
753 .size write_rdramb_new, .-write_rdramb_new
755 .global write_rdramh_new
756 .type write_rdramh_new, %function
758 ldr r2, [fp, #address-dynarec_local]
759 ldrh r0, [fp, #hword-dynarec_local]
763 .size write_rdramh_new, .-write_rdramh_new
765 .global write_rdramd_new
766 .type write_rdramd_new, %function
768 ldr r2, [fp, #address-dynarec_local]
769 /* ldrd r0, [fp, #dword-dynarec_local]*/
770 ldr r0, [fp, #dword-dynarec_local]
771 ldr r1, [fp, #dword+4-dynarec_local]
775 .size write_rdramd_new, .-write_rdramd_new
777 .global do_invalidate
778 .type do_invalidate, %function
780 ldr r2, [fp, #address-dynarec_local]
782 ldr r1, [fp, #invc_ptr-dynarec_local]
788 .size do_invalidate, .-do_invalidate
790 .global read_nomem_new
791 .type read_nomem_new, %function
796 /* should never happen */
799 ldr r2, [fp, #address-dynarec_local]
800 add r12, fp, #memory_map-dynarec_local
802 ldr r12, [r12, r0, lsl #2]
806 ldr r0, [r2, r12, lsl #2]
807 str r0, [fp, #readmem_dword-dynarec_local]
810 .size read_nomem_new, .-read_nomem_new
812 .global read_nomemb_new
813 .type read_nomemb_new, %function
818 ldr r2, [fp, #address-dynarec_local]
819 add r12, fp, #memory_map-dynarec_local
823 ldr r12, [r12, r0, lsl #2]
827 ldr r0, [fp, #word-dynarec_local]
828 str r0, [r2, r12, lsl #2]
830 .size write_nomem_new, .-write_nomem_new
832 .global write_nomemb_new
833 .type write_nomemb_new, %function
838 ldr r2, [fp, #address-dynarec_local]
839 add r12, fp, #memory_map-dynarec_local
843 ldr r12, [r12, r0, lsl #2]
848 ldrb r0, [fp, #byte-dynarec_local]
849 strb r0, [r2, r12, lsl #2]
851 .size write_nomemb_new, .-write_nomemb_new
853 .global write_nomemh_new
854 .type write_nomemh_new, %function
859 ldr r2, [fp, #address-dynarec_local]
860 add r12, fp, #memory_map-dynarec_local
864 ldr r12, [r12, r0, lsl #2]
869 ldrh r0, [fp, #hword-dynarec_local]
872 .size write_nomemh_new, .-write_nomemh_new
874 .global write_nomemd_new
875 .type write_nomemd_new, %function
880 ldr r2, [fp, #address-dynarec_local]
881 add r12, fp, #memory_map-dynarec_local
885 ldr r12, [r12, r0, lsl #2]
890 ldr r0, [fp, #dword+4-dynarec_local]
891 ldr r1, [fp, #dword-dynarec_local]
892 /* strd r0, [r2, r12]*/
896 .size write_nomemd_new, .-write_nomemd_new
898 .global tlb_exception
899 .type tlb_exception, %function
903 /* r3 = instr addr/flags */
904 ldr r4, [fp, #reg_cop0+48-dynarec_local] /* Status */
905 add r5, fp, #memory_map-dynarec_local
907 orr r1, r1, r3, lsl #31
909 ldr r7, [r5, r6, lsl #2]
911 str r4, [fp, #reg_cop0+48-dynarec_local] /* Status */
913 str r1, [fp, #reg_cop0+52-dynarec_local] /* Cause */
915 ldr r0, [r8, r7, lsl #2]
916 add r4, r8, r1, asr #29
917 add r5, fp, #reg-dynarec_local
918 str r4, [fp, #reg_cop0+56-dynarec_local] /* EPC */
920 ldr r8, [fp, #reg_cop0+16-dynarec_local] /* Context */
923 and r7, r7, r0, lsr #18
925 sub r2, r2, r1, asr #16
926 bic r9, r9, #0x0F800000
933 add r4, r2, r1, asr #16
934 add r6, fp, #reg+4-dynarec_local
936 str r4, [fp, #reg_cop0+32-dynarec_local] /* BadVAddr */
938 and r4, r9, r4, lsr #9
941 str r8, [fp, #reg_cop0+16-dynarec_local] /* Context */
943 ldr r1, [fp, #next_interupt-dynarec_local]
944 ldr r10, [fp, #reg_cop0+36-dynarec_local] /* Count */
945 str r1, [fp, #last_count-dynarec_local]
948 .size tlb_exception, .-tlb_exception
951 .type breakpoint, %function
953 /* Set breakpoint here for debugging */
955 .size breakpoint, .-breakpoint
956 .section .note.GNU-stack,"",%progbits