X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libpcsxcore%2Fnew_dynarec%2Fassem_arm.c;h=bdb81b4d5f8599ca639326e3eefe9de6ccf1a4d2;hb=65722e0455a2a42eece5e67ce2e92bfac03e1368;hp=6570f1e807fce17621b61ef9abacee43d8a6d360;hpb=882a08fc49541450bc403b2e920e4bccc257dfdf;p=pcsx_rearmed.git diff --git a/libpcsxcore/new_dynarec/assem_arm.c b/libpcsxcore/new_dynarec/assem_arm.c index 6570f1e8..bdb81b4d 100644 --- a/libpcsxcore/new_dynarec/assem_arm.c +++ b/libpcsxcore/new_dynarec/assem_arm.c @@ -27,8 +27,6 @@ #include "pcnt.h" #include "arm_features.h" -#define unused __attribute__((unused)) - #ifdef DRC_DBG #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-variable" @@ -219,16 +217,26 @@ static void alloc_arm_reg(struct regstat *cur,int i,signed char reg,int hr) } } - cur->regmap[hr]=reg; - cur->dirty&=~(1<dirty|=dirty<isconst&=~(1<regmap[hr] < 0 || !((cur->noevict >> hr) & 1)); + cur->regmap[hr] = reg; + cur->dirty &= ~(1 << hr); + cur->dirty |= dirty << hr; + cur->isconst &= ~(1u << hr); + cur->noevict |= 1u << hr; } // Alloc cycle count into dedicated register -static void alloc_cc(struct regstat *cur,int i) +static void alloc_cc(struct regstat *cur, int i) { - alloc_arm_reg(cur,i,CCREG,HOST_CCREG); + alloc_arm_reg(cur, i, CCREG, HOST_CCREG); +} + +static void alloc_cc_optional(struct regstat *cur, int i) +{ + if (cur->regmap[HOST_CCREG] < 0) { + alloc_arm_reg(cur, i, CCREG, HOST_CCREG); + cur->noevict &= ~(1u << HOST_CCREG); + } } /* Assembler */ @@ -353,12 +361,24 @@ static void emit_neg(int rs, int rt) output_w32(0xe2600000|rd_rn_rm(rt,rs,0)); } +static void emit_negs(int rs, int rt) +{ + assem_debug("rsbs %s,%s,#0\n",regname[rt],regname[rs]); + output_w32(0xe2700000|rd_rn_rm(rt,rs,0)); +} + static void emit_sub(int rs1,int rs2,int rt) { assem_debug("sub %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); output_w32(0xe0400000|rd_rn_rm(rt,rs1,rs2)); } +static void emit_subs(int rs1,int rs2,int rt) +{ + assem_debug("subs %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); + output_w32(0xe0500000|rd_rn_rm(rt,rs1,rs2)); +} + static void emit_zeroreg(int rt) { assem_debug("mov %s,#0\n",regname[rt]); @@ -432,7 +452,6 @@ static void emit_loadreg(int r, int hr) //case HIREG: addr = &hi; break; //case LOREG: addr = &lo; break; case CCREG: addr = &cycle_count; break; - case CSREG: addr = &Status; break; case INVCP: addr = &invc_ptr; break; case ROREG: addr = &ram_offset; break; default: @@ -491,6 +510,12 @@ static void emit_not(int rs,int rt) output_w32(0xe1e00000|rd_rn_rm(rt,0,rs)); } +static void emit_mvneq(int rs,int rt) +{ + assem_debug("mvneq %s,%s\n",regname[rt],regname[rs]); + output_w32(0x01e00000|rd_rn_rm(rt,0,rs)); +} + static void emit_and(u_int rs1,u_int rs2,u_int rt) { assem_debug("and %s,%s,%s\n",regname[rt],regname[rs1],regname[rs2]); @@ -574,29 +599,42 @@ static void emit_addimm(u_int rs,int imm,u_int rt) else if(rs!=rt) emit_mov(rs,rt); } -static void emit_addimm_and_set_flags(int imm,int rt) +static void emit_addimm_ptr(u_int rs, uintptr_t imm, u_int rt) +{ + emit_addimm(rs, imm, rt); +} + +static void emit_addimm_and_set_flags3(u_int rs, int imm, u_int rt) { assert(imm>-65536&&imm<65536); u_int armval; - if(genimm(imm,&armval)) { - assem_debug("adds %s,%s,#%d\n",regname[rt],regname[rt],imm); - output_w32(0xe2900000|rd_rn_rm(rt,rt,0)|armval); - }else if(genimm(-imm,&armval)) { - assem_debug("subs %s,%s,#%d\n",regname[rt],regname[rt],imm); - output_w32(0xe2500000|rd_rn_rm(rt,rt,0)|armval); - }else if(imm<0) { - assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF00); + if (genimm(imm, &armval)) { + assem_debug("adds %s,%s,#%d\n",regname[rt],regname[rs],imm); + output_w32(0xe2900000|rd_rn_rm(rt,rs,0)|armval); + } else if (genimm(-imm, &armval)) { + assem_debug("subs %s,%s,#%d\n",regname[rt],regname[rs],imm); + output_w32(0xe2500000|rd_rn_rm(rt,rs,0)|armval); + } else if (rs != rt) { + emit_movimm(imm, rt); + emit_adds(rs, rt, rt); + } else if (imm < 0) { + assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],(-imm)&0xFF00); assem_debug("subs %s,%s,#%d\n",regname[rt],regname[rt],(-imm)&0xFF); - output_w32(0xe2400000|rd_rn_imm_shift(rt,rt,(-imm)>>8,8)); + output_w32(0xe2400000|rd_rn_imm_shift(rt,rs,(-imm)>>8,8)); output_w32(0xe2500000|rd_rn_imm_shift(rt,rt,(-imm)&0xff,0)); - }else{ - assem_debug("add %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF00); + } else { + assem_debug("add %s,%s,#%d\n",regname[rt],regname[rs],imm&0xFF00); assem_debug("adds %s,%s,#%d\n",regname[rt],regname[rt],imm&0xFF); - output_w32(0xe2800000|rd_rn_imm_shift(rt,rt,imm>>8,8)); + output_w32(0xe2800000|rd_rn_imm_shift(rt,rs,imm>>8,8)); output_w32(0xe2900000|rd_rn_imm_shift(rt,rt,imm&0xff,0)); } } +static void emit_addimm_and_set_flags(int imm, u_int rt) +{ + emit_addimm_and_set_flags3(rt, imm, rt); +} + static void emit_addnop(u_int r) { assert(r<16); @@ -853,7 +891,7 @@ static void emit_cmovs_imm(int imm,int rt) output_w32(0x43a00000|rd_rn_rm(rt,0,0)|armval); } -static void emit_cmovne_reg(int rs,int rt) +static unused void emit_cmovne_reg(int rs,int rt) { assem_debug("movne %s,%s\n",regname[rt],regname[rs]); output_w32(0x11a00000|rd_rn_rm(rt,0,rs)); @@ -1009,6 +1047,14 @@ static void emit_jge(const void *a_) output_w32(0xaa000000|offset); } +static void emit_jo(const void *a_) +{ + int a = (int)a_; + assem_debug("bvs %x\n",a); + u_int offset=genjmp(a); + output_w32(0x6a000000|offset); +} + static void emit_jno(const void *a_) { int a = (int)a_; @@ -1033,6 +1079,15 @@ static void emit_jcc(const void *a_) output_w32(0x3a000000|offset); } +static void *emit_cbz(int rs, const void *a) +{ + void *ret; + emit_test(rs, rs); + ret = out; + emit_jeq(a); + return ret; +} + static unused void emit_callreg(u_int r) { assert(r<15); @@ -1206,7 +1261,7 @@ static void emit_readword(void *addr, int rt) { uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local; assert(offset<4096); - assem_debug("ldr %s,fp+%d\n",regname[rt],offset); + assem_debug("ldr %s,fp+%#x%s\n", regname[rt], offset, fpofs_name(offset)); output_w32(0xe5900000|rd_rn_rm(rt,FP,0)|offset); } #define emit_readptr emit_readword @@ -1266,7 +1321,7 @@ static void emit_writeword(int rt, void *addr) { uintptr_t offset = (u_char *)addr - (u_char *)&dynarec_local; assert(offset<4096); - assem_debug("str %s,fp+%d\n",regname[rt],offset); + assem_debug("str %s,fp+%#x%s\n", regname[rt], offset, fpofs_name(offset)); output_w32(0xe5800000|rd_rn_rm(rt,FP,0)|offset); } @@ -1392,13 +1447,10 @@ static void emit_cmov2imm_e_ne_compact(int imm1,int imm2,u_int rt) } // special case for checking invalid_code -static void emit_cmpmem_indexedsr12_reg(int base,int r,int imm) +static void emit_ldrb_indexedsr12_reg(int base, int r, int rt) { - assert(imm<128&&imm>=0); - assert(r>=0&&r<16); - assem_debug("ldrb lr,%s,%s lsr #12\n",regname[base],regname[r]); - output_w32(0xe7d00000|rd_rn_rm(HOST_TEMPREG,base,r)|0x620); - emit_cmpimm(HOST_TEMPREG,imm); + assem_debug("ldrb %s,%s,%s lsr #12\n",regname[rt],regname[base],regname[r]); + output_w32(0xe7d00000|rd_rn_rm(rt,base,r)|0x620); } static void emit_callne(int a) @@ -1622,7 +1674,7 @@ static void do_readstub(int n) u_int reglist=stubs[n].e; const signed char *i_regmap=i_regs->regmap; int rt; - if(dops[i].itype==C1LS||dops[i].itype==C2LS||dops[i].itype==LOADLR) { + if(dops[i].itype==C2LS||dops[i].itype==LOADLR) { rt=get_reg(i_regmap,FTEMP); }else{ rt=get_reg(i_regmap,dops[i].rt1); @@ -1649,7 +1701,7 @@ static void do_readstub(int n) emit_shrimm(rs,12,temp2); emit_readword_dualindexedx4(temp,temp2,temp2); emit_lsls_imm(temp2,1,temp2); - if(dops[i].itype==C1LS||dops[i].itype==C2LS||(rt>=0&&dops[i].rt1!=0)) { + if(dops[i].itype==C2LS||(rt>=0&&dops[i].rt1!=0)) { switch(type) { case LOADB_STUB: emit_ldrccsb_dualindexed(temp2,rs,rt); break; case LOADBU_STUB: emit_ldrccb_dualindexed(temp2,rs,rt); break; @@ -1682,7 +1734,7 @@ static void do_readstub(int n) emit_loadreg(CCREG,2); emit_addimm(cc<0?2:cc,(int)stubs[n].d,2); emit_far_call(handler); - if(dops[i].itype==C1LS||dops[i].itype==C2LS||(rt>=0&&dops[i].rt1!=0)) { + if(dops[i].itype==C2LS||(rt>=0&&dops[i].rt1!=0)) { mov_loadtype_adj(type,0,rt); } if(restore_jump) @@ -1694,28 +1746,27 @@ static void do_readstub(int n) static void inline_readstub(enum stub_type type, int i, u_int addr, const signed char regmap[], int target, int adj, u_int reglist) { - int rs=get_reg(regmap,target); - int rt=get_reg(regmap,target); - if(rs<0) rs=get_reg_temp(regmap); - assert(rs>=0); + int ra = cinfo[i].addr; + int rt = get_reg(regmap,target); + assert(ra >= 0); u_int is_dynamic; uintptr_t host_addr = 0; void *handler; int cc=get_reg(regmap,CCREG); - if(pcsx_direct_read(type,addr,adj,cc,target?rs:-1,rt)) + if(pcsx_direct_read(type,addr,adj,cc,target?ra:-1,rt)) return; handler = get_direct_memhandler(mem_rtab, addr, type, &host_addr); if (handler == NULL) { if(rt<0||dops[i].rt1==0) return; if(addr!=host_addr) - emit_movimm_from(addr,rs,host_addr,rs); + emit_movimm_from(addr,ra,host_addr,ra); switch(type) { - case LOADB_STUB: emit_movsbl_indexed(0,rs,rt); break; - case LOADBU_STUB: emit_movzbl_indexed(0,rs,rt); break; - case LOADH_STUB: emit_movswl_indexed(0,rs,rt); break; - case LOADHU_STUB: emit_movzwl_indexed(0,rs,rt); break; - case LOADW_STUB: emit_readword_indexed(0,rs,rt); break; + case LOADB_STUB: emit_movsbl_indexed(0,ra,rt); break; + case LOADBU_STUB: emit_movzbl_indexed(0,ra,rt); break; + case LOADH_STUB: emit_movswl_indexed(0,ra,rt); break; + case LOADHU_STUB: emit_movzwl_indexed(0,ra,rt); break; + case LOADW_STUB: emit_readword_indexed(0,ra,rt); break; default: assert(0); } return; @@ -1736,8 +1787,8 @@ static void inline_readstub(enum stub_type type, int i, u_int addr, save_regs(reglist); if(target==0) emit_movimm(addr,0); - else if(rs!=0) - emit_mov(rs,0); + else if(ra!=0) + emit_mov(ra,0); if(cc<0) emit_loadreg(CCREG,2); if(is_dynamic) { @@ -1748,7 +1799,7 @@ static void inline_readstub(enum stub_type type, int i, u_int addr, emit_readword(&last_count,3); emit_addimm(cc<0?2:cc,adj,2); emit_add(2,3,2); - emit_writeword(2,&Count); + emit_writeword(2,&psxRegs.cycle); } emit_far_call(handler); @@ -1778,7 +1829,7 @@ static void do_writestub(int n) u_int reglist=stubs[n].e; const signed char *i_regmap=i_regs->regmap; int rt,r; - if(dops[i].itype==C1LS||dops[i].itype==C2LS) { + if(dops[i].itype==C2LS) { rt=get_reg(i_regmap,r=FTEMP); }else{ rt=get_reg(i_regmap,r=dops[i].rs2); @@ -1850,19 +1901,19 @@ static void do_writestub(int n) static void inline_writestub(enum stub_type type, int i, u_int addr, const signed char regmap[], int target, int adj, u_int reglist) { - int rs=get_reg_temp(regmap); - int rt=get_reg(regmap,target); - assert(rs>=0); + int ra = cinfo[i].addr; + int rt = get_reg(regmap, target); + assert(ra>=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); + emit_movimm_from(addr,ra,host_addr,ra); 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; + case STOREB_STUB: emit_writebyte_indexed(rt,0,ra); break; + case STOREH_STUB: emit_writehword_indexed(rt,0,ra); break; + case STOREW_STUB: emit_writeword_indexed(rt,0,ra); break; default: assert(0); } return; @@ -1870,7 +1921,7 @@ static void inline_writestub(enum stub_type type, int i, u_int addr, // call a memhandler save_regs(reglist); - pass_args(rs,rt); + pass_args(ra,rt); int cc=get_reg(regmap,CCREG); if(cc<0) emit_loadreg(CCREG,2); @@ -2086,15 +2137,11 @@ static void multdiv_assemble_arm(int i, const struct regstat *i_regs) // case 0x19: MULTU // case 0x1A: DIV // case 0x1B: DIVU - // case 0x1C: DMULT - // case 0x1D: DMULTU - // case 0x1E: DDIV - // case 0x1F: DDIVU if(dops[i].rs1&&dops[i].rs2) { - if((dops[i].opcode2&4)==0) // 32-bit + switch (dops[i].opcode2) { - if(dops[i].opcode2==0x18) // MULT + case 0x18: // MULT { signed char m1=get_reg(i_regs->regmap,dops[i].rs1); signed char m2=get_reg(i_regs->regmap,dops[i].rs2); @@ -2106,7 +2153,8 @@ static void multdiv_assemble_arm(int i, const struct regstat *i_regs) assert(lo>=0); emit_smull(m1,m2,hi,lo); } - if(dops[i].opcode2==0x19) // MULTU + break; + case 0x19: // MULTU { signed char m1=get_reg(i_regs->regmap,dops[i].rs1); signed char m2=get_reg(i_regs->regmap,dops[i].rs2); @@ -2118,14 +2166,16 @@ static void multdiv_assemble_arm(int i, const struct regstat *i_regs) assert(lo>=0); emit_umull(m1,m2,hi,lo); } - if(dops[i].opcode2==0x1A) // DIV + break; + case 0x1A: // DIV { signed char d1=get_reg(i_regs->regmap,dops[i].rs1); signed char d2=get_reg(i_regs->regmap,dops[i].rs2); - assert(d1>=0); - assert(d2>=0); signed char quotient=get_reg(i_regs->regmap,LOREG); signed char remainder=get_reg(i_regs->regmap,HIREG); + void *jaddr_div0; + assert(d1>=0); + assert(d2>=0); assert(quotient>=0); assert(remainder>=0); emit_movs(d1,remainder); @@ -2133,11 +2183,12 @@ static void multdiv_assemble_arm(int i, const struct regstat *i_regs) emit_negmi(quotient,quotient); // .. quotient and .. emit_negmi(remainder,remainder); // .. remainder for div0 case (will be negated back after jump) emit_movs(d2,HOST_TEMPREG); - emit_jeq(out+52); // Division by zero + jaddr_div0 = out; + emit_jeq(0); // Division by zero emit_negsmi(HOST_TEMPREG,HOST_TEMPREG); #ifdef HAVE_ARMV5 emit_clz(HOST_TEMPREG,quotient); - emit_shl(HOST_TEMPREG,quotient,HOST_TEMPREG); + emit_shl(HOST_TEMPREG,quotient,HOST_TEMPREG); // shifted divisor #else emit_movimm(0,quotient); emit_addpl_imm(quotient,1,quotient); @@ -2153,23 +2204,27 @@ static void multdiv_assemble_arm(int i, const struct regstat *i_regs) emit_jcc(out-16); // -4 emit_teq(d1,d2); emit_negmi(quotient,quotient); + set_jump_target(jaddr_div0, out); emit_test(d1,d1); emit_negmi(remainder,remainder); } - if(dops[i].opcode2==0x1B) // DIVU + break; + case 0x1B: // DIVU { signed char d1=get_reg(i_regs->regmap,dops[i].rs1); // dividend signed char d2=get_reg(i_regs->regmap,dops[i].rs2); // divisor - assert(d1>=0); - assert(d2>=0); signed char quotient=get_reg(i_regs->regmap,LOREG); signed char remainder=get_reg(i_regs->regmap,HIREG); + void *jaddr_div0; + assert(d1>=0); + assert(d2>=0); assert(quotient>=0); assert(remainder>=0); emit_mov(d1,remainder); emit_movimm(0xffffffff,quotient); // div0 case emit_test(d2,d2); - emit_jeq(out+40); // Division by zero + jaddr_div0 = out; + emit_jeq(0); // Division by zero #ifdef HAVE_ARMV5 emit_clz(d2,HOST_TEMPREG); emit_movimm(1<<31,quotient); @@ -2187,20 +2242,54 @@ static void multdiv_assemble_arm(int i, const struct regstat *i_regs) emit_adcs(quotient,quotient,quotient); emit_shrcc_imm(d2,1,d2); emit_jcc(out-16); // -4 + set_jump_target(jaddr_div0, out); } + break; } - else // 64-bit - assert(0); } else { - // Multiply by zero is zero. - // MIPS does not have a divide by zero exception. - // The result is undefined, we return zero. signed char hr=get_reg(i_regs->regmap,HIREG); signed char lr=get_reg(i_regs->regmap,LOREG); - if(hr>=0) emit_zeroreg(hr); - if(lr>=0) emit_zeroreg(lr); + if ((dops[i].opcode2==0x1A || dops[i].opcode2==0x1B) && dops[i].rs2==0) // div 0 + { + if (dops[i].rs1) { + signed char numerator = get_reg(i_regs->regmap, dops[i].rs1); + assert(numerator >= 0); + if (hr < 0) + hr = HOST_TEMPREG; + emit_movs(numerator, hr); + if (lr >= 0) { + if (dops[i].opcode2 == 0x1A) { // DIV + emit_movimm(0xffffffff, lr); + emit_negmi(lr, lr); + } + else + emit_movimm(~0, lr); + } + } + else { + if (hr >= 0) emit_zeroreg(hr); + if (lr >= 0) emit_movimm(~0,lr); + } + } + else if ((dops[i].opcode2==0x1A || dops[i].opcode2==0x1B) && dops[i].rs1==0) + { + signed char denominator = get_reg(i_regs->regmap, dops[i].rs2); + assert(denominator >= 0); + if (hr >= 0) emit_zeroreg(hr); + if (lr >= 0) { + emit_zeroreg(lr); + emit_test(denominator, denominator); + emit_mvneq(lr, lr); + } + } + else + { + // Multiply by zero is zero. + if (hr >= 0) emit_zeroreg(hr); + if (lr >= 0) emit_zeroreg(lr); + } } } #define multdiv_assemble multdiv_assemble_arm