From b9b61529b6c9bf30a3146178e2dda31b15ff3614 Mon Sep 17 00:00:00 2001 From: notaz Date: Sun, 5 Dec 2010 16:48:35 +0200 Subject: [PATCH] drc: initial cop2/gte implementation (works, mostly) --- Makefile | 3 + libpcsxcore/new_dynarec/assem_arm.c | 219 +++++++++++++++++++- libpcsxcore/new_dynarec/emu_if.c | 28 ++- libpcsxcore/new_dynarec/emu_if.h | 5 + libpcsxcore/new_dynarec/linkage_arm.s | 6 +- libpcsxcore/new_dynarec/new_dynarec.c | 279 ++++++++++++++++++++++---- libpcsxcore/new_dynarec/new_dynarec.h | 1 + 7 files changed, 487 insertions(+), 54 deletions(-) diff --git a/Makefile b/Makefile index 79a8f2de..37d13118 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,9 @@ endif ifndef DEBUG CFLAGS += -O2 endif +ifdef DRC_DBG +CFLAGS += -DDRC_DBG +endif TARGET = pcsx all: $(TARGET) diff --git a/libpcsxcore/new_dynarec/assem_arm.c b/libpcsxcore/new_dynarec/assem_arm.c index 4bddd8c5..83b115d0 100644 --- a/libpcsxcore/new_dynarec/assem_arm.c +++ b/libpcsxcore/new_dynarec/assem_arm.c @@ -965,12 +965,26 @@ void emit_testimm(int rs,int imm) output_w32(0xe3100000|rd_rn_rm(0,rs,0)|armval); } +void emit_testeqimm(int rs,int imm) +{ + u_int armval; + assem_debug("tsteq %s,$%d\n",regname[rs],imm); + assert(genimm(imm,&armval)); + output_w32(0x03100000|rd_rn_rm(0,rs,0)|armval); +} + void emit_not(int rs,int rt) { assem_debug("mvn %s,%s\n",regname[rt],regname[rs]); output_w32(0xe1e00000|rd_rn_rm(rt,0,rs)); } +void emit_mvnmi(int rs,int rt) +{ + assem_debug("mvnmi %s,%s\n",regname[rt],regname[rs]); + output_w32(0x41e00000|rd_rn_rm(rt,0,rs)); +} + 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]); @@ -1283,6 +1297,17 @@ void emit_shrdimm(int rs,int rs2,u_int imm,int rt) output_w32(0xe1800000|rd_rn_rm(rt,rt,rs2)|((32-imm)<<7)); } +void emit_signextend16(int rs,int rt) +{ + #ifdef ARMv5_ONLY + emit_shlimm(rs,16,rt); + emit_sarimm(rt,16,rt); + #else + assem_debug("sxth %s,%s\n",regname[rt],regname[rs]); + output_w32(0xe6bf0070|rd_rn_rm(rt,0,rs)); + #endif +} + void emit_shl(u_int rs,u_int shift,u_int rt) { assert(rs<16); @@ -2364,6 +2389,22 @@ void emit_orrvs_imm(int rs,int imm,int rt) output_w32(0x63800000|rd_rn_rm(rt,rs,0)|armval); } +void emit_orrne_imm(int rs,int imm,int rt) +{ + u_int armval; + assert(genimm(imm,&armval)); + assem_debug("orrne %s,%s,#%d\n",regname[rt],regname[rs],imm); + output_w32(0x13800000|rd_rn_rm(rt,rs,0)|armval); +} + +void emit_andne_imm(int rs,int imm,int rt) +{ + u_int armval; + assert(genimm(imm,&armval)); + assem_debug("andne %s,%s,#%d\n",regname[rt],regname[rs],imm); + output_w32(0x12000000|rd_rn_rm(rt,rs,0)|armval); +} + void emit_jno_unlikely(int a) { //emit_jno(a); @@ -2506,7 +2547,7 @@ do_readstub(int n) int addr=get_reg(i_regmap,AGEN1+(i&1)); int rth,rt; int ds; - if(itype[i]==C1LS||itype[i]==LOADLR) { + if(itype[i]==C1LS||itype[i]==C2LS||itype[i]==LOADLR) { rth=get_reg(i_regmap,FTEMP|64); rt=get_reg(i_regmap,FTEMP); }else{ @@ -2667,7 +2708,7 @@ do_writestub(int n) int addr=get_reg(i_regmap,AGEN1+(i&1)); int rth,rt,r; int ds; - if(itype[i]==C1LS) { + if(itype[i]==C1LS||itype[i]==C2LS) { rth=get_reg(i_regmap,FTEMP|64); rt=get_reg(i_regmap,r=FTEMP); }else{ @@ -3350,7 +3391,177 @@ void cop0_assemble(int i,struct regstat *i_regs) } } -void cop1_unusable(int i, struct regstat *i_regs) +static void cop2_get_dreg(u_int copr,signed char tl,signed char temp) +{ + switch (copr) { + case 1: + case 3: + case 5: + case 8: + case 9: + case 10: + case 11: + emit_readword((int)®_cop2d[copr],tl); + emit_signextend16(tl,tl); + emit_writeword(tl,(int)®_cop2d[copr]); // hmh + break; + case 7: + case 16: + case 17: + case 18: + case 19: + emit_readword((int)®_cop2d[copr],tl); + emit_andimm(tl,0xffff,tl); + emit_writeword(tl,(int)®_cop2d[copr]); + break; + case 15: + emit_readword((int)®_cop2d[14],tl); // SXY2 + emit_writeword(tl,(int)®_cop2d[copr]); + break; + case 28: + case 30: + emit_movimm(0,tl); + break; + case 29: + emit_readword((int)®_cop2d[9],temp); + emit_testimm(temp,0x8000); // do we need this? + emit_andimm(temp,0xf80,temp); + emit_andne_imm(temp,0,temp); + emit_shr(temp,7,tl); + emit_readword((int)®_cop2d[10],temp); + emit_testimm(temp,0x8000); + emit_andimm(temp,0xf80,temp); + emit_andne_imm(temp,0,temp); + emit_orrshr(temp,2,tl); + emit_readword((int)®_cop2d[11],temp); + emit_testimm(temp,0x8000); + emit_andimm(temp,0xf80,temp); + emit_andne_imm(temp,0,temp); + emit_orrshl(temp,3,tl); + emit_writeword(tl,(int)®_cop2d[copr]); + break; + default: + emit_readword((int)®_cop2d[copr],tl); + break; + } +} + +static void cop2_put_dreg(u_int copr,signed char sl,signed char temp) +{ + switch (copr) { + case 15: + emit_readword((int)®_cop2d[13],temp); // SXY1 + emit_writeword(sl,(int)®_cop2d[copr]); + emit_writeword(temp,(int)®_cop2d[12]); // SXY0 + emit_readword((int)®_cop2d[14],temp); // SXY2 + emit_writeword(sl,(int)®_cop2d[14]); + emit_writeword(temp,(int)®_cop2d[13]); // SXY1 + break; + case 28: + emit_andimm(sl,0x001f,temp); + emit_shl(temp,7,temp); + emit_writeword(temp,(int)®_cop2d[9]); + emit_andimm(sl,0x03e0,temp); + emit_shl(temp,2,temp); + emit_writeword(temp,(int)®_cop2d[10]); + emit_andimm(sl,0x7c00,temp); + emit_shr(temp,3,temp); + emit_writeword(temp,(int)®_cop2d[11]); + emit_writeword(sl,(int)®_cop2d[28]); + break; + case 30: + emit_movs(sl,temp); + emit_mvnmi(temp,temp); + emit_clz(temp,temp); + emit_writeword(sl,(int)®_cop2d[30]); + emit_writeword(temp,(int)®_cop2d[31]); + break; + case 7: + case 29: + case 31: + break; + default: + emit_writeword(sl,(int)®_cop2d[copr]); + break; + } +} + +void cop2_assemble(int i,struct regstat *i_regs) +{ + u_int copr=(source[i]>>11)&0x1f; + signed char temp=get_reg(i_regs->regmap,-1); + if (opcode2[i]==0) { // MFC2 + signed char tl=get_reg(i_regs->regmap,rt1[i]); + if(tl>=0) + cop2_get_dreg(copr,tl,temp); + } + else if (opcode2[i]==4) { // MTC2 + signed char sl=get_reg(i_regs->regmap,rs1[i]); + cop2_put_dreg(copr,sl,temp); + } + else if (opcode2[i]==2) // CFC2 + { + signed char tl=get_reg(i_regs->regmap,rt1[i]); + if(tl>=0) + emit_readword((int)®_cop2c[copr],tl); + } + else if (opcode2[i]==6) // CTC2 + { + signed char sl=get_reg(i_regs->regmap,rs1[i]); + switch(copr) { + case 4: + case 12: + case 20: + case 26: + case 27: + case 29: + case 30: + emit_signextend16(sl,temp); + break; + case 31: + //value = value & 0x7ffff000; + //if (value & 0x7f87e000) value |= 0x80000000; + emit_shrimm(sl,12,temp); + emit_shlimm(temp,12,temp); + emit_testimm(temp,0x7f000000); + emit_testeqimm(temp,0x00870000); + emit_testeqimm(temp,0x0000e000); + emit_orrne_imm(temp,0x80000000,temp); + break; + default: + temp=sl; + break; + } + emit_writeword(temp,(int)®_cop2c[copr]); + assert(sl>=0); + } +} + +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; + for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap,CCREG); + emit_movimm(source[i],temp); // opcode + if (cc>=0&>e_cycletab[c2op]) + emit_addimm(cc,gte_cycletab[c2op]/2,cc); // XXX: cound just adjust ccadj? + emit_writeword(temp,(int)&psxRegs.code); + emit_call((int)gte_handlers[c2op]); + } + + if(i>=slen-1||itype[i+1]!=C2OP) + restore_regs(reglist); +} + +void cop1_unusable(int i,struct regstat *i_regs) { // XXX: should just just do the exception instead if(!cop1_usable) { @@ -4442,3 +4653,5 @@ void arch_init() { rounding_modes[3]=0x2<<22; // floor #endif } + +// vim:shiftwidth=2:expandtab diff --git a/libpcsxcore/new_dynarec/emu_if.c b/libpcsxcore/new_dynarec/emu_if.c index 4d6b6259..cd447263 100644 --- a/libpcsxcore/new_dynarec/emu_if.c +++ b/libpcsxcore/new_dynarec/emu_if.c @@ -11,15 +11,13 @@ //#define evprintf printf #define evprintf(...) -//#define DRC_DBG - char invalid_code[0x100000]; void MTC0_() { extern void psxMTC0(); - printf("ari64 MTC0 %08x\n", psxRegs.code); + memprintf("ari64 MTC0 %08x\n", psxRegs.code); psxMTC0(); pending_exception = 1; /* FIXME? */ } @@ -93,10 +91,23 @@ void (*writemem[0x10000])(); void (*writememb[0x10000])(); void (*writememh[0x10000])(); +void *gte_handlers[64]; + +/* from gte.txt.. not sure if this is any good. */ +const char gte_cycletab[64] = { + /* 1 2 3 4 5 6 7 8 9 a b c d e f */ + 0, 15, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 6, 0, 0, 0, + 8, 8, 8, 19, 13, 0, 44, 0, 0, 0, 0, 17, 11, 0, 14, 0, + 30, 0, 0, 0, 0, 0, 0, 0, 5, 8, 17, 0, 0, 5, 6, 0, + 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 39, +}; static int ari64_init() { + extern void (*psxCP2[64])(); + extern void psxNULL(); size_t i; + new_dynarec_init(); for (i = 0; i < sizeof(readmem) / sizeof(readmem[0]); i++) { @@ -108,7 +119,12 @@ static int ari64_init() writemem[i] = write_mem32; } - psxHLEt_addr = (void *)psxHLEt; + for (i = 0; i < sizeof(gte_handlers) / sizeof(gte_handlers[0]); i++) + if (psxCP2[i] != psxNULL) + gte_handlers[i] = psxCP2[i]; + + psxHLEt_addr = (void *)psxHLEt; // FIXME: rm + return 0; } static void ari64_reset() @@ -121,9 +137,9 @@ static void ari64_execute() { next_interupt = psxNextsCounter + psxNextCounter; - evprintf("psxNextsCounter %d, psxNextCounter %d, Count %d\n", psxNextsCounter, psxNextCounter, psxRegs.CP0.r[9]); + evprintf("psxNextsCounter %d, psxNextCounter %d\n", psxNextsCounter, psxNextCounter); evprintf("ari64_execute %08x, %d->%d\n", psxRegs.pc, psxRegs.cycle, next_interupt); - new_dyna_start(psxRegs.pc); + new_dyna_start(); evprintf("ari64_execute end %08x, %d->%d\n", psxRegs.pc, psxRegs.cycle, next_interupt); } diff --git a/libpcsxcore/new_dynarec/emu_if.h b/libpcsxcore/new_dynarec/emu_if.h index 8777fa58..700182a1 100644 --- a/libpcsxcore/new_dynarec/emu_if.h +++ b/libpcsxcore/new_dynarec/emu_if.h @@ -23,6 +23,11 @@ extern int reg_cop0[]; #define EntryHi psxRegs.CP0.n.EntryHi #define Count psxRegs.cycle // psxRegs.CP0.n.Count +/* COP2/GTE */ +extern int reg_cop2d[], reg_cop2c[]; +extern void *gte_handlers[64]; +extern const char gte_cycletab[64]; + /* dummy */ extern int FCR0, FCR31; diff --git a/libpcsxcore/new_dynarec/linkage_arm.s b/libpcsxcore/new_dynarec/linkage_arm.s index d1a93e86..aeb8baa3 100644 --- a/libpcsxcore/new_dynarec/linkage_arm.s +++ b/libpcsxcore/new_dynarec/linkage_arm.s @@ -35,6 +35,8 @@ rdram = 0x80000000 .global hi .global lo .global reg_cop0 + .global reg_cop2d + .global reg_cop2c .global FCR0 .global FCR31 .global next_interupt @@ -59,7 +61,6 @@ rdram = 0x80000000 /* psx */ .global psxRegs .global psxHLEt_addr - .global code .bss .align 4 @@ -139,7 +140,6 @@ pcaddr = PC code = PC + 4 .type code, %object .size code, 4 -.global cycle cycle = code + 4 .type cycle, %object .size cycle, 4 @@ -681,7 +681,7 @@ jump_hlecall: ldr r3, [fp, #psxHLEt_addr-dynarec_local] /* psxHLEt */ str r2, [fp, #cycle-dynarec_local] /* PCSX cycle counter */ adr lr, pcsx_return - ldr pc, [r3, r1, lsl #2] + ldr pc, [r3, r1, lsl #2] @ FIXME .size jump_hlecall, .-jump_hlecall new_dyna_leave: diff --git a/libpcsxcore/new_dynarec/new_dynarec.c b/libpcsxcore/new_dynarec/new_dynarec.c index 95d433fb..62250d91 100644 --- a/libpcsxcore/new_dynarec/new_dynarec.c +++ b/libpcsxcore/new_dynarec/new_dynarec.c @@ -135,7 +135,7 @@ struct ll_entry #define CCREG 36 // Cycle count #define INVCP 37 // Pointer to invalid_code #define TEMPREG 38 -#define FTEMP 38 // FPU temporary register +#define FTEMP 38 // FPU/LDL/LDR temporary register #define PTEMP 39 // Prefetch temporary register #define TLREG 40 // TLB mapping offset #define RHASH 41 // Return address hash @@ -176,6 +176,9 @@ struct ll_entry #define SPAN 24 // Branch/delay slot spans 2 pages #define NI 25 // Not implemented #define HLECALL 26// PCSX fake opcodes for HLE +#define COP2 27 // Coprocessor 2 move +#define C2LS 28 // Coprocessor 2 load/store +#define C2OP 29 // Coprocessor 2 operation /* stubs */ #define CC_STUB 1 @@ -633,7 +636,7 @@ void lsn(u_char hsn[], int i, int *preferred_reg) } // On some architectures stores need invc_ptr #if defined(HOST_IMM8) - if(itype[i+j]==STORE || itype[i+j]==STORELR || (opcode[i+j]&0x3b)==0x39) { + if(itype[i+j]==STORE || itype[i+j]==STORELR || (opcode[i+j]&0x3b)==0x39 || (opcode[i+j]&0x3b)==0x3a) { hsn[INVCP]=j; } #endif @@ -670,7 +673,7 @@ void lsn(u_char hsn[], int i, int *preferred_reg) hsn[RHTBL]=1; } // Coprocessor load/store needs FTEMP, even if not declared - if(itype[i]==C1LS) { + if(itype[i]==C1LS||itype[i]==C2LS) { hsn[FTEMP]=0; } // Load L/R also uses FTEMP as a temporary register @@ -682,7 +685,7 @@ void lsn(u_char hsn[], int i, int *preferred_reg) hsn[FTEMP]=0; } // Don't remove the TLB registers either - if(itype[i]==LOAD || itype[i]==LOADLR || itype[i]==STORE || itype[i]==STORELR || itype[i]==C1LS ) { + if(itype[i]==LOAD || itype[i]==LOADLR || itype[i]==STORE || itype[i]==STORELR || itype[i]==C1LS || itype[i]==C2LS) { hsn[TLREG]=0; } // Don't remove the miniht registers @@ -1646,6 +1649,22 @@ void c1ls_alloc(struct regstat *current,int i) alloc_reg_temp(current,i,-1); } +void c2ls_alloc(struct regstat *current,int i) +{ + clear_const(current,rt1[i]); + if(needed_again(rs1[i],i)) alloc_reg(current,i,rs1[i]); + alloc_reg(current,i,FTEMP); + // If using TLB, need a register for pointer to the mapping table + if(using_tlb) alloc_reg(current,i,TLREG); + #if defined(HOST_IMM8) + // On CPUs without 32-bit immediates we need a pointer to invalid_code + else if((opcode[i]&0x3b)==0x3a) // SWC2/SDC2 + alloc_reg(current,i,INVCP); + #endif + // We need a temporary register for address generation + alloc_reg_temp(current,i,-1); +} + #ifndef multdiv_alloc void multdiv_alloc(struct regstat *current,int i) { @@ -1783,6 +1802,10 @@ void float_alloc(struct regstat *current,int i) alloc_reg(current,i,CSREG); // Load status alloc_reg_temp(current,i,-1); } +void c2op_alloc(struct regstat *current,int i) +{ + alloc_reg_temp(current,i,-1); +} void fcomp_alloc(struct regstat *current,int i) { alloc_reg(current,i,CSREG); // Load status @@ -1844,11 +1867,15 @@ void delayslot_alloc(struct regstat *current,int i) cop0_alloc(current,i); break; case COP1: + case COP2: cop1_alloc(current,i); break; case C1LS: c1ls_alloc(current,i); break; + case C2LS: + c2ls_alloc(current,i); + break; case FCONV: fconv_alloc(current,i); break; @@ -1858,6 +1885,9 @@ void delayslot_alloc(struct regstat *current,int i) case FCOMP: fcomp_alloc(current,i); break; + case C2OP: + c2op_alloc(current,i); + break; } } @@ -3534,6 +3564,87 @@ void c1ls_assemble(int i,struct regstat *i_regs) #endif } +void c2ls_assemble(int i,struct regstat *i_regs) +{ + int s,tl; + int ar; + int offset; + int c=0; + int jaddr,jaddr2=0,jaddr3,type; + int agr=AGEN1+(i&1); + u_int hr,reglist=0; + u_int copr=(source[i]>>16)&0x1f; + s=get_reg(i_regs->regmap,rs1[i]); + tl=get_reg(i_regs->regmap,FTEMP); + offset=imm[i]; + assert(rs1[i]>0); + assert(tl>=0); + assert(!using_tlb); + + for(hr=0;hrregmap[hr]>=0) reglist|=1<regmap[HOST_CCREG]==CCREG) + reglist&=~(1<regmap,agr); + if(ar<0) ar=get_reg(i_regs->regmap,-1); + reglist|=1<=0) ar=s; + assert(ar>=0); + + if (opcode[i]==0x3a) { // SWC2 + cop2_get_dreg(copr,tl,HOST_TEMPREG); + } + if(s>=0) c=(i_regs->wasconst>>s)&1; + if(!c) { + emit_cmpimm(offset||c||s<0?ar:s,0x800000); + jaddr2=(int)out; + emit_jno(0); + } + else if(((signed int)(constmap[i][s]+offset))>=(signed int)0x80800000) { + jaddr2=(int)out; + emit_jmp(0); // inline_readstub/inline_writestub? Very rare case + } + if (opcode[i]==0x32) { // LWC2 + #ifdef HOST_IMM_ADDR32 + if(c) emit_readword_tlb(constmap[i][s]+offset,-1,tl); + else + #endif + emit_readword_indexed(0,ar,tl); + type=LOADW_STUB; + } + if (opcode[i]==0x3a) { // SWC2 +#ifdef DESTRUCTIVE_SHIFT + if(!offset&&!c&&s>=0) emit_mov(s,ar); +#endif + emit_writeword_indexed(tl,0,ar); + type=STOREW_STUB; + } + if(jaddr2) + add_stub(type,jaddr2,(int)out,i,ar,(int)i_regs,ccadj[i],reglist); + if (opcode[i]==0x3a) { // SWC2 +#if defined(HOST_IMM8) + int ir=get_reg(i_regs->regmap,INVCP); + assert(ir>=0); + emit_cmpmem_indexedsr12_reg(ir,ar,1); +#else + emit_cmpmem_indexedsr12_imm((int)invalid_code,ar,1); +#endif + jaddr3=(int)out; + emit_jne(0); + add_stub(INVCODE_STUB,jaddr3,(int)out,reglist|(1<regmap,agr); if(ra<0) ra=get_reg(i_regs->regmap,-1); } - if(itype[i]==C1LS) { - if (opcode[i]==0x31||opcode[i]==0x35) // LWC1/LDC1 + if(itype[i]==C1LS||itype[i]==C2LS) { + if ((opcode[i]&0x3b)==0x31||(opcode[i]&0x3b)==0x32) // LWC1/LDC1/LWC2/LDC2 ra=get_reg(i_regs->regmap,FTEMP); else { // SWC1/SDC1 ra=get_reg(i_regs->regmap,agr); @@ -3853,7 +3971,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[]) else if(c) { if(rm>=0) { if(!entry||entry[rm]!=mgr) { - if(itype[i]==STORE||itype[i]==STORELR||opcode[i]==0x39||opcode[i]==0x3D) { + if(itype[i]==STORE||itype[i]==STORELR||(opcode[i]&0x3b)==0x39||(opcode[i]&0x3b)==0x3a) { // Stores to memory go thru the mapper to detect self-modifying // code, loads don't. if((unsigned int)(constmap[i][rs]+offset)>=0xC0000000 || @@ -3873,7 +3991,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[]) emit_movimm((constmap[i][rs]+offset)&0xFFFFFFF8,ra); // LDL/LDR }else{ #ifdef HOST_IMM_ADDR32 - if((itype[i]!=LOAD&&opcode[i]!=0x31&&opcode[i]!=0x35) || + if((itype[i]!=LOAD&&(opcode[i]&0x3b)!=0x31&&(opcode[i]&0x3b)!=0x32) || // LWC1/LDC1/LWC2/LDC2 (using_tlb&&((signed int)constmap[i][rs]+offset)>=(signed int)0xC0000000)) #endif emit_movimm(constmap[i][rs]+offset,ra); @@ -3891,7 +4009,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[]) } } // Preload constants for next instruction - if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS) { + if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS||itype[i+1]==C2LS) { int agr,ra; #ifndef HOST_IMM_ADDR32 // Mapper entry @@ -3902,7 +4020,8 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[]) int offset=imm[i+1]; int c=(regs[i+1].wasconst>>rs)&1; if(c) { - if(itype[i+1]==STORE||itype[i+1]==STORELR||opcode[i+1]==0x39||opcode[i+1]==0x3D) { + if(itype[i+1]==STORE||itype[i+1]==STORELR + ||(opcode[i+1]&0x3b)==0x39||(opcode[i+1]&0x3b)==0x3a) { // SWC1/SDC1, SWC2/SDC2 // Stores to memory go thru the mapper to detect self-modifying // code, loads don't. if((unsigned int)(constmap[i+1][rs]+offset)>=0xC0000000 || @@ -3932,7 +4051,7 @@ void address_generation(int i,struct regstat *i_regs,signed char entry[]) emit_movimm((constmap[i+1][rs]+offset)&0xFFFFFFF8,ra); // LDL/LDR }else{ #ifdef HOST_IMM_ADDR32 - if((itype[i+1]!=LOAD&&opcode[i+1]!=0x31&&opcode[i+1]!=0x35) || + if((itype[i+1]!=LOAD&&(opcode[i+1]&0x3b)!=0x31&&(opcode[i+1]&0x3b)!=0x32) || // LWC1/LDC1/LWC2/LDC2 (using_tlb&&((signed int)constmap[i+1][rs]+offset)>=(signed int)0xC0000000)) #endif emit_movimm(constmap[i+1][rs]+offset,ra); @@ -4446,7 +4565,7 @@ void ds_assemble_entry(int i) wb_register(CCREG,regs[t].regmap_entry,regs[t].wasdirty,regs[t].was32); load_regs(regs[t].regmap_entry,regs[t].regmap,regs[t].was32,rs1[t],rs2[t]); address_generation(t,®s[t],regs[t].regmap_entry); - if(itype[t]==STORE||itype[t]==STORELR||(opcode[t]&0x3b)==0x39) + if(itype[t]==STORE||itype[t]==STORELR||(opcode[t]&0x3b)==0x39||(opcode[t]&0x3b)==0x3a) load_regs(regs[t].regmap_entry,regs[t].regmap,regs[t].was32,INVCP,INVCP); cop1_usable=0; is_delayslot=0; @@ -4473,6 +4592,12 @@ void ds_assemble_entry(int i) cop1_assemble(t,®s[t]);break; case C1LS: c1ls_assemble(t,®s[t]);break; + case COP2: + cop2_assemble(t,®s[t]);break; + case C2LS: + c2ls_assemble(t,®s[t]);break; + case C2OP: + c2op_assemble(t,®s[t]);break; case FCONV: fconv_assemble(t,®s[t]);break; case FLOAT: @@ -6272,7 +6397,7 @@ static void pagespan_ds() emit_writeword(HOST_BTREG,(int)&branch_target); load_regs(regs[0].regmap_entry,regs[0].regmap,regs[0].was32,rs1[0],rs2[0]); address_generation(0,®s[0],regs[0].regmap_entry); - if(itype[0]==STORE||itype[0]==STORELR||(opcode[0]&0x3b)==0x39) + if(itype[0]==STORE||itype[0]==STORELR||(opcode[0]&0x3b)==0x39||(opcode[0]&0x3b)==0x3a) load_regs(regs[0].regmap_entry,regs[0].regmap,regs[0].was32,INVCP,INVCP); cop1_usable=0; is_delayslot=0; @@ -6299,6 +6424,12 @@ static void pagespan_ds() cop1_assemble(0,®s[0]);break; case C1LS: c1ls_assemble(0,®s[0]);break; + case COP2: + cop2_assemble(0,®s[0]);break; + case C2LS: + c2ls_assemble(0,®s[0]);break; + case C2OP: + c2op_assemble(0,®s[0]);break; case FCONV: fconv_assemble(0,®s[0]);break; case FLOAT: @@ -6780,17 +6911,20 @@ static void provisional_32bit() if(op2==0) is32|=1LL<>11)&0x1f); // MTC1 else printf (" %x: %s\n",start+i*4,insn[i]); break; + case COP2: + if(opcode2[i]<3) + printf (" %x: %s r%d,cpr2[%d]\n",start+i*4,insn[i],rt1[i],(source[i]>>11)&0x1f); // MFC2 + else if(opcode2[i]>3) + printf (" %x: %s r%d,cpr2[%d]\n",start+i*4,insn[i],rs1[i],(source[i]>>11)&0x1f); // MTC2 + else printf (" %x: %s\n",start+i*4,insn[i]); + break; case C1LS: printf (" %x: %s cpr1[%d],r%d+%x\n",start+i*4,insn[i],(source[i]>>16)&0x1f,rs1[i],imm[i]); break; + case C2LS: + printf (" %x: %s cpr2[%d],r%d+%x\n",start+i*4,insn[i],(source[i]>>16)&0x1f,rs1[i],imm[i]); + break; default: //printf (" %s %8x\n",insn[i],source[i]); printf (" %x: %s\n",start+i*4,insn[i]); @@ -7895,12 +8039,30 @@ int new_recompile_block(int addr) case 0x37: strcpy(insn[i],"LD"); type=LOAD; break; case 0x38: strcpy(insn[i],"SC"); type=NI; break; case 0x39: strcpy(insn[i],"SWC1"); type=C1LS; break; -#ifdef PCSX - case 0x3B: strcpy(insn[i],"HLECALL"); type=HLECALL; break; -#endif case 0x3C: strcpy(insn[i],"SCD"); type=NI; break; case 0x3D: strcpy(insn[i],"SDC1"); type=C1LS; break; case 0x3F: strcpy(insn[i],"SD"); type=STORE; break; +#ifdef PCSX + case 0x12: strcpy(insn[i],"COP2"); type=NI; + op2=(source[i]>>21)&0x1f; + switch(op2) + { + case 0x00: strcpy(insn[i],"MFC2"); type=COP2; break; + case 0x02: strcpy(insn[i],"CFC2"); type=COP2; break; + case 0x04: strcpy(insn[i],"MTC2"); type=COP2; break; + case 0x06: strcpy(insn[i],"CTC2"); type=COP2; break; + default: + if (gte_handlers[source[i]&0x3f]!=NULL) { + snprintf(insn[i], sizeof(insn[i]), "COP2 %x", source[i]&0x3f); + type=C2OP; + } + break; + } + break; + case 0x32: strcpy(insn[i],"LWC2"); type=C2LS; break; + case 0x3A: strcpy(insn[i],"SWC2"); type=C2LS; break; + case 0x3B: strcpy(insn[i],"HLECALL"); type=HLECALL; break; +#endif default: strcpy(insn[i],"???"); type=NI; printf("NI %08x @%08x\n", source[i], addr + i*4); break; @@ -8076,6 +8238,7 @@ int new_recompile_block(int addr) if(op2==16) if((source[i]&0x3f)==0x18) rs2[i]=CCREG; // ERET break; case COP1: + case COP2: rs1[i]=0; rs2[i]=0; rt1[i]=0; @@ -8092,6 +8255,13 @@ int new_recompile_block(int addr) rt2[i]=0; imm[i]=(short)source[i]; break; + case C2LS: + rs1[i]=(source[i]>>21)&0x1F; + rs2[i]=0; + rt1[i]=0; + rt2[i]=0; + imm[i]=(short)source[i]; + break; case FLOAT: case FCONV: rs1[i]=0; @@ -8734,11 +8904,18 @@ int new_recompile_block(int addr) cop0_alloc(¤t,i); break; case COP1: + case COP2: cop1_alloc(¤t,i); break; case C1LS: c1ls_alloc(¤t,i); break; + case C2LS: + c2ls_alloc(¤t,i); + break; + case C2OP: + c2op_alloc(¤t,i); + break; case FCONV: fconv_alloc(¤t,i); break; @@ -9208,7 +9385,7 @@ int new_recompile_block(int addr) if(dep1[i+1]==(regs[i].regmap_entry[hr]&63)) nr|=1<>2; if(t>0&&(itype[t-1]!=UJUMP&&itype[t-1]!=RJUMP&&itype[t-1]!=CJUMP&&itype[t-1]!=SJUMP&&itype[t-1]!=FJUMP)) // loop_preload can't handle jumps into delay slots @@ -9447,7 +9627,8 @@ int new_recompile_block(int addr) else if(branch_regs[i].regmap[hr]>=0) f_regmap[hr]=branch_regs[i].regmap[hr]; if(itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS ||itype[i+1]==SHIFT||itype[i+1]==COP1||itype[i+1]==FLOAT - ||itype[i+1]==FCOMP||itype[i+1]==FCONV) + ||itype[i+1]==FCOMP||itype[i+1]==FCONV + ||itype[i+1]==COP2||itype[i+1]==C2LS||itype[i+1]==C2OP) { // Test both in case the delay slot is ooo, // could be done better... @@ -9486,8 +9667,8 @@ int new_recompile_block(int addr) while(k>1&®s[k-1].regmap[hr]==-1) { if(itype[k-1]==STORE||itype[k-1]==STORELR ||itype[k-1]==C1LS||itype[k-1]==SHIFT||itype[k-1]==COP1 - ||itype[k-1]==FLOAT||itype[k-1]==FCONV - ||itype[k-1]==FCOMP) { + ||itype[k-1]==FLOAT||itype[k-1]==FCONV||itype[k-1]==FCOMP + ||itype[k-1]==COP2||itype[k-1]==C2LS||itype[k-1]==C2OP) { if(count_free_regs(regs[k-1].regmap)<2) { //printf("no free regs for store %x\n",start+(k-1)*4); break; @@ -9596,7 +9777,8 @@ int new_recompile_block(int addr) } if(itype[j]==STORE||itype[j]==STORELR||itype[j]==C1LS ||itype[j]==SHIFT||itype[j]==COP1||itype[j]==FLOAT - ||itype[j]==FCOMP||itype[j]==FCONV) { + ||itype[j]==FCOMP||itype[j]==FCONV + ||itype[j]==COP2||itype[j]==C2LS||itype[j]==C2OP) { if(count_free_regs(regs[j].regmap)<2) { //printf("No free regs for store %x\n",start+j*4); break; @@ -9638,7 +9820,8 @@ int new_recompile_block(int addr) if(regs[j].regmap[HOST_CCREG]!=-1) break; if(itype[j]==STORE||itype[j]==STORELR||itype[j]==C1LS ||itype[j]==SHIFT||itype[j]==COP1||itype[j]==FLOAT - ||itype[j]==FCOMP||itype[j]==FCONV) { + ||itype[j]==FCOMP||itype[j]==FCONV + ||itype[j]==COP2||itype[j]==C2LS||itype[j]==C2OP) { if(count_free_regs(regs[j].regmap)<2) { //printf("no free regs for store %x\n",start+j*4); break; @@ -9671,7 +9854,8 @@ int new_recompile_block(int addr) while(regs[k-1].regmap[HOST_CCREG]==-1) { if(itype[k-1]==STORE||itype[k-1]==STORELR||itype[k-1]==C1LS ||itype[k-1]==SHIFT||itype[k-1]==COP1||itype[k-1]==FLOAT - ||itype[k-1]==FCONV||itype[k-1]==FCOMP) { + ||itype[k-1]==FCONV||itype[k-1]==FCOMP + ||itype[k-1]==COP2||itype[k-1]==C2LS||itype[k-1]==C2OP) { if(count_free_regs(regs[k-1].regmap)<2) { //printf("no free regs for store %x\n",start+(k-1)*4); break; @@ -9702,7 +9886,8 @@ int new_recompile_block(int addr) if(itype[i]!=STORE&&itype[i]!=STORELR&&itype[i]!=C1LS&&itype[i]!=SHIFT&& itype[i]!=NOP&&itype[i]!=MOV&&itype[i]!=ALU&&itype[i]!=SHIFTIMM&& itype[i]!=IMM16&&itype[i]!=LOAD&&itype[i]!=COP1&&itype[i]!=FLOAT&& - itype[i]!=FCONV&&itype[i]!=FCOMP) + itype[i]!=FCONV&&itype[i]!=FCOMP&& + itype[i]!=COP2&&itype[i]!=C2LS&&itype[i]!=C2OP) { memcpy(f_regmap,regs[i].regmap,sizeof(f_regmap)); } @@ -9717,7 +9902,8 @@ int new_recompile_block(int addr) { if(!bt[i+1]) { - if(itype[i]==ALU||itype[i]==MOV||itype[i]==LOAD||itype[i]==SHIFTIMM||itype[i]==IMM16||(itype[i]==COP1&&opcode2[i]<3)) + if(itype[i]==ALU||itype[i]==MOV||itype[i]==LOAD||itype[i]==SHIFTIMM||itype[i]==IMM16 + ||((itype[i]==COP1||itype[i]==COP2)&&opcode2[i]<3)) { if(rs1[i+1]) { if((hr=get_reg(regs[i+1].regmap,rs1[i+1]))>=0) @@ -9784,7 +9970,7 @@ int new_recompile_block(int addr) } } #ifndef HOST_IMM_ADDR32 - if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS) { + if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR||itype[i+1]==C1LS||itype[i+1]==C2LS) { hr=get_reg(regs[i+1].regmap,TLREG); if(hr>=0) { int sr=get_reg(regs[i+1].regmap,rs1[i+1]); @@ -9822,7 +10008,8 @@ int new_recompile_block(int addr) } } #endif - if(itype[i+1]==STORE||itype[i+1]==STORELR||opcode[i+1]==0x39||opcode[i+1]==0x3D) { // SB/SH/SW/SD/SWC1/SDC1 + if(itype[i+1]==STORE||itype[i+1]==STORELR + ||(opcode[i+1]&0x3b)==0x39||(opcode[i+1]&0x3b)==0x3a) { // SB/SH/SW/SD/SWC1/SDC1/SWC2/SDC2 if(get_reg(regs[i+1].regmap,rs1[i+1])<0) { hr=get_reg2(regs[i].regmap,regs[i+1].regmap,-1); if(hr<0) hr=get_reg(regs[i+1].regmap,-1); @@ -9841,7 +10028,7 @@ int new_recompile_block(int addr) } } } - if(itype[i+1]==LOADLR||opcode[i+1]==0x31||opcode[i+1]==0x35) { // LWC1/LDC1 + if(itype[i+1]==LOADLR||(opcode[i+1]&0x3b)==0x31||(opcode[i+1]&0x3b)==0x32) { // LWC1/LDC1, LWC2/LDC2 if(get_reg(regs[i+1].regmap,rs1[i+1])<0) { int nr; hr=get_reg(regs[i+1].regmap,FTEMP); @@ -9876,12 +10063,12 @@ int new_recompile_block(int addr) } } } - if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR/*||itype[i+1]==C1LS*/) { + if(itype[i+1]==LOAD||itype[i+1]==LOADLR||itype[i+1]==STORE||itype[i+1]==STORELR/*||itype[i+1]==C1LS||||itype[i+1]==C2LS*/) { if(itype[i+1]==LOAD) hr=get_reg(regs[i+1].regmap,rt1[i+1]); - if(itype[i+1]==LOADLR||opcode[i+1]==0x31||opcode[i+1]==0x35) // LWC1/LDC1 + if(itype[i+1]==LOADLR||(opcode[i+1]&0x3b)==0x31||(opcode[i+1]&0x3b)==0x32) // LWC1/LDC1, LWC2/LDC2 hr=get_reg(regs[i+1].regmap,FTEMP); - if(itype[i+1]==STORE||itype[i+1]==STORELR||opcode[i+1]==0x39||opcode[i+1]==0x3D) { // SWC1/SDC1 + if(itype[i+1]==STORE||itype[i+1]==STORELR||(opcode[i+1]&0x3b)==0x39||(opcode[i+1]&0x3b)==0x3a) { // SWC1/SDC1/SWC2/SDC2 hr=get_reg(regs[i+1].regmap,AGEN1+((i+1)&1)); if(hr<0) hr=get_reg(regs[i+1].regmap,-1); } @@ -10297,7 +10484,7 @@ int new_recompile_block(int addr) load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,rs1[i+1],rs1[i+1]); if(rs2[i+1]!=rs1[i+1]&&rs2[i+1]!=rs1[i]&&rs2[i+1]!=rs2[i]) load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,rs2[i+1],rs2[i+1]); - if(itype[i+1]==STORE||itype[i+1]==STORELR||(opcode[i+1]&0x3b)==0x39) + if(itype[i+1]==STORE||itype[i+1]==STORELR||(opcode[i+1]&0x3b)==0x39||(opcode[i+1]&0x3b)==0x3a) load_regs(regs[i].regmap_entry,regs[i].regmap,regs[i].was32,INVCP,INVCP); } else if(i+1