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=ddbfafaa6394073664528eefdbc750ab8e48ea19;hp=57c6e917e4ad3ff6debdd8bf54a1cb5fc9a9dd48;hb=82ed88ebe25a0312aab83623b5a983bd96f3d830;hpb=13e35c04a17506ac0848d7fb089fa817b3d697e9 diff --git a/libpcsxcore/new_dynarec/assem_arm.c b/libpcsxcore/new_dynarec/assem_arm.c index 57c6e917..ddbfafaa 100644 --- a/libpcsxcore/new_dynarec/assem_arm.c +++ b/libpcsxcore/new_dynarec/assem_arm.c @@ -19,6 +19,12 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#ifdef PCSX +#include "../gte_arm.h" +#include "../gte_neon.h" +#include "pcnt.h" +#endif + extern int cycle_count; extern int last_count; extern int pcaddr; @@ -245,6 +251,7 @@ int verify_dirty(int addr) #endif if((*ptr&0xFF000000)!=0xeb000000) ptr++; assert((*ptr&0xFF000000)==0xeb000000); // bl instruction +#ifndef DISABLE_TLB u_int verifier=(int)ptr+((signed int)(*ptr<<8)>>6)+8; // get target of bl if(verifier==(u_int)verify_code_vm||verifier==(u_int)verify_code_ds) { unsigned int page=source>>12; @@ -255,6 +262,7 @@ int verify_dirty(int addr) } source = source+(map_value<<2); } +#endif //printf("verify_dirty: %x %x %x\n",source,copy,len); return !memcmp((void *)source,(void *)copy,len); } @@ -298,11 +306,13 @@ void get_bounds(int addr,u_int *start,u_int *end) #endif if((*ptr&0xFF000000)!=0xeb000000) ptr++; assert((*ptr&0xFF000000)==0xeb000000); // bl instruction +#ifndef DISABLE_TLB u_int verifier=(int)ptr+((signed int)(*ptr<<8)>>6)+8; // get target of bl if(verifier==(u_int)verify_code_vm||verifier==(u_int)verify_code_ds) { if(memory_map[source>>12]>=0x80000000) source = 0; else source = source+(memory_map[source>>12]<<2); } +#endif *start=source; *end=source+len; } @@ -1920,6 +1930,16 @@ void emit_movzwl_indexed(int offset, int rs, int rt) output_w32(0xe15000b0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf)); } } +static void emit_ldrd(int offset, int rs, int rt) +{ + assert(offset>-256&&offset<256); + assem_debug("ldrd %s,%s+%d\n",regname[rt],regname[rs],offset); + if(offset>=0) { + output_w32(0xe1c000d0|rd_rn_rm(rt,rs,0)|((offset<<4)&0xf00)|(offset&0xf)); + }else{ + output_w32(0xe14000d0|rd_rn_rm(rt,rs,0)|(((-offset)<<4)&0xf00)|((-offset)&0xf)); + } +} void emit_readword(int addr, int rt) { u_int offset = addr-(u_int)&dynarec_local; @@ -2154,6 +2174,14 @@ void emit_shrcc_imm(int rs,u_int imm,int rt) output_w32(0x31a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7)); } +void emit_shrne_imm(int rs,u_int imm,int rt) +{ + assert(imm>0); + assert(imm<32); + assem_debug("lsrne %s,%s,#%d\n",regname[rt],regname[rs],imm); + output_w32(0x11a00000|rd_rn_rm(rt,0,rs)|0x20|(imm<<7)); +} + void emit_negmi(int rs, int rt) { assem_debug("rsbmi %s,%s,#0\n",regname[rt],regname[rs]); @@ -2556,34 +2584,40 @@ void emit_jno_unlikely(int a) output_w32(0x72800000|rd_rn_rm(15,15,0)); } -// Save registers before function call -void save_regs(u_int reglist) +static void save_regs_all(u_int reglist) { - reglist&=0x100f; // only save the caller-save registers, r0-r3, r12 + int i; if(!reglist) return; assem_debug("stmia fp,{"); - if(reglist&1) assem_debug("r0, "); - if(reglist&2) assem_debug("r1, "); - if(reglist&4) assem_debug("r2, "); - if(reglist&8) assem_debug("r3, "); - if(reglist&0x1000) assem_debug("r12"); + for(i=0;i<16;i++) + if(reglist&(1<=0&&rt1[i]!=0)) { - switch(type) { - case LOADB_STUB: emit_signextend8(0,rt); break; - case LOADBU_STUB: emit_andimm(0,0xff,rt); break; - case LOADH_STUB: emit_signextend16(0,rt); break; - case LOADHU_STUB: emit_andimm(0,0xffff,rt); break; - case LOADW_STUB: if(rt!=0) emit_mov(0,rt); break; - } + mov_loadtype_adj(type,0,rt); } if(restore_jump) set_jump_target(restore_jump,(int)out); @@ -2914,7 +2971,10 @@ inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, i if(rs<0) rs=get_reg(regmap,-1); assert(rs>=0); #ifdef PCSX - u_int handler,host_addr=0; + u_int handler,host_addr=0,is_dynamic,far_call=0; + int cc=get_reg(regmap,CCREG); + if(pcsx_direct_read(type,addr,CLOCK_ADJUST(adj+1),cc,target?rs:-1,rt)) + return; handler=get_direct_memhandler(mem_rtab,addr,type,&host_addr); if (handler==0) { if(rt<0) @@ -2931,6 +2991,15 @@ inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, i } return; } + is_dynamic=pcsxmem_is_handler_dynamic(addr); + if(is_dynamic) { + if(type==LOADB_STUB||type==LOADBU_STUB) + handler=(int)jump_handler_read8; + if(type==LOADH_STUB||type==LOADHU_STUB) + handler=(int)jump_handler_read16; + if(type==LOADW_STUB) + handler=(int)jump_handler_read32; + } // call a memhandler if(rt>=0) @@ -2940,22 +3009,30 @@ inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, i emit_movimm(addr,0); else if(rs!=0) emit_mov(rs,0); - int cc=get_reg(regmap,CCREG); - if(cc<0) - emit_loadreg(CCREG,2); - emit_readword((int)&last_count,3); - emit_addimm(cc<0?2:cc,CLOCK_DIVIDER*(adj+1),2); - emit_add(2,3,3); - emit_writeword(3,(int)&Count); - int offset=(int)handler-(int)out-8; if(offset<-33554432||offset>=33554432) { // unreachable memhandler, a plugin func perhaps - emit_movimm(handler,1); - emit_callreg(1); + emit_movimm(handler,12); + far_call=1; + } + if(cc<0) + emit_loadreg(CCREG,2); + if(is_dynamic) { + emit_movimm(((u_int *)mem_rtab)[addr>>12]<<1,1); + emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2); + } + else { + emit_readword((int)&last_count,3); + emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2); + emit_add(2,3,2); + emit_writeword(2,(int)&Count); } + + if(far_call) + emit_callreg(12); else emit_call(handler); + if(rt>=0) { switch(type) { case LOADB_STUB: emit_signextend8(0,rt); break; @@ -3005,7 +3082,7 @@ inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, i //emit_movimm(ftable,0); emit_movimm(((u_int *)ftable)[addr>>16],0); //emit_readword((int)&last_count,12); - emit_addimm(cc<0?2:cc,CLOCK_DIVIDER*(adj+1),2); + emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2); #ifndef PCSX if((signed int)addr>=(signed int)0xC0000000) { // Pagefault address @@ -3022,7 +3099,7 @@ inline_readstub(int type, int i, u_int addr, signed char regmap[], int target, i // but not doing so causes random crashes... emit_readword((int)&Count,HOST_TEMPREG); emit_readword((int)&next_interupt,2); - emit_addimm(HOST_TEMPREG,-CLOCK_DIVIDER*(adj+1),HOST_TEMPREG); + emit_addimm(HOST_TEMPREG,-CLOCK_ADJUST(adj+1),HOST_TEMPREG); emit_writeword(2,(int)&last_count); emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc); if(cc<0) { @@ -3122,10 +3199,10 @@ do_writestub(int n) int cc=get_reg(i_regmap,CCREG); if(cc<0) emit_loadreg(CCREG,2); - emit_addimm(cc<0?2:cc,CLOCK_DIVIDER*stubs[n][6]+2,2); + emit_addimm(cc<0?2:cc,CLOCK_ADJUST((int)stubs[n][6]+1),2); // returns new cycle_count emit_call(handler); - emit_addimm(0,-CLOCK_DIVIDER*stubs[n][6]-2,cc<0?2:cc); + emit_addimm(0,-CLOCK_ADJUST((int)stubs[n][6]+1),cc<0?2:cc); if(cc<0) emit_storereg(CCREG,2); if(restore_jump) @@ -3237,11 +3314,11 @@ inline_writestub(int type, int i, u_int addr, signed char regmap[], int target, int cc=get_reg(regmap,CCREG); if(cc<0) emit_loadreg(CCREG,2); - emit_addimm(cc<0?2:cc,CLOCK_DIVIDER*(adj+1),2); + emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2); emit_movimm(handler,3); // returns new cycle_count emit_call((int)jump_handler_write_h); - emit_addimm(0,-CLOCK_DIVIDER*(adj+1),cc<0?2:cc); + emit_addimm(0,-CLOCK_ADJUST(adj+1),cc<0?2:cc); if(cc<0) emit_storereg(CCREG,2); restore_regs(reglist); @@ -3298,7 +3375,7 @@ inline_writestub(int type, int i, u_int addr, signed char regmap[], int target, //emit_movimm(ftable,0); emit_movimm(((u_int *)ftable)[addr>>16],0); //emit_readword((int)&last_count,12); - emit_addimm(cc<0?2:cc,CLOCK_DIVIDER*(adj+1),2); + emit_addimm(cc<0?2:cc,CLOCK_ADJUST(adj+1),2); #ifndef PCSX if((signed int)addr>=(signed int)0xC0000000) { // Pagefault address @@ -3312,7 +3389,7 @@ inline_writestub(int type, int i, u_int addr, signed char regmap[], int target, emit_call((int)&indirect_jump); emit_readword((int)&Count,HOST_TEMPREG); emit_readword((int)&next_interupt,2); - emit_addimm(HOST_TEMPREG,-CLOCK_DIVIDER*(adj+1),HOST_TEMPREG); + emit_addimm(HOST_TEMPREG,-CLOCK_ADJUST(adj+1),HOST_TEMPREG); emit_writeword(2,(int)&last_count); emit_sub(HOST_TEMPREG,2,cc<0?HOST_TEMPREG:cc); if(cc<0) { @@ -3351,9 +3428,9 @@ do_unalignedwritestub(int n) int cc=get_reg(i_regmap,CCREG); if(cc<0) emit_loadreg(CCREG,2); - emit_addimm(cc<0?2:cc,CLOCK_DIVIDER*stubs[n][6]+2,2); + emit_addimm(cc<0?2:cc,CLOCK_ADJUST((int)stubs[n][6]+1),2); emit_call((int)(opcode[i]==0x2a?jump_handle_swl:jump_handle_swr)); - emit_addimm(0,-CLOCK_DIVIDER*stubs[n][6]-2,cc<0?2:cc); + emit_addimm(0,-CLOCK_ADJUST((int)stubs[n][6]+1),cc<0?2:cc); if(cc<0) emit_storereg(CCREG,2); restore_regs(reglist); @@ -3504,10 +3581,12 @@ do_cop1stub(int n) wb_dirtys(i_regs->regmap_entry,i_regs->was32,i_regs->wasdirty); if(regs[i].regmap_entry[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); emit_movimm(start+(i-ds)*4,EAX); // Get PC - emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); // CHECK: is this right? There should probably be an extra cycle... + emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG); // CHECK: is this right? There should probably be an extra cycle... emit_jmp(ds?(int)fp_exception_ds:(int)fp_exception); } +#ifndef DISABLE_TLB + /* TLB */ int do_tlb_r(int s,int ar,int map,int x,int a,int shift,int c,u_int addr) @@ -3591,6 +3670,17 @@ generate_map_const(u_int addr,int reg) { emit_movimm((addr>>12)+(((u_int)memory_map-(u_int)&dynarec_local)>>2),reg); } +#else + +static int do_tlb_r() { return 0; } +static int do_tlb_r_branch() { return 0; } +static int gen_tlb_addr_r() { return 0; } +static int do_tlb_w() { return 0; } +static int do_tlb_w_branch() { return 0; } +static int gen_tlb_addr_w() { return 0; } + +#endif // DISABLE_TLB + /* Special assem */ void shift_assemble_arm(int i,struct regstat *i_regs) @@ -4046,7 +4136,7 @@ void cop0_assemble(int i,struct regstat *i_regs) emit_readword((int)&last_count,ECX); emit_loadreg(CCREG,HOST_CCREG); // TODO: do proper reg alloc emit_add(HOST_CCREG,ECX,HOST_CCREG); - emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG); emit_writeword(HOST_CCREG,(int)&Count); } emit_call((int)MFC0); @@ -4061,19 +4151,21 @@ void cop0_assemble(int i,struct regstat *i_regs) signed char s=get_reg(i_regs->regmap,rs1[i]); char copr=(source[i]>>11)&0x1f; assert(s>=0); +#ifdef MUPEN64 emit_writeword(s,(int)&readmem_dword); wb_register(rs1[i],i_regs->regmap,i_regs->dirty,i_regs->is32); -#ifdef MUPEN64 emit_addimm(FP,(int)&fake_pc-(int)&dynarec_local,0); emit_movimm((source[i]>>11)&0x1f,1); emit_writeword(0,(int)&PC); emit_writebyte(1,(int)&(fake_pc.f.r.nrd)); +#else + wb_register(rs1[i],i_regs->regmap,i_regs->dirty,i_regs->is32); #endif if(copr==9||copr==11||copr==12||copr==13) { - emit_readword((int)&last_count,ECX); + emit_readword((int)&last_count,HOST_TEMPREG); emit_loadreg(CCREG,HOST_CCREG); // TODO: do proper reg alloc - emit_add(HOST_CCREG,ECX,HOST_CCREG); - emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); + emit_add(HOST_CCREG,HOST_TEMPREG,HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG); emit_writeword(HOST_CCREG,(int)&Count); } // What a mess. The status register (12) can enable interrupts, @@ -4089,19 +4181,23 @@ void cop0_assemble(int i,struct regstat *i_regs) emit_writeword(HOST_CCREG,(int)&last_count); emit_movimm(0,HOST_CCREG); emit_storereg(CCREG,HOST_CCREG); + if(s!=1) + emit_mov(s,1); emit_movimm(copr,0); emit_call((int)pcsx_mtc0_ds); return; } #endif - emit_movimm(start+i*4+4,0); - emit_movimm(0,1); - emit_writeword(0,(int)&pcaddr); - emit_writeword(1,(int)&pending_exception); + emit_movimm(start+i*4+4,HOST_TEMPREG); + emit_writeword(HOST_TEMPREG,(int)&pcaddr); + emit_movimm(0,HOST_TEMPREG); + emit_writeword(HOST_TEMPREG,(int)&pending_exception); } //else if(copr==12&&is_delayslot) emit_call((int)MTC0_R12); //else #ifdef PCSX + if(s!=1) + emit_mov(s,1); emit_movimm(copr,0); emit_call((int)pcsx_mtc0); #else @@ -4110,7 +4206,7 @@ void cop0_assemble(int i,struct regstat *i_regs) if(copr==9||copr==11||copr==12||copr==13) { emit_readword((int)&Count,HOST_CCREG); emit_readword((int)&next_interupt,ECX); - emit_addimm(HOST_CCREG,-CLOCK_DIVIDER*ccadj[i],HOST_CCREG); + emit_addimm(HOST_CCREG,-CLOCK_ADJUST(ccadj[i]),HOST_CCREG); emit_sub(HOST_CCREG,ECX,HOST_CCREG); emit_writeword(ECX,(int)&last_count); emit_storereg(CCREG,HOST_CCREG); @@ -4142,7 +4238,7 @@ void cop0_assemble(int i,struct regstat *i_regs) emit_readword((int)&last_count,ECX); if(i_regs->regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); emit_add(HOST_CCREG,ECX,HOST_CCREG); - emit_addimm(HOST_CCREG,CLOCK_DIVIDER*ccadj[i],HOST_CCREG); + emit_addimm(HOST_CCREG,CLOCK_ADJUST(ccadj[i]),HOST_CCREG); emit_writeword(HOST_CCREG,(int)&Count); emit_call((int)TLBWR_new); } @@ -4163,7 +4259,7 @@ void cop0_assemble(int i,struct regstat *i_regs) { int count=ccadj[i]; if(i_regs->regmap[HOST_CCREG]!=CCREG) emit_loadreg(CCREG,HOST_CCREG); - emit_addimm(HOST_CCREG,CLOCK_DIVIDER*count,HOST_CCREG); // TODO: Should there be an extra cycle here? + emit_addimm(HOST_CCREG,CLOCK_ADJUST(count),HOST_CCREG); // TODO: Should there be an extra cycle here? emit_jmp((int)jump_eret); } #endif @@ -4311,36 +4407,104 @@ void cop2_assemble(int i,struct regstat *i_regs) } } -void c2op_assemble(int i,struct regstat *i_regs) +static void c2op_prologue(u_int op,u_int reglist) +{ + save_regs_all(reglist); +#ifdef PCNT + emit_movimm(op,0); + emit_call((int)pcnt_gte_start); +#endif + emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0); // cop2 regs +} + +static void c2op_epilogue(u_int op,u_int reglist) +{ +#ifdef PCNT + emit_movimm(op,0); + emit_call((int)pcnt_gte_end); +#endif + restore_regs_all(reglist); +} + +static void c2op_assemble(int i,struct regstat *i_regs) { signed char temp=get_reg(i_regs->regmap,-1); u_int c2op=source[i]&0x3f; u_int hr,reglist=0; - int need_flags; + int need_flags,need_ir; for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap,CCREG); - emit_movimm(source[i],1); // opcode - if (cc>=0&>e_cycletab[c2op]) - emit_addimm(cc,gte_cycletab[c2op]/2,cc); // XXX: could just adjust ccadj? - emit_addimm(FP,(int)&psxRegs.CP2D.r[0]-(int)&dynarec_local,0); // cop2 regs - emit_writeword(1,(int)&psxRegs.code); need_flags=!(gte_unneeded[i+1]>>63); // +1 because of how liveness detection works - assem_debug("gte unneeded %016llx, need_flags %d\n",gte_unneeded[i+1],need_flags); + need_ir=(gte_unneeded[i+1]&0xe00)!=0xe00; + assem_debug("gte unneeded %016llx, need_flags %d, need_ir %d\n", + gte_unneeded[i+1],need_flags,need_ir); #ifdef ARMv5_ONLY // let's take more risk here need_flags=need_flags&>e_reads_flags; #endif - emit_call((int)(need_flags?gte_handlers[c2op]:gte_handlers_nf[c2op])); - } + switch(c2op) { + case GTE_MVMVA: { + int shift = (source[i] >> 19) & 1; + int v = (source[i] >> 15) & 3; + int cv = (source[i] >> 13) & 3; + int mx = (source[i] >> 17) & 3; + int lm = (source[i] >> 10) & 1; + reglist&=0x10ff; // +{r4-r7} + c2op_prologue(c2op,reglist); + /* r4,r5 = VXYZ(v) packed; r6 = &MX11(mx); r7 = &CV1(cv) */ + if(v<3) + emit_ldrd(v*8,0,4); + else { + emit_movzwl_indexed(9*4,0,4); // gteIR + emit_movzwl_indexed(10*4,0,6); + emit_movzwl_indexed(11*4,0,5); + emit_orrshl_imm(6,16,4); + } + if(mx<3) + emit_addimm(0,32*4+mx*8*4,6); + else + emit_readword((int)&zeromem_ptr,6); + if(cv<3) + emit_addimm(0,32*4+(cv*8+5)*4,7); + else + emit_readword((int)&zeromem_ptr,7); +#ifdef __ARM_NEON__ + emit_movimm(source[i],1); // opcode + emit_call((int)gteMVMVA_part_neon); + if(need_flags) { + emit_movimm(lm,1); + emit_call((int)gteMACtoIR_flags_neon); + } +#else + if(cv==3&&shift) + emit_call((int)gteMVMVA_part_cv3sh12_arm); + else { + emit_movimm(shift,1); + emit_call((int)(need_flags?gteMVMVA_part_arm:gteMVMVA_part_nf_arm)); + } + if(need_flags||need_ir) { + if(need_flags) + emit_call((int)(lm?gteMACtoIR_lm1:gteMACtoIR_lm0)); + else + emit_call((int)(lm?gteMACtoIR_lm1_nf:gteMACtoIR_lm0_nf)); // lm0 borked + } +#endif + break; + } - if(i>=slen-1||itype[i+1]!=C2OP) - restore_regs(reglist); + default: + reglist&=0x100f; + c2op_prologue(c2op,reglist); + emit_movimm(source[i],1); // opcode + emit_writeword(1,(int)&psxRegs.code); + emit_call((int)(need_flags?gte_handlers[c2op]:gte_handlers_nf[c2op])); + break; + } + c2op_epilogue(c2op,reglist); + } } void cop1_unusable(int i,struct regstat *i_regs)