diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 45913800fd..21219fb30e 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -530,6 +530,8 @@ public: p.Do(isProcessingCallbacks); p.Do(currentMipscallId); p.Do(currentCallbackId); + + // TODO: How do I "version" adding a DoState method to ThreadContext? p.Do(context); if (s <= 2) { diff --git a/Core/MIPS/ARM/ArmCompVFPU.cpp b/Core/MIPS/ARM/ArmCompVFPU.cpp index e67c9bed0d..5f16d55654 100644 --- a/Core/MIPS/ARM/ArmCompVFPU.cpp +++ b/Core/MIPS/ARM/ArmCompVFPU.cpp @@ -202,13 +202,6 @@ namespace MIPSComp SetCC(CC_GT); VMOV(fpr.V(vregs[i]), S1); SetCC(CC_AL); - - /* - VABS(S1, fpr.V(vregs[i])); // S1 = fabs(x) - VSUB(fpr.V(vregs[i]), fpr.V(vregs[i]), S0); // S2 = fabs(x-0.5f) {VABD} - VABS(fpr.V(vregs[i]), fpr.V(vregs[i])); - VSUB(fpr.V(vregs[i]), S1, fpr.V(vregs[i])); // v[i] = S1 - S2 + 0.5f - VADD(fpr.V(vregs[i]), fpr.V(vregs[i]), S0);*/ } else if (sat == 3) { fpr.MapRegV(vregs[i], MAP_DIRTY); @@ -224,16 +217,6 @@ namespace MIPSComp SetCC(CC_GT); VMOV(fpr.V(vregs[i]), S1); SetCC(CC_AL); - - // clamped = fabs(x) - fabs(x-1.0f); // [-1, 1] - /* - fpr.MapRegV(vregs[i], MAP_DIRTY); - MOVI2F(S0, 1.0f, R0); - VABS(S1, fpr.V(vregs[i])); // S1 = fabs(x) - VSUB(fpr.V(vregs[i]), fpr.V(vregs[i]), S0); // S2 = fabs(x-1.0f) {VABD} - VABS(fpr.V(vregs[i]), fpr.V(vregs[i])); - VSUB(fpr.V(vregs[i]), S1, fpr.V(vregs[i])); // v[i] = S1 - S2 - */ } } } diff --git a/Core/MIPS/ARM/ArmRegCacheFPU.cpp b/Core/MIPS/ARM/ArmRegCacheFPU.cpp index 076f376e50..75fcd562a4 100644 --- a/Core/MIPS/ARM/ArmRegCacheFPU.cpp +++ b/Core/MIPS/ARM/ArmRegCacheFPU.cpp @@ -371,10 +371,17 @@ void ArmRegCacheFPU::FlushAll() { int ArmRegCacheFPU::GetMipsRegOffset(MIPSReg r) { // These are offsets within the MIPSState structure. First there are the GPRS, then FPRS, then the "VFPURs", then the VFPU ctrls. - if (r < 32 + 128 + NUM_TEMPS) - return (r + 32) << 2; - ERROR_LOG(JIT, "bad mips register %i, out of range", r); - return 0; // or what? + if (r < 0 || r > 32 + 128 + NUM_TEMPS) { + ERROR_LOG(JIT, "bad mips register %i, out of range", r); + return 0; // or what? + } + + if (r < 32 || r > 32 + 128) { + return (32 + r) << 2; + } else { + // r is between 32 and 128 + 32 + return (32 + 32 + voffset[r - 32]) << 2; + } } void ArmRegCacheFPU::SpillLock(MIPSReg r1, MIPSReg r2, MIPSReg r3, MIPSReg r4) { diff --git a/Core/MIPS/MIPS.cpp b/Core/MIPS/MIPS.cpp index d8b76f4709..f6e28c53ff 100644 --- a/Core/MIPS/MIPS.cpp +++ b/Core/MIPS/MIPS.cpp @@ -44,6 +44,9 @@ MIPSState *currentMIPS = &mipsr4k; MIPSDebugInterface debugr4k(&mipsr4k); MIPSDebugInterface *currentDebugMIPS = &debugr4k; +u8 voffset[128]; +u8 fromvoffset[128]; + #ifndef M_LOG2E #define M_E 2.71828182845904523536f @@ -89,6 +92,48 @@ const float cst_constants[32] = { MIPSState::MIPSState() { MIPSComp::jit = 0; + + // Initialize vorder + + // This reordering of the VFPU registers in RAM means that instead of being like this: + + // 0x00 0x20 0x40 0x60 -> "columns", the most common direction + // 0x01 0x21 0x41 0x61 + // 0x02 0x22 0x42 0x62 + // 0x03 0x23 0x43 0x63 + + // 0x04 0x24 0x44 0x64 + // 0x06 0x26 0x45 0x65 + // .... + + // the VPU registers are effectively organized like this: + // 0x00 0x01 0x02 0x03 + // 0x04 0x05 0x06 0x07 + // 0x08 0x09 0x0a 0x0b + // .... + + // Advantages: + // * Columns can be flushed and reloaded faster "at once" + // * 4x4 Matrices are contiguous in RAM, making them, too, fast-loadable in NEON + + // Disadvantages: + // * Extra indirection, can be confusing and slower (interpreter only) + // * Flushing and reloading row registers is now slower + + int i = 0; + for (int m = 0; m < 8; m++) { + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 4; x++) { + voffset[i++] = m * 4 + x * 32 + y; + } + } + } + + // And the inverse. + for (int i = 0; i < 128; i++) { + fromvoffset[voffset[i]] = i; + } + } MIPSState::~MIPSState() @@ -146,7 +191,7 @@ void MIPSState::Reset() } void MIPSState::DoState(PointerWrap &p) { - auto s = p.Section("MIPSState", 1, 2); + auto s = p.Section("MIPSState", 1, 3); if (!s) return; @@ -160,7 +205,15 @@ void MIPSState::DoState(PointerWrap &p) { p.DoArray(r, sizeof(r) / sizeof(r[0])); p.DoArray(f, sizeof(f) / sizeof(f[0])); - p.DoArray(v, sizeof(v) / sizeof(v[0])); + if (s <= 2) { + float vtemp[128]; + p.DoArray(vtemp, sizeof(v) / sizeof(v[0])); + for (int i = 0; i < 128; i++) { + v[voffset[i]] = vtemp[i]; + } + } else { + p.DoArray(v, sizeof(v) / sizeof(v[0])); + } p.DoArray(vfpuCtrl, sizeof(vfpuCtrl) / sizeof(vfpuCtrl[0])); p.Do(pc); p.Do(nextPC); diff --git a/Core/MIPS/MIPS.h b/Core/MIPS/MIPS.h index 84c047c64b..3714b04b88 100644 --- a/Core/MIPS/MIPS.h +++ b/Core/MIPS/MIPS.h @@ -115,6 +115,12 @@ enum VCondition VC_NS }; +// In memory, we order the VFPU registers differently. +// Games use columns a whole lot more than rows, and it would thus be good if columns +// were contiguous in memory. Also, matrices aren't but should be. +extern u8 voffset[128]; +extern u8 fromvoffset[128]; + class MIPSState { public: diff --git a/Core/MIPS/MIPSDebugInterface.h b/Core/MIPS/MIPSDebugInterface.h index 895454ef43..20ae2a74fd 100644 --- a/Core/MIPS/MIPSDebugInterface.h +++ b/Core/MIPS/MIPSDebugInterface.h @@ -107,7 +107,7 @@ public: return temp; case 2: - memcpy(&temp, &cpu->v[index], 4); + memcpy(&temp, &cpu->v[voffset[index]], 4); return temp; default: @@ -129,7 +129,7 @@ public: break; case 2: - memcpy(&cpu->v[index], &value, 4); + memcpy(&cpu->v[voffset[index]], &value, 4); break; default: diff --git a/Core/MIPS/MIPSIntVFPU.cpp b/Core/MIPS/MIPSIntVFPU.cpp index 35cb7c6b23..dc94cb5d84 100644 --- a/Core/MIPS/MIPSIntVFPU.cpp +++ b/Core/MIPS/MIPSIntVFPU.cpp @@ -52,8 +52,8 @@ #include #define R(i) (currentMIPS->r[i]) -#define V(i) (currentMIPS->v[i]) -#define VI(i) (currentMIPS->vi[i]) +#define V(i) (currentMIPS->v[voffset[i]]) +#define VI(i) (currentMIPS->vi[voffset[i]]) #define FI(i) (currentMIPS->fi[i]) #define FsI(i) (currentMIPS->fs[i]) #define PC (currentMIPS->pc) @@ -107,7 +107,7 @@ inline float nanclamp(float f, float lower, float upper) } -void ApplyPrefixST(float *v, u32 data, VectorSize size) +void ApplyPrefixST(float *r, u32 data, VectorSize size) { // Possible optimization shortcut: if (data == 0xe4) @@ -119,7 +119,7 @@ void ApplyPrefixST(float *v, u32 data, VectorSize size) for (int i = 0; i < n; i++) { - origV[i] = v[i]; + origV[i] = r[i]; } for (int i = 0; i < n; i++) @@ -141,17 +141,17 @@ void ApplyPrefixST(float *v, u32 data, VectorSize size) regnum = 0; } - v[i] = origV[regnum]; + r[i] = origV[regnum]; if (abs) - v[i] = fabs(v[i]); + r[i] = fabs(r[i]); } else { - v[i] = constantArray[regnum + (abs<<2)]; + r[i] = constantArray[regnum + (abs<<2)]; } if (negate) - v[i] = -v[i]; + r[i] = -r[i]; } } diff --git a/Core/MIPS/MIPSVFPUUtils.cpp b/Core/MIPS/MIPSVFPUUtils.cpp index 5b63141de4..50b7213d59 100644 --- a/Core/MIPS/MIPSVFPUUtils.cpp +++ b/Core/MIPS/MIPSVFPUUtils.cpp @@ -22,8 +22,8 @@ #include -#define V(i) (currentMIPS->v[i]) -#define VI(i) (currentMIPS->vi[i]) +#define V(i) (currentMIPS->v[voffset[i]]) +#define VI(i) (currentMIPS->vi[voffset[i]]) void GetVectorRegs(u8 regs[4], VectorSize N, int vectorReg) { int mtx = (vectorReg >> 2) & 7; diff --git a/Core/MIPS/PPC/PpcRegCacheFPU.cpp b/Core/MIPS/PPC/PpcRegCacheFPU.cpp index 9646c389f9..dd2e53322a 100644 --- a/Core/MIPS/PPC/PpcRegCacheFPU.cpp +++ b/Core/MIPS/PPC/PpcRegCacheFPU.cpp @@ -344,10 +344,17 @@ void PpcRegCacheFPU::FlushAll() { int PpcRegCacheFPU::GetMipsRegOffset(MIPSReg r) { // These are offsets within the MIPSState structure. First there are the GPRS, then FPRS, then the "VFPURs", then the VFPU ctrls. - if (r < 32 + 128 + NUM_TEMPS) - return (r + 32) << 2; - ERROR_LOG(JIT, "bad mips register %i, out of range", r); - return 0; // or what? + if (r < 0 || r > 32 + 128 + NUM_TEMPS) { + ERROR_LOG(JIT, "bad mips register %i, out of range", r); + return 0; // or what? + } + + if (r < 32 || r > 32 + 128) { + return (32 + r) << 2; + } else { + // r is between 32 and 128 + 32 + return (32 + 32 + voffset[r - 32]) << 2; + } } void PpcRegCacheFPU::SpillLock(MIPSReg r1, MIPSReg r2, MIPSReg r3, MIPSReg r4) { diff --git a/Core/MIPS/x86/RegCacheFPU.cpp b/Core/MIPS/x86/RegCacheFPU.cpp index 1913f16507..829c4dad19 100644 --- a/Core/MIPS/x86/RegCacheFPU.cpp +++ b/Core/MIPS/x86/RegCacheFPU.cpp @@ -65,16 +65,16 @@ void FPURegCache::SpillLock(int p1, int p2, int p3, int p4) { if (p4 != 0xFF) regs[p4].locked = true; } -void FPURegCache::SpillLockV(const u8 *v, VectorSize sz) { +void FPURegCache::SpillLockV(const u8 *vec, VectorSize sz) { for (int i = 0; i < GetNumVectorElements(sz); i++) { - vregs[v[i]].locked = true; + vregs[vec[i]].locked = true; } } void FPURegCache::SpillLockV(int vec, VectorSize sz) { - u8 v[4]; - GetVectorRegs(v, sz, vec); - SpillLockV(v, sz); + u8 r[4]; + GetVectorRegs(r, sz, vec); + SpillLockV(r, sz); } void FPURegCache::MapRegV(int vreg, int flags) { @@ -82,18 +82,18 @@ void FPURegCache::MapRegV(int vreg, int flags) { } void FPURegCache::MapRegsV(int vec, VectorSize sz, int flags) { - u8 v[4]; - GetVectorRegs(v, sz, vec); - SpillLockV(v, sz); + u8 r[4]; + GetVectorRegs(r, sz, vec); + SpillLockV(r, sz); for (int i = 0; i < GetNumVectorElements(sz); i++) { - MapReg(v[i] + 32, (flags & MAP_NOINIT) == 0, (flags & MAP_DIRTY) != 0); + MapReg(r[i] + 32, (flags & MAP_NOINIT) == 0, (flags & MAP_DIRTY) != 0); } } -void FPURegCache::MapRegsV(const u8 *v, VectorSize sz, int flags) { - SpillLockV(v, sz); +void FPURegCache::MapRegsV(const u8 *r, VectorSize sz, int flags) { + SpillLockV(r, sz); for (int i = 0; i < GetNumVectorElements(sz); i++) { - MapReg(v[i] + 32, (flags & MAP_NOINIT) == 0, (flags & MAP_DIRTY) != 0); + MapReg(r[i] + 32, (flags & MAP_NOINIT) == 0, (flags & MAP_DIRTY) != 0); } } @@ -205,7 +205,7 @@ OpArg FPURegCache::GetDefaultLocation(int reg) const { if (reg < 32) { return M(&mips->f[reg]); } else if (reg < 32 + 128) { - return M(&mips->v[reg - 32]); + return M(&mips->v[voffset[reg - 32]]); } else { return M(&tempValues[reg - 32 - 128]); } diff --git a/Core/MIPS/x86/RegCacheFPU.h b/Core/MIPS/x86/RegCacheFPU.h index c8bba7fb0e..a194aa5a92 100644 --- a/Core/MIPS/x86/RegCacheFPU.h +++ b/Core/MIPS/x86/RegCacheFPU.h @@ -154,6 +154,7 @@ public: void FlushX(X64Reg reg); X64Reg GetFreeXReg(); + private: const int *GetAllocationOrder(int &count); void SetupInitialRegs(); diff --git a/Windows/Debugger/Debugger_VFPUDlg.cpp b/Windows/Debugger/Debugger_VFPUDlg.cpp index 67b4450cd1..beb8caf41e 100644 --- a/Windows/Debugger/Debugger_VFPUDlg.cpp +++ b/Windows/Debugger/Debugger_VFPUDlg.cpp @@ -168,8 +168,8 @@ BOOL CVFPUDlg::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) for (int row = 0; row<4; row++) { - float val = mipsr4k.v[column*32+row+matrix*4]; - u32 hex = mipsr4k.vi[column*32+row+matrix*4]; + float val = mipsr4k.v[voffset[column*32+row+matrix*4]]; + u32 hex = mipsr4k.vi[voffset[column*32+row+matrix*4]]; switch (mode) { case 0: temp_len = sprintf_s(temp,"%f",val); break;