#include "../psxcommon.h" #include "reguse.h" #include "../r3000a.h" //#define SAME_CYCLE_MODE static const int useBSC[64] = { /*recSPECIAL*/ REGUSE_SUB | REGUSE_SPECIAL, /*recREGIMM*/ REGUSE_SUB | REGUSE_REGIMM, /*recJ*/ REGUSE_JUMP, /*recJAL*/ REGUSE_JUMP | REGUSE_R31_W, /*recBEQ*/ REGUSE_BRANCH | REGUSE_RS_R | REGUSE_RT_R, /*recBNE*/ REGUSE_BRANCH | REGUSE_RS_R | REGUSE_RT_R, /*recBLEZ*/ REGUSE_BRANCH | REGUSE_RS_R, /*recBGTZ*/ REGUSE_BRANCH | REGUSE_RS_R, /*recADDI*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_W, /*recADDIU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_W, /*recSLTI*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_W, /*recSLTIU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_W, /*recANDI*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_W, /*recORI*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_W, /*recXORI*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_W, /*recLUI*/ REGUSE_ACC | REGUSE_RT_W, /*recCOP0*/ REGUSE_SUB | REGUSE_COP0, REGUSE_NONE, /*recCOP2*/ REGUSE_SUB | REGUSE_COP2, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, /*recLB*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W, /*recLH*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W, /*recLWL*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT, /*recLW*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W, /*recLBU*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W, /*recLHU*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W, /*recLWR*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT, REGUSE_NONE, /*recSB*/ REGUSE_MEM_W | REGUSE_RS_R | REGUSE_RT_R, /*recSH*/ REGUSE_MEM_W | REGUSE_RS_R | REGUSE_RT_R, /*recSWL*/ REGUSE_MEM | REGUSE_RS_R | REGUSE_RT_R, /*recSW*/ REGUSE_MEM_W | REGUSE_RS_R | REGUSE_RT_R, REGUSE_NONE, REGUSE_NONE, /*recSWR*/ REGUSE_MEM | REGUSE_RS_R | REGUSE_RT_R, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, /*recLWC2*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_COP2_RT_W, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, /*recSWC2*/ REGUSE_MEM_W | REGUSE_RS_R | REGUSE_COP2_RT_R, /*recHLE*/ REGUSE_UNKNOWN, // TODO: can this be done in a better way REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE }; static const int useSPC[64] = { /*recSLL*/ REGUSE_ACC | REGUSE_RT_R | REGUSE_RD_W, REGUSE_NONE, /*recSRL*/ REGUSE_ACC | REGUSE_RT_R | REGUSE_RD_W, /*recSRA*/ REGUSE_ACC | REGUSE_RT_R | REGUSE_RD_W, /*recSLLV*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, REGUSE_NONE, /*recSRLV*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, /*recSRAV*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, /*recJR*/ REGUSE_JUMPR | REGUSE_RS_R, /*recJALR*/ REGUSE_JUMPR | REGUSE_RS_R | REGUSE_RD_W, REGUSE_NONE, REGUSE_NONE, /*rSYSCALL*/ REGUSE_SYS | REGUSE_PC | REGUSE_COP0_STATUS | REGUSE_EXCEPTION, /*recBREAK*/ REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, /*recMFHI*/ REGUSE_LOGIC | REGUSE_RD_W | REGUSE_HI_R, /*recMTHI*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_HI_W, /*recMFLO*/ REGUSE_LOGIC | REGUSE_RD_W | REGUSE_LO_R, /*recMTLO*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_LO_W, REGUSE_NONE, REGUSE_NONE , REGUSE_NONE, REGUSE_NONE, /*recMULT*/ REGUSE_MULT | REGUSE_RS_R | REGUSE_RT_R | REGUSE_LO_W | REGUSE_HI_W, /*recMULTU*/ REGUSE_MULT | REGUSE_RS_R | REGUSE_RT_R | REGUSE_LO_W | REGUSE_HI_W, /*recDIV*/ REGUSE_MULT | REGUSE_RS_R | REGUSE_RT_R | REGUSE_LO_W | REGUSE_HI_W, /*recDIVU*/ REGUSE_MULT | REGUSE_RS_R | REGUSE_RT_R | REGUSE_LO_W | REGUSE_HI_W, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, /*recADD*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, /*recADDU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, /*recSUB*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, /*recSUBU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, /*recAND*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, /*recOR*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, /*recXOR*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, /*recNOR*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, REGUSE_NONE, REGUSE_NONE, /*recSLT*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, /*recSLTU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE }; static const int useREGIMM[32] = { /*recBLTZ*/ REGUSE_BRANCH | REGUSE_RS_R, /*recBGEZ*/ REGUSE_BRANCH | REGUSE_RS_R, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, /*recBLTZAL*/REGUSE_BRANCH | REGUSE_RS_R | REGUSE_R31_W, /*recBGEZAL*/REGUSE_BRANCH | REGUSE_RS_R | REGUSE_R31_W, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE }; static const int useCP0[32] = { /*recMFC0*/ REGUSE_LOGIC | REGUSE_RT_W | REGUSE_COP0_RD_R, REGUSE_NONE, /*recCFC0*/ REGUSE_LOGIC | REGUSE_RT_W | REGUSE_COP0_RD_R, REGUSE_NONE, /*recMTC0*/ REGUSE_LOGIC | REGUSE_RT_R | REGUSE_COP0_RD_W, REGUSE_NONE, /*recCTC0*/ REGUSE_LOGIC | REGUSE_RT_R | REGUSE_COP0_RD_W, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, /*recRFE*/ REGUSE_LOGIC | REGUSE_COP0_STATUS, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE }; // TODO: make more explicit static const int useCP2[64] = { /*recBASIC*/ REGUSE_SUB | REGUSE_BASIC, /*recRTPS*/ REGUSE_GTE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, /*recNCLIP*/ REGUSE_GTE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, /*recOP*/ REGUSE_GTE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, /*recDPCS*/ REGUSE_GTE, /*recINTPL*/ REGUSE_GTE, /*recMVMVA*/ REGUSE_GTE, /*recNCDS*/ REGUSE_GTE, /*recCDP*/ REGUSE_GTE, REGUSE_NONE, /*recNCDT*/ REGUSE_GTE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, /*recNCCS*/ REGUSE_GTE, /*recCC*/ REGUSE_GTE, REGUSE_NONE, /*recNCS*/ REGUSE_GTE, REGUSE_NONE, /*recNCT*/ REGUSE_GTE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, /*recSQR*/ REGUSE_GTE, /*recDCPL*/ REGUSE_GTE, /*recDPCT*/ REGUSE_GTE, REGUSE_NONE, REGUSE_NONE, /*recAVSZ3*/ REGUSE_GTE, /*recAVSZ4*/ REGUSE_GTE, REGUSE_NONE, /*recRTPT*/ REGUSE_GTE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, /*recGPF*/ REGUSE_GTE, /*recGPL*/ REGUSE_GTE, /*recNCCT*/ REGUSE_GTE }; static const int useCP2BSC[32] = { /*recMFC2*/ REGUSE_LOGIC | REGUSE_RT_W | REGUSE_COP2_RD_R, REGUSE_NONE, /*recCFC2*/ REGUSE_LOGIC | REGUSE_RT_W | REGUSE_COP2_RD_R, REGUSE_NONE, /*recMTC2*/ REGUSE_LOGIC | REGUSE_RT_R | REGUSE_COP2_RD_W, REGUSE_NONE, /*recCTC2*/ REGUSE_LOGIC | REGUSE_RT_R | REGUSE_COP2_RD_W, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE }; static int getRegUse(u32 code) __attribute__ ((__pure__)); static int getRegUse(u32 code) { int use = useBSC[code>>26]; switch (use & REGUSE_SUBMASK) { case REGUSE_NONE: break; case REGUSE_SPECIAL: use = useSPC[_fFunct_(code)]; break; case REGUSE_REGIMM: use = useREGIMM[_fRt_(code)]; break; case REGUSE_COP0: use = useCP0[_fRs_(code)]; break; case REGUSE_COP2: use = useCP2[_fFunct_(code)]; if ((use & REGUSE_SUBMASK) == REGUSE_BASIC) use = useCP2BSC[_fRs_(code)]; break; default: use = REGUSE_UNKNOWN; break; } if ((use & REGUSE_COP0_RD_W)) { if (_fRd_(code) == 12 || _fRd_(code) == 13) { use = REGUSE_UNKNOWN; } } return use; } /* returns how psxreg is used in the code instruction */ int useOfPsxReg(u32 code, int use, int psxreg) { int retval = REGUSE_NONE; // get use if it wasn't supplied if (-1 == use) use = getRegUse(code); // if we don't know what the usage is, assume it's read from if (REGUSE_UNKNOWN == use) return REGUSE_READ; if (psxreg < 32) { // check for 3 standard types if ((use & REGUSE_RT) && _fRt_(code) == (u32)psxreg) { retval |= ((use & REGUSE_RT_R) ? REGUSE_READ:0) | ((use & REGUSE_RT_W) ? REGUSE_WRITE:0); } if ((use & REGUSE_RS) && _fRs_(code) == (u32)psxreg) { retval |= ((use & REGUSE_RS_R) ? REGUSE_READ:0) | ((use & REGUSE_RS_W) ? REGUSE_WRITE:0); } if ((use & REGUSE_RD) && _fRd_(code) == (u32)psxreg) { retval |= ((use & REGUSE_RD_R) ? REGUSE_READ:0) | ((use & REGUSE_RD_W) ? REGUSE_WRITE:0); } // some instructions explicitly writes to r31 if ((use & REGUSE_R31_W) && 31 == psxreg) { retval |= REGUSE_WRITE; } } else if (psxreg == 32) { // Special register LO retval |= ((use & REGUSE_LO_R) ? REGUSE_READ:0) | ((use & REGUSE_LO_W) ? REGUSE_WRITE:0); } else if (psxreg == 33) { // Special register HI retval |= ((use & REGUSE_HI_R) ? REGUSE_READ:0) | ((use & REGUSE_HI_W) ? REGUSE_WRITE:0); } return retval; } //#define NOREGUSE_FOLLOW static int _nextPsxRegUse(u32 pc, int psxreg, int numInstr) __attribute__ ((__pure__, __unused__)); static int _nextPsxRegUse(u32 pc, int psxreg, int numInstr) { u32 *ptr, code, bPC = 0; int i, use, reguse = 0; for (i=0; i= 2) break; // only follow 1 branch } if (reguse == REGUSE_NONE) return reguse; if (bPC) { reguse1 = reguse; pc = bPC; bPC = 0; b = 1; goto retry; } return reguse1 | reguse; #endif } int isPsxRegUsed(u32 pc, int psxreg) { int use = nextPsxRegUse(pc, psxreg); if (use == REGUSE_NONE) return 2; // unknown use - assume it is used else if (use & REGUSE_READ) return 1; // the next use is a read else return 0; // the next use is a write, i.e. current value is not important }