diff --git a/CMakeLists.txt b/CMakeLists.txt
index 691997d997..7b28f37763 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -618,7 +618,9 @@ elseif(X86)
Core/MIPS/x86/JitCache.cpp
Core/MIPS/x86/JitCache.h
Core/MIPS/x86/RegCache.cpp
- Core/MIPS/x86/RegCache.h)
+ Core/MIPS/x86/RegCache.h
+ Core/MIPS/x86/RegCacheFPU.cpp
+ Core/MIPS/x86/RegCacheFPU.h)
endif()
# 'ppsspp_jni' on ANDROID, 'Core' everywhere else
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 142f3b401a..40ec87f5e0 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -222,6 +222,12 @@
true
true
+
+ true
+ true
+ true
+ true
+
true
true
@@ -257,6 +263,7 @@
+
@@ -370,6 +377,12 @@
true
true
+
+ true
+ true
+ true
+ true
+
@@ -382,6 +395,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index c7baaebccd..aeafbe3ada 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -369,6 +369,12 @@
Ext
+
+ MIPS\x86
+
+
+ MIPS\ARM
+
@@ -683,6 +689,12 @@
Ext
+
+ MIPS\x86
+
+
+ MIPS\ARM
+
diff --git a/Core/MIPS/ARM/ArmRegCache.cpp b/Core/MIPS/ARM/ArmRegCache.cpp
index 3b9122bb18..4b539787eb 100644
--- a/Core/MIPS/ARM/ArmRegCache.cpp
+++ b/Core/MIPS/ARM/ArmRegCache.cpp
@@ -1,8 +1,8 @@
-// Copyright (C) 2003 Dolphin Project.
+// Copyright (c) 2012- PPSSPP Project.
// 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, version 2.0.
+// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -12,8 +12,8 @@
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "ArmRegCache.h"
#include "ArmEmitter.h"
diff --git a/Core/MIPS/ARM/ArmRegCache.h b/Core/MIPS/ARM/ArmRegCache.h
index f05451218e..7a57d7a4d7 100644
--- a/Core/MIPS/ARM/ArmRegCache.h
+++ b/Core/MIPS/ARM/ArmRegCache.h
@@ -1,8 +1,8 @@
-// Copyright (C) 2003 Dolphin Project.
+// Copyright (c) 2012- PPSSPP Project.
// 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, version 2.0.
+// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -12,8 +12,8 @@
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
-// Official SVN repository and contact information can be found at
-// http://code.google.com/p/dolphin-emu/
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
diff --git a/Core/MIPS/ARM/ArmRegCacheFPU.cpp b/Core/MIPS/ARM/ArmRegCacheFPU.cpp
new file mode 100644
index 0000000000..59314f3d5f
--- /dev/null
+++ b/Core/MIPS/ARM/ArmRegCacheFPU.cpp
@@ -0,0 +1,20 @@
+// Copyright (c) 2012- PPSSPP Project.
+
+// 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, version 2.0 or later versions.
+
+// 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 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#include "Common/ArmEmitter.h"
+#include "Core/MIPS/ARM/ArmRegCacheFPU.h"
+
diff --git a/Core/MIPS/ARM/ArmRegCacheFPU.h b/Core/MIPS/ARM/ArmRegCacheFPU.h
new file mode 100644
index 0000000000..6b9fef2345
--- /dev/null
+++ b/Core/MIPS/ARM/ArmRegCacheFPU.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2012- PPSSPP Project.
+
+// 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, version 2.0 or later versions.
+
+// 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 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#pragma once
+
+#include "Common/ArmEmitter.h"
+
+
+// The PSP has 160 FP registers: 32 FPRs + 128 VFPU registers.
+
+
+class FPURegCache {
+public:
+
+};
\ No newline at end of file
diff --git a/Core/MIPS/x86/CompFPU.cpp b/Core/MIPS/x86/CompFPU.cpp
index f017c4f5d0..59e4f28eb5 100644
--- a/Core/MIPS/x86/CompFPU.cpp
+++ b/Core/MIPS/x86/CompFPU.cpp
@@ -46,7 +46,7 @@ void Jit::CompFPTriArith(u32 op, void (XEmitter::*arith)(X64Reg reg, OpArg), boo
int ft = _FT;
int fs = _FS;
int fd = _FD;
- fpr.Lock(ft, fs, fd);
+ fpr.SpillLock(ft, fs, fd);
if (false && fs == fd)
{
@@ -66,7 +66,7 @@ void Jit::CompFPTriArith(u32 op, void (XEmitter::*arith)(X64Reg reg, OpArg), boo
(this->*arith)(XMM0, R(XMM1));
MOVSS(fpr.RX(fd), R(XMM0));
}
- fpr.UnlockAll();
+ fpr.ReleaseSpillLocks();
}
void Jit::Comp_FPU3op(u32 op)
@@ -97,7 +97,7 @@ void Jit::Comp_FPULS(u32 op)
{
case 49: //FI(ft) = Memory::Read_U32(addr); break; //lwc1
gpr.Lock(rs);
- fpr.Lock(ft);
+ fpr.SpillLock(ft);
fpr.BindToRegister(ft, false, true);
if (gpr.R(rs).IsImm())
@@ -181,11 +181,11 @@ void Jit::Comp_FPULS(u32 op)
}
gpr.UnlockAll();
- fpr.UnlockAll();
+ fpr.ReleaseSpillLocks();
break;
case 57: //Memory::Write_U32(FI(ft), addr); break; //swc1
gpr.Lock(rs);
- fpr.Lock(ft);
+ fpr.SpillLock(ft);
fpr.BindToRegister(ft, true, false);
if (gpr.R(rs).IsImm())
@@ -263,7 +263,7 @@ void Jit::Comp_FPULS(u32 op)
}
gpr.UnlockAll();
- fpr.UnlockAll();
+ fpr.ReleaseSpillLocks();
break;
default:
@@ -285,28 +285,28 @@ void Jit::Comp_FPU2op(u32 op)
switch (op & 0x3f)
{
case 5: //F(fd) = fabsf(F(fs)); break; //abs
- fpr.Lock(fd, fs);
+ fpr.SpillLock(fd, fs);
fpr.BindToRegister(fd, fd == fs, true);
MOVSS(fpr.RX(fd), fpr.R(fs));
PAND(fpr.RX(fd), M((void *)ssNoSignMask));
- fpr.UnlockAll();
+ fpr.ReleaseSpillLocks();
break;
case 6: //F(fd) = F(fs); break; //mov
if (fd != fs) {
- fpr.Lock(fd, fs);
+ fpr.SpillLock(fd, fs);
fpr.BindToRegister(fd, fd == fs, true);
MOVSS(fpr.RX(fd), fpr.R(fs));
- fpr.UnlockAll();
+ fpr.ReleaseSpillLocks();
}
break;
case 7: //F(fd) = -F(fs); break; //neg
- fpr.Lock(fd, fs);
+ fpr.SpillLock(fd, fs);
fpr.BindToRegister(fd, fd == fs, true);
MOVSS(fpr.RX(fd), fpr.R(fs));
PXOR(fpr.RX(fd), M((void *)ssSignBits2));
- fpr.UnlockAll();
+ fpr.ReleaseSpillLocks();
break;
case 12: //FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s
@@ -321,11 +321,11 @@ void Jit::Comp_FPU2op(u32 op)
return;
case 13: //FsI(fd) = F(fs)>=0 ? (int)floorf(F(fs)) : (int)ceilf(F(fs)); break;//trunc.w.s
- fpr.Lock(fs, fd);
+ fpr.SpillLock(fs, fd);
fpr.StoreFromRegister(fd);
CVTTSS2SI(EAX, fpr.R(fs));
MOV(32, fpr.R(fd), R(EAX));
- fpr.UnlockAll();
+ fpr.ReleaseSpillLocks();
break;
case 14: //FsI(fd) = (int)ceilf (F(fs)); break; //ceil.w.s
@@ -363,10 +363,10 @@ void Jit::Comp_mxc1(u32 op)
case 4: //FI(fs) = R(rt); break; //mtc1
// Cross move! slightly tricky
gpr.StoreFromRegister(rt);
- fpr.Lock(fs);
+ fpr.SpillLock(fs);
fpr.BindToRegister(fs, false, true);
MOVSS(fpr.RX(fs), gpr.R(rt));
- fpr.UnlockAll();
+ fpr.ReleaseSpillLocks();
return;
case 6: //currentMIPS->WriteFCR(fs, R(rt)); break; //ctc1
diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp
index befb910367..7f08025c3d 100644
--- a/Core/MIPS/x86/CompVFPU.cpp
+++ b/Core/MIPS/x86/CompVFPU.cpp
@@ -58,7 +58,7 @@ void Jit::Comp_SVQ(u32 op)
if (!g_Config.bFastMemory) {
DISABLE;
}
- fpr.Flush(FLUSH_ALL);
+ fpr.Flush();
gpr.BindToRegister(rs, true, true);
u8 vregs[4];
@@ -92,7 +92,7 @@ void Jit::Comp_SVQ(u32 op)
if (!g_Config.bFastMemory) {
DISABLE;
}
- fpr.Flush(FLUSH_ALL);
+ fpr.Flush();
gpr.BindToRegister(rs, true, true);
u8 vregs[4];
diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp
index 963cf8e0f5..84f0a9121a 100644
--- a/Core/MIPS/x86/Jit.cpp
+++ b/Core/MIPS/x86/Jit.cpp
@@ -106,8 +106,8 @@ Jit::Jit(MIPSState *mips) : blocks(mips), mips_(mips)
void Jit::FlushAll()
{
- gpr.Flush(FLUSH_ALL);
- fpr.Flush(FLUSH_ALL);
+ gpr.Flush();
+ fpr.Flush();
}
void Jit::WriteDowncount(int offset)
diff --git a/Core/MIPS/x86/Jit.h b/Core/MIPS/x86/Jit.h
index 5b14dd768d..6599a54c71 100644
--- a/Core/MIPS/x86/Jit.h
+++ b/Core/MIPS/x86/Jit.h
@@ -17,17 +17,18 @@
#pragma once
-#include "../../../Globals.h"
-#include "../../../Common/Thunk.h"
+#include "Globals.h"
+#include "Common/Thunk.h"
#include "Asm.h"
#if defined(ARM)
#error DO NOT BUILD X86 JIT ON ARM
#endif
-#include "x64Emitter.h"
+#include "Common/x64Emitter.h"
#include "JitCache.h"
#include "RegCache.h"
+#include "RegCacheFPU.h"
namespace MIPSComp
{
diff --git a/Core/MIPS/x86/RegCache.cpp b/Core/MIPS/x86/RegCache.cpp
index 02c447a488..cb863533ef 100644
--- a/Core/MIPS/x86/RegCache.cpp
+++ b/Core/MIPS/x86/RegCache.cpp
@@ -15,12 +15,12 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
-#include "../MIPS.h"
-#include "../MIPSTables.h"
-#include "../MIPSAnalyst.h"
-#include "Jit.h"
-#include "Asm.h"
-#include "RegCache.h"
+#include "Core/MIPS/MIPS.h"
+#include "Core/MIPS/MIPSTables.h"
+#include "Core/MIPS/MIPSAnalyst.h"
+#include "Core/MIPS/x86/Jit.h"
+#include "Core/MIPS/x86/Asm.h"
+#include "Core/MIPS/x86/RegCache.h"
using namespace Gen;
@@ -59,7 +59,7 @@ void GPRRegCache::Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats) {
// todo: sort to find the most popular regs
/*
int maxPreload = 2;
- for (int i = 0; i < 32; i++)
+ for (int i = 0; i < NUM_MIPS_GPRS; i++)
{
if (stats.numReads[i] > 2 || stats.numWrites[i] >= 2)
{
@@ -94,7 +94,7 @@ void GPRRegCache::LockX(int x1, int x2, int x3, int x4) {
}
void GPRRegCache::UnlockAll() {
- for (int i = 0; i < 32; i++)
+ for (int i = 0; i < NUM_MIPS_GPRS; i++)
regs[i].locked = false;
}
@@ -144,7 +144,7 @@ void GPRRegCache::FlushR(X64Reg reg)
}
int GPRRegCache::SanityCheck() const {
- for (int i = 0; i < 32; i++) {
+ for (int i = 0; i < NUM_MIPS_GPRS; i++) {
if (regs[i].away) {
if (regs[i].location.IsSimpleReg()) {
Gen::X64Reg simple = regs[i].location.GetSimpleReg();
@@ -276,13 +276,13 @@ void GPRRegCache::StoreFromRegister(int i) {
}
}
-void GPRRegCache::Flush(FlushMode mode)
+void GPRRegCache::Flush()
{
for (int i = 0; i < NUM_X_REGS; i++) {
if (xregs[i].allocLocked)
PanicAlert("Someone forgot to unlock X64 reg %i.", i);
}
- for (int i = 0; i < 32; i++) {
+ for (int i = 0; i < NUM_MIPS_GPRS; i++) {
if (regs[i].locked) {
PanicAlert("Somebody forgot to unlock MIPS reg %i.", i);
}
@@ -299,174 +299,4 @@ void GPRRegCache::Flush(FlushMode mode)
}
}
}
-}
-
-FPURegCache::FPURegCache() : emit(0), mips(0) {
- memset(regs, 0, sizeof(regs));
- memset(xregs, 0, sizeof(xregs));
-}
-
-void FPURegCache::Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats) {
- this->mips = mips;
- for (int i = 0; i < NUM_X_REGS; i++) {
- xregs[i].free = true;
- xregs[i].dirty = false;
- xregs[i].allocLocked = false;
- }
- for (int i = 0; i < 32; i++) {
- regs[i].location = GetDefaultLocation(i);
- regs[i].away = false;
- regs[i].locked = false;
- }
-}
-
-void FPURegCache::Lock(int p1, int p2, int p3, int p4) {
- regs[p1].locked = true;
- if (p2 != 0xFF) regs[p2].locked = true;
- if (p3 != 0xFF) regs[p3].locked = true;
- if (p4 != 0xFF) regs[p4].locked = true;
-}
-
-void FPURegCache::UnlockAll() {
- for (int i = 0; i < 32; i++)
- regs[i].locked = false;
-}
-
-void FPURegCache::UnlockAllX() {
- for (int i = 0; i < NUM_X_REGS; i++)
- xregs[i].allocLocked = false;
-}
-
-void FPURegCache::BindToRegister(int i, bool doLoad, bool makeDirty) {
- _assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - load - imm");
- if (!regs[i].away) {
- // Reg is at home in the memory register file. Let's pull it out.
- X64Reg xr = GetFreeXReg();
- _assert_msg_(DYNA_REC, xr < NUM_X_REGS, "WTF - load - invalid reg");
- xregs[xr].mipsReg = i;
- xregs[xr].free = false;
- xregs[xr].dirty = makeDirty;
- OpArg newloc = ::Gen::R(xr);
- if (doLoad)
- {
- if (!regs[i].location.IsImm() && (regs[i].location.offset & 0x3))
- {
- PanicAlert("WARNING - misaligned fp register location %i", i);
- }
- emit->MOVSS(xr, regs[i].location);
- }
- regs[i].location = newloc;
- regs[i].away = true;
- } else {
- // There are no immediates in the FPR reg file, so we already had this in a register. Make dirty as necessary.
- xregs[RX(i)].dirty |= makeDirty;
- }
-}
-
-void FPURegCache::StoreFromRegister(int i) {
- _assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - store - imm");
- if (regs[i].away) {
- X64Reg xr = regs[i].location.GetSimpleReg();
- _assert_msg_(DYNA_REC, xr < NUM_X_REGS, "WTF - store - invalid reg");
- xregs[xr].free = true;
- xregs[xr].dirty = false;
- xregs[xr].mipsReg = -1;
- OpArg newLoc = GetDefaultLocation(i);
- emit->MOVSS(newLoc, xr);
- regs[i].location = newLoc;
- regs[i].away = false;
- } else {
- // _assert_msg_(DYNA_REC,0,"already stored");
- }
-}
-
-void FPURegCache::Flush(FlushMode mode) {
- for (int i = 0; i < NUM_X_REGS; i++) {
- if (xregs[i].allocLocked)
- PanicAlert("Someone forgot to unlock X64 reg %i.", i);
- }
- for (int i = 0; i < 32; i++) {
- if (regs[i].locked) {
- PanicAlert("Somebody forgot to unlock MIPS reg %i.", i);
- }
- if (regs[i].away) {
- if (regs[i].location.IsSimpleReg()) {
- X64Reg xr = RX(i);
- StoreFromRegister(i);
- xregs[xr].dirty = false;
- } else if (regs[i].location.IsImm()) {
- StoreFromRegister(i);
- } else {
- _assert_msg_(DYNA_REC,0,"Jit64 - Flush unhandled case, reg %i PC: %08x", i, mips->pc);
- }
- }
- }
-}
-
-OpArg FPURegCache::GetDefaultLocation(int reg) const {
- return M(&mips->f[reg]);
-}
-
-int FPURegCache::SanityCheck() const {
- for (int i = 0; i < 32; i++) {
- if (regs[i].away) {
- if (regs[i].location.IsSimpleReg()) {
- Gen::X64Reg simple = regs[i].location.GetSimpleReg();
- if (xregs[simple].allocLocked)
- return 1;
- if (xregs[simple].mipsReg != i)
- return 2;
- }
- else if (regs[i].location.IsImm())
- return 3;
- }
- }
- return 0;
-}
-
-const int *FPURegCache::GetAllocationOrder(int &count) {
- static const int allocationOrder[] = {
-#ifdef _M_X64
- XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, XMM2, XMM3, XMM4, XMM5
-#elif _M_IX86
- XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
-#endif
- };
- count = sizeof(allocationOrder) / sizeof(int);
- return allocationOrder;
-}
-
-X64Reg FPURegCache::GetFreeXReg() {
- int aCount;
- const int *aOrder = GetAllocationOrder(aCount);
- for (int i = 0; i < aCount; i++) {
- X64Reg xr = (X64Reg)aOrder[i];
- if (!xregs[xr].allocLocked && xregs[xr].free) {
- return (X64Reg)xr;
- }
- }
- //Okay, not found :( Force grab one
-
- //TODO - add a pass to grab xregs whose mipsreg is not used in the next 3 instructions
- for (int i = 0; i < aCount; i++) {
- X64Reg xr = (X64Reg)aOrder[i];
- if (xregs[xr].allocLocked)
- continue;
- int preg = xregs[xr].mipsReg;
- if (!regs[preg].locked) {
- StoreFromRegister(preg);
- return xr;
- }
- }
- //Still no dice? Die!
- _assert_msg_(DYNA_REC, 0, "Regcache ran out of regs");
- return (X64Reg) -1;
-}
-
-void FPURegCache::FlushR(X64Reg reg) {
- if (reg >= NUM_X_REGS)
- PanicAlert("Flushing non existent reg");
- if (!xregs[reg].free) {
- StoreFromRegister(xregs[reg].mipsReg);
- }
}
\ No newline at end of file
diff --git a/Core/MIPS/x86/RegCache.h b/Core/MIPS/x86/RegCache.h
index 46c7a3b66e..c1a12b22d9 100644
--- a/Core/MIPS/x86/RegCache.h
+++ b/Core/MIPS/x86/RegCache.h
@@ -21,36 +21,20 @@
#include "../MIPSAnalyst.h"
using namespace Gen;
-enum FlushMode
-{
- FLUSH_ALL
-};
-enum GrabMode
-{
- M_READ = 1,
- M_WRITE = 2,
- M_READWRITE = 3,
-};
-
-struct MIPSCachedReg
-{
+struct MIPSCachedReg {
OpArg location;
bool away; // value not in source register
bool locked;
};
-struct X64CachedReg
-{
+struct X64CachedReg {
int mipsReg;
bool dirty;
bool free;
bool allocLocked;
};
-typedef int XReg;
-typedef int PReg;
-
#ifdef _M_X64
#define NUM_X_REGS 16
#elif _M_IX86
@@ -59,12 +43,10 @@ typedef int PReg;
// TODO: Add more cachable regs, like HI, LO
#define NUM_MIPS_GPRS 32
-#define NUM_MIPS_FPRS 32
class GPRRegCache
{
public:
- MIPSState *mips;
GPRRegCache();
~GPRRegCache() {}
void Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats);
@@ -81,7 +63,7 @@ public:
FlushR(reg1); FlushR(reg2);
LockX(reg1); LockX(reg2);
}
- void Flush(FlushMode mode);
+ void Flush();
int SanityCheck() const;
void KillImmediate(int preg, bool doLoad, bool makeDirty);
@@ -104,69 +86,17 @@ public:
void UnlockAll();
void UnlockAllX();
- X64Reg GetFreeXReg();
-
void SetImmediate32(int preg, u32 immValue);
bool IsImmediate(int preg) const;
u32 GetImmediate32(int preg) const;
-private:
- MIPSCachedReg regs[NUM_MIPS_GPRS];
- X64CachedReg xregs[NUM_X_REGS];
-
- const int *GetAllocationOrder(int &count);
-
- XEmitter *emit;
-};
-
-
-// Now also with VFPU support!
-class FPURegCache
-{
-public:
MIPSState *mips;
- FPURegCache();
- ~FPURegCache() {}
-
- void Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats);
- void BindToRegister(int preg, bool doLoad = true, bool makeDirty = true);
- void StoreFromRegister(int preg);
- OpArg GetDefaultLocation(int reg) const;
-
- void SetEmitter(XEmitter *emitter) {emit = emitter;}
-
- void FlushLockX(X64Reg reg) {
- FlushR(reg);
- LockX(reg);
- }
- void FlushLockX(X64Reg reg1, X64Reg reg2) {
- FlushR(reg1); FlushR(reg2);
- LockX(reg1); LockX(reg2);
- }
- void Flush(FlushMode mode);
- int SanityCheck() const;
-
- const OpArg &R(int preg) const {return regs[preg].location;}
- X64Reg RX(int preg) const
- {
- if (regs[preg].away && regs[preg].location.IsSimpleReg())
- return regs[preg].location.GetSimpleReg();
- PanicAlert("Not so simple - %i", preg);
- return (X64Reg)-1;
- }
-
- // Register locking. Prevents them from being spilled.
- void Lock(int p1, int p2=0xff, int p3=0xff, int p4=0xff);
- void LockX(int x1, int x2=0xff, int x3=0xff, int x4=0xff);
- void UnlockAll();
- void UnlockAllX();
private:
X64Reg GetFreeXReg();
- void FlushR(X64Reg reg);
const int *GetAllocationOrder(int &count);
- MIPSCachedReg regs[NUM_MIPS_FPRS];
+ MIPSCachedReg regs[NUM_MIPS_GPRS];
X64CachedReg xregs[NUM_X_REGS];
XEmitter *emit;
diff --git a/Core/MIPS/x86/RegCacheFPU.cpp b/Core/MIPS/x86/RegCacheFPU.cpp
new file mode 100644
index 0000000000..7625b486d9
--- /dev/null
+++ b/Core/MIPS/x86/RegCacheFPU.cpp
@@ -0,0 +1,192 @@
+// Copyright (c) 2012- PPSSPP Project.
+
+// 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, version 2.0 or later versions.
+
+// 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 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#pragma once
+
+#include "Common/Log.h"
+#include "Common/x64Emitter.h"
+#include "Core/MIPS/MIPSAnalyst.h"
+#include "Core/MIPS/x86/RegCacheFPU.h"
+
+FPURegCache::FPURegCache() : emit(0), mips(0) {
+ memset(regs, 0, sizeof(regs));
+ memset(xregs, 0, sizeof(xregs));
+ vregs = regs + 32;
+}
+
+void FPURegCache::Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats) {
+ this->mips = mips;
+ for (int i = 0; i < NUM_X_FPREGS; i++) {
+ xregs[i].mipsReg = -1;
+ xregs[i].dirty = false;
+ }
+ for (int i = 0; i < NUM_MIPS_FPRS; i++) {
+ regs[i].location = GetDefaultLocation(i);
+ regs[i].away = false;
+ regs[i].locked = false;
+ }
+}
+
+void FPURegCache::SpillLock(int p1, int p2, int p3, int p4) {
+ regs[p1].locked = true;
+ if (p2 != 0xFF) regs[p2].locked = true;
+ if (p3 != 0xFF) regs[p3].locked = true;
+ if (p4 != 0xFF) regs[p4].locked = true;
+}
+
+void FPURegCache::SpillLockV(const u8 *v, VectorSize vsz) {
+ for (int i = 0; i < GetNumVectorElements(vsz); i++) {
+ vregs[i].locked = true;
+ }
+}
+
+void FPURegCache::SpillLockV(int vec, VectorSize vsz) {
+ u8 v[4];
+ GetVectorRegs(v, vsz, vec);
+ SpillLockV(v, vsz);
+}
+
+void FPURegCache::ReleaseSpillLocks() {
+ for (int i = 0; i < NUM_MIPS_FPRS; i++)
+ regs[i].locked = false;
+}
+
+void FPURegCache::BindToRegister(int i, bool doLoad, bool makeDirty) {
+ _assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - load - imm");
+ if (!regs[i].away) {
+ // Reg is at home in the memory register file. Let's pull it out.
+ X64Reg xr = GetFreeXReg();
+ _assert_msg_(DYNA_REC, xr < NUM_X_FPREGS, "WTF - load - invalid reg");
+ xregs[xr].mipsReg = i;
+ xregs[xr].dirty = makeDirty;
+ OpArg newloc = ::Gen::R(xr);
+ if (doLoad) {
+ if (!regs[i].location.IsImm() && (regs[i].location.offset & 0x3)) {
+ PanicAlert("WARNING - misaligned fp register location %i", i);
+ }
+ emit->MOVSS(xr, regs[i].location);
+ }
+ regs[i].location = newloc;
+ regs[i].away = true;
+ } else {
+ // There are no immediates in the FPR reg file, so we already had this in a register. Make dirty as necessary.
+ xregs[RX(i)].dirty |= makeDirty;
+ }
+}
+
+void FPURegCache::StoreFromRegister(int i) {
+ _assert_msg_(DYNA_REC, !regs[i].location.IsImm(), "WTF - store - imm");
+ if (regs[i].away) {
+ X64Reg xr = regs[i].location.GetSimpleReg();
+ _assert_msg_(DYNA_REC, xr < NUM_X_FPREGS, "WTF - store - invalid reg");
+ xregs[xr].dirty = false;
+ xregs[xr].mipsReg = -1;
+ OpArg newLoc = GetDefaultLocation(i);
+ emit->MOVSS(newLoc, xr);
+ regs[i].location = newLoc;
+ regs[i].away = false;
+ } else {
+ // _assert_msg_(DYNA_REC,0,"already stored");
+ }
+}
+
+void FPURegCache::Flush() {
+ for (int i = 0; i < NUM_MIPS_FPRS; i++) {
+ if (regs[i].locked) {
+ PanicAlert("Somebody forgot to unlock MIPS reg %i.", i);
+ }
+ if (regs[i].away) {
+ if (regs[i].location.IsSimpleReg()) {
+ X64Reg xr = RX(i);
+ StoreFromRegister(i);
+ xregs[xr].dirty = false;
+ } else if (regs[i].location.IsImm()) {
+ StoreFromRegister(i);
+ } else {
+ _assert_msg_(DYNA_REC,0,"Jit64 - Flush unhandled case, reg %i PC: %08x", i, mips->pc);
+ }
+ }
+ }
+}
+
+OpArg FPURegCache::GetDefaultLocation(int reg) const {
+ if (reg < 32) {
+ return M(&mips->f[reg]);
+ } else {
+ return M(&mips->v[reg - 32]);
+ }
+}
+
+int FPURegCache::SanityCheck() const {
+ for (int i = 0; i < NUM_MIPS_FPRS; i++) {
+ if (regs[i].away) {
+ if (regs[i].location.IsSimpleReg()) {
+ Gen::X64Reg simple = regs[i].location.GetSimpleReg();
+ if (xregs[simple].mipsReg != i)
+ return 2;
+ }
+ else if (regs[i].location.IsImm())
+ return 3;
+ }
+ }
+ return 0;
+}
+
+const int *FPURegCache::GetAllocationOrder(int &count) {
+ static const int allocationOrder[] = {
+#ifdef _M_X64
+ XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, XMM2, XMM3, XMM4, XMM5
+#elif _M_IX86
+ XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
+#endif
+ };
+ count = sizeof(allocationOrder) / sizeof(int);
+ return allocationOrder;
+}
+
+X64Reg FPURegCache::GetFreeXReg() {
+ int aCount;
+ const int *aOrder = GetAllocationOrder(aCount);
+ for (int i = 0; i < aCount; i++) {
+ X64Reg xr = (X64Reg)aOrder[i];
+ if (xregs[xr].mipsReg == -1) {
+ return (X64Reg)xr;
+ }
+ }
+ //Okay, not found :( Force grab one
+
+ //TODO - add a pass to grab xregs whose mipsreg is not used in the next 3 instructions
+ for (int i = 0; i < aCount; i++) {
+ X64Reg xr = (X64Reg)aOrder[i];
+ int preg = xregs[xr].mipsReg;
+ if (!regs[preg].locked) {
+ StoreFromRegister(preg);
+ return xr;
+ }
+ }
+ //Still no dice? Die!
+ _assert_msg_(DYNA_REC, 0, "Regcache ran out of regs");
+ return (X64Reg) -1;
+}
+
+void FPURegCache::FlushR(X64Reg reg) {
+ if (reg >= NUM_X_FPREGS)
+ PanicAlert("Flushing non existent reg");
+ if (xregs[reg].mipsReg != -1) {
+ StoreFromRegister(xregs[reg].mipsReg);
+ }
+}
\ No newline at end of file
diff --git a/Core/MIPS/x86/RegCacheFPU.h b/Core/MIPS/x86/RegCacheFPU.h
new file mode 100644
index 0000000000..f4c2fff3ed
--- /dev/null
+++ b/Core/MIPS/x86/RegCacheFPU.h
@@ -0,0 +1,107 @@
+// Copyright (c) 2012- PPSSPP Project.
+
+// 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, version 2.0 or later versions.
+
+// 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 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#pragma once
+
+#include "Common/x64Emitter.h"
+#include "Core/MIPS/MIPS.h"
+#include "Core/MIPS/MIPSAnalyst.h"
+#include "Core/MIPS/MIPSVFPUUtils.h"
+
+using namespace Gen;
+
+
+// GPRs are numbered 0 to 31
+// VFPU regs are numbered 32 to 160.
+
+#define NUM_MIPS_FPRS (32 + 128)
+
+#ifdef _M_X64
+#define NUM_X_FPREGS 16
+#elif _M_IX86
+#define NUM_X_FPREGS 8
+#endif
+
+struct X64CachedFPReg {
+ int mipsReg;
+ bool dirty;
+};
+
+struct MIPSCachedFPReg {
+ OpArg location;
+ bool away; // value not in source register
+ bool locked;
+};
+
+// The PSP has 160 FP registers: 32 FPRs + 128 VFPU registers.
+// Soon we will support them all.
+
+class FPURegCache
+{
+public:
+ FPURegCache();
+ ~FPURegCache() {}
+
+ void Start(MIPSState *mips, MIPSAnalyst::AnalysisResults &stats);
+ void BindToRegister(int preg, bool doLoad = true, bool makeDirty = true);
+ void StoreFromRegister(int preg);
+ OpArg GetDefaultLocation(int reg) const;
+
+ void SetEmitter(XEmitter *emitter) {emit = emitter;}
+
+ void Flush();
+ int SanityCheck() const;
+
+ const OpArg &R(int freg) const {return regs[freg].location;}
+ const OpArg &V(int vreg) const {return regs[32 + vreg].location;}
+
+ X64Reg RX(int freg) const
+ {
+ if (regs[freg].away && regs[freg].location.IsSimpleReg())
+ return regs[freg].location.GetSimpleReg();
+ PanicAlert("Not so simple - f%i", freg);
+ return (X64Reg)-1;
+ }
+
+ X64Reg VX(int vreg) const
+ {
+ if (regs[vreg + 32].away && regs[vreg + 32].location.IsSimpleReg())
+ return regs[vreg + 32].location.GetSimpleReg();
+ PanicAlert("Not so simple - v%i", vreg);
+ return (X64Reg)-1;
+ }
+
+ // Register locking. Prevents them from being spilled.
+ void SpillLock(int p1, int p2=0xff, int p3=0xff, int p4=0xff);
+ void ReleaseSpillLocks();
+
+ void SpillLockV(const u8 *v, VectorSize vsz);
+ void SpillLockV(int vec, VectorSize vsz);
+
+ MIPSState *mips;
+
+private:
+ X64Reg GetFreeXReg();
+ void FlushR(X64Reg reg);
+ const int *GetAllocationOrder(int &count);
+
+ MIPSCachedFPReg regs[NUM_MIPS_FPRS];
+ X64CachedFPReg xregs[NUM_X_FPREGS];
+ MIPSCachedFPReg *vregs;
+
+ XEmitter *emit;
+};
diff --git a/Qt/Core.pro b/Qt/Core.pro
index dbafc2514b..cf96fac6ea 100755
--- a/Qt/Core.pro
+++ b/Qt/Core.pro
@@ -18,12 +18,13 @@ arm {
../Core/MIPS/ARM/ArmJit.cpp \
../Core/MIPS/ARM/ArmJitCache.cpp \
../Core/MIPS/ARM/ArmRegCache.cpp \
+ ../Core/MIPS/ARM/ArmRegCacheFPU.cpp \
../ext/disarm.cpp
-
HEADERS += ../Core/MIPS/ARM/ArmAsm.h \
../Core/MIPS/ARM/ArmJit.h \
../Core/MIPS/ARM/ArmJitCache.h \
../Core/MIPS/ARM/ArmRegCache.h
+ ../Core/MIPS/ARM/ArmRegCacheFPU.h
}
x86 {
SOURCES += ../Core/MIPS/x86/Asm.cpp \
@@ -34,11 +35,13 @@ x86 {
../Core/MIPS/x86/CompVFPU.cpp \
../Core/MIPS/x86/Jit.cpp \
../Core/MIPS/x86/JitCache.cpp \
- ../Core/MIPS/x86/RegCache.cpp
+ ../Core/MIPS/x86/RegCache.cpp \
+ ../Core/MIPS/x86/RegCacheFPU.cpp
HEADERS += ../Core/MIPS/x86/Asm.h \
../Core/MIPS/x86/Jit.h \
../Core/MIPS/x86/JitCache.h \
- ../Core/MIPS/x86/RegCache.h
+ ../Core/MIPS/x86/RegCache.h \
+ ../Core/MIPS/x86/RegCacheFPU.h
}
SOURCES += ../Core/CPU.cpp \ # Core
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index 3e3356e0d8..68366e380c 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -177,6 +177,7 @@ LOCAL_SRC_FILES := \
$(SRC)/Core/MIPS/ARM/ArmAsm.cpp \
$(SRC)/Core/MIPS/ARM/ArmJit.cpp \
$(SRC)/Core/MIPS/ARM/ArmRegCache.cpp \
+ $(SRC)/Core/MIPS/ARM/ArmRegCacheFPU.cpp \
$(SRC)/Core/Util/BlockAllocator.cpp \
$(SRC)/Core/Util/ppge_atlas.cpp \
$(SRC)/Core/Util/PPGeDraw.cpp
diff --git a/ext/snappy/snappy-stubs-public.h b/ext/snappy/snappy-stubs-public.h
index e97fc24682..9b52a5d2d0 100644
--- a/ext/snappy/snappy-stubs-public.h
+++ b/ext/snappy/snappy-stubs-public.h
@@ -52,9 +52,11 @@ typedef uint64_t uint64;
typedef std::string string;
+#ifndef DISALLOW_COPY_AND_ASSIGN
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
+#endif
} // namespace snappy