1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus/PCSX - assem_arm64.c *
3 * Copyright (C) 2009-2011 Ari64 *
4 * Copyright (C) 2010-2021 notaz *
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. *
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. *
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 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
22 #include "arm_features.h"
24 #if defined(BASE_ADDR_FIXED)
25 #elif defined(BASE_ADDR_DYNAMIC)
26 u_char *translation_cache;
28 u_char translation_cache[1 << TARGET_SIZE_2] __attribute__((aligned(4096)));
31 #define CALLER_SAVE_REGS 0x0007ffff
33 #define unused __attribute__((unused))
35 static u_int needs_clear_cache[1<<(TARGET_SIZE_2-17)];
37 //void indirect_jump_indexed();
38 //void indirect_jump();
40 //void jump_vaddr_r0();
42 void * const jump_vaddr_reg[32];
46 static void set_jump_target(void *addr, void *target_)
51 // from a pointer to external jump stub (which was produced by emit_extjump2)
52 // find where the jumping insn is
53 static void *find_extjump_insn(void *stub)
59 // find where external branch is liked to using addr of it's stub:
60 // get address that insn one after stub loads (dyna_linker arg1),
61 // treat it as a pointer to branch insn,
62 // return addr where that branch jumps to
63 static void *get_pointer(void *stub)
65 //printf("get_pointer(%x)\n",(int)stub);
70 // Find the "clean" entry point from a "dirty" entry point
71 // by skipping past the call to verify_code
72 static void *get_clean_addr(void *addr)
78 static int verify_dirty(u_int *ptr)
84 // This doesn't necessarily find all clean entry points, just
85 // guarantees that it's not dirty
86 static int isclean(void *addr)
92 // get source that block at addr was compiled from (host pointers)
93 static void get_bounds(void *addr, u_char **start, u_char **end)
98 // Allocate a specific ARM register.
99 static void alloc_arm_reg(struct regstat *cur,int i,signed char reg,int hr)
104 // see if it's already allocated (and dealloc it)
105 for(n=0;n<HOST_REGS;n++)
107 if(n!=EXCLUDE_REG&&cur->regmap[n]==reg) {
108 dirty=(cur->dirty>>n)&1;
114 cur->dirty&=~(1<<hr);
115 cur->dirty|=dirty<<hr;
116 cur->isconst&=~(1<<hr);
119 // Alloc cycle count into dedicated register
120 static void alloc_cc(struct regstat *cur,int i)
122 alloc_arm_reg(cur,i,CCREG,HOST_CCREG);
130 static unused const char *regname[32] = {
131 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
132 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
133 "ip0", "ip1", "r18", "r19", "r20", "r21", "r22", "r23"
134 "r24", "r25", "r26", "r27", "r28", "fp", "lr", "sp"
137 static void output_w32(u_int word)
139 *((u_int *)out) = word;
143 static u_int rm_rd(u_int rm, u_int rd)
147 return (rm << 16) | rd;
150 static u_int rm_rn_rd(u_int rm, u_int rn, u_int rd)
155 return (rm << 16) | (rn << 5) | rd;
158 static u_int rm_imm6_rn_rd(u_int rm, u_int imm6, u_int rn, u_int rd)
161 return rm_rn_rd(rm, rn, rd) | (imm6 << 10);
164 static u_int imm16_rd(u_int imm16, u_int rd)
166 assert(imm16 < 0x10000);
168 return (imm16 << 5) | rd;
171 static u_int imm12_rn_rd(u_int imm12, u_int rn, u_int rd)
173 assert(imm12 < 0x1000);
176 return (imm12 << 10) | (rn << 5) | rd;
179 #pragma GCC diagnostic ignored "-Wunused-function"
180 static u_int genjmp(u_char *addr)
182 intptr_t offset = addr - out;
183 if (offset < -134217728 || offset > 134217727) {
184 if ((uintptr_t)addr > 2) {
185 SysPrintf("%s: out of range: %08x\n", __func__, offset);
190 return ((u_int)offset >> 2) & 0x01ffffff;
193 static u_int genjmpcc(u_char *addr)
195 intptr_t offset = addr - out;
196 if (offset < -1048576 || offset > 1048572) {
197 if ((uintptr_t)addr > 2) {
198 SysPrintf("%s: out of range: %08x\n", __func__, offset);
203 return ((u_int)offset >> 2) & 0xfffff;
206 static void emit_mov(u_int rs, u_int rt)
208 assem_debug("mov %s,%s\n", regname[rt], regname[rs]);
209 output_w32(0x2a0003e0 | rm_rd(rs, rt));
212 static void emit_movs(u_int rs, u_int rt)
214 assem_debug("movs %s,%s\n", regname[rt], regname[rs]);
215 output_w32(0x31000000 | imm12_rn_rd(0, rs, rt));
218 static void emit_add(u_int rs1, u_int rs2, u_int rt)
220 assem_debug("add %s, %s, %s\n", regname[rt], regname[rs1], regname[rs2]);
221 output_w32(0x0b000000 | rm_imm6_rn_rd(rs2, 0, rs1, rt));
224 static void emit_sbc(u_int rs1,u_int rs2,u_int rt)
226 assem_debug("sbc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
230 static void emit_neg(u_int rs, u_int rt)
232 assem_debug("rsb %s,%s,#0\n",regname[rt],regname[rs]);
236 static void emit_negs(u_int rs, u_int rt)
238 assem_debug("rsbs %s,%s,#0\n",regname[rt],regname[rs]);
242 static void emit_sub(u_int rs1, u_int rs2, u_int rt)
244 assem_debug("sub %s, %s, %s\n", regname[rt], regname[rs1], regname[rs2]);
245 output_w32(0x4b000000 | rm_imm6_rn_rd(rs2, 0, rs1, rt));
248 static void emit_subs(u_int rs1,u_int rs2,u_int rt)
250 assem_debug("subs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
254 static void emit_zeroreg(u_int rt)
256 assem_debug("mov %s,#0\n",regname[rt]);
260 static void emit_movimm(u_int imm, u_int rt)
262 assem_debug("mov %s,#%#x\n", regname[rt], imm);
263 if ((imm & 0xffff0000) == 0)
264 output_w32(0x52800000 | imm16_rd(imm, rt));
265 else if ((imm & 0xffff0000) == 0xffff0000)
268 output_w32(0x52800000 | imm16_rd(imm & 0xffff, rt));
269 output_w32(0x72a00000 | imm16_rd(imm >> 16, rt));
273 static void emit_readword(void *addr, u_int rt)
275 uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
276 if (!(offset & 3) && offset <= 16380) {
277 assem_debug("ldr %s,[x%d+%#lx]\n", regname[rt], FP, offset);
278 output_w32(0xb9400000 | imm12_rn_rd(offset >> 2, FP, rt));
284 static void emit_loadreg(u_int r, u_int hr)
290 void *addr = &psxRegs.GPR.r[r];
292 //case HIREG: addr = &hi; break;
293 //case LOREG: addr = &lo; break;
294 case CCREG: addr = &cycle_count; break;
295 case CSREG: addr = &Status; break;
296 case INVCP: addr = &invc_ptr; break;
297 default: assert(r < 34); break;
299 emit_readword(addr, hr);
303 static void emit_writeword(u_int rt, void *addr)
305 uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
306 if (!(offset & 3) && offset <= 16380) {
307 assem_debug("str %s,[x%d+%#lx]\n", regname[rt], FP, offset);
308 output_w32(0xb9000000 | imm12_rn_rd(offset >> 2, FP, rt));
314 static void emit_storereg(u_int r, u_int hr)
317 void *addr = &psxRegs.GPR.r[r];
319 //case HIREG: addr = &hi; break;
320 //case LOREG: addr = &lo; break;
321 case CCREG: addr = &cycle_count; break;
322 default: assert(r < 34); break;
324 emit_writeword(hr, addr);
327 static void emit_test(u_int rs, u_int rt)
329 assem_debug("tst %s,%s\n",regname[rs],regname[rt]);
333 static void emit_testimm(u_int rs,int imm)
335 assem_debug("tst %s,#%#x\n", regname[rs], imm);
339 static void emit_testeqimm(u_int rs,int imm)
341 assem_debug("tsteq %s,$%d\n",regname[rs],imm);
345 static void emit_not(u_int rs,u_int rt)
347 assem_debug("mvn %s,%s\n",regname[rt],regname[rs]);
351 static void emit_mvnmi(u_int rs,u_int rt)
353 assem_debug("mvnmi %s,%s\n",regname[rt],regname[rs]);
357 static void emit_and(u_int rs1,u_int rs2,u_int rt)
359 assem_debug("and %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
363 static void emit_or(u_int rs1,u_int rs2,u_int rt)
365 assem_debug("orr %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
369 static void emit_orrshl_imm(u_int rs,u_int imm,u_int rt)
374 assem_debug("orr %s,%s,%s,lsl #%d\n",regname[rt],regname[rt],regname[rs],imm);
378 static void emit_orrshr_imm(u_int rs,u_int imm,u_int rt)
383 assem_debug("orr %s,%s,%s,lsr #%d\n",regname[rt],regname[rt],regname[rs],imm);
387 static void emit_or_and_set_flags(u_int rs1,u_int rs2,u_int rt)
389 assem_debug("orrs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
393 static void emit_xor(u_int rs1,u_int rs2,u_int rt)
395 assem_debug("eor %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
399 static void emit_addimm(u_int rs, uintptr_t imm, u_int rt)
402 assem_debug("add %s,%s,%#lx\n", regname[rt], regname[rs], imm);
403 output_w32(0x11000000 | imm12_rn_rd(imm, rs, rt));
405 else if (-imm < 4096) {
406 assem_debug("sub %s,%s,%#lx\n", regname[rt], regname[rs], imm);
407 output_w32(0x51000000 | imm12_rn_rd(imm, rs, rt));
413 static void emit_addimm_and_set_flags(int imm, u_int rt)
418 static void emit_addimm_no_flags(u_int imm,u_int rt)
420 emit_addimm(rt,imm,rt);
423 static void emit_adcimm(u_int rs,int imm,u_int rt)
425 assem_debug("adc %s,%s,#%#x\n",regname[rt],regname[rs],imm);
429 static void emit_rscimm(u_int rs,int imm,u_int rt)
431 assem_debug("rsc %s,%s,#%#x\n",regname[rt],regname[rs],imm);
435 static void emit_addimm64_32(u_int rsh,u_int rsl,int imm,u_int rth,u_int rtl)
440 static void emit_andimm(u_int rs,int imm,u_int rt)
445 static void emit_orimm(u_int rs,int imm,u_int rt)
450 static void emit_xorimm(u_int rs,int imm,u_int rt)
455 static void emit_shlimm(u_int rs,u_int imm,u_int rt)
459 assem_debug("lsl %s,%s,#%d\n",regname[rt],regname[rs],imm);
463 static void emit_lsls_imm(u_int rs,int imm,u_int rt)
467 assem_debug("lsls %s,%s,#%d\n",regname[rt],regname[rs],imm);
471 static unused void emit_lslpls_imm(u_int rs,int imm,u_int rt)
475 assem_debug("lslpls %s,%s,#%d\n",regname[rt],regname[rs],imm);
479 static void emit_shrimm(u_int rs,u_int imm,u_int rt)
483 assem_debug("lsr %s,%s,#%d\n",regname[rt],regname[rs],imm);
487 static void emit_sarimm(u_int rs,u_int imm,u_int rt)
491 assem_debug("asr %s,%s,#%d\n",regname[rt],regname[rs],imm);
495 static void emit_rorimm(u_int rs,u_int imm,u_int rt)
499 assem_debug("ror %s,%s,#%d\n",regname[rt],regname[rs],imm);
503 static void emit_signextend16(u_int rs, u_int rt)
505 assem_debug("sxth %s,%s\n", regname[rt], regname[rs]);
509 static void emit_shl(u_int rs,u_int shift,u_int rt)
517 static void emit_shr(u_int rs,u_int shift,u_int rt)
522 assem_debug("lsr %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
526 static void emit_sar(u_int rs,u_int shift,u_int rt)
531 assem_debug("asr %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
535 static void emit_orrshl(u_int rs,u_int shift,u_int rt)
540 assem_debug("orr %s,%s,%s,lsl %s\n",regname[rt],regname[rt],regname[rs],regname[shift]);
544 static void emit_orrshr(u_int rs,u_int shift,u_int rt)
549 assem_debug("orr %s,%s,%s,lsr %s\n",regname[rt],regname[rt],regname[rs],regname[shift]);
553 static void emit_cmpimm(u_int rs,int imm)
558 static void emit_cmovne_imm(int imm,u_int rt)
560 assem_debug("movne %s,#%#x\n",regname[rt],imm);
564 static void emit_cmovl_imm(int imm,u_int rt)
566 assem_debug("movlt %s,#%#x\n",regname[rt],imm);
570 static void emit_cmovb_imm(int imm,u_int rt)
572 assem_debug("movcc %s,#%#x\n",regname[rt],imm);
576 static void emit_cmovs_imm(int imm,u_int rt)
578 assem_debug("movmi %s,#%#x\n",regname[rt],imm);
582 static void emit_cmovne_reg(u_int rs,u_int rt)
584 assem_debug("movne %s,%s\n",regname[rt],regname[rs]);
588 static void emit_cmovl_reg(u_int rs,u_int rt)
590 assem_debug("movlt %s,%s\n",regname[rt],regname[rs]);
594 static void emit_cmovs_reg(u_int rs,u_int rt)
596 assem_debug("movmi %s,%s\n",regname[rt],regname[rs]);
600 static void emit_slti32(u_int rs,int imm,u_int rt)
602 if(rs!=rt) emit_zeroreg(rt);
604 if(rs==rt) emit_movimm(0,rt);
605 emit_cmovl_imm(1,rt);
608 static void emit_sltiu32(u_int rs,int imm,u_int rt)
610 if(rs!=rt) emit_zeroreg(rt);
612 if(rs==rt) emit_movimm(0,rt);
613 emit_cmovb_imm(1,rt);
616 static void emit_cmp(u_int rs,u_int rt)
618 assem_debug("cmp %s,%s\n",regname[rs],regname[rt]);
622 static void emit_set_gz32(u_int rs, u_int rt)
624 //assem_debug("set_gz32\n");
627 emit_cmovl_imm(0,rt);
630 static void emit_set_nz32(u_int rs, u_int rt)
632 //assem_debug("set_nz32\n");
636 static void emit_set_if_less32(u_int rs1, u_int rs2, u_int rt)
638 //assem_debug("set if less (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]);
639 if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt);
641 if(rs1==rt||rs2==rt) emit_movimm(0,rt);
642 emit_cmovl_imm(1,rt);
645 static void emit_set_if_carry32(u_int rs1, u_int rs2, u_int rt)
647 //assem_debug("set if carry (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]);
648 if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt);
650 if(rs1==rt||rs2==rt) emit_movimm(0,rt);
651 emit_cmovb_imm(1,rt);
654 static void emit_call(const void *a_)
656 intptr_t diff = (u_char *)a_ - out;
657 assem_debug("bl %p (%p+%lx)%s\n", a_, out, diff, func_name(a));
659 if (-134217728 <= diff && diff <= 134217727)
660 output_w32(0x94000000 | ((diff >> 2) & 0x03ffffff));
665 #pragma GCC diagnostic ignored "-Wunused-variable"
666 static void emit_jmp(const void *a_)
668 uintptr_t a = (uintptr_t)a_;
669 assem_debug("b %p (%p+%lx)%s\n", a_, out, (u_char *)a_ - out, func_name(a));
673 static void emit_jne(const void *a_)
675 uintptr_t a = (uintptr_t)a_;
676 assem_debug("bne %p\n", a_);
680 static void emit_jeq(const void *a)
682 assem_debug("beq %p\n",a);
686 static void emit_js(const void *a)
688 assem_debug("bmi %p\n",a);
692 static void emit_jns(const void *a)
694 assem_debug("bpl %p\n",a);
698 static void emit_jl(const void *a)
700 assem_debug("blt %p\n",a);
704 static void emit_jge(const void *a)
706 assem_debug("bge %p\n",a);
710 static void emit_jno(const void *a)
712 assem_debug("bvc %p\n",a);
716 static void emit_jc(const void *a)
718 assem_debug("bcs %p\n",a);
722 static void emit_jcc(const void *a)
724 assem_debug("bcc %p\n", a);
728 static void emit_callreg(u_int r)
731 assem_debug("blx %s\n", regname[r]);
735 static void emit_jmpreg(u_int r)
737 assem_debug("mov pc,%s\n",regname[r]);
741 static void emit_retreg(u_int r)
743 assem_debug("ret %s\n", r == LR ? "" : regname[r]);
744 output_w32(0xd65f0000 | rm_rn_rd(0, r, 0));
747 static void emit_ret(void)
752 static void emit_readword_indexed(int offset, u_int rs, u_int rt)
754 assem_debug("ldr %s,%s+%d\n",regname[rt],regname[rs],offset);
758 static void emit_movsbl_indexed(int offset, u_int rs, u_int rt)
760 assem_debug("ldrsb %s,%s+%d\n",regname[rt],regname[rs],offset);
764 static void emit_movswl_indexed(int offset, u_int rs, u_int rt)
766 assem_debug("ldrsh %s,%s+%d\n",regname[rt],regname[rs],offset);
770 static void emit_movzbl_indexed(int offset, u_int rs, u_int rt)
772 assem_debug("ldrb %s,%s+%d\n",regname[rt],regname[rs],offset);
776 static void emit_movzwl_indexed(int offset, u_int rs, u_int rt)
778 assem_debug("ldrh %s,%s+%d\n",regname[rt],regname[rs],offset);
782 static void emit_writeword_indexed(u_int rt, int offset, u_int rs)
784 assem_debug("str %s,[%s+%#x]\n", regname[rt], regname[rs], offset);
785 if (!(offset & 3) && offset <= 16380)
786 output_w32(0xb9000000 | imm12_rn_rd(offset >> 2, rs, rt));
791 static void emit_writehword_indexed(u_int rt, int offset, u_int rs)
793 assem_debug("strh %s,[%s+%#x]\n", regname[rt], regname[rs], offset);
794 if (!(offset & 1) && offset <= 8190)
795 output_w32(0x79000000 | imm12_rn_rd(offset >> 1, rs, rt));
800 static void emit_writebyte_indexed(u_int rt, int offset, u_int rs)
802 assem_debug("strb %s,[%s+%#x]\n", regname[rt], regname[rs], offset);
803 if ((u_int)offset < 4096)
804 output_w32(0x39000000 | imm12_rn_rd(offset, rs, rt));
809 static void emit_umull(u_int rs1, u_int rs2, u_int hi, u_int lo)
811 assem_debug("umull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
819 static void emit_smull(u_int rs1, u_int rs2, u_int hi, u_int lo)
821 assem_debug("smull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
829 static void emit_clz(u_int rs,u_int rt)
831 assem_debug("clz %s,%s\n",regname[rt],regname[rs]);
835 // Load 2 immediates optimizing for small code size
836 static void emit_mov2imm_compact(int imm1,u_int rt1,int imm2,u_int rt2)
841 // Conditionally select one of two immediates, optimizing for small code size
842 // This will only be called if HAVE_CMOV_IMM is defined
843 static void emit_cmov2imm_e_ne_compact(int imm1,int imm2,u_int rt)
848 // special case for checking invalid_code
849 static void emit_cmpmem_indexedsr12_reg(int base,u_int r,int imm)
851 assert(imm<128&&imm>=0);
853 assem_debug("ldrb lr,%s,%s lsr #12\n",regname[base],regname[r]);
857 // Used to preload hash table entries
858 static unused void emit_prefetchreg(u_int r)
860 assem_debug("pld %s\n",regname[r]);
864 // Special case for mini_ht
865 static void emit_ldreq_indexed(u_int rs, u_int offset, u_int rt)
868 assem_debug("ldreq %s,[%s, #%#x]\n",regname[rt],regname[rs],offset);
872 static void emit_orrne_imm(u_int rs,int imm,u_int rt)
874 assem_debug("orrne %s,%s,#%#x\n",regname[rt],regname[rs],imm);
878 static void emit_andne_imm(u_int rs,int imm,u_int rt)
880 assem_debug("andne %s,%s,#%#x\n",regname[rt],regname[rs],imm);
884 static unused void emit_addpl_imm(u_int rs,int imm,u_int rt)
886 assem_debug("addpl %s,%s,#%#x\n",regname[rt],regname[rs],imm);
890 static void emit_ldst(int is_st, int is64, u_int rt, u_int rn, u_int ofs)
892 u_int op = 0xb9000000;
893 const char *ldst = is_st ? "st" : "ld";
894 char rp = is64 ? 'x' : 'w';
895 assem_debug("%sr %c%d,[x%d,#%#x]\n", ldst, rp, rt, rn, ofs);
897 assert((ofs & ((1 << (2+is64)) - 1)) == 0);
898 ofs = (ofs >> (2+is64));
899 assert(ofs <= 0xfff);
900 if (!is_st) op |= 0x00400000;
901 if (is64) op |= 0x40000000;
902 output_w32(op | (ofs << 15) | imm12_rn_rd(ofs, rn, rt));
905 static void emit_ldstp(int is_st, int is64, u_int rt1, u_int rt2, u_int rn, int ofs)
907 u_int op = 0x29000000;
908 const char *ldst = is_st ? "st" : "ld";
909 char rp = is64 ? 'x' : 'w';
910 assem_debug("%sp %c%d,%c%d,[x%d,#%#x]\n", ldst, rp, rt1, rp, rt2, rn, ofs);
912 assert((ofs & ((1 << (2+is64)) - 1)) == 0);
913 ofs = (ofs >> (2+is64));
914 assert(-64 <= ofs && ofs <= 63);
916 if (!is_st) op |= 0x00400000;
917 if (is64) op |= 0x80000000;
918 output_w32(op | (ofs << 15) | rm_rn_rd(rt2, rn, rt1));
921 static void save_load_regs_all(int is_store, u_int reglist)
925 for (r = 0; reglist; r++, reglist >>= 1) {
929 emit_ldstp(is_store, 1, pair[0], pair[1], SP, SSP_CALLEE_REGS + ofs);
935 emit_ldst(is_store, 1, pair[0], SP, SSP_CALLEE_REGS + ofs);
938 assert(ofs <= SSP_CALLER_REGS);
941 // Save registers before function call
942 static void save_regs(u_int reglist)
944 reglist &= CALLER_SAVE_REGS; // only save the caller-save registers
945 save_load_regs_all(1, reglist);
948 // Restore registers after function call
949 static void restore_regs(u_int reglist)
951 reglist &= CALLER_SAVE_REGS;
952 save_load_regs_all(0, reglist);
957 static void literal_pool(int n)
962 static void literal_pool_jumpover(int n)
966 static void emit_extjump2(u_char *addr, int target, void *linker)
971 static void emit_extjump(void *addr, int target)
973 emit_extjump2(addr, target, dyna_linker);
976 static void emit_extjump_ds(void *addr, int target)
978 emit_extjump2(addr, target, dyna_linker_ds);
981 // put rt_val into rt, potentially making use of rs with value rs_val
982 static void emit_movimm_from(u_int rs_val, u_int rs, uintptr_t rt_val, u_int rt)
984 intptr_t diff = rt_val - rs_val;
985 if (-4096 < diff && diff < 4096)
986 emit_addimm(rs, diff, rt);
988 // TODO: for inline_writestub, etc
992 // return 1 if above function can do it's job cheaply
993 static int is_similar_value(u_int v1, u_int v2)
996 return -4096 < diff && diff < 4096;
999 //#include "pcsxmem.h"
1000 //#include "pcsxmem_inline.c"
1002 static void do_readstub(int n)
1004 assem_debug("do_readstub %x\n",start+stubs[n].a*4);
1008 static void inline_readstub(enum stub_type type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist)
1013 static void do_writestub(int n)
1015 assem_debug("do_writestub %x\n",start+stubs[n].a*4);
1019 static void inline_writestub(enum stub_type type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist)
1021 int rs = get_reg(regmap,-1);
1022 int rt = get_reg(regmap,target);
1025 uintptr_t host_addr = 0;
1026 void *handler = get_direct_memhandler(mem_wtab, addr, type, &host_addr);
1027 if (handler == NULL) {
1028 if (addr != host_addr)
1029 emit_movimm_from(addr, rs, host_addr, rs);
1031 case STOREB_STUB: emit_writebyte_indexed(rt, 0, rs); break;
1032 case STOREH_STUB: emit_writehword_indexed(rt, 0, rs); break;
1033 case STOREW_STUB: emit_writeword_indexed(rt, 0, rs); break;
1039 // call a memhandler
1041 //pass_args(rs, rt);
1042 int cc = get_reg(regmap, CCREG);
1044 emit_addimm(cc, CLOCK_ADJUST(adj+1), 2);
1045 //emit_movimm((uintptr_t)handler, 3);
1046 // returns new cycle_count
1048 emit_readword(&last_count, HOST_TEMPREG);
1049 emit_writeword(rs, &address); // some handlers still need it
1050 emit_add(2, HOST_TEMPREG, 2);
1051 emit_writeword(2, &Count);
1054 emit_readword(&next_interupt, 0);
1055 emit_readword(&Count, 1);
1056 emit_writeword(0, &last_count);
1059 emit_addimm(cc,-CLOCK_ADJUST(adj+1),cc);
1060 restore_regs(reglist);
1063 static void do_unalignedwritestub(int n)
1065 assem_debug("do_unalignedwritestub %x\n",start+stubs[n].a*4);
1069 static void do_invstub(int n)
1074 void *do_dirty_stub(int i)
1076 assem_debug("do_dirty_stub %x\n",start+i*4);
1077 // Careful about the code output here, verify_dirty needs to parse it.
1083 static void do_dirty_stub_ds()
1085 // Careful about the code output here, verify_dirty needs to parse it.
1091 #define shift_assemble shift_assemble_arm64
1093 static void shift_assemble_arm64(int i,struct regstat *i_regs)
1097 #define loadlr_assemble loadlr_assemble_arm64
1099 static void loadlr_assemble_arm64(int i,struct regstat *i_regs)
1104 static void c2op_assemble(int i,struct regstat *i_regs)
1109 static void multdiv_assemble_arm64(int i,struct regstat *i_regs)
1113 #define multdiv_assemble multdiv_assemble_arm64
1115 static void do_preload_rhash(u_int r) {
1116 // Don't need this for ARM. On x86, this puts the value 0xf8 into the
1117 // register. On ARM the hash can be done with a single instruction (below)
1120 static void do_preload_rhtbl(u_int ht) {
1121 emit_addimm(FP, (u_char *)&mini_ht - (u_char *)&dynarec_local, ht);
1124 static void do_rhash(u_int rs,u_int rh) {
1125 emit_andimm(rs, 0xf8, rh);
1128 static void do_miniht_load(int ht,u_int rh) {
1129 assem_debug("ldr %s,[%s,%s]!\n",regname[rh],regname[ht],regname[rh]);
1133 static void do_miniht_jump(u_int rs,u_int rh,int ht) {
1135 emit_ldreq_indexed(ht,4,15);
1136 //emit_jmp(jump_vaddr_reg[rs]);
1140 static void do_miniht_insert(u_int return_address,u_int rt,int temp) {
1144 static void mark_clear_cache(void *target)
1146 u_long offset = (u_char *)target - translation_cache;
1147 u_int mask = 1u << ((offset >> 12) & 31);
1148 if (!(needs_clear_cache[offset >> 17] & mask)) {
1149 char *start = (char *)((u_long)target & ~4095ul);
1150 start_tcache_write(start, start + 4096);
1151 needs_clear_cache[offset >> 17] |= mask;
1155 // Clearing the cache is rather slow on ARM Linux, so mark the areas
1156 // that need to be cleared, and then only clear these areas once.
1157 static void do_clear_cache()
1160 for (i=0;i<(1<<(TARGET_SIZE_2-17));i++)
1162 u_int bitmap=needs_clear_cache[i];
1164 u_char *start, *end;
1168 start=translation_cache+i*131072+j*4096;
1176 end_tcache_write(start, end);
1182 needs_clear_cache[i]=0;
1187 // CPU-architecture-specific initialization
1188 static void arch_init() {
1191 // vim:shiftwidth=2:expandtab