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 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
37 .global reg_cop1_simple
38 .global reg_cop1_double
42 .global rounding_modes
46 .global pending_exception
60 .global restore_candidate
64 .type dynarec_local, %object
65 .size dynarec_local, 64
67 .space 64+16+16+8+8+8+8+256+8+8+128+128+128+16+8+132+4+256+512+4194304
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 .type readmem_dword, %object
94 .size readmem_dword, 8
95 dword = readmem_dword + 8
106 .size byte, 1 /* 1 byte free */
123 .type reg_cop0, %object
125 reg_cop1_simple = reg_cop0 + 128
126 .type reg_cop1_simple, %object
127 .size reg_cop1_simple, 128
128 reg_cop1_double = reg_cop1_simple + 128
129 .type reg_cop1_double, %object
130 .size reg_cop1_double, 128
131 rounding_modes = reg_cop1_double + 128
132 .type rounding_modes, %object
133 .size rounding_modes, 16
134 branch_target = rounding_modes + 16
135 .type branch_target, %object
136 .size branch_target, 4
137 PC = branch_target + 4
141 .type fake_pc, %object
144 mini_ht = fake_pc + 136
145 .type mini_ht, %object
147 restore_candidate = mini_ht + 256
148 .type restore_candidate, %object
149 .size restore_candidate, 512
150 memory_map = restore_candidate + 512
151 .type memory_map, %object
152 .size memory_map, 4194304
157 .type dyna_linker, %function
159 /* r0 = virtual target address */
160 /* r1 = instruction to patch */
166 ldrge r12, [r4, r5, lsl #2]
173 eor r2, r2, r12, lsr #12
174 and r6, r6, r12, lsr #12
178 ldr r5, [r3, r2, lsl #2]
194 add r1, r1, r12, asr #6
196 moveq pc, r4 /* Stale i-cache */
199 and r1, r7, #0xff000000
202 add r1, r1, r2, lsr #8
206 /* hash_table lookup */
209 eor r4, r0, r0, lsl #16
215 ldr r5, [r3, r2, lsl #2]
222 /* jump_dirty lookup */
232 /* hash_table insert */
243 bl new_recompile_block
251 .size dyna_linker, .-dyna_linker
252 .global exec_pagefault
253 .type exec_pagefault, %function
255 /* r0 = instruction pointer */
256 /* r1 = fault address */
258 ldr r3, [fp, #reg_cop0+48-dynarec_local] /* Status */
260 ldr r4, [fp, #reg_cop0+16-dynarec_local] /* Context */
261 bic r6, r6, #0x0F800000
262 str r0, [fp, #reg_cop0+56-dynarec_local] /* EPC */
264 str r1, [fp, #reg_cop0+32-dynarec_local] /* BadVAddr */
266 str r3, [fp, #reg_cop0+48-dynarec_local] /* Status */
267 and r5, r6, r1, lsr #9
268 str r2, [fp, #reg_cop0+52-dynarec_local] /* Cause */
269 and r1, r1, r6, lsl #9
270 str r1, [fp, #reg_cop0+40-dynarec_local] /* EntryHi */
272 str r4, [fp, #reg_cop0+16-dynarec_local] /* Context */
276 .size exec_pagefault, .-exec_pagefault
277 /* Special dynamic linker for the case where a page fault
278 may occur in a branch delay slot */
279 .global dyna_linker_ds
280 .type dyna_linker_ds, %function
282 /* r0 = virtual target address */
283 /* r1 = instruction to patch */
289 ldrge r12, [r4, r5, lsl #2]
296 eor r2, r2, r12, lsr #12
297 and r6, r6, r12, lsr #12
301 ldr r5, [r3, r2, lsl #2]
317 add r1, r1, r12, asr #6
319 moveq pc, r4 /* Stale i-cache */
322 and r1, r7, #0xff000000
325 add r1, r1, r2, lsr #8
329 /* hash_table lookup */
332 eor r4, r0, r0, lsl #16
338 ldr r5, [r3, r2, lsl #2]
345 /* jump_dirty lookup */
355 /* hash_table insert */
368 bl new_recompile_block
375 mov r2, #0x80000008 /* High bit set indicates pagefault in delay slot */
378 .size dyna_linker_ds, .-dyna_linker_ds
388 .global jump_vaddr_r0
389 .type jump_vaddr_r0, %function
391 eor r2, r0, r0, lsl #16
393 .size jump_vaddr_r0, .-jump_vaddr_r0
394 .global jump_vaddr_r1
395 .type jump_vaddr_r1, %function
397 eor r2, r1, r1, lsl #16
400 .size jump_vaddr_r1, .-jump_vaddr_r1
401 .global jump_vaddr_r2
402 .type jump_vaddr_r2, %function
405 eor r2, r2, r2, lsl #16
407 .size jump_vaddr_r2, .-jump_vaddr_r2
408 .global jump_vaddr_r3
409 .type jump_vaddr_r3, %function
411 eor r2, r3, r3, lsl #16
414 .size jump_vaddr_r3, .-jump_vaddr_r3
415 .global jump_vaddr_r4
416 .type jump_vaddr_r4, %function
418 eor r2, r4, r4, lsl #16
421 .size jump_vaddr_r4, .-jump_vaddr_r4
422 .global jump_vaddr_r5
423 .type jump_vaddr_r5, %function
425 eor r2, r5, r5, lsl #16
428 .size jump_vaddr_r5, .-jump_vaddr_r5
429 .global jump_vaddr_r6
430 .type jump_vaddr_r6, %function
432 eor r2, r6, r6, lsl #16
435 .size jump_vaddr_r6, .-jump_vaddr_r6
436 .global jump_vaddr_r8
437 .type jump_vaddr_r8, %function
439 eor r2, r8, r8, lsl #16
442 .size jump_vaddr_r8, .-jump_vaddr_r8
443 .global jump_vaddr_r9
444 .type jump_vaddr_r9, %function
446 eor r2, r9, r9, lsl #16
449 .size jump_vaddr_r9, .-jump_vaddr_r9
450 .global jump_vaddr_r10
451 .type jump_vaddr_r10, %function
453 eor r2, r10, r10, lsl #16
456 .size jump_vaddr_r10, .-jump_vaddr_r10
457 .global jump_vaddr_r12
458 .type jump_vaddr_r12, %function
460 eor r2, r12, r12, lsl #16
463 .size jump_vaddr_r12, .-jump_vaddr_r12
464 .global jump_vaddr_r7
465 .type jump_vaddr_r7, %function
467 eor r2, r7, r7, lsl #16
469 .size jump_vaddr_r7, .-jump_vaddr_r7
471 .type jump_vaddr, %function
475 and r2, r3, r2, lsr #12
482 str r10, [fp, #cycle_count-dynarec_local]
484 ldr r10, [fp, #cycle_count-dynarec_local]
486 .size jump_vaddr, .-jump_vaddr
488 .global verify_code_ds
489 .type verify_code_ds, %function
491 str r8, [fp, #branch_target-dynarec_local]
492 .size verify_code_ds, .-verify_code_ds
493 .global verify_code_vm
494 .type verify_code_vm, %function
496 /* r0 = instruction pointer (virtual address) */
497 /* r1 = source (virtual address) */
502 add r12, fp, #memory_map-dynarec_local
506 ldr r6, [r12, r4, lsl #2]
510 add r1, r1, r6, lsl #2
516 ldr r7, [r12, r4, lsl #2]
519 .size verify_code_vm, .-verify_code_vm
521 .type verify_code, %function
550 ldr r8, [fp, #branch_target-dynarec_local]
555 .size verify_code, .-verify_code
558 .type cc_interrupt, %function
560 ldr r0, [fp, #last_count-dynarec_local]
564 str r1, [fp, #pending_exception-dynarec_local]
565 and r2, r2, r10, lsr #17
566 add r3, fp, #restore_candidate-dynarec_local
567 str r10, [fp, #reg_cop0+36-dynarec_local] /* Count */
575 ldr r10, [fp, #reg_cop0+36-dynarec_local] /* Count */
576 ldr r0, [fp, #next_interupt-dynarec_local]
577 ldr r1, [fp, #pending_exception-dynarec_local]
578 ldr r2, [fp, #stop-dynarec_local]
579 str r0, [fp, #last_count-dynarec_local]
586 ldr r0, [fp, #pcaddr-dynarec_local]
591 ldmia r12, {r4, r5, r6, r7, r8, r9, sl, fp, pc}
593 /* Move 'dirty' blocks to the 'clean' list */
605 .size cc_interrupt, .-cc_interrupt
608 .type do_interrupt, %function
610 ldr r0, [fp, #pcaddr-dynarec_local]
612 ldr r1, [fp, #next_interupt-dynarec_local]
613 ldr r10, [fp, #reg_cop0+36-dynarec_local] /* Count */
614 str r1, [fp, #last_count-dynarec_local]
618 .size do_interrupt, .-do_interrupt
621 .type fp_exception, %function
625 ldr r1, [fp, #reg_cop0+48-dynarec_local] /* Status */
627 str r0, [fp, #reg_cop0+56-dynarec_local] /* EPC */
630 str r1, [fp, #reg_cop0+48-dynarec_local] /* Status */
631 str r2, [fp, #reg_cop0+52-dynarec_local] /* Cause */
635 .size fp_exception, .-fp_exception
637 .global fp_exception_ds
638 .type fp_exception_ds, %function
640 mov r2, #0x90000000 /* Set high bit if delay slot */
642 .size fp_exception_ds, .-fp_exception_ds
645 .type jump_syscall, %function
647 ldr r1, [fp, #reg_cop0+48-dynarec_local] /* Status */
649 str r0, [fp, #reg_cop0+56-dynarec_local] /* EPC */
652 str r1, [fp, #reg_cop0+48-dynarec_local] /* Status */
653 str r2, [fp, #reg_cop0+52-dynarec_local] /* Cause */
657 .size jump_syscall, .-jump_syscall
659 .global indirect_jump_indexed
660 .type indirect_jump_indexed, %function
661 indirect_jump_indexed:
662 ldr r0, [r0, r1, lsl #2]
663 .size indirect_jump_indexed, .-indirect_jump_indexed
665 .global indirect_jump
666 .type indirect_jump, %function
668 ldr r12, [fp, #last_count-dynarec_local]
670 str r2, [fp, #reg_cop0+36-dynarec_local] /* Count */
672 .size indirect_jump, .-indirect_jump
675 .type jump_eret, %function
677 ldr r1, [fp, #reg_cop0+48-dynarec_local] /* Status */
678 ldr r0, [fp, #last_count-dynarec_local]
681 str r1, [fp, #reg_cop0+48-dynarec_local] /* Status */
682 str r10, [fp, #reg_cop0+36-dynarec_local] /* Count */
684 ldr r1, [fp, #next_interupt-dynarec_local]
685 ldr r0, [fp, #reg_cop0+56-dynarec_local] /* EPC */
686 str r1, [fp, #last_count-dynarec_local]
690 add r6, fp, #reg+256-dynarec_local
696 eor r3, r3, r2, asr #31
701 ldr r2, [fp, #hi-dynarec_local]
702 ldr r3, [fp, #hi+4-dynarec_local]
703 eors r3, r3, r2, asr #31
704 ldr r2, [fp, #lo-dynarec_local]
705 ldreq r3, [fp, #lo+4-dynarec_local]
706 eoreq r3, r3, r2, asr #31
712 str r0, [fp, #pcaddr-dynarec_local]
714 ldr r0, [fp, #pcaddr-dynarec_local]
716 .size jump_eret, .-jump_eret
718 .global new_dyna_start
719 .type new_dyna_start, %function
723 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
793 ldr r2, [fp, #address-dynarec_local]
794 add r12, fp, #memory_map-dynarec_local
796 ldr r12, [r12, r0, lsl #2]
800 ldr r0, [r2, r12, lsl #2]
801 str r0, [fp, #readmem_dword-dynarec_local]
803 .size read_nomem_new, .-read_nomem_new
805 .global read_nomemb_new
806 .type read_nomemb_new, %function
808 ldr r2, [fp, #address-dynarec_local]
809 add r12, fp, #memory_map-dynarec_local
811 ldr r12, [r12, r0, lsl #2]
816 ldrb r0, [r2, r12, lsl #2]
817 str r0, [fp, #readmem_dword-dynarec_local]
819 .size read_nomemb_new, .-read_nomemb_new
821 .global read_nomemh_new
822 .type read_nomemh_new, %function
824 ldr r2, [fp, #address-dynarec_local]
825 add r12, fp, #memory_map-dynarec_local
827 ldr r12, [r12, r0, lsl #2]
834 str r0, [fp, #readmem_dword-dynarec_local]
836 .size read_nomemh_new, .-read_nomemh_new
838 .global read_nomemd_new
839 .type read_nomemd_new, %function
841 ldr r2, [fp, #address-dynarec_local]
842 add r12, fp, #memory_map-dynarec_local
844 ldr r12, [r12, r0, lsl #2]
849 /* ldrd r0, [r2, r12]*/
853 str r0, [fp, #readmem_dword+4-dynarec_local]
854 str r1, [fp, #readmem_dword-dynarec_local]
856 .size read_nomemd_new, .-read_nomemd_new
858 .global write_nomem_new
859 .type write_nomem_new, %function
864 ldr r2, [fp, #address-dynarec_local]
865 add r12, fp, #memory_map-dynarec_local
869 ldr r12, [r12, r0, lsl #2]
873 ldr r0, [fp, #word-dynarec_local]
874 str r0, [r2, r12, lsl #2]
876 .size write_nomem_new, .-write_nomem_new
878 .global write_nomemb_new
879 .type write_nomemb_new, %function
884 ldr r2, [fp, #address-dynarec_local]
885 add r12, fp, #memory_map-dynarec_local
889 ldr r12, [r12, r0, lsl #2]
894 ldrb r0, [fp, #byte-dynarec_local]
895 strb r0, [r2, r12, lsl #2]
897 .size write_nomemb_new, .-write_nomemb_new
899 .global write_nomemh_new
900 .type write_nomemh_new, %function
905 ldr r2, [fp, #address-dynarec_local]
906 add r12, fp, #memory_map-dynarec_local
910 ldr r12, [r12, r0, lsl #2]
915 ldrh r0, [fp, #hword-dynarec_local]
918 .size write_nomemh_new, .-write_nomemh_new
920 .global write_nomemd_new
921 .type write_nomemd_new, %function
926 ldr r2, [fp, #address-dynarec_local]
927 add r12, fp, #memory_map-dynarec_local
931 ldr r12, [r12, r0, lsl #2]
936 ldr r0, [fp, #dword+4-dynarec_local]
937 ldr r1, [fp, #dword-dynarec_local]
938 /* strd r0, [r2, r12]*/
942 .size write_nomemd_new, .-write_nomemd_new
944 .global tlb_exception
945 .type tlb_exception, %function
949 /* r3 = instr addr/flags */
950 ldr r4, [fp, #reg_cop0+48-dynarec_local] /* Status */
951 add r5, fp, #memory_map-dynarec_local
953 orr r1, r1, r3, lsl #31
955 ldr r7, [r5, r6, lsl #2]
957 str r4, [fp, #reg_cop0+48-dynarec_local] /* Status */
959 str r1, [fp, #reg_cop0+52-dynarec_local] /* Cause */
961 ldr r0, [r8, r7, lsl #2]
962 add r4, r8, r1, asr #29
963 add r5, fp, #reg-dynarec_local
964 str r4, [fp, #reg_cop0+56-dynarec_local] /* EPC */
966 ldr r8, [fp, #reg_cop0+16-dynarec_local] /* Context */
969 and r7, r7, r0, lsr #18
971 sub r2, r2, r1, asr #16
972 bic r9, r9, #0x0F800000
979 add r4, r2, r1, asr #16
980 add r6, fp, #reg+4-dynarec_local
982 str r4, [fp, #reg_cop0+32-dynarec_local] /* BadVAddr */
984 and r4, r9, r4, lsr #9
987 str r8, [fp, #reg_cop0+16-dynarec_local] /* Context */
989 ldr r1, [fp, #next_interupt-dynarec_local]
990 ldr r10, [fp, #reg_cop0+36-dynarec_local] /* Count */
991 str r1, [fp, #last_count-dynarec_local]
994 .size tlb_exception, .-tlb_exception
997 .type breakpoint, %function
999 /* Set breakpoint here for debugging */
1001 .size breakpoint, .-breakpoint
1002 .section .note.GNU-stack,"",%progbits