aboutsummaryrefslogtreecommitdiff
path: root/libpcsxcore/ppc/reguse.c
diff options
context:
space:
mode:
authorPCSX* teams2010-11-16 14:15:22 +0200
committerGrazvydas Ignotas2010-11-16 14:15:22 +0200
commitef79bbde537d6b9c745a7d86cb9df1d04c35590d (patch)
treeef8d2520dbb9e1e345b41b12c9959f300ca8fd10 /libpcsxcore/ppc/reguse.c
downloadpcsx_rearmed-ef79bbde537d6b9c745a7d86cb9df1d04c35590d.tar.gz
pcsx_rearmed-ef79bbde537d6b9c745a7d86cb9df1d04c35590d.tar.bz2
pcsx_rearmed-ef79bbde537d6b9c745a7d86cb9df1d04c35590d.zip
pcsxr-1.9.92
Diffstat (limited to 'libpcsxcore/ppc/reguse.c')
-rw-r--r--libpcsxcore/ppc/reguse.c419
1 files changed, 419 insertions, 0 deletions
diff --git a/libpcsxcore/ppc/reguse.c b/libpcsxcore/ppc/reguse.c
new file mode 100644
index 0000000..47d70a5
--- /dev/null
+++ b/libpcsxcore/ppc/reguse.c
@@ -0,0 +1,419 @@
+
+#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<numInstr; ) {
+ // load current instruction
+ ptr = PSXM(pc);
+ if (ptr==NULL) {
+ // going nowhere... might as well assume a write, since we will hopefully never reach here
+ reguse = REGUSE_WRITE;
+ break;
+ }
+ code = SWAP32(*ptr);
+ // get usage patterns for instruction
+ use = getRegUse(code);
+ // find the use of psxreg in the instruction
+ reguse = useOfPsxReg(code, use, psxreg);
+
+ // return if we have found a use
+ if (reguse != REGUSE_NONE)
+ break;
+
+ // goto next instruction
+ pc += 4;
+ i++;
+
+ // check for code branches/jumps
+ if (i != numInstr) {
+ if ((use & REGUSE_TYPEM) == REGUSE_BRANCH) {
+#ifndef NOREGUSE_FOLLOW
+ // check delay slot
+ reguse = _nextPsxRegUse(pc, psxreg, 1);
+ if (reguse != REGUSE_NONE) break;
+
+ bPC = _fImm_(code) * 4 + pc;
+ reguse = _nextPsxRegUse(pc+4, psxreg, (numInstr-i-1)/2);
+ if (reguse != REGUSE_NONE) {
+ int reguse2 = _nextPsxRegUse(bPC, psxreg, (numInstr-i-1)/2);
+ if (reguse2 != REGUSE_NONE)
+ reguse |= reguse2;
+ else
+ reguse = REGUSE_NONE;
+ }
+#endif
+ break;
+ } else if ((use & REGUSE_TYPEM) == REGUSE_JUMP) {
+#ifndef NOREGUSE_FOLLOW
+ // check delay slot
+ reguse = _nextPsxRegUse(pc, psxreg, 1);
+ if (reguse != REGUSE_NONE) break;
+
+ bPC = _fTarget_(code) * 4 + (pc & 0xf0000000);
+ reguse = _nextPsxRegUse(bPC, psxreg, numInstr-i-1);
+#endif
+ break;
+ } else if ((use & REGUSE_TYPEM) == REGUSE_JUMPR) {
+#ifndef NOREGUSE_FOLLOW
+ // jump to unknown location - bail after checking delay slot
+ reguse = _nextPsxRegUse(pc, psxreg, 1);
+#endif
+ break;
+ } else if ((use & REGUSE_TYPEM) == REGUSE_SYS) {
+ break;
+ }
+ }
+ }
+
+ return reguse;
+}
+
+
+int nextPsxRegUse(u32 pc, int psxreg)
+{
+#if 1
+ if (psxreg == 0)
+ return REGUSE_WRITE; // pretend we are writing to it to fool compiler
+
+#ifdef SAME_CYCLE_MODE
+ return REGUSE_READ;
+#else
+ return _nextPsxRegUse(pc, psxreg, 80);
+#endif
+#else
+ u32 code, bPC = 0;
+ int use, reguse = 0, reguse1 = 0, b = 0, i, index = 0;
+
+retry:
+ for (i=index; i<80; i++) {
+ code = PSXMu32(pc);
+ use = getRegUse(code);
+ reguse = useOfPsxReg(code, use, psxreg);
+
+ if (reguse != REGUSE_NONE) break;
+
+ pc += 4;
+ if ((use & REGUSE_TYPEM) == REGUSE_BRANCH) {
+ if (b == 0) {
+ bPC = _fImm_(code) * 4 + pc;
+ index = i+1;
+ }
+ b += 1; // TODO: follow branches
+ continue;
+ } else if ((use & REGUSE_TYPEM) == REGUSE_JUMP) {
+ if (b == 0) {
+ bPC = _fTarget_(code) * 4 + (pc & 0xf0000000);
+ }
+ b = 2;
+ continue;
+ } else if ((use & REGUSE_TYPEM) == REGUSE_JUMPR ||
+ (use & REGUSE_TYPEM) == REGUSE_SYS) {
+ b = 2;
+ continue;
+ }
+
+ if (b == 2 && bPC && index == 0) {
+ pc = bPC; bPC = 0;
+ b = 1;
+ }
+ if (b >= 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
+}