summaryrefslogtreecommitdiff
path: root/libpcsxcore/pgxp_debug.c
diff options
context:
space:
mode:
authoriCatButler <i.am.catbutler@gmail.com>2016-07-30 17:43:12 +0100
committeriCatButler <i.am.catbutler@gmail.com>2016-07-30 17:43:12 +0100
commit69f33a4782857bf2027db6c81f670409bed76b43 (patch)
treeca5ac7afe837748e8c1db89c2519eabf367df4ea /libpcsxcore/pgxp_debug.c
parentd5b40fbbe0eee90573ec1848ac135962fba9438e (diff)
downloadpcsxr-69f33a4782857bf2027db6c81f670409bed76b43.tar.gz
Various CPU updates
- Sign extend values read using LH - Add conversion functions to represent Signed/Unsigned 16-bit ranges - Add overflow and truncation functions for 16-bit ranges - Sign extend imm value in ADD(U) - Add component overflow and truncation to ADD/SUB functions - Construct new value in logic operators where result using inputs is undefined - Return a valid W component from logic operators (if either input has one) - Compare against high value (y), then low value (x) in less than operators - Use doubles and implement overflow for Multiply operations to try to increase accuracy - Use unsigned values in both MUL and DIV operations to make output as accurate as possible - Implement several variants of shift operators. Trying both arithmetically correct and more analytical approaches with varying success. Debug updates - Added ability to force all values to be equal to low precision values before operating on them - Added feature to test output of operations against a tolerance and print only those which fail GPU updates - Colour vertices with valid XY coordinates but no W as cyan to make them easier to spot - Remove cyan colouring for stale vertices (wasn't useful) - Added ability to skip debug rendering when needed (like seeing the output of offscreen rendering applied to a sprite). - Added new mode which shows primitive type
Diffstat (limited to 'libpcsxcore/pgxp_debug.c')
-rw-r--r--libpcsxcore/pgxp_debug.c170
1 files changed, 136 insertions, 34 deletions
diff --git a/libpcsxcore/pgxp_debug.c b/libpcsxcore/pgxp_debug.c
index 4bd1567e..beb12526 100644
--- a/libpcsxcore/pgxp_debug.c
+++ b/libpcsxcore/pgxp_debug.c
@@ -119,14 +119,14 @@ static PGXP_CPU_OpData PGXP_BSC_LUT[64] = {
#define PGXP_Data_DIVU { DBG_E_DIVU, fOp_CPU_Hi | fOp_CPU_Lo, fOp_CPU_Rs | fOp_CPU_Rt, 4, 4, "/", "DIVU", (void(*)())PGXP_CPU_DIVU }
// Shift operations (sa)
-#define PGXP_Data_SLL { DBG_E_SLL, fOp_CPU_Rd, fOp_CPU_Rt | fOp_Sa, 2, 2, ">>", "SLL", (void(*)())PGXP_CPU_SLL }
-#define PGXP_Data_SRL { DBG_E_SRL, fOp_CPU_Rd, fOp_CPU_Rt | fOp_Sa, 2, 2, "<<", "SRL", (void(*)())PGXP_CPU_SRL }
-#define PGXP_Data_SRA { DBG_E_SRA, fOp_CPU_Rd, fOp_CPU_Rt | fOp_Sa, 2, 2, "<<", "SRA", (void(*)())PGXP_CPU_SRA }
+#define PGXP_Data_SLL { DBG_E_SLL, fOp_CPU_Rd, fOp_CPU_Rt | fOp_Sa, 2, 2, "<<", "SLL", (void(*)())PGXP_CPU_SLL }
+#define PGXP_Data_SRL { DBG_E_SRL, fOp_CPU_Rd, fOp_CPU_Rt | fOp_Sa, 2, 2, ">>", "SRL", (void(*)())PGXP_CPU_SRL }
+#define PGXP_Data_SRA { DBG_E_SRA, fOp_CPU_Rd, fOp_CPU_Rt | fOp_Sa, 2, 2, ">>", "SRA", (void(*)())PGXP_CPU_SRA }
// Shift operations variable
-#define PGXP_Data_SLLV { DBG_E_SLLV, fOp_CPU_Rd, fOp_CPU_Rt | fOp_CPU_Rs, 3, 3, ">>", "SLLV", (void(*)())PGXP_CPU_SLLV }
-#define PGXP_Data_SRLV { DBG_E_SRLV, fOp_CPU_Rd, fOp_CPU_Rt | fOp_CPU_Rs, 3, 3, "<<", "SRLV", (void(*)())PGXP_CPU_SRLV }
-#define PGXP_Data_SRAV { DBG_E_SRAV, fOp_CPU_Rd, fOp_CPU_Rt | fOp_CPU_Rs, 3, 3, "<<", "SRAV", (void(*)())PGXP_CPU_SRAV }
+#define PGXP_Data_SLLV { DBG_E_SLLV, fOp_CPU_Rd, fOp_CPU_Rt | fOp_CPU_Rs, 3, 3, "<<", "SLLV", (void(*)())PGXP_CPU_SLLV }
+#define PGXP_Data_SRLV { DBG_E_SRLV, fOp_CPU_Rd, fOp_CPU_Rt | fOp_CPU_Rs, 3, 3, ">>", "SRLV", (void(*)())PGXP_CPU_SRLV }
+#define PGXP_Data_SRAV { DBG_E_SRAV, fOp_CPU_Rd, fOp_CPU_Rt | fOp_CPU_Rs, 3, 3, ">>", "SRAV", (void(*)())PGXP_CPU_SRAV }
// Move registers
#define PGXP_Data_MFHI { DBG_E_MFHI, fOp_CPU_Rd, fOp_CPU_Hi, 2, 2, "<-", "MFHI", (void(*)())PGXP_CPU_MFHI }
@@ -203,11 +203,96 @@ PGXP_CPU_OpData GetOpData(u32 instr)
return pOpData;
}
-void PrintOperands(char* szBuffer, u32 instr, u32 flags, const char* szDelim, psx_value* psx_regs, u32* regIdx)
+PGXP_value* GetReg(u32 instr, u32 flag, u32 psxValue)
+{
+ // iCB Hack: reorder Rs and Rt for SLLV SRLV and SRAV
+ if ((op(instr) == 0) && (func(instr) > 3) && (func(instr) < 8))
+ flag = (flag == fOp_CPU_Rs) ? fOp_CPU_Rt : ((flag == fOp_CPU_Rt) ? fOp_CPU_Rs : flag);
+ // /iCB Hack
+
+ switch (flag)
+ {
+ case fOp_CPU_Hi:
+ return &CPU_Hi;
+ case fOp_CPU_Lo:
+ return &CPU_Lo;
+ case fOp_CPU_Rd:
+ return &CPU_reg[rd(instr)];
+ case fOp_CPU_Rs:
+ return &CPU_reg[rs(instr)];
+ case fOp_CPU_Rt:
+ return &CPU_reg[rt(instr)];
+ case fOp_GTE_Dd:
+ return &GTE_data_reg[rd(instr)];
+ case fOp_GTE_Dt:
+ return &GTE_data_reg[rt(instr)];
+ case fOp_GTE_Cd:
+ return &GTE_ctrl_reg[rd(instr)];
+ case fOp_GTE_Ct:
+ return &GTE_ctrl_reg[rt(instr)];
+ case fOp_CP0_Dd:
+ return &CP0_reg[rd(instr)];
+ case fOp_CP0_Cd:
+ return &CP0_reg[rd(instr)];
+ case fOp_Ad:
+ return GetPtr(psxValue);
+ default:
+ return NULL;
+ }
+}
+
+void ForceValues(u32 instr, u32 flags, psx_value* psx_regs, u32 startIdx)
+{
+ PGXP_value* pReg = NULL;
+ u32 regIdx = startIdx;
+
+ for (u32 opdIdx = 0; opdIdx < 14; opdIdx++)
+ {
+ u32 flag = 1 << opdIdx;
+
+ // iCB: Skip Load operations as data at address is unknown
+ if ((flags & flag) && (flag != fOp_Ad))
+ {
+ pReg = GetReg(instr, flag, psx_regs[regIdx].d);
+
+ if (pReg)
+ {
+ SetValue(pReg, psx_regs[regIdx].d);
+ regIdx++;
+ }
+ }
+ }
+}
+
+void TestValues(u32 instr, u32 flags, psx_value* psx_regs, u32 *test_flags, u32 startIdx)
+{
+ PGXP_value* pReg = NULL;
+ u32 regIdx = startIdx;
+
+ for (u32 opdIdx = 0; opdIdx < 14; opdIdx++)
+ {
+ u32 flag = 1 << opdIdx;
+
+ // iCB: Skip Store operations as data at address is unknown
+ if ((flags & flag) && (flag != fOp_Ad))
+ {
+ pReg = GetReg(instr, flag, psx_regs[regIdx].d);
+
+ if (pReg)
+ {
+ test_flags[regIdx] = ValueToTolerance(pReg, psx_regs[regIdx].d, PGXP_DEBUG_TOLERANCE);
+ regIdx++;
+ }
+ }
+ }
+}
+
+void PrintOperands(char* szBuffer, u32 instr, u32 flags, const char* szDelim, psx_value* psx_regs, u32 startIdx)
{
char szTempBuffer[256];
PGXP_value* pReg = NULL;
psx_value psx_reg;
+ u32 regIdx = startIdx;
char szOpdName[16];
const char* szPre = "";
@@ -217,7 +302,7 @@ void PrintOperands(char* szBuffer, u32 instr, u32 flags, const char* szDelim, ps
u32 flag = 1 << opdIdx;
// iCB Hack: reorder Rs and Rt for SLLV SRLV and SRAV
- if ((op(instr) < 8) && (op(instr) > 3))
+ if ((op(instr) == 0) && (func(instr) > 3) && (func(instr) < 8))
flag = (flag == fOp_CPU_Rs) ? fOp_CPU_Rt : ((flag == fOp_CPU_Rt) ? fOp_CPU_Rs : flag);
// /iCB Hack
@@ -228,62 +313,62 @@ void PrintOperands(char* szBuffer, u32 instr, u32 flags, const char* szDelim, ps
case fOp_CPU_Hi:
pReg = &CPU_Hi;
sprintf(szOpdName, "Hi");
- psx_reg = psx_regs[(*regIdx)++];
+ psx_reg = psx_regs[regIdx++];
break;
case fOp_CPU_Lo:
pReg = &CPU_Lo;
sprintf(szOpdName, "Lo");
- psx_reg = psx_regs[(*regIdx)++];
+ psx_reg = psx_regs[regIdx++];
break;
case fOp_CPU_Rd:
pReg = &CPU_reg[rd(instr)];
sprintf(szOpdName, "Rd[%d]", rd(instr));
- psx_reg = psx_regs[(*regIdx)++];
+ psx_reg = psx_regs[regIdx++];
break;
case fOp_CPU_Rs:
pReg = &CPU_reg[rs(instr)];
sprintf(szOpdName, "Rs[%d]", rs(instr));
- psx_reg = psx_regs[(*regIdx)++];
+ psx_reg = psx_regs[regIdx++];
break;
case fOp_CPU_Rt:
pReg = &CPU_reg[rt(instr)];
sprintf(szOpdName, "Rt[%d]", rt(instr));
- psx_reg = psx_regs[(*regIdx)++];
+ psx_reg = psx_regs[regIdx++];
break;
case fOp_GTE_Dd:
pReg = &GTE_data_reg[rd(instr)];
sprintf(szOpdName, "GTE_Dd[%d]", rd(instr));
- psx_reg = psx_regs[(*regIdx)++];
+ psx_reg = psx_regs[regIdx++];
break;
case fOp_GTE_Dt:
pReg = &GTE_data_reg[rt(instr)];
sprintf(szOpdName, "GTE_Dt[%d]", rt(instr));
- psx_reg = psx_regs[(*regIdx)++];
+ psx_reg = psx_regs[regIdx++];
break;
case fOp_GTE_Cd:
pReg = &GTE_ctrl_reg[rd(instr)];
sprintf(szOpdName, "GTE_Cd[%d]", rd(instr));
- psx_reg = psx_regs[(*regIdx)++];
+ psx_reg = psx_regs[regIdx++];
break;
case fOp_GTE_Ct:
pReg = &GTE_ctrl_reg[rt(instr)];
sprintf(szOpdName, "GTE_Ct[%d]", rt(instr));
- psx_reg = psx_regs[(*regIdx)++];
+ psx_reg = psx_regs[regIdx++];
break;
case fOp_CP0_Dd:
pReg = &CP0_reg[rd(instr)];
sprintf(szOpdName, "CP0_Dd[%d]", rd(instr));
- psx_reg = psx_regs[(*regIdx)++];
+ psx_reg = psx_regs[regIdx++];
break;
case fOp_CP0_Cd:
pReg = &CP0_reg[rd(instr)];
sprintf(szOpdName, "CP0_Cd[%d]", rd(instr));
- psx_reg = psx_regs[(*regIdx)++];
+ psx_reg = psx_regs[regIdx++];
break;
case fOp_Ad:
pReg = NULL;
sprintf(szOpdName, "Addr");
- psx_reg = psx_regs[(*regIdx)++];
+ psx_reg = psx_regs[regIdx++];
break;
case fOp_Sa:
pReg = NULL;
@@ -333,8 +418,9 @@ void PGXP_CPU_DebugOutput(u32 eOp, u32 instr, u32 numOps, u32 op1, u32 op2, u32
char szOutputBuffer[256];
char szInputBuffer[512];
PGXP_CPU_OpData opData = GetOpData(instr);
- psx_value psx_regs[4];
- u32 regIdx = 0;
+ u32 test_flags[4] = { VALID_ALL, VALID_ALL, VALID_ALL, VALID_ALL };
+ psx_value psx_regs[4];
+ u32 inIdx = 0;
psx_regs[0].d = op1;
psx_regs[1].d = op2;
psx_regs[2].d = op3;
@@ -353,22 +439,29 @@ void PGXP_CPU_DebugOutput(u32 eOp, u32 instr, u32 numOps, u32 op1, u32 op2, u32
// /iCB Hack
+ // skip output arguments to find first input
+ for (u32 opdIdx = 0; opdIdx < 12; opdIdx++)
+ {
+ if (opData.OutputFlags & (1 << opdIdx))
+ inIdx++;
+ }
+
+#ifdef PGXP_FORCE_INPUT_VALUES
+ ForceValues(instr, opData.InputFlags, psx_regs, inIdx);
+#endif
+
+
+#ifdef PGXP_OUTPUT_ALL
// reset buffers
if (pgxp_debug)
{
memset(szInputBuffer, 0, sizeof(szInputBuffer));
memset(szOutputBuffer, 0, sizeof(szOutputBuffer));
- // skip output arguments
- for (u32 opdIdx = 0; opdIdx < 12; opdIdx++)
- {
- if (opData.OutputFlags & (1 << opdIdx))
- regIdx++;
- }
-
// Print inputs
- PrintOperands(szInputBuffer, instr, opData.InputFlags, opData.szOpString, psx_regs, &regIdx);
+ PrintOperands(szInputBuffer, instr, opData.InputFlags, opData.szOpString, psx_regs, inIdx);
}
+#endif
// Call function
if (numOps != opData.numArgs)
@@ -396,19 +489,28 @@ void PGXP_CPU_DebugOutput(u32 eOp, u32 instr, u32 numOps, u32 op1, u32 op2, u32
break;
}
+#ifdef PGXP_TEST_OUTPUT_VALUES
+ TestValues(instr, opData.OutputFlags, psx_regs, test_flags, 0);
+#endif//PGXP_TEST_OUTPUT_VALUES
+
+#ifdef PGXP_OUTPUT_ALL
// Print operation details
if (pgxp_debug)
{
sprintf(szOutputBuffer, "%s %x %x: ", opData.szOpName, op(instr), func(instr));
// Print outputs
- regIdx = 0;
- PrintOperands(szOutputBuffer, instr, opData.OutputFlags, "/", psx_regs, &regIdx);
+ PrintOperands(szOutputBuffer, instr, opData.OutputFlags, "/", psx_regs, 0);
strcat(szOutputBuffer, "=");
#ifdef GTE_LOG
- GTE_LOG("PGXP_Trace: %s %s|", szOutputBuffer, szInputBuffer);
-#endif
+#ifdef PGXP_TEST_OUTPUT_VALUES
+ if((test_flags[0] & test_flags[1] & VALID_01) != VALID_01)
+#endif//PGXP_TEST_OUTPUT_VALUES
+ GTE_LOG("PGXP_Trace: %s %s|", szOutputBuffer, szInputBuffer);
+#endif//GTE_LOG
+
}
+#endif//PGXP_OUTPUT_ALL
}
void PGXP_psxTraceOp(u32 eOp, u32 instr)