X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=libpcsxcore%2Fnew_dynarec%2Fassem_arm.c;h=21640f84ad0d2313a934c86e1e544eabea1d9209;hp=da32f5b782f5bb06124024269e028062c7af0fe4;hb=HEAD;hpb=9de8a0c3587effdbd19584cbca3baf566d1d21bd diff --git a/libpcsxcore/new_dynarec/assem_arm.c b/libpcsxcore/new_dynarec/assem_arm.c index da32f5b7..70798eff 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" @@ -194,6 +192,7 @@ static void *find_extjump_insn(void *stub) // get address that insn one after stub loads (dyna_linker arg1), // treat it as a pointer to branch insn, // return addr where that branch jumps to +#if 0 static void *get_pointer(void *stub) { //printf("get_pointer(%x)\n",(int)stub); @@ -201,107 +200,7 @@ static void *get_pointer(void *stub) assert((*i_ptr&0x0f000000)==0x0a000000); // b return (u_char *)i_ptr+((*i_ptr<<8)>>6)+8; } - -// Find the "clean" entry point from a "dirty" entry point -// by skipping past the call to verify_code -static void *get_clean_addr(void *addr) -{ - signed int *ptr = addr; - #ifndef HAVE_ARMV7 - ptr+=4; - #else - ptr+=6; - #endif - if((*ptr&0xFF000000)!=0xeb000000) ptr++; - assert((*ptr&0xFF000000)==0xeb000000); // bl instruction - ptr++; - if((*ptr&0xFF000000)==0xea000000) { - return (char *)ptr+((*ptr<<8)>>6)+8; // follow jump - } - return ptr; -} - -static int verify_dirty(const u_int *ptr) -{ - #ifndef HAVE_ARMV7 - u_int offset; - // get from literal pool - assert((*ptr&0xFFFF0000)==0xe59f0000); - offset=*ptr&0xfff; - u_int source=*(u_int*)((void *)ptr+offset+8); - ptr++; - assert((*ptr&0xFFFF0000)==0xe59f0000); - offset=*ptr&0xfff; - u_int copy=*(u_int*)((void *)ptr+offset+8); - ptr++; - assert((*ptr&0xFFFF0000)==0xe59f0000); - offset=*ptr&0xfff; - u_int len=*(u_int*)((void *)ptr+offset+8); - ptr++; - ptr++; - #else - // ARMv7 movw/movt - assert((*ptr&0xFFF00000)==0xe3000000); - u_int source=(ptr[0]&0xFFF)+((ptr[0]>>4)&0xF000)+((ptr[2]<<16)&0xFFF0000)+((ptr[2]<<12)&0xF0000000); - u_int copy=(ptr[1]&0xFFF)+((ptr[1]>>4)&0xF000)+((ptr[3]<<16)&0xFFF0000)+((ptr[3]<<12)&0xF0000000); - u_int len=(ptr[4]&0xFFF)+((ptr[4]>>4)&0xF000); - ptr+=6; - #endif - if((*ptr&0xFF000000)!=0xeb000000) ptr++; - assert((*ptr&0xFF000000)==0xeb000000); // bl instruction - //printf("verify_dirty: %x %x %x\n",source,copy,len); - return !memcmp((void *)source,(void *)copy,len); -} - -// This doesn't necessarily find all clean entry points, just -// guarantees that it's not dirty -static int isclean(void *addr) -{ - #ifndef HAVE_ARMV7 - u_int *ptr=((u_int *)addr)+4; - #else - u_int *ptr=((u_int *)addr)+6; - #endif - if((*ptr&0xFF000000)!=0xeb000000) ptr++; - if((*ptr&0xFF000000)!=0xeb000000) return 1; // bl instruction - if((int)ptr+((*ptr<<8)>>6)+8==(int)verify_code) return 0; - if((int)ptr+((*ptr<<8)>>6)+8==(int)verify_code_ds) return 0; - return 1; -} - -// get source that block at addr was compiled from (host pointers) -static void get_bounds(void *addr, u_char **start, u_char **end) -{ - u_int *ptr = addr; - #ifndef HAVE_ARMV7 - u_int offset; - // get from literal pool - assert((*ptr&0xFFFF0000)==0xe59f0000); - offset=*ptr&0xfff; - u_int source=*(u_int*)((void *)ptr+offset+8); - ptr++; - //assert((*ptr&0xFFFF0000)==0xe59f0000); - //offset=*ptr&0xfff; - //u_int copy=*(u_int*)((void *)ptr+offset+8); - ptr++; - assert((*ptr&0xFFFF0000)==0xe59f0000); - offset=*ptr&0xfff; - u_int len=*(u_int*)((void *)ptr+offset+8); - ptr++; - ptr++; - #else - // ARMv7 movw/movt - assert((*ptr&0xFFF00000)==0xe3000000); - u_int source=(ptr[0]&0xFFF)+((ptr[0]>>4)&0xF000)+((ptr[2]<<16)&0xFFF0000)+((ptr[2]<<12)&0xF0000000); - //u_int copy=(ptr[1]&0xFFF)+((ptr[1]>>4)&0xF000)+((ptr[3]<<16)&0xFFF0000)+((ptr[3]<<12)&0xF0000000); - u_int len=(ptr[4]&0xFFF)+((ptr[4]>>4)&0xF000); - ptr+=6; - #endif - if((*ptr&0xFF000000)!=0xeb000000) ptr++; - assert((*ptr&0xFF000000)==0xeb000000); // bl instruction - *start=(u_char *)source; - *end=(u_char *)source+len; -} +#endif // Allocate a specific ARM register. static void alloc_arm_reg(struct regstat *cur,int i,signed char reg,int hr) @@ -318,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 */ @@ -452,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]); @@ -522,12 +443,8 @@ static void emit_pcreladdr(u_int rt) static void emit_loadreg(int r, int hr) { - if(r&64) { - SysPrintf("64bit load in 32bit mode!\n"); - assert(0); - return; - } - if((r&63)==0) + assert(hr != EXCLUDE_REG); + if (r == 0) emit_zeroreg(hr); else { void *addr; @@ -535,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: @@ -552,11 +468,7 @@ static void emit_loadreg(int r, int hr) static void emit_storereg(int r, int hr) { - if(r&64) { - SysPrintf("64bit store in 32bit mode!\n"); - assert(0); - return; - } + assert(hr != EXCLUDE_REG); int addr = (int)&psxRegs.GPR.r[r]; switch (r) { //case HIREG: addr = &hi; break; @@ -598,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]); @@ -681,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); @@ -960,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)); @@ -1006,6 +937,12 @@ static void emit_cmp(int rs,int rt) output_w32(0xe1500000|rd_rn_rm(0,rs,rt)); } +static void emit_cmpcs(int rs,int rt) +{ + assem_debug("cmpcs %s,%s\n",regname[rs],regname[rt]); + output_w32(0x21500000|rd_rn_rm(0,rs,rt)); +} + static void emit_set_gz32(int rs, int rt) { //assem_debug("set_gz32\n"); @@ -1110,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_; @@ -1134,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); @@ -1307,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 @@ -1367,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); } @@ -1493,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) @@ -1632,7 +1583,7 @@ static void literal_pool_jumpover(int n) } // parsed by get_pointer, find_extjump_insn -static void emit_extjump2(u_char *addr, u_int target, void *linker) +static void emit_extjump(u_char *addr, u_int target) { u_char *ptr=(u_char *)addr; assert((ptr[3]&0x0e)==0xa); @@ -1642,18 +1593,7 @@ static void emit_extjump2(u_char *addr, u_int target, void *linker) emit_loadlp((u_int)addr,1); assert(ndrc->translation_cache <= addr && addr < ndrc->translation_cache + sizeof(ndrc->translation_cache)); - //assert((target>=0x80000000&&target<0x80800000)||(target>0xA4000000&&target<0xA4001000)); -//DEBUG > -#ifdef DEBUG_CYCLE_COUNT - emit_readword(&last_count,ECX); - emit_add(HOST_CCREG,ECX,HOST_CCREG); - emit_readword(&next_interupt,ECX); - emit_writeword(HOST_CCREG,&Count); - emit_sub(HOST_CCREG,ECX,HOST_CCREG); - emit_writeword(ECX,&last_count); -#endif -//DEBUG < - emit_far_jump(linker); + emit_far_jump(dyna_linker); } static void check_extjump2(void *src) @@ -1734,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); @@ -1761,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; @@ -1794,7 +1734,15 @@ 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 0 + if (type == LOADW_STUB) { + // new cycle_count returned in r2 + emit_addimm(2, -(int)stubs[n].d, cc<0?2:cc); + if (cc < 0) + emit_storereg(CCREG, 2); + } +#endif + if(dops[i].itype==C2LS||(rt>=0&&dops[i].rt1!=0)) { mov_loadtype_adj(type,0,rt); } if(restore_jump) @@ -1806,28 +1754,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; @@ -1848,8 +1795,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) { @@ -1860,11 +1807,19 @@ 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); +#if 0 + if (type == LOADW_STUB) { + // new cycle_count returned in r2 + emit_addimm(2, -adj, cc<0?2:cc); + if (cc < 0) + emit_storereg(CCREG, 2); + } +#endif if(rt>=0&&dops[i].rt1!=0) { switch(type) { case LOADB_STUB: emit_signextend8(0,rt); break; @@ -1890,7 +1845,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); @@ -1948,9 +1903,9 @@ static void do_writestub(int n) if(cc<0) emit_loadreg(CCREG,2); emit_addimm(cc<0?2:cc,(int)stubs[n].d,2); - // returns new cycle_count emit_far_call(handler); - emit_addimm(0,-(int)stubs[n].d,cc<0?2:cc); + // new cycle_count returned in r2 + emit_addimm(2,-(int)stubs[n].d,cc<0?2:cc); if(cc<0) emit_storereg(CCREG,2); if(restore_jump) @@ -1962,19 +1917,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; @@ -1982,56 +1937,20 @@ 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); emit_addimm(cc<0?2:cc,adj,2); emit_movimm((u_int)handler,3); - // returns new cycle_count emit_far_call(jump_handler_write_h); - emit_addimm(0,-adj,cc<0?2:cc); + // new cycle_count returned in r2 + emit_addimm(2,-adj,cc<0?2:cc); if(cc<0) emit_storereg(CCREG,2); restore_regs(reglist); } -// this output is parsed by verify_dirty, get_bounds, isclean, get_clean_addr -static void do_dirty_stub_emit_args(u_int arg0, u_int source_len) -{ - #ifndef HAVE_ARMV7 - emit_loadlp((int)source, 1); - emit_loadlp((int)copy, 2); - emit_loadlp(source_len, 3); - #else - emit_movw(((u_int)source)&0x0000FFFF, 1); - emit_movw(((u_int)copy)&0x0000FFFF, 2); - emit_movt(((u_int)source)&0xFFFF0000, 1); - emit_movt(((u_int)copy)&0xFFFF0000, 2); - emit_movw(source_len, 3); - #endif - emit_movimm(arg0, 0); -} - -static void *do_dirty_stub(int i, u_int source_len) -{ - assem_debug("do_dirty_stub %x\n",start+i*4); - do_dirty_stub_emit_args(start + i*4, source_len); - emit_far_call(verify_code); - void *entry = out; - load_regs_entry(i); - if (entry == out) - entry = instr_addr[i]; - emit_jmp(instr_addr[i]); - return entry; -} - -static void do_dirty_stub_ds(u_int source_len) -{ - do_dirty_stub_emit_args(start + 1, source_len); - emit_far_call(verify_code_ds); -} - /* Special assem */ static void c2op_prologue(u_int op, int i, const struct regstat *i_regs, u_int reglist) @@ -2234,15 +2153,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); @@ -2254,7 +2169,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); @@ -2266,14 +2182,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); @@ -2281,11 +2199,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); @@ -2301,23 +2220,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); @@ -2335,20 +2258,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