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 extern int cycle_count;
36 extern int last_count;
38 extern int pending_exception;
39 extern int branch_target;
40 extern u_int mini_ht[32][2];
42 static u_int needs_clear_cache[1<<(TARGET_SIZE_2-17)];
44 //void indirect_jump_indexed();
45 //void indirect_jump();
47 //void jump_vaddr_r0();
49 void * const jump_vaddr_reg[32];
53 static void set_jump_target(void *addr, void *target_)
58 // from a pointer to external jump stub (which was produced by emit_extjump2)
59 // find where the jumping insn is
60 static void *find_extjump_insn(void *stub)
66 // find where external branch is liked to using addr of it's stub:
67 // get address that insn one after stub loads (dyna_linker arg1),
68 // treat it as a pointer to branch insn,
69 // return addr where that branch jumps to
70 static void *get_pointer(void *stub)
72 //printf("get_pointer(%x)\n",(int)stub);
77 // Find the "clean" entry point from a "dirty" entry point
78 // by skipping past the call to verify_code
79 static void *get_clean_addr(void *addr)
85 static int verify_dirty(u_int *ptr)
91 // This doesn't necessarily find all clean entry points, just
92 // guarantees that it's not dirty
93 static int isclean(void *addr)
99 // get source that block at addr was compiled from (host pointers)
100 static void get_bounds(void *addr, u_char **start, u_char **end)
105 // Allocate a specific ARM register.
106 static void alloc_arm_reg(struct regstat *cur,int i,signed char reg,int hr)
111 // see if it's already allocated (and dealloc it)
112 for(n=0;n<HOST_REGS;n++)
114 if(n!=EXCLUDE_REG&&cur->regmap[n]==reg) {
115 dirty=(cur->dirty>>n)&1;
121 cur->dirty&=~(1<<hr);
122 cur->dirty|=dirty<<hr;
123 cur->isconst&=~(1<<hr);
126 // Alloc cycle count into dedicated register
127 static void alloc_cc(struct regstat *cur,int i)
129 alloc_arm_reg(cur,i,CCREG,HOST_CCREG);
137 static unused const char *regname[32] = {
138 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
139 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
140 "ip0", "ip1", "r18", "r19", "r20", "r21", "r22", "r23"
141 "r24", "r25", "r26", "r27", "r28", "fp", "lr", "sp"
144 #pragma GCC diagnostic ignored "-Wunused-function"
145 static void output_w32(u_int word)
147 *((u_int *)out) = word;
151 static u_int rm_rn_rd(u_int rm, u_int rn, u_int rd)
156 return (rm << 16) | (rn << 5) | rd;
159 static u_int imm16_rd(u_int imm16, u_int rd)
161 assert(imm16 < 0x10000);
163 return (imm16 << 5) | rd;
166 static u_int genjmp(u_char *addr)
168 intptr_t offset = addr - out;
169 if (offset < -134217728 || offset > 134217727) {
170 if ((uintptr_t)addr > 2) {
171 SysPrintf("%s: out of range: %08x\n", __func__, offset);
176 return ((u_int)offset >> 2) & 0x01ffffff;
179 static u_int genjmpcc(u_char *addr)
181 intptr_t offset = addr - out;
182 if (offset < -1048576 || offset > 1048572) {
183 if ((uintptr_t)addr > 2) {
184 SysPrintf("%s: out of range: %08x\n", __func__, offset);
189 return ((u_int)offset >> 2) & 0xfffff;
192 static void emit_mov(u_int rs, u_int rt)
194 assem_debug("mov %s,%s\n",regname[rt],regname[rs]);
198 static void emit_movs(u_int rs, u_int rt)
200 assem_debug("mov %s,%s\n",regname[rt],regname[rs]);
204 static void emit_add(u_int rs1,u_int rs2,u_int rt)
206 assem_debug("add %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
210 static void emit_sbc(u_int rs1,u_int rs2,u_int rt)
212 assem_debug("sbc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
216 static void emit_neg(u_int rs, u_int rt)
218 assem_debug("rsb %s,%s,#0\n",regname[rt],regname[rs]);
222 static void emit_negs(u_int rs, u_int rt)
224 assem_debug("rsbs %s,%s,#0\n",regname[rt],regname[rs]);
228 static void emit_sub(u_int rs1,u_int rs2,u_int rt)
230 assem_debug("sub %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
234 static void emit_subs(u_int rs1,u_int rs2,u_int rt)
236 assem_debug("subs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
240 static void emit_zeroreg(u_int rt)
242 assem_debug("mov %s,#0\n",regname[rt]);
246 static void emit_movw(u_int imm,u_int rt)
249 assem_debug("movw %s,#%d (0x%x)\n",regname[rt],imm,imm);
253 static void emit_movt(u_int imm,u_int rt)
255 assem_debug("movt %s,#%d (0x%x)\n",regname[rt],imm&0xffff0000,imm&0xffff0000);
259 static void emit_movimm(u_int imm, u_int rt)
261 assem_debug("mov %s,#%x\n", regname[rt], imm);
262 if ((imm & 0xffff0000) == 0)
263 output_w32(0x52800000 | imm16_rd(imm, rt));
264 else if ((imm & 0xffff0000) == 0xffff0000)
267 output_w32(0x52800000 | imm16_rd(imm & 0xffff, rt));
268 output_w32(0x72a00000 | imm16_rd(imm >> 16, rt));
272 static void emit_loadreg(u_int r, u_int hr)
278 void *addr = ®[r];
280 case HIREG: addr = &hi; break;
281 case LOREG: addr = &lo; break;
282 case CCREG: addr = &cycle_count; break;
283 case CSREG: addr = &Status; break;
284 case INVCP: addr = &invc_ptr; break;
285 default: assert(r < 32); break;
287 uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
288 assert(offset < 4096);
289 assem_debug("ldr %s,fp+%lx\n", regname[hr], offset);
294 static void emit_storereg(u_int r, int hr)
297 void *addr = ®[r];
299 case HIREG: addr = &hi; break;
300 case LOREG: addr = &lo; break;
301 case CCREG: addr = &cycle_count; break;
302 default: assert(r < 32); break;
304 uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
305 assert(offset < 4096);
306 assem_debug("str %s,fp+%lx\n", regname[hr], offset);
310 static void emit_test(u_int rs, u_int rt)
312 assem_debug("tst %s,%s\n",regname[rs],regname[rt]);
316 static void emit_testimm(u_int rs,int imm)
318 assem_debug("tst %s,#%d\n",regname[rs],imm);
322 static void emit_testeqimm(u_int rs,int imm)
324 assem_debug("tsteq %s,$%d\n",regname[rs],imm);
328 static void emit_not(u_int rs,u_int rt)
330 assem_debug("mvn %s,%s\n",regname[rt],regname[rs]);
334 static void emit_mvnmi(u_int rs,u_int rt)
336 assem_debug("mvnmi %s,%s\n",regname[rt],regname[rs]);
340 static void emit_and(u_int rs1,u_int rs2,u_int rt)
342 assem_debug("and %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
346 static void emit_or(u_int rs1,u_int rs2,u_int rt)
348 assem_debug("orr %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
352 static void emit_orrshl_imm(u_int rs,u_int imm,u_int rt)
357 assem_debug("orr %s,%s,%s,lsl #%d\n",regname[rt],regname[rt],regname[rs],imm);
361 static void emit_orrshr_imm(u_int rs,u_int imm,u_int rt)
366 assem_debug("orr %s,%s,%s,lsr #%d\n",regname[rt],regname[rt],regname[rs],imm);
370 static void emit_or_and_set_flags(u_int rs1,u_int rs2,u_int rt)
372 assem_debug("orrs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
376 static void emit_xor(u_int rs1,u_int rs2,u_int rt)
378 assem_debug("eor %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
382 static void emit_addimm(u_int rs, uintptr_t imm, u_int rt)
389 static void emit_addimm_and_set_flags(int imm, u_int rt)
394 static void emit_addimm_no_flags(u_int imm,u_int rt)
396 emit_addimm(rt,imm,rt);
399 static void emit_addnop(u_int r)
402 assem_debug("add %s,%s,#0 (nop)\n",regname[r],regname[r]);
406 static void emit_adcimm(u_int rs,int imm,u_int rt)
408 assem_debug("adc %s,%s,#%d\n",regname[rt],regname[rs],imm);
412 static void emit_rscimm(u_int rs,int imm,u_int rt)
414 assem_debug("rsc %s,%s,#%d\n",regname[rt],regname[rs],imm);
418 static void emit_addimm64_32(u_int rsh,u_int rsl,int imm,u_int rth,u_int rtl)
423 static void emit_andimm(u_int rs,int imm,u_int rt)
428 static void emit_orimm(u_int rs,int imm,u_int rt)
433 static void emit_xorimm(u_int rs,int imm,u_int rt)
438 static void emit_shlimm(u_int rs,u_int imm,u_int rt)
442 assem_debug("lsl %s,%s,#%d\n",regname[rt],regname[rs],imm);
446 static void emit_lsls_imm(u_int rs,int imm,u_int rt)
450 assem_debug("lsls %s,%s,#%d\n",regname[rt],regname[rs],imm);
454 static unused void emit_lslpls_imm(u_int rs,int imm,u_int rt)
458 assem_debug("lslpls %s,%s,#%d\n",regname[rt],regname[rs],imm);
462 static void emit_shrimm(u_int rs,u_int imm,u_int rt)
466 assem_debug("lsr %s,%s,#%d\n",regname[rt],regname[rs],imm);
470 static void emit_sarimm(u_int rs,u_int imm,u_int rt)
474 assem_debug("asr %s,%s,#%d\n",regname[rt],regname[rs],imm);
478 static void emit_rorimm(u_int rs,u_int imm,u_int rt)
482 assem_debug("ror %s,%s,#%d\n",regname[rt],regname[rs],imm);
486 static void emit_signextend16(u_int rs, u_int rt)
488 assem_debug("sxth %s,%s\n", regname[rt], regname[rs]);
492 static void emit_shl(u_int rs,u_int shift,u_int rt)
500 static void emit_shr(u_int rs,u_int shift,u_int rt)
505 assem_debug("lsr %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
509 static void emit_sar(u_int rs,u_int shift,u_int rt)
514 assem_debug("asr %s,%s,%s\n",regname[rt],regname[rs],regname[shift]);
518 static void emit_orrshl(u_int rs,u_int shift,u_int rt)
523 assem_debug("orr %s,%s,%s,lsl %s\n",regname[rt],regname[rt],regname[rs],regname[shift]);
527 static void emit_orrshr(u_int rs,u_int shift,u_int rt)
532 assem_debug("orr %s,%s,%s,lsr %s\n",regname[rt],regname[rt],regname[rs],regname[shift]);
536 static void emit_cmpimm(u_int rs,int imm)
541 static void emit_cmovne_imm(int imm,u_int rt)
543 assem_debug("movne %s,#%d\n",regname[rt],imm);
547 static void emit_cmovl_imm(int imm,u_int rt)
549 assem_debug("movlt %s,#%d\n",regname[rt],imm);
553 static void emit_cmovb_imm(int imm,u_int rt)
555 assem_debug("movcc %s,#%d\n",regname[rt],imm);
559 static void emit_cmovs_imm(int imm,u_int rt)
561 assem_debug("movmi %s,#%d\n",regname[rt],imm);
565 static void emit_cmovne_reg(u_int rs,u_int rt)
567 assem_debug("movne %s,%s\n",regname[rt],regname[rs]);
571 static void emit_cmovl_reg(u_int rs,u_int rt)
573 assem_debug("movlt %s,%s\n",regname[rt],regname[rs]);
577 static void emit_cmovs_reg(u_int rs,u_int rt)
579 assem_debug("movmi %s,%s\n",regname[rt],regname[rs]);
583 static void emit_slti32(u_int rs,int imm,u_int rt)
585 if(rs!=rt) emit_zeroreg(rt);
587 if(rs==rt) emit_movimm(0,rt);
588 emit_cmovl_imm(1,rt);
591 static void emit_sltiu32(u_int rs,int imm,u_int rt)
593 if(rs!=rt) emit_zeroreg(rt);
595 if(rs==rt) emit_movimm(0,rt);
596 emit_cmovb_imm(1,rt);
599 static void emit_cmp(u_int rs,u_int rt)
601 assem_debug("cmp %s,%s\n",regname[rs],regname[rt]);
605 static void emit_set_gz32(u_int rs, u_int rt)
607 //assem_debug("set_gz32\n");
610 emit_cmovl_imm(0,rt);
613 static void emit_set_nz32(u_int rs, u_int rt)
615 //assem_debug("set_nz32\n");
619 static void emit_set_if_less32(u_int rs1, u_int rs2, u_int rt)
621 //assem_debug("set if less (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]);
622 if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt);
624 if(rs1==rt||rs2==rt) emit_movimm(0,rt);
625 emit_cmovl_imm(1,rt);
628 static void emit_set_if_carry32(u_int rs1, u_int rs2, u_int rt)
630 //assem_debug("set if carry (%%%s,%%%s),%%%s\n",regname[rs1],regname[rs2],regname[rt]);
631 if(rs1!=rt&&rs2!=rt) emit_zeroreg(rt);
633 if(rs1==rt||rs2==rt) emit_movimm(0,rt);
634 emit_cmovb_imm(1,rt);
637 #pragma GCC diagnostic ignored "-Wunused-variable"
638 static void emit_call(const void *a_)
640 uintptr_t a = (uintptr_t)a_;
641 assem_debug("bl %p (%p+%lx)%s\n", a_, out, (u_char *)a_ - out, func_name(a));
645 static void emit_jmp(const void *a_)
647 uintptr_t a = (uintptr_t)a_;
648 assem_debug("b %p (%p+%lx)%s\n", a_, out, (u_char *)a_ - out, func_name(a));
652 static void emit_jne(const void *a_)
654 uintptr_t a = (uintptr_t)a_;
655 assem_debug("bne %p\n", a_);
659 static void emit_jeq(int a)
661 assem_debug("beq %x\n",a);
665 static void emit_js(int a)
667 assem_debug("bmi %x\n",a);
671 static void emit_jns(int a)
673 assem_debug("bpl %x\n",a);
677 static void emit_jl(int a)
679 assem_debug("blt %x\n",a);
683 static void emit_jge(int a)
685 assem_debug("bge %x\n",a);
689 static void emit_jno(int a)
691 assem_debug("bvc %x\n",a);
695 static void emit_jc(int a)
697 assem_debug("bcs %x\n",a);
701 static void emit_jcc(void *a_)
703 uintptr_t a = (uintptr_t)a_;
704 assem_debug("bcc %p\n", a_);
708 static void emit_callreg(u_int r)
711 assem_debug("blx %s\n", regname[r]);
715 static void emit_jmpreg(u_int r)
717 assem_debug("mov pc,%s\n",regname[r]);
721 static void emit_retreg(u_int r)
723 assem_debug("ret %s\n", r == LR ? "" : regname[r]);
724 output_w32(0xd65f0000 | rm_rn_rd(0, r, 0));
727 static void emit_ret(void)
732 static void emit_readword_indexed(int offset, u_int rs, u_int rt)
734 assem_debug("ldr %s,%s+%d\n",regname[rt],regname[rs],offset);
738 static void emit_readword_dualindexedx4(u_int rs1, u_int rs2, u_int rt)
740 assem_debug("ldr %s,%s,%s lsl #2\n",regname[rt],regname[rs1],regname[rs2]);
744 static void emit_ldrcc_dualindexed(u_int rs1, u_int rs2, u_int rt)
746 assem_debug("ldrcc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
750 static void emit_ldrccb_dualindexed(u_int rs1, u_int rs2, u_int rt)
752 assem_debug("ldrccb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
756 static void emit_ldrccsb_dualindexed(u_int rs1, u_int rs2, u_int rt)
758 assem_debug("ldrccsb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
762 static void emit_ldrcch_dualindexed(u_int rs1, u_int rs2, u_int rt)
764 assem_debug("ldrcch %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
768 static void emit_ldrccsh_dualindexed(u_int rs1, u_int rs2, u_int rt)
770 assem_debug("ldrccsh %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
774 static void emit_movsbl_indexed(int offset, u_int rs, u_int rt)
776 assem_debug("ldrsb %s,%s+%d\n",regname[rt],regname[rs],offset);
780 static void emit_movswl_indexed(int offset, u_int rs, u_int rt)
782 assem_debug("ldrsh %s,%s+%d\n",regname[rt],regname[rs],offset);
786 static void emit_movzbl_indexed(int offset, u_int rs, u_int rt)
788 assem_debug("ldrb %s,%s+%d\n",regname[rt],regname[rs],offset);
792 static void emit_movzwl_indexed(int offset, u_int rs, u_int rt)
794 assem_debug("ldrh %s,%s+%d\n",regname[rt],regname[rs],offset);
798 static void emit_ldrd(int offset, u_int rs, u_int rt)
800 assem_debug("ldrd %s,%s+%d\n",regname[rt],regname[rs],offset);
804 static void emit_readword(void *addr, u_int rt)
806 uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
808 assem_debug("ldr %s,fp+%lx\n", regname[rt], offset);
812 static void emit_writeword_indexed(u_int rt, int offset, u_int rs)
814 assert(offset>-4096&&offset<4096);
815 assem_debug("str %s,%s+%x\n",regname[rt],regname[rs],offset);
819 static void emit_writehword_indexed(u_int rt, int offset, u_int rs)
821 assert(offset>-256&&offset<256);
822 assem_debug("strh %s,%s+%d\n",regname[rt],regname[rs],offset);
826 static void emit_writebyte_indexed(u_int rt, int offset, u_int rs)
828 assert(offset>-4096&&offset<4096);
829 assem_debug("strb %s,%s+%d\n",regname[rt],regname[rs],offset);
833 static void emit_strcc_dualindexed(u_int rs1, u_int rs2, u_int rt)
835 assem_debug("strcc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
839 static void emit_strccb_dualindexed(u_int rs1, u_int rs2, u_int rt)
841 assem_debug("strccb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
845 static void emit_strcch_dualindexed(u_int rs1, u_int rs2, u_int rt)
847 assem_debug("strcch %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]);
851 static void emit_writeword(u_int rt, void *addr)
853 uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local;
855 assem_debug("str %s,fp+%lx\n", regname[rt], offset);
859 static void emit_umull(u_int rs1, u_int rs2, u_int hi, u_int lo)
861 assem_debug("umull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
869 static void emit_smull(u_int rs1, u_int rs2, u_int hi, u_int lo)
871 assem_debug("smull %s, %s, %s, %s\n",regname[lo],regname[hi],regname[rs1],regname[rs2]);
879 static void emit_clz(u_int rs,u_int rt)
881 assem_debug("clz %s,%s\n",regname[rt],regname[rs]);
885 // Load 2 immediates optimizing for small code size
886 static void emit_mov2imm_compact(int imm1,u_int rt1,int imm2,u_int rt2)
891 // Conditionally select one of two immediates, optimizing for small code size
892 // This will only be called if HAVE_CMOV_IMM is defined
893 static void emit_cmov2imm_e_ne_compact(int imm1,int imm2,u_int rt)
898 // special case for checking invalid_code
899 static void emit_cmpmem_indexedsr12_reg(int base,u_int r,int imm)
901 assert(imm<128&&imm>=0);
903 assem_debug("ldrb lr,%s,%s lsr #12\n",regname[base],regname[r]);
907 // Used to preload hash table entries
908 static unused void emit_prefetchreg(u_int r)
910 assem_debug("pld %s\n",regname[r]);
914 // Special case for mini_ht
915 static void emit_ldreq_indexed(u_int rs, u_int offset, u_int rt)
918 assem_debug("ldreq %s,[%s, #%d]\n",regname[rt],regname[rs],offset);
922 static void emit_orrne_imm(u_int rs,int imm,u_int rt)
924 assem_debug("orrne %s,%s,#%d\n",regname[rt],regname[rs],imm);
928 static void emit_andne_imm(u_int rs,int imm,u_int rt)
930 assem_debug("andne %s,%s,#%d\n",regname[rt],regname[rs],imm);
934 static unused void emit_addpl_imm(u_int rs,int imm,u_int rt)
936 assem_debug("addpl %s,%s,#%d\n",regname[rt],regname[rs],imm);
940 static void save_regs_all(u_int reglist)
946 static void restore_regs_all(u_int reglist)
952 // Save registers before function call
953 static void save_regs(u_int reglist)
955 reglist &= CALLER_SAVE_REGS; // only save the caller-save registers
956 save_regs_all(reglist);
959 // Restore registers after function call
960 static void restore_regs(u_int reglist)
962 reglist &= CALLER_SAVE_REGS;
963 restore_regs_all(reglist);
968 static void literal_pool(int n)
973 static void literal_pool_jumpover(int n)
977 static void emit_extjump2(u_char *addr, int target, void *linker)
982 static void emit_extjump(void *addr, int target)
984 emit_extjump2(addr, target, dyna_linker);
987 static void emit_extjump_ds(void *addr, int target)
989 emit_extjump2(addr, target, dyna_linker_ds);
992 // put rt_val into rt, potentially making use of rs with value rs_val
993 static void emit_movimm_from(u_int rs_val,u_int rs,u_int rt_val,u_int rt)
998 // return 1 if above function can do it's job cheaply
999 static int is_similar_value(u_int v1,u_int v2)
1005 //#include "pcsxmem.h"
1006 //#include "pcsxmem_inline.c"
1008 static void do_readstub(int n)
1010 assem_debug("do_readstub %x\n",start+stubs[n].a*4);
1014 static void inline_readstub(enum stub_type type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist)
1019 static void do_writestub(int n)
1021 assem_debug("do_writestub %x\n",start+stubs[n].a*4);
1025 static void inline_writestub(enum stub_type type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist)
1030 static void do_unalignedwritestub(int n)
1032 assem_debug("do_unalignedwritestub %x\n",start+stubs[n].a*4);
1036 static void do_invstub(int n)
1041 void *do_dirty_stub(int i)
1043 assem_debug("do_dirty_stub %x\n",start+i*4);
1044 // Careful about the code output here, verify_dirty needs to parse it.
1050 static void do_dirty_stub_ds()
1052 // Careful about the code output here, verify_dirty needs to parse it.
1058 #define shift_assemble shift_assemble_arm64
1060 static void shift_assemble_arm64(int i,struct regstat *i_regs)
1064 #define loadlr_assemble loadlr_assemble_arm64
1066 static void loadlr_assemble_arm64(int i,struct regstat *i_regs)
1071 static void c2op_assemble(int i,struct regstat *i_regs)
1076 static void multdiv_assemble_arm64(int i,struct regstat *i_regs)
1080 #define multdiv_assemble multdiv_assemble_arm64
1082 static void do_preload_rhash(u_int r) {
1083 // Don't need this for ARM. On x86, this puts the value 0xf8 into the
1084 // register. On ARM the hash can be done with a single instruction (below)
1087 static void do_preload_rhtbl(u_int ht) {
1088 emit_addimm(FP, (u_char *)&mini_ht - (u_char *)&dynarec_local, ht);
1091 static void do_rhash(u_int rs,u_int rh) {
1092 emit_andimm(rs, 0xf8, rh);
1095 static void do_miniht_load(int ht,u_int rh) {
1096 assem_debug("ldr %s,[%s,%s]!\n",regname[rh],regname[ht],regname[rh]);
1100 static void do_miniht_jump(u_int rs,u_int rh,int ht) {
1102 emit_ldreq_indexed(ht,4,15);
1103 //emit_jmp(jump_vaddr_reg[rs]);
1107 static void do_miniht_insert(u_int return_address,u_int rt,int temp) {
1111 static void mark_clear_cache(void *target)
1113 u_long offset = (u_char *)target - translation_cache;
1114 u_int mask = 1u << ((offset >> 12) & 31);
1115 if (!(needs_clear_cache[offset >> 17] & mask)) {
1116 char *start = (char *)((u_long)target & ~4095ul);
1117 start_tcache_write(start, start + 4096);
1118 needs_clear_cache[offset >> 17] |= mask;
1122 // Clearing the cache is rather slow on ARM Linux, so mark the areas
1123 // that need to be cleared, and then only clear these areas once.
1124 static void do_clear_cache()
1127 for (i=0;i<(1<<(TARGET_SIZE_2-17));i++)
1129 u_int bitmap=needs_clear_cache[i];
1131 u_char *start, *end;
1135 start=translation_cache+i*131072+j*4096;
1143 end_tcache_write(start, end);
1149 needs_clear_cache[i]=0;
1154 // CPU-architecture-specific initialization
1155 static void arch_init() {
1158 // vim:shiftwidth=2:expandtab