X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=source%2Fmupen64plus-rsp-z64%2Fsrc%2Frsp_recomp.cpp;fp=source%2Fmupen64plus-rsp-z64%2Fsrc%2Frsp_recomp.cpp;h=f771955a8dd1faa86495eb17a147b91c2da2b73a;hb=fc5d46b49a19d41f9f2da5a9336daec452900475;hp=0000000000000000000000000000000000000000;hpb=292f9317f53c38c181439013be7276f86517fd6b;p=mupen64plus-pandora.git diff --git a/source/mupen64plus-rsp-z64/src/rsp_recomp.cpp b/source/mupen64plus-rsp-z64/src/rsp_recomp.cpp new file mode 100644 index 0000000..f771955 --- /dev/null +++ b/source/mupen64plus-rsp-z64/src/rsp_recomp.cpp @@ -0,0 +1,574 @@ +/* + * z64 + * + * Copyright (C) 2007 ziggy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * +**/ + +#include "rsp_recomp.h" +#include + +#define GENDEBUG + +struct gen_t { + UINT32 crc; + int lbc; + rsp_bc_t * bc; +#ifdef GENDEBUG + char name[32]; +#endif +}; + +struct opinfo_t { + int visit, labeled; + int label; + + unsigned int nbgen; + unsigned int szgen; + gen_t * gentable; + gen_t * curgen; +}; + +struct branch_t { + int start, end; +}; + +static int curvisit; +static opinfo_t opinfo[0x1000/4]; +static int jumps[0x1000]; +static unsigned int nb_branches; +static branch_t branches[256]; +static unsigned int nb_labels; +static int labels[256]; + +#define OPI(pc) opinfo[(pc)>>2] +/*inline*/ void SETLABEL(int pc) { + //printf("%x\n", pc); + //pc &= 0xfff; + assert(pc >= 0 && pc < 0x1000); + if (OPI(pc).labeled != curvisit) { + labels[nb_labels] = pc; + OPI(pc).label = nb_labels++; + assert(nb_labels < sizeof(labels)/sizeof(labels[0])); + OPI(pc).labeled = curvisit; + } +} + +#define ABS(addr) (((addr) << 2) & 0xfff) +#define REL(offset) ((pc + ((offset) << 2)) & 0xfff) + +static UINT32 prep_gen(int pc, UINT32 crc, int & len) +{ + UINT32 op; + int br = 0; + + branches[nb_branches].start = pc; + + while ( !br ) + { + if (OPI(pc).visit == curvisit) { + SETLABEL((pc)&0xfff); + SETLABEL((pc+4)&0xfff); + break; + } + + OPI(pc).visit = curvisit; + + op = ROPCODE(pc); + crc = ((crc<<1)|(crc>>31))^op^pc; + pc = (pc+4)&0xfff; + len++; + + switch (op >> 26) + { + case 0x00: /* SPECIAL */ + { + switch (op & 0x3f) + { + case 0x08: /* JR */ + br = 1; + break; + case 0x09: /* JALR */ + //br = 1; + break; + case 0x0d: /* BREAK */ + br = 1; + break; + } + break; + } + + case 0x01: /* REGIMM */ + { + switch (RTREG) + { + case 0x00: /* BLTZ */ + case 0x01: /* BGEZ */ + SETLABEL(REL(SIMM16)); + break; + case 0x11: /* BGEZAL */ + //br = 1; + break; + } + break; + } + + case 0x02: /* J */ + SETLABEL(ABS(UIMM26)); + br = 1; + break; + case 0x04: /* BEQ */ + case 0x05: /* BNE */ + case 0x06: /* BLEZ */ + case 0x07: /* BGTZ */ + SETLABEL(REL(SIMM16)); + break; + case 0x03: /* JAL */ + //SETLABEL(ABS(UIMM26)); + //br = 1; + break; + } + + } + + branches[nb_branches++].end = pc; + assert(nb_branches < sizeof(branches)/sizeof(branches[0])); + + return crc; +} + +static void rsp_gen(int pc) +{ + unsigned int i; + + curvisit++; + if (!curvisit) { + // we looped, reset all visit counters + for (i=0; i<0x1000/4; i++) { + opinfo[i].visit = 0; + opinfo[i].labeled = 0; + } + curvisit++; + } + + nb_branches = 0; + nb_labels = 0; + + int len = 0; + UINT32 crc = prep_gen(pc, 0, len); + + for (i=0; igentable) { + for (i=0; inbgen; i++) + if (opi->gentable[i].crc == crc) { + opi->curgen = opi->gentable + i; + return; + } + } + if (opi->nbgen >= opi->szgen) { + if (opi->szgen) + opi->szgen *= 2; + else + opi->szgen = 4; + opi->gentable = (gen_t *) realloc(opi->gentable, sizeof(gen_t)*(opi->szgen)); + } + gen_t * gen; + gen = opi->gentable + opi->nbgen++; + gen->crc = crc; + opi->curgen = gen; + + // convert to bytecode + unsigned int lbc = 0; + static rsp_bc_t bc[0x1000*2+10]; + for (i=0; i>3)&0xffc; + // char s[128]; + // rsp_dasm_one(s, realpc, bc[i].op); + // printf("%3x\t%s\n", realpc, s); + // } + switch (bc[i].op2) { + case RSP_JUMPLOCAL: + case RSP_CONDJUMPLOCAL: + case RSP_LOOP: + { + // int pc; + // for (pc = 0; pc>5)<<2) == bc[i].flags) + // break; + // assert(pc < lbc); + // bc[i].flags = pc<<5; + bc[i].flags = jumps[bc[i].flags]<<5; + break; + } + } + } + + gen->lbc = lbc; + gen->bc = (rsp_bc_t *) malloc(sizeof(rsp_bc_t)*lbc); + memcpy(gen->bc, bc, sizeof(rsp_bc_t)*lbc); +} + +void rsp_invalidate(int begin, int len) +{ + //printf("invalidate %x %x\n", begin, len); + begin = 0; len = 0x1000; + assert(begin+len<=0x1000); + while (len > 0) { + OPI(begin).curgen = 0; + begin += 4; + len -= 4; + } + rsp.inval_gen = 1; +} + +inline void rsp_execute_one(RSP_REGS & rsp, const UINT32 op) +{ + switch (op >> 26) + { + case 0x12: /* COP2 */ + { + handle_vector_ops(op); + break; + } + + case 0x32: /* LWC2 */ handle_lwc2(op); break; + case 0x3a: /* SWC2 */ handle_swc2(op); break; + + default: + { + unimplemented_opcode(op); + break; + } + } +} + +static int cond; +static int run(RSP_REGS & rsp, gen_t * gen) +{ + int pc = 0; + + cond = 0; + for ( ; ; ) { + const rsp_bc_t & bc = gen->bc[pc]; + const UINT32 op = bc.op; + const int op2 = bc.op2; + + // if (op2 < RSP_CONTROL_OFFS) { + // int realpc = (bc.flags>>3)&0xffc; + // char s[128]; + // rsp_dasm_one(s, realpc, op); + // fprintf(stderr, "%3x\t%s\n", realpc, s); + // } + + pc++; + switch (op2) { + case RSP_LOOP: + pc = bc.flags>>5; + break; + case RSP_JUMPLOCAL: + case RSP_CONDJUMPLOCAL: + if (cond) { + pc = bc.flags>>5; + cond = 0; + } + break; + case RSP_JUMP: + case RSP_CONDJUMP: + if (cond) { + return 0; + } + break; + + #define _LINK(l) rsp.r[l] = ((bc.flags >>3)+8)&0xffc + #define _JUMP_PC(a) { cond=1; rsp.nextpc = ((a) & 0xfff); } + #define _JUMP_PC_L(a, l) { _LINK(l); _JUMP_PC(a); } + #define _JUMP_REL(a) _JUMP_PC(((bc.flags >>3)+4+(a<<2))&0xffc) + #define _JUMP_REL_L(a, l) _JUMP_PC_L(((bc.flags >>3)+4+(a<<2))&0xffc, l) + + case RSP_SLL: if (RDREG) RDVAL = (UINT32)RTVAL << SHIFT; break; + case RSP_SRL: if (RDREG) RDVAL = (UINT32)RTVAL >> SHIFT; break; + case RSP_SRA: if (RDREG) RDVAL = (INT32)RTVAL >> SHIFT; break; + case RSP_SLLV: if (RDREG) RDVAL = (UINT32)RTVAL << (RSVAL & 0x1f); break; + case RSP_SRLV: if (RDREG) RDVAL = (UINT32)RTVAL >> (RSVAL & 0x1f); break; + case RSP_SRAV: if (RDREG) RDVAL = (INT32)RTVAL >> (RSVAL & 0x1f); break; + case RSP_JR: _JUMP_PC(RSVAL); break; + case RSP_JALR: _JUMP_PC_L(RSVAL, RDREG); break; + case RSP_BREAK: + { + *z64_rspinfo.SP_STATUS_REG |= (SP_STATUS_HALT | SP_STATUS_BROKE ); + if ((*z64_rspinfo.SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) { + *z64_rspinfo.MI_INTR_REG |= 1; + z64_rspinfo.CheckInterrupts(); + } + return 1; + } + case RSP_ADD: if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break; + case RSP_ADDU: if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break; + case RSP_SUB: if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break; + case RSP_SUBU: if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break; + case RSP_AND: if (RDREG) RDVAL = RSVAL & RTVAL; break; + case RSP_OR: if (RDREG) RDVAL = RSVAL | RTVAL; break; + case RSP_XOR: if (RDREG) RDVAL = RSVAL ^ RTVAL; break; + case RSP_NOR: if (RDREG) RDVAL = ~(RSVAL | RTVAL); break; + case RSP_SLT: if (RDREG) RDVAL = (INT32)RSVAL < (INT32)RTVAL; break; + case RSP_SLTU: if (RDREG) RDVAL = (UINT32)RSVAL < (UINT32)RTVAL; break; + case RSP_BLTZ: if ((INT32)(RSVAL) < 0) cond = 1; break; + case RSP_BGEZ: if ((INT32)(RSVAL) >= 0) cond = 1; break; + case RSP_BGEZAL: _LINK(31); if ((INT32)(RSVAL) >= 0) _JUMP_REL(SIMM16); break; + case RSP_J: cond = 1; break; + case RSP_JAL: _JUMP_PC_L(UIMM26<<2, 31); break; + case RSP_BEQ: if (RSVAL == RTVAL) cond = 1; break; + case RSP_BNE: if (RSVAL != RTVAL) cond = 1; break; + case RSP_BLEZ: if ((INT32)RSVAL <= 0) cond = 1; break; + case RSP_BGTZ: if ((INT32)RSVAL > 0) cond = 1; break; + case RSP_ADDI: if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break; + case RSP_ADDIU: if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break; + case RSP_SLTI: if (RTREG) RTVAL = (INT32)(RSVAL) < ((INT32)SIMM16); break; + case RSP_SLTIU: if (RTREG) RTVAL = (UINT32)(RSVAL) < (UINT32)((INT32)SIMM16); break; + case RSP_ANDI: if (RTREG) RTVAL = RSVAL & UIMM16; break; + case RSP_ORI: if (RTREG) RTVAL = RSVAL | UIMM16; break; + case RSP_XORI: if (RTREG) RTVAL = RSVAL ^ UIMM16; break; + case RSP_LUI: if (RTREG) RTVAL = UIMM16 << 16; break; + + case RSP_COP0: + { + switch ((op >> 21) & 0x1f) + { + case 0x00: /* MFC0 */ + if (RTREG) + RTVAL = get_cop0_reg(RDREG); + break; + case 0x04: /* MTC0 */ + set_cop0_reg(RDREG, RTVAL); + if (rsp.inval_gen) { + rsp.inval_gen = 0; + sp_pc = ((bc.flags >>3) + 4)&0xffc; + return 2; + } + break; + default: + log(M64MSG_WARNING, "unimplemented cop0 %x (%x)\n", (op >> 21) & 0x1f, op); + break; + } + break; + } + + case RSP_MFC2: + { + // 31 25 20 15 10 6 0 + // --------------------------------------------------- + // | 010010 | 00000 | TTTTT | DDDDD | IIII | 0000000 | + // --------------------------------------------------- + // + + int el = (op >> 7) & 0xf; + UINT16 b1 = VREG_B(VS1REG, (el+0) & 0xf); + UINT16 b2 = VREG_B(VS1REG, (el+1) & 0xf); + if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2)); + break; + } + case RSP_CFC2: + { + // 31 25 20 15 10 0 + // ------------------------------------------------ + // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 | + // ------------------------------------------------ + // + + // VP to sign extend or to not sign extend ? + //if (RTREG) RTVAL = (INT16)rsp.flag[RDREG]; + if (RTREG) RTVAL = rsp.flag[RDREG]; + break; + } + case RSP_MTC2: + { + // 31 25 20 15 10 6 0 + // --------------------------------------------------- + // | 010010 | 00100 | TTTTT | DDDDD | IIII | 0000000 | + // --------------------------------------------------- + // + + int el = (op >> 7) & 0xf; + VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff; + VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff; + break; + } + case RSP_CTC2: + { + // 31 25 20 15 10 0 + // ------------------------------------------------ + // | 010010 | 00110 | TTTTT | DDDDD | 00000000000 | + // ------------------------------------------------ + // + + rsp.flag[RDREG] = RTVAL & 0xffff; + break; + } + case RSP_LB: if (RTREG) RTVAL = (INT32)(INT8)READ8(RSVAL + SIMM16); break; + case RSP_LH: if (RTREG) RTVAL = (INT32)(INT16)READ16(RSVAL + SIMM16); break; + case RSP_LW: if (RTREG) RTVAL = READ32(RSVAL + SIMM16); break; + case RSP_LBU: if (RTREG) RTVAL = (UINT8)READ8(RSVAL + SIMM16); break; + case RSP_LHU: if (RTREG) RTVAL = (UINT16)READ16(RSVAL + SIMM16); break; + case RSP_SB: WRITE8(RSVAL + SIMM16, RTVAL); break; + case RSP_SH: WRITE16(RSVAL + SIMM16, RTVAL); break; + case RSP_SW: WRITE32(RSVAL + SIMM16, RTVAL); break; + + default: + switch (op >> 26) + { + case 0x12: /* COP2 */ + handle_vector_ops(op); + break; + case 0x32: /* LWC2 */ + handle_lwc2(op); + break; + case 0x3a: /* SWC2 */ + handle_swc2(op); + break; + } + } + } +} + +int rsp_gen_cache_hit; +int rsp_gen_cache_miss; +int rsp_jump(int pc) +{ + pc &= 0xfff; + sp_pc = pc; + rsp.nextpc = ~0; + opinfo_t * opi = &OPI(pc); + gen_t * gen = opi->curgen; + rsp_gen_cache_hit++; + if (!gen) { + rsp_gen_cache_miss++; + rsp_gen(pc); + } + gen = opi->curgen; + //fprintf(stderr, "rsp_jump %x (%s)\n", pc, gen->name); + + int res = run(rsp, gen); + + //fprintf(stderr, "r31 %x from %x nextpc %x pc %x res %d (%s)\n", rsp.r[31], pc, rsp.nextpc, sp_pc, res, gen->name); + if (rsp.nextpc != ~0U) + { + sp_pc = (rsp.nextpc & 0xfff); + rsp.nextpc = ~0U; + } + else + { + //sp_pc = ((sp_pc+4)&0xfff); + } + return res; +}