X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=libpcsxcore%2Fnew_dynarec%2Fassem_arm64.c;h=df5b5aaa2d0409751429c6b0bfe1e30391801e55;hp=f9c837edae96bf89f5a5a7d43e8d71cc9bc8fac4;hb=687b45804b5c028dd5644bda85981c0235eb4d32;hpb=be516ebe45e48044b599e9d9f9f2d296c3f3ee62 diff --git a/libpcsxcore/new_dynarec/assem_arm64.c b/libpcsxcore/new_dynarec/assem_arm64.c index f9c837ed..df5b5aaa 100644 --- a/libpcsxcore/new_dynarec/assem_arm64.c +++ b/libpcsxcore/new_dynarec/assem_arm64.c @@ -32,13 +32,6 @@ u_char translation_cache[1 << TARGET_SIZE_2] __attribute__((aligned(4096))); #define unused __attribute__((unused)) -extern int cycle_count; -extern int last_count; -extern int pcaddr; -extern int pending_exception; -extern int branch_target; -extern u_int mini_ht[32][2]; - static u_int needs_clear_cache[1<<(TARGET_SIZE_2-17)]; //void indirect_jump_indexed(); @@ -141,13 +134,19 @@ static unused const char *regname[32] = { "r24", "r25", "r26", "r27", "r28", "fp", "lr", "sp" }; -#pragma GCC diagnostic ignored "-Wunused-function" static void output_w32(u_int word) { *((u_int *)out) = word; out += 4; } +static u_int rm_rd(u_int rm, u_int rd) +{ + assert(rm < 31); + assert(rd < 31); + return (rm << 16) | rd; +} + static u_int rm_rn_rd(u_int rm, u_int rn, u_int rd) { assert(rm < 31); @@ -156,6 +155,12 @@ static u_int rm_rn_rd(u_int rm, u_int rn, u_int rd) return (rm << 16) | (rn << 5) | rd; } +static u_int rm_imm6_rn_rd(u_int rm, u_int imm6, u_int rn, u_int rd) +{ + assert(imm6 <= 63); + return rm_rn_rd(rm, rn, rd) | (imm6 << 10); +} + static u_int imm16_rd(u_int imm16, u_int rd) { assert(imm16 < 0x10000); @@ -163,6 +168,15 @@ static u_int imm16_rd(u_int imm16, u_int rd) return (imm16 << 5) | rd; } +static u_int imm12_rn_rd(u_int imm12, u_int rn, u_int rd) +{ + assert(imm12 < 0x1000); + assert(rn < 31); + assert(rd < 31); + return (imm12 << 10) | (rn << 5) | rd; +} + +#pragma GCC diagnostic ignored "-Wunused-function" static u_int genjmp(u_char *addr) { intptr_t offset = addr - out; @@ -191,20 +205,20 @@ static u_int genjmpcc(u_char *addr) static void emit_mov(u_int rs, u_int rt) { - assem_debug("mov %s,%s\n",regname[rt],regname[rs]); - assert(0); + assem_debug("mov %s,%s\n", regname[rt], regname[rs]); + output_w32(0x2a0003e0 | rm_rd(rs, rt)); } static void emit_movs(u_int rs, u_int rt) { - assem_debug("mov %s,%s\n",regname[rt],regname[rs]); - assert(0); + assem_debug("movs %s,%s\n", regname[rt], regname[rs]); + output_w32(0x31000000 | imm12_rn_rd(0, rs, rt)); } -static void emit_add(u_int rs1,u_int rs2,u_int rt) +static void emit_add(u_int rs1, u_int rs2, u_int rt) { - assem_debug("add %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); - assert(0); + assem_debug("add %s, %s, %s\n", regname[rt], regname[rs1], regname[rs2]); + output_w32(0x0b000000 | rm_imm6_rn_rd(rs2, 0, rs1, rt)); } static void emit_sbc(u_int rs1,u_int rs2,u_int rt) @@ -225,10 +239,10 @@ static void emit_negs(u_int rs, u_int rt) assert(0); } -static void emit_sub(u_int rs1,u_int rs2,u_int rt) +static void emit_sub(u_int rs1, u_int rs2, u_int rt) { - assem_debug("sub %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); - assert(0); + assem_debug("sub %s, %s, %s\n", regname[rt], regname[rs1], regname[rs2]); + output_w32(0x4b000000 | rm_imm6_rn_rd(rs2, 0, rs1, rt)); } static void emit_subs(u_int rs1,u_int rs2,u_int rt) @@ -243,22 +257,9 @@ static void emit_zeroreg(u_int rt) assert(0); } -static void emit_movw(u_int imm,u_int rt) -{ - assert(imm<65536); - assem_debug("movw %s,#%d (0x%x)\n",regname[rt],imm,imm); - assert(0); -} - -static void emit_movt(u_int imm,u_int rt) -{ - assem_debug("movt %s,#%d (0x%x)\n",regname[rt],imm&0xffff0000,imm&0xffff0000); - assert(0); -} - static void emit_movimm(u_int imm, u_int rt) { - assem_debug("mov %s,#%x\n", regname[rt], imm); + assem_debug("mov %s,#%#x\n", regname[rt], imm); if ((imm & 0xffff0000) == 0) output_w32(0x52800000 | imm16_rd(imm, rt)); else if ((imm & 0xffff0000) == 0xffff0000) @@ -269,6 +270,17 @@ static void emit_movimm(u_int imm, u_int rt) } } +static void emit_readword(void *addr, u_int rt) +{ + uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local; + if (!(offset & 3) && offset <= 16380) { + assem_debug("ldr %s,[x%d+%#lx]\n", regname[rt], FP, offset); + output_w32(0xb9400000 | imm12_rn_rd(offset >> 2, FP, rt)); + } + else + assert(0); +} + static void emit_loadreg(u_int r, u_int hr) { assert(r < 64); @@ -284,14 +296,22 @@ static void emit_loadreg(u_int r, u_int hr) case INVCP: addr = &invc_ptr; break; default: assert(r < 32); break; } - uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local; - assert(offset < 4096); - assem_debug("ldr %s,fp+%lx\n", regname[hr], offset); - assert(0); + emit_readword(addr, hr); } } -static void emit_storereg(u_int r, int hr) +static void emit_writeword(u_int rt, void *addr) +{ + uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local; + if (!(offset & 3) && offset <= 16380) { + assem_debug("str %s,[x%d+%#lx]\n", regname[rt], FP, offset); + output_w32(0xb9000000 | imm12_rn_rd(offset >> 2, FP, rt)); + } + else + assert(0); +} + +static void emit_storereg(u_int r, u_int hr) { assert(r < 64); void *addr = ®[r]; @@ -301,10 +321,7 @@ static void emit_storereg(u_int r, int hr) case CCREG: addr = &cycle_count; break; default: assert(r < 32); break; } - uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local; - assert(offset < 4096); - assem_debug("str %s,fp+%lx\n", regname[hr], offset); - assert(0); + emit_writeword(hr, addr); } static void emit_test(u_int rs, u_int rt) @@ -315,7 +332,7 @@ static void emit_test(u_int rs, u_int rt) static void emit_testimm(u_int rs,int imm) { - assem_debug("tst %s,#%d\n",regname[rs],imm); + assem_debug("tst %s,#%#x\n", regname[rs], imm); assert(0); } @@ -381,9 +398,16 @@ static void emit_xor(u_int rs1,u_int rs2,u_int rt) static void emit_addimm(u_int rs, uintptr_t imm, u_int rt) { - assert(rs < 31); - assert(rt < 31); - assert(0); + if (imm < 4096) { + assem_debug("add %s,%s,%#lx\n", regname[rt], regname[rs], imm); + output_w32(0x11000000 | imm12_rn_rd(imm, rs, rt)); + } + else if (-imm < 4096) { + assem_debug("sub %s,%s,%#lx\n", regname[rt], regname[rs], imm); + output_w32(0x51000000 | imm12_rn_rd(imm, rs, rt)); + } + else + assert(0); } static void emit_addimm_and_set_flags(int imm, u_int rt) @@ -396,22 +420,15 @@ static void emit_addimm_no_flags(u_int imm,u_int rt) emit_addimm(rt,imm,rt); } -static void emit_addnop(u_int r) -{ - assert(r<16); - assem_debug("add %s,%s,#0 (nop)\n",regname[r],regname[r]); - assert(0); -} - static void emit_adcimm(u_int rs,int imm,u_int rt) { - assem_debug("adc %s,%s,#%d\n",regname[rt],regname[rs],imm); + assem_debug("adc %s,%s,#%#x\n",regname[rt],regname[rs],imm); assert(0); } static void emit_rscimm(u_int rs,int imm,u_int rt) { - assem_debug("rsc %s,%s,#%d\n",regname[rt],regname[rs],imm); + assem_debug("rsc %s,%s,#%#x\n",regname[rt],regname[rs],imm); assert(0); } @@ -540,25 +557,25 @@ static void emit_cmpimm(u_int rs,int imm) static void emit_cmovne_imm(int imm,u_int rt) { - assem_debug("movne %s,#%d\n",regname[rt],imm); + assem_debug("movne %s,#%#x\n",regname[rt],imm); assert(0); } static void emit_cmovl_imm(int imm,u_int rt) { - assem_debug("movlt %s,#%d\n",regname[rt],imm); + assem_debug("movlt %s,#%#x\n",regname[rt],imm); assert(0); } static void emit_cmovb_imm(int imm,u_int rt) { - assem_debug("movcc %s,#%d\n",regname[rt],imm); + assem_debug("movcc %s,#%#x\n",regname[rt],imm); assert(0); } static void emit_cmovs_imm(int imm,u_int rt) { - assem_debug("movmi %s,#%d\n",regname[rt],imm); + assem_debug("movmi %s,#%#x\n",regname[rt],imm); assert(0); } @@ -634,14 +651,18 @@ static void emit_set_if_carry32(u_int rs1, u_int rs2, u_int rt) emit_cmovb_imm(1,rt); } -#pragma GCC diagnostic ignored "-Wunused-variable" static void emit_call(const void *a_) { - uintptr_t a = (uintptr_t)a_; - assem_debug("bl %p (%p+%lx)%s\n", a_, out, (u_char *)a_ - out, func_name(a)); - assert(0); + intptr_t diff = (u_char *)a_ - out; + assem_debug("bl %p (%p+%lx)%s\n", a_, out, diff, func_name(a)); + assert(!(diff & 3)); + if (-134217728 <= diff && diff <= 134217727) + output_w32(0x94000000 | ((diff >> 2) & 0x03ffffff)); + else + assert(0); } +#pragma GCC diagnostic ignored "-Wunused-variable" static void emit_jmp(const void *a_) { uintptr_t a = (uintptr_t)a_; @@ -735,42 +756,6 @@ static void emit_readword_indexed(int offset, u_int rs, u_int rt) assert(0); } -static void emit_readword_dualindexedx4(u_int rs1, u_int rs2, u_int rt) -{ - assem_debug("ldr %s,%s,%s lsl #2\n",regname[rt],regname[rs1],regname[rs2]); - assert(0); -} - -static void emit_ldrcc_dualindexed(u_int rs1, u_int rs2, u_int rt) -{ - assem_debug("ldrcc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); - assert(0); -} - -static void emit_ldrccb_dualindexed(u_int rs1, u_int rs2, u_int rt) -{ - assem_debug("ldrccb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); - assert(0); -} - -static void emit_ldrccsb_dualindexed(u_int rs1, u_int rs2, u_int rt) -{ - assem_debug("ldrccsb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); - assert(0); -} - -static void emit_ldrcch_dualindexed(u_int rs1, u_int rs2, u_int rt) -{ - assem_debug("ldrcch %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); - assert(0); -} - -static void emit_ldrccsh_dualindexed(u_int rs1, u_int rs2, u_int rt) -{ - assem_debug("ldrccsh %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); - assert(0); -} - static void emit_movsbl_indexed(int offset, u_int rs, u_int rt) { assem_debug("ldrsb %s,%s+%d\n",regname[rt],regname[rs],offset); @@ -795,65 +780,31 @@ static void emit_movzwl_indexed(int offset, u_int rs, u_int rt) assert(0); } -static void emit_ldrd(int offset, u_int rs, u_int rt) -{ - assem_debug("ldrd %s,%s+%d\n",regname[rt],regname[rs],offset); - assert(0); -} - -static void emit_readword(void *addr, u_int rt) -{ - uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local; - assert(offset<4096); - assem_debug("ldr %s,fp+%lx\n", regname[rt], offset); - assert(0); -} - static void emit_writeword_indexed(u_int rt, int offset, u_int rs) { - assert(offset>-4096&&offset<4096); - assem_debug("str %s,%s+%x\n",regname[rt],regname[rs],offset); - assert(0); + assem_debug("str %s,[%s+%#x]\n", regname[rt], regname[rs], offset); + if (!(offset & 3) && offset <= 16380) + output_w32(0xb9000000 | imm12_rn_rd(offset >> 2, rs, rt)); + else + assert(0); } static void emit_writehword_indexed(u_int rt, int offset, u_int rs) { - assert(offset>-256&&offset<256); - assem_debug("strh %s,%s+%d\n",regname[rt],regname[rs],offset); - assert(0); + assem_debug("strh %s,[%s+%#x]\n", regname[rt], regname[rs], offset); + if (!(offset & 1) && offset <= 8190) + output_w32(0x79000000 | imm12_rn_rd(offset >> 1, rs, rt)); + else + assert(0); } static void emit_writebyte_indexed(u_int rt, int offset, u_int rs) { - assert(offset>-4096&&offset<4096); - assem_debug("strb %s,%s+%d\n",regname[rt],regname[rs],offset); - assert(0); -} - -static void emit_strcc_dualindexed(u_int rs1, u_int rs2, u_int rt) -{ - assem_debug("strcc %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); - assert(0); -} - -static void emit_strccb_dualindexed(u_int rs1, u_int rs2, u_int rt) -{ - assem_debug("strccb %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); - assert(0); -} - -static void emit_strcch_dualindexed(u_int rs1, u_int rs2, u_int rt) -{ - assem_debug("strcch %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); - assert(0); -} - -static void emit_writeword(u_int rt, void *addr) -{ - uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local; - assert(offset<4096); - assem_debug("str %s,fp+%lx\n", regname[rt], offset); - assert(0); + assem_debug("strb %s,[%s+%#x]\n", regname[rt], regname[rs], offset); + if ((u_int)offset < 4096) + output_w32(0x39000000 | imm12_rn_rd(offset, rs, rt)); + else + assert(0); } static void emit_umull(u_int rs1, u_int rs2, u_int hi, u_int lo) @@ -915,52 +866,91 @@ static unused void emit_prefetchreg(u_int r) static void emit_ldreq_indexed(u_int rs, u_int offset, u_int rt) { assert(offset<4096); - assem_debug("ldreq %s,[%s, #%d]\n",regname[rt],regname[rs],offset); + assem_debug("ldreq %s,[%s, #%#x]\n",regname[rt],regname[rs],offset); assert(0); } static void emit_orrne_imm(u_int rs,int imm,u_int rt) { - assem_debug("orrne %s,%s,#%d\n",regname[rt],regname[rs],imm); + assem_debug("orrne %s,%s,#%#x\n",regname[rt],regname[rs],imm); assert(0); } static void emit_andne_imm(u_int rs,int imm,u_int rt) { - assem_debug("andne %s,%s,#%d\n",regname[rt],regname[rs],imm); + assem_debug("andne %s,%s,#%#x\n",regname[rt],regname[rs],imm); assert(0); } static unused void emit_addpl_imm(u_int rs,int imm,u_int rt) { - assem_debug("addpl %s,%s,#%d\n",regname[rt],regname[rs],imm); + assem_debug("addpl %s,%s,#%#x\n",regname[rt],regname[rs],imm); assert(0); } -static void save_regs_all(u_int reglist) +static void emit_ldst(int is_st, int is64, u_int rt, u_int rn, u_int ofs) { - if(!reglist) return; - assert(0); + u_int op = 0xb9000000; + const char *ldst = is_st ? "st" : "ld"; + char rp = is64 ? 'x' : 'w'; + assem_debug("%sr %c%d,[x%d,#%#x]\n", ldst, rp, rt, rn, ofs); + is64 = is64 ? 1 : 0; + assert((ofs & ((1 << (2+is64)) - 1)) == 0); + ofs = (ofs >> (2+is64)); + assert(ofs <= 0xfff); + if (!is_st) op |= 0x00400000; + if (is64) op |= 0x40000000; + output_w32(op | (ofs << 15) | imm12_rn_rd(ofs, rn, rt)); } -static void restore_regs_all(u_int reglist) +static void emit_ldstp(int is_st, int is64, u_int rt1, u_int rt2, u_int rn, int ofs) { - if(!reglist) return; - assert(0); + u_int op = 0x29000000; + const char *ldst = is_st ? "st" : "ld"; + char rp = is64 ? 'x' : 'w'; + assem_debug("%sp %c%d,%c%d,[x%d,#%#x]\n", ldst, rp, rt1, rp, rt2, rn, ofs); + is64 = is64 ? 1 : 0; + assert((ofs & ((1 << (2+is64)) - 1)) == 0); + ofs = (ofs >> (2+is64)); + assert(-64 <= ofs && ofs <= 63); + ofs &= 0x7f; + if (!is_st) op |= 0x00400000; + if (is64) op |= 0x80000000; + output_w32(op | (ofs << 15) | rm_rn_rd(rt2, rn, rt1)); +} + +static void save_load_regs_all(int is_store, u_int reglist) +{ + int ofs = 0, c = 0; + u_int r, pair[2]; + for (r = 0; reglist; r++, reglist >>= 1) { + if (reglist & 1) + pair[c++] = r; + if (c == 2) { + emit_ldstp(is_store, 1, pair[0], pair[1], SP, SSP_CALLEE_REGS + ofs); + ofs += 8 * 2; + c = 0; + } + } + if (c) { + emit_ldst(is_store, 1, pair[0], SP, SSP_CALLEE_REGS + ofs); + ofs += 8; + } + assert(ofs <= SSP_CALLER_REGS); } // Save registers before function call static void save_regs(u_int reglist) { reglist &= CALLER_SAVE_REGS; // only save the caller-save registers - save_regs_all(reglist); + save_load_regs_all(1, reglist); } // Restore registers after function call static void restore_regs(u_int reglist) { reglist &= CALLER_SAVE_REGS; - restore_regs_all(reglist); + save_load_regs_all(0, reglist); } /* Stubs/epilogue */ @@ -990,16 +980,21 @@ static void emit_extjump_ds(void *addr, int target) } // put rt_val into rt, potentially making use of rs with value rs_val -static void emit_movimm_from(u_int rs_val,u_int rs,u_int rt_val,u_int rt) +static void emit_movimm_from(u_int rs_val, u_int rs, uintptr_t rt_val, u_int rt) { - assert(0); + intptr_t diff = rt_val - rs_val; + if (-4096 < diff && diff < 4096) + emit_addimm(rs, diff, rt); + else + // TODO: for inline_writestub, etc + assert(0); } // return 1 if above function can do it's job cheaply -static int is_similar_value(u_int v1,u_int v2) +static int is_similar_value(u_int v1, u_int v2) { - assert(0); - return 0; + int diff = v1 - v2; + return -4096 < diff && diff < 4096; } //#include "pcsxmem.h" @@ -1024,7 +1019,46 @@ static void do_writestub(int n) static void inline_writestub(enum stub_type type, int i, u_int addr, signed char regmap[], int target, int adj, u_int reglist) { - assert(0); + int rs = get_reg(regmap,-1); + int rt = get_reg(regmap,target); + assert(rs >= 0); + assert(rt >= 0); + uintptr_t host_addr = 0; + void *handler = get_direct_memhandler(mem_wtab, addr, type, &host_addr); + if (handler == NULL) { + if (addr != host_addr) + emit_movimm_from(addr, rs, host_addr, rs); + switch(type) { + case STOREB_STUB: emit_writebyte_indexed(rt, 0, rs); break; + case STOREH_STUB: emit_writehword_indexed(rt, 0, rs); break; + case STOREW_STUB: emit_writeword_indexed(rt, 0, rs); break; + default: assert(0); + } + return; + } + + // call a memhandler + save_regs(reglist); + //pass_args(rs, rt); + int cc = get_reg(regmap, CCREG); + assert(cc >= 0); + emit_addimm(cc, CLOCK_ADJUST(adj+1), 2); + //emit_movimm((uintptr_t)handler, 3); + // returns new cycle_count + + emit_readword(&last_count, HOST_TEMPREG); + emit_writeword(rs, &address); // some handlers still need it + emit_add(2, HOST_TEMPREG, 2); + emit_writeword(2, &Count); + emit_mov(1, 0); + emit_call(handler); + emit_readword(&next_interupt, 0); + emit_readword(&Count, 1); + emit_writeword(0, &last_count); + emit_sub(1, 0, cc); + + emit_addimm(cc,-CLOCK_ADJUST(adj+1),cc); + restore_regs(reglist); } static void do_unalignedwritestub(int n)