mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-15 02:29:51 +01:00
Merge branch 'master' into TemporaryHackishBranch
# Conflicts: # Core/MIPS/ARM64/Arm64CompVFPU.cpp # Core/MIPS/MIPSIntVFPU.cpp # Core/MIPS/MIPSVFPUUtils.h
This commit is contained in:
commit
e136416ffd
20 files changed
+378
-162
No files matched your search
+15
-18
@@ -92,43 +92,40 @@ static std::mutex externalEventLock;
|
||||
std::vector<MHzChangeCallback> mhzChangeCallbacks;
|
||||
|
||||
void FireMhzChange() {
|
||||
for (auto it = mhzChangeCallbacks.begin(), end = mhzChangeCallbacks.end(); it != end; ++it) {
|
||||
MHzChangeCallback cb = *it;
|
||||
for (MHzChangeCallback cb : mhzChangeCallbacks) {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
||||
void SetClockFrequencyMHz(int cpuMhz)
|
||||
{
|
||||
void SetClockFrequencyHz(int cpuHz) {
|
||||
// When the mhz changes, we keep track of what "time" it was before hand.
|
||||
// This way, time always moves forward, even if mhz is changed.
|
||||
lastGlobalTimeUs = GetGlobalTimeUs();
|
||||
lastGlobalTimeTicks = GetTicks();
|
||||
|
||||
CPU_HZ = cpuMhz * 1000000;
|
||||
CPU_HZ = cpuHz;
|
||||
// TODO: Rescale times of scheduled events?
|
||||
|
||||
FireMhzChange();
|
||||
}
|
||||
|
||||
int GetClockFrequencyMHz()
|
||||
{
|
||||
return CPU_HZ / 1000000;
|
||||
int GetClockFrequencyHz() {
|
||||
return CPU_HZ;
|
||||
}
|
||||
|
||||
u64 GetGlobalTimeUsScaled()
|
||||
{
|
||||
s64 ticksSinceLast = GetTicks() - lastGlobalTimeTicks;
|
||||
int freq = GetClockFrequencyMHz();
|
||||
s64 usSinceLast = ticksSinceLast / freq;
|
||||
return lastGlobalTimeUs + usSinceLast;
|
||||
u64 GetGlobalTimeUsScaled() {
|
||||
return GetGlobalTimeUs();
|
||||
}
|
||||
|
||||
u64 GetGlobalTimeUs()
|
||||
{
|
||||
u64 GetGlobalTimeUs() {
|
||||
s64 ticksSinceLast = GetTicks() - lastGlobalTimeTicks;
|
||||
int freq = GetClockFrequencyMHz();
|
||||
s64 usSinceLast = ticksSinceLast / freq;
|
||||
int freq = GetClockFrequencyHz();
|
||||
s64 usSinceLast = ticksSinceLast * 1000000 / freq;
|
||||
if (ticksSinceLast > UINT_MAX) {
|
||||
// Adjust the calculated value to avoid overflow errors.
|
||||
lastGlobalTimeUs += usSinceLast;
|
||||
lastGlobalTimeTicks = GetTicks();
|
||||
}
|
||||
return lastGlobalTimeUs + usSinceLast;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -67,7 +67,7 @@ inline s64 usToCycles(u64 us) {
|
||||
}
|
||||
|
||||
inline s64 cyclesToUs(s64 cycles) {
|
||||
return cycles / (CPU_HZ / 1000000);
|
||||
return (cycles * 1000000) / CPU_HZ;
|
||||
}
|
||||
|
||||
namespace CoreTiming
|
||||
@@ -121,8 +121,8 @@ namespace CoreTiming
|
||||
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
void SetClockFrequencyMHz(int cpuMhz);
|
||||
int GetClockFrequencyMHz();
|
||||
void SetClockFrequencyHz(int cpuHz);
|
||||
int GetClockFrequencyHz();
|
||||
extern int slicelength;
|
||||
|
||||
}; // end of namespace
|
||||
@@ -1069,10 +1069,10 @@ static u32 sceDisplayGetVcount() {
|
||||
}
|
||||
|
||||
static u32 __DisplayGetCurrentHcount() {
|
||||
const static int ticksPerVblank333 = 333 * 1000000 / 60 / hCountPerVblank;
|
||||
const int ticksIntoFrame = CoreTiming::GetTicks() - frameStartTicks;
|
||||
const int ticksPerVblank = CoreTiming::GetClockFrequencyHz() / 60 / hCountPerVblank;
|
||||
// Can't seem to produce a 0 on real hardware, offsetting by 1 makes things look right.
|
||||
return 1 + (ticksIntoFrame / (CoreTiming::GetClockFrequencyMHz() * ticksPerVblank333 / 333));
|
||||
return 1 + (ticksIntoFrame / ticksPerVblank);
|
||||
}
|
||||
|
||||
static u32 __DisplayGetAccumulatedHcount() {
|
||||
|
||||
+139
-69
@@ -57,10 +57,57 @@ static int powerCbSlots[numberOfCBPowerSlots];
|
||||
static std::vector<VolatileWaitingThread> volatileWaitingThreads;
|
||||
|
||||
// Should this belong here, or in CoreTiming?
|
||||
static int RealpllFreq = 222;
|
||||
static int RealbusFreq = 111;
|
||||
static int pllFreq = 222;
|
||||
static int busFreq = 111;
|
||||
static int RealpllFreq = 222000000;
|
||||
static int RealbusFreq = 111000000;
|
||||
static int pllFreq = 222000000;
|
||||
static int busFreq = 111000000;
|
||||
|
||||
// The CPU mhz can only be a multiple of the PLL divided by 511.
|
||||
int PowerCpuMhzToHz(int desired, int pllHz) {
|
||||
double maxfreq = desired * 1000000.0;
|
||||
|
||||
double step = (double)pllHz / 511.0;
|
||||
// These values seem to be locked.
|
||||
if (pllHz >= 333000000 && desired == 333) {
|
||||
return 333000000;
|
||||
} else if (pllHz >= 222000000 && desired == 222) {
|
||||
return 222000000;
|
||||
}
|
||||
|
||||
double freq = 0;
|
||||
while (freq + step < maxfreq) {
|
||||
freq += step;
|
||||
}
|
||||
|
||||
// We match the PSP's HLE funcs better when we have the same float error, it seems.
|
||||
return (float)(freq / 1000000.0f) * 1000000;
|
||||
}
|
||||
|
||||
int PowerPllMhzToHz(int mhz) {
|
||||
// These seem to be the only steps it has.
|
||||
if (mhz <= 190)
|
||||
return 190285721;
|
||||
if (mhz <= 222)
|
||||
return 222000000;
|
||||
if (mhz <= 266)
|
||||
return 266399994;
|
||||
if (mhz <= 333)
|
||||
return 333000000;
|
||||
return mhz * 1000000;
|
||||
}
|
||||
|
||||
int PowerBusMhzToHz(int mhz) {
|
||||
// These seem to be the only steps it has.
|
||||
if (mhz <= 95)
|
||||
return 95142860;
|
||||
if (mhz <= 111)
|
||||
return 111000000;
|
||||
if (mhz <= 133)
|
||||
return 133199997;
|
||||
if (mhz <= 166)
|
||||
return 166500000;
|
||||
return mhz * 1000000;
|
||||
}
|
||||
|
||||
void __PowerInit() {
|
||||
memset(powerCbSlots, 0, sizeof(powerCbSlots));
|
||||
@@ -68,15 +115,15 @@ void __PowerInit() {
|
||||
volatileWaitingThreads.clear();
|
||||
|
||||
if (g_Config.iLockedCPUSpeed > 0) {
|
||||
CoreTiming::SetClockFrequencyMHz(g_Config.iLockedCPUSpeed);
|
||||
pllFreq = g_Config.iLockedCPUSpeed;
|
||||
busFreq = g_Config.iLockedCPUSpeed / 2;
|
||||
pllFreq = PowerPllMhzToHz(g_Config.iLockedCPUSpeed);
|
||||
busFreq = PowerBusMhzToHz(pllFreq / 2000000);
|
||||
CoreTiming::SetClockFrequencyHz(PowerCpuMhzToHz(g_Config.iLockedCPUSpeed, pllFreq));
|
||||
} else {
|
||||
pllFreq = 222;
|
||||
busFreq = 111;
|
||||
pllFreq = PowerPllMhzToHz(222);
|
||||
busFreq = PowerBusMhzToHz(111);
|
||||
}
|
||||
RealpllFreq = 222;
|
||||
RealbusFreq = 111;
|
||||
RealpllFreq = PowerPllMhzToHz(222);
|
||||
RealbusFreq = PowerBusMhzToHz(111);
|
||||
}
|
||||
|
||||
void __PowerDoState(PointerWrap &p) {
|
||||
@@ -87,17 +134,20 @@ void __PowerDoState(PointerWrap &p) {
|
||||
if (s >= 2) {
|
||||
p.Do(RealpllFreq);
|
||||
p.Do(RealbusFreq);
|
||||
}
|
||||
else {
|
||||
RealpllFreq = 222;
|
||||
RealbusFreq = 111;
|
||||
|
||||
if (RealpllFreq < 1000000)
|
||||
RealpllFreq = PowerPllMhzToHz(RealpllFreq);
|
||||
if (RealbusFreq < 1000000)
|
||||
RealbusFreq = PowerBusMhzToHz(RealbusFreq);
|
||||
} else {
|
||||
RealpllFreq = PowerPllMhzToHz(222);
|
||||
RealbusFreq = PowerBusMhzToHz(111);
|
||||
}
|
||||
if (g_Config.iLockedCPUSpeed > 0) {
|
||||
CoreTiming::SetClockFrequencyMHz(g_Config.iLockedCPUSpeed);
|
||||
pllFreq = g_Config.iLockedCPUSpeed;
|
||||
busFreq = g_Config.iLockedCPUSpeed / 2;
|
||||
}
|
||||
else {
|
||||
pllFreq = PowerPllMhzToHz(g_Config.iLockedCPUSpeed);
|
||||
busFreq = PowerBusMhzToHz(pllFreq / 2000000);
|
||||
CoreTiming::SetClockFrequencyHz(PowerCpuMhzToHz(g_Config.iLockedCPUSpeed, pllFreq));
|
||||
} else {
|
||||
pllFreq = RealpllFreq;
|
||||
busFreq = RealbusFreq;
|
||||
}
|
||||
@@ -372,104 +422,124 @@ static int sceKernelVolatileMemLock(int type, u32 paddr, u32 psize) {
|
||||
|
||||
|
||||
static u32 scePowerSetClockFrequency(u32 pllfreq, u32 cpufreq, u32 busfreq) {
|
||||
// 190 might (probably) be a typo for 19, but it's what the actual PSP validates against.
|
||||
if (pllfreq < 19 || pllfreq < cpufreq || pllfreq > 333) {
|
||||
return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid pll frequency");
|
||||
}
|
||||
if (cpufreq == 0 || cpufreq > 333) {
|
||||
WARN_LOG(HLE,"scePowerSetClockFrequency(%i,%i,%i): invalid frequency", pllfreq, cpufreq, busfreq);
|
||||
return SCE_KERNEL_ERROR_INVALID_VALUE;
|
||||
return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid cpu frequency");
|
||||
}
|
||||
if (busfreq == 0 || busfreq > 166) {
|
||||
return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid bus frequency");
|
||||
}
|
||||
// TODO: More restrictions.
|
||||
if (g_Config.iLockedCPUSpeed > 0) {
|
||||
INFO_LOG(HLE, "scePowerSetClockFrequency(%i,%i,%i): locked by user config at %i, %i, %i", pllfreq, cpufreq, busfreq, g_Config.iLockedCPUSpeed, g_Config.iLockedCPUSpeed, busFreq);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
INFO_LOG(HLE, "scePowerSetClockFrequency(%i,%i,%i)", pllfreq, cpufreq, busfreq);
|
||||
}
|
||||
if (RealpllFreq != pllfreq || RealbusFreq != busfreq) {
|
||||
RealpllFreq = pllfreq;
|
||||
RealbusFreq = busfreq;
|
||||
// Only reschedules when the stepped PLL frequency changes.
|
||||
// It seems like the busfreq parameter has no effect (but can cause errors.)
|
||||
if (RealpllFreq != PowerPllMhzToHz(pllfreq)) {
|
||||
int oldPll = RealpllFreq / 1000000;
|
||||
|
||||
RealpllFreq = PowerPllMhzToHz(pllfreq);
|
||||
RealbusFreq = PowerBusMhzToHz(RealpllFreq / 2000000);
|
||||
if (g_Config.iLockedCPUSpeed <= 0) {
|
||||
pllFreq = pllfreq;
|
||||
busFreq = busfreq;
|
||||
CoreTiming::SetClockFrequencyMHz(cpufreq);
|
||||
pllFreq = RealpllFreq;
|
||||
busFreq = RealbusFreq;
|
||||
CoreTiming::SetClockFrequencyHz(PowerCpuMhzToHz(cpufreq, pllFreq));
|
||||
}
|
||||
return hleDelayResult(0, "scepower set clockFrequency", 150000);
|
||||
|
||||
// The delay depends on the source and destination frequency, most are 150ms.
|
||||
int newPll = RealpllFreq / 1000000;
|
||||
int usec = 150000;
|
||||
if ((newPll == 190 && oldPll == 222) || (newPll == 222 && oldPll == 190))
|
||||
usec = 15700;
|
||||
else if ((newPll == 266 && oldPll == 333) || (newPll == 333 && oldPll == 266))
|
||||
usec = 16600;
|
||||
|
||||
return hleDelayResult(0, "scepower set clockFrequency", usec);
|
||||
}
|
||||
if (g_Config.iLockedCPUSpeed <= 0)
|
||||
CoreTiming::SetClockFrequencyMHz(cpufreq);
|
||||
CoreTiming::SetClockFrequencyHz(PowerCpuMhzToHz(cpufreq, pllFreq));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 scePowerSetCpuClockFrequency(u32 cpufreq) {
|
||||
if(g_Config.iLockedCPUSpeed > 0) {
|
||||
DEBUG_LOG(HLE,"scePowerSetCpuClockFrequency(%i): locked by user config at %i", cpufreq, g_Config.iLockedCPUSpeed);
|
||||
if (cpufreq == 0 || cpufreq > 333) {
|
||||
return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid frequency");
|
||||
}
|
||||
else {
|
||||
if (cpufreq == 0 || cpufreq > 333) {
|
||||
WARN_LOG(HLE,"scePowerSetCpuClockFrequency(%i): invalid frequency", cpufreq);
|
||||
return SCE_KERNEL_ERROR_INVALID_VALUE;
|
||||
}
|
||||
CoreTiming::SetClockFrequencyMHz(cpufreq);
|
||||
INFO_LOG(HLE,"scePowerSetCpuClockFrequency(%i)", cpufreq);
|
||||
if (g_Config.iLockedCPUSpeed > 0) {
|
||||
return hleLogDebug(SCEMISC, 0, "locked by user config at %i", g_Config.iLockedCPUSpeed);
|
||||
}
|
||||
return 0;
|
||||
CoreTiming::SetClockFrequencyHz(PowerCpuMhzToHz(cpufreq, pllFreq));
|
||||
return hleLogSuccessI(SCEMISC, 0);
|
||||
}
|
||||
|
||||
static u32 scePowerSetBusClockFrequency(u32 busfreq) {
|
||||
if(g_Config.iLockedCPUSpeed > 0) {
|
||||
DEBUG_LOG(HLE,"scePowerSetBusClockFrequency(%i): locked by user config at %i", busfreq, busFreq);
|
||||
if (busfreq == 0 || busfreq > 111) {
|
||||
return hleLogWarning(SCEMISC, SCE_KERNEL_ERROR_INVALID_VALUE, "invalid frequency");
|
||||
}
|
||||
else {
|
||||
if (busfreq == 0 || busfreq > 111) {
|
||||
WARN_LOG(HLE,"scePowerSetBusClockFrequency(%i): invalid frequency", busfreq);
|
||||
return SCE_KERNEL_ERROR_INVALID_VALUE;
|
||||
}
|
||||
// TODO: It seems related to other frequencies, though.
|
||||
busFreq = busfreq;
|
||||
INFO_LOG_REPORT_ONCE(SetBusClockFrequency,HLE,"scePowerSetBusClockFrequency(%i)", busfreq);
|
||||
if (g_Config.iLockedCPUSpeed > 0) {
|
||||
return hleLogDebug(SCEMISC, 0, "locked by user config at %i", g_Config.iLockedCPUSpeed / 2);
|
||||
}
|
||||
return 0;
|
||||
|
||||
// The value passed is validated, but then doesn't seem to matter for the result.
|
||||
// However, this sets a different hz than scePowerSetClockFrequency would have.
|
||||
|
||||
if (pllFreq <= 190)
|
||||
busFreq = 94956673;
|
||||
else if (pllFreq <= 222)
|
||||
busFreq = 111000000;
|
||||
else if (pllFreq <= 266)
|
||||
busFreq = 132939331;
|
||||
else if (pllFreq <= 333)
|
||||
busFreq = 165848343;
|
||||
else
|
||||
busFreq = pllFreq / 2;
|
||||
|
||||
return hleLogSuccessI(SCEMISC, 0);
|
||||
}
|
||||
|
||||
static u32 scePowerGetCpuClockFrequencyInt() {
|
||||
int cpuFreq = CoreTiming::GetClockFrequencyMHz();
|
||||
DEBUG_LOG(HLE,"%i=scePowerGetCpuClockFrequencyInt()", cpuFreq);
|
||||
return cpuFreq;
|
||||
int cpuFreq = CoreTiming::GetClockFrequencyHz() / 1000000;
|
||||
return hleLogSuccessI(SCEMISC, cpuFreq);
|
||||
}
|
||||
|
||||
static u32 scePowerGetPllClockFrequencyInt() {
|
||||
INFO_LOG(HLE,"%i=scePowerGetPllClockFrequencyInt()", pllFreq);
|
||||
return pllFreq;
|
||||
return hleLogSuccessInfoI(SCEMISC, pllFreq / 1000000);
|
||||
}
|
||||
|
||||
static u32 scePowerGetBusClockFrequencyInt() {
|
||||
INFO_LOG(HLE,"%i=scePowerGetBusClockFrequencyInt()", busFreq);
|
||||
return busFreq;
|
||||
return hleLogSuccessInfoI(SCEMISC, busFreq / 1000000);
|
||||
}
|
||||
|
||||
static float scePowerGetCpuClockFrequencyFloat() {
|
||||
int cpuFreq = CoreTiming::GetClockFrequencyMHz();
|
||||
DEBUG_LOG(HLE, "%f=scePowerGetCpuClockFrequencyFloat()", (float)cpuFreq);
|
||||
return (float) cpuFreq;
|
||||
float cpuFreq = CoreTiming::GetClockFrequencyHz() / 1000000.0f;
|
||||
DEBUG_LOG(SCEMISC, "%f=scePowerGetCpuClockFrequencyFloat()", (float)cpuFreq);
|
||||
return cpuFreq;
|
||||
}
|
||||
|
||||
static float scePowerGetPllClockFrequencyFloat() {
|
||||
INFO_LOG(HLE, "%f=scePowerGetPllClockFrequencyFloat()", (float)pllFreq);
|
||||
return (float) pllFreq;
|
||||
INFO_LOG(SCEMISC, "%f=scePowerGetPllClockFrequencyFloat()", (float)pllFreq / 1000000.0f);
|
||||
return (float) pllFreq / 1000000.0f;
|
||||
}
|
||||
|
||||
static float scePowerGetBusClockFrequencyFloat() {
|
||||
INFO_LOG(HLE, "%f=scePowerGetBusClockFrequencyFloat()", (float)busFreq);
|
||||
return (float) busFreq;
|
||||
INFO_LOG(SCEMISC, "%f=scePowerGetBusClockFrequencyFloat()", (float)busFreq / 1000000.0f);
|
||||
return (float) busFreq / 1000000.0f;
|
||||
}
|
||||
|
||||
static int scePowerTick() {
|
||||
DEBUG_LOG(HLE, "scePowerTick()");
|
||||
DEBUG_LOG(SCEMISC, "scePowerTick()");
|
||||
// Don't think we need to do anything.
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static u32 IsPSPNonFat() {
|
||||
DEBUG_LOG(HLE, "%d=scePower_a85880d0_IsPSPNonFat()", g_Config.iPSPModel);
|
||||
DEBUG_LOG(SCEMISC, "%d=scePower_a85880d0_IsPSPNonFat()", g_Config.iPSPModel);
|
||||
|
||||
return g_Config.iPSPModel;
|
||||
}
|
||||
|
||||
@@ -247,6 +247,9 @@ void Arm64Jit::GenerateFixedCode(const JitOptions &jo) {
|
||||
}
|
||||
|
||||
LDR(INDEX_UNSIGNED, SCRATCH1, CTXREG, offsetof(MIPSState, pc));
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
ANDI2R(SCRATCH1, SCRATCH1, 0x3FFFFFFF);
|
||||
#endif
|
||||
LDR(SCRATCH1, MEMBASEREG, SCRATCH1_64);
|
||||
LSR(SCRATCH2, SCRATCH1, 24); // or UBFX(SCRATCH2, SCRATCH1, 24, 8)
|
||||
ANDI2R(SCRATCH1, SCRATCH1, 0x00FFFFFF);
|
||||
|
||||
@@ -43,7 +43,7 @@ using namespace MIPSAnalyst;
|
||||
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; }
|
||||
//#define CONDITIONAL_DISABLE(flag) { Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }
|
||||
#define DISABLE { Comp_Generic(op); return; }
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; }
|
||||
// #define CONDITIONAL_DISABLE(flag) { Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }
|
||||
#define DISABLE { Comp_Generic(op); return; }
|
||||
|
||||
@@ -102,7 +102,11 @@ void Arm64Jit::Comp_FPULS(MIPSOpcode op)
|
||||
fpr.SpillLock(ft);
|
||||
fpr.MapReg(ft, MAP_NOINIT | MAP_DIRTY);
|
||||
if (gpr.IsImm(rs)) {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
u32 addr = (offset + gpr.GetImm(rs)) & 0x3FFFFFFF;
|
||||
#else
|
||||
u32 addr = offset + gpr.GetImm(rs);
|
||||
#endif
|
||||
gpr.SetRegImm(SCRATCH1, addr);
|
||||
} else {
|
||||
gpr.MapReg(rs);
|
||||
@@ -129,7 +133,11 @@ void Arm64Jit::Comp_FPULS(MIPSOpcode op)
|
||||
|
||||
fpr.MapReg(ft);
|
||||
if (gpr.IsImm(rs)) {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
u32 addr = (offset + gpr.GetImm(rs)) & 0x3FFFFFFF;
|
||||
#else
|
||||
u32 addr = offset + gpr.GetImm(rs);
|
||||
#endif
|
||||
gpr.SetRegImm(SCRATCH1, addr);
|
||||
} else {
|
||||
gpr.MapReg(rs);
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; }
|
||||
//#define CONDITIONAL_DISABLE(flag) { Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }
|
||||
#define DISABLE { Comp_Generic(op); return; }
|
||||
|
||||
@@ -56,6 +56,9 @@ namespace MIPSComp {
|
||||
} else {
|
||||
MOV(SCRATCH1, gpr.R(rs));
|
||||
}
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
ANDI2R(SCRATCH1, SCRATCH1, 0x3FFFFFFF);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<FixupBranch> Arm64Jit::SetScratch1ForSafeAddress(MIPSGPReg rs, s16 offset, ARM64Reg tempReg) {
|
||||
@@ -135,12 +138,17 @@ namespace MIPSComp {
|
||||
std::vector<FixupBranch> skips;
|
||||
|
||||
if (gpr.IsImm(rs) && Memory::IsValidAddress(iaddr)) {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
u32 addr = iaddr & 0x3FFFFFFF;
|
||||
#else
|
||||
u32 addr = iaddr;
|
||||
#endif
|
||||
// Need to initialize since this only loads part of the register.
|
||||
// But rs no longer matters (even if rs == rt) since we have the address.
|
||||
gpr.MapReg(rt, load ? MAP_DIRTY : 0);
|
||||
gpr.SetRegImm(SCRATCH1, iaddr & ~3);
|
||||
gpr.SetRegImm(SCRATCH1, addr & ~3);
|
||||
|
||||
u8 shift = (iaddr & 3) * 8;
|
||||
u8 shift = (addr & 3) * 8;
|
||||
|
||||
switch (o) {
|
||||
case 34: // lwl
|
||||
@@ -347,7 +355,12 @@ namespace MIPSComp {
|
||||
}
|
||||
|
||||
if (gpr.IsImm(rs) && Memory::IsValidAddress(iaddr)) {
|
||||
if (offset == 0) {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
u32 addr = iaddr & 0x3FFFFFFF;
|
||||
#else
|
||||
u32 addr = iaddr;
|
||||
#endif
|
||||
if (addr == iaddr && offset == 0) {
|
||||
// It was already safe. Let's shove it into a reg and use it directly.
|
||||
if (targetReg == INVALID_REG) {
|
||||
load ? gpr.MapDirtyIn(rt, rs) : gpr.MapInIn(rt, rs);
|
||||
@@ -360,7 +373,7 @@ namespace MIPSComp {
|
||||
gpr.MapReg(rt, load ? MAP_NOINIT : 0);
|
||||
targetReg = gpr.R(rt);
|
||||
}
|
||||
gpr.SetRegImm(SCRATCH1, iaddr);
|
||||
gpr.SetRegImm(SCRATCH1, addr);
|
||||
addrReg = SCRATCH1;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
|
||||
// Currently known non working ones should have DISABLE.
|
||||
|
||||
// #define CONDITIONAL_DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; }
|
||||
// #define CONDITIONAL_DISABLE(flag) { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; }
|
||||
#define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; }
|
||||
#define DISABLE { fpr.ReleaseSpillLocksAndDiscardTemps(); Comp_Generic(op); return; }
|
||||
|
||||
@@ -222,7 +222,11 @@ namespace MIPSComp {
|
||||
// CC might be set by slow path below, so load regs first.
|
||||
fpr.MapRegV(vt, MAP_DIRTY | MAP_NOINIT);
|
||||
if (gpr.IsImm(rs)) {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
u32 addr = (offset + gpr.GetImm(rs)) & 0x3FFFFFFF;
|
||||
#else
|
||||
u32 addr = offset + gpr.GetImm(rs);
|
||||
#endif
|
||||
gpr.SetRegImm(SCRATCH1, addr);
|
||||
} else {
|
||||
gpr.MapReg(rs);
|
||||
@@ -251,7 +255,11 @@ namespace MIPSComp {
|
||||
// CC might be set by slow path below, so load regs first.
|
||||
fpr.MapRegV(vt);
|
||||
if (gpr.IsImm(rs)) {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
u32 addr = (offset + gpr.GetImm(rs)) & 0x3FFFFFFF;
|
||||
#else
|
||||
u32 addr = offset + gpr.GetImm(rs);
|
||||
#endif
|
||||
gpr.SetRegImm(SCRATCH1, addr);
|
||||
} else {
|
||||
gpr.MapReg(rs);
|
||||
@@ -293,7 +301,11 @@ namespace MIPSComp {
|
||||
fpr.MapRegsAndSpillLockV(vregs, V_Quad, MAP_DIRTY | MAP_NOINIT);
|
||||
|
||||
if (gpr.IsImm(rs)) {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
u32 addr = (imm + gpr.GetImm(rs)) & 0x3FFFFFFF;
|
||||
#else
|
||||
u32 addr = imm + gpr.GetImm(rs);
|
||||
#endif
|
||||
gpr.SetRegImm(SCRATCH1_64, addr + (uintptr_t)Memory::base);
|
||||
} else {
|
||||
gpr.MapReg(rs);
|
||||
@@ -326,7 +338,11 @@ namespace MIPSComp {
|
||||
fpr.MapRegsAndSpillLockV(vregs, V_Quad, 0);
|
||||
|
||||
if (gpr.IsImm(rs)) {
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
u32 addr = (imm + gpr.GetImm(rs)) & 0x3FFFFFFF;
|
||||
#else
|
||||
u32 addr = imm + gpr.GetImm(rs);
|
||||
#endif
|
||||
gpr.SetRegImm(SCRATCH1_64, addr + (uintptr_t)Memory::base);
|
||||
} else {
|
||||
gpr.MapReg(rs);
|
||||
@@ -1080,7 +1096,7 @@ namespace MIPSComp {
|
||||
fpr.ReleaseSpillLocksAndDiscardTemps();
|
||||
} else {
|
||||
fpr.MapRegV(vd);
|
||||
MOVI2F(fpr.V(vd), 0.0f, SCRATCH1);
|
||||
fp.MOVI2F(fpr.V(vd), 0.0f, SCRATCH1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -440,6 +440,9 @@ Arm64Gen::ARM64Reg Arm64RegCache::MapRegAsPointer(MIPSGPReg reg) {
|
||||
if (!jo_->enablePointerify) {
|
||||
// Convert to a pointer by adding the base and clearing off the top bits.
|
||||
// If SP, we can probably avoid the top bit clear, let's play with that later.
|
||||
#ifdef MASKED_PSP_MEMORY
|
||||
emit_->ANDI2R(EncodeRegTo64(a), EncodeRegTo64(a), 0x3FFFFFFF);
|
||||
#endif
|
||||
emit_->ADD(EncodeRegTo64(a), EncodeRegTo64(a), MEMBASEREG);
|
||||
mr[reg].loc = ML_ARMREG_AS_PTR;
|
||||
} else if (!ar[a].pointerified) {
|
||||
|
||||
@@ -1651,6 +1651,7 @@ namespace MIPSComp {
|
||||
// Vector quaternion product (n = 4, weird prefixes)
|
||||
// d[0 .. 2] = t[0 .. 2] X s[0 .. 2] + s[3] * t[0 .. 2] + t[3] * s[0 .. 2]
|
||||
// d[3] = s[3]*t[3] - s[0 .. 2] dot t[0 .. 3]
|
||||
// Note: Behaves as if it's implemented through a series of vdots.
|
||||
|
||||
VectorSize sz = GetVecSize(op);
|
||||
int n = GetNumVectorElements(sz);
|
||||
|
||||
+77
-50
@@ -96,8 +96,7 @@ inline float nanclamp(float f, float lower, float upper)
|
||||
}
|
||||
|
||||
|
||||
void ApplyPrefixST(float *r, u32 data, VectorSize size, float invalid = 0.0f)
|
||||
{
|
||||
void ApplyPrefixST(float *r, u32 data, VectorSize size, float invalid = 0.0f) {
|
||||
// Possible optimization shortcut:
|
||||
if (data == 0xe4)
|
||||
return;
|
||||
@@ -106,26 +105,25 @@ void ApplyPrefixST(float *r, u32 data, VectorSize size, float invalid = 0.0f)
|
||||
float origV[4]{ invalid, invalid, invalid, invalid };
|
||||
static const float constantArray[8] = {0.f, 1.f, 2.f, 0.5f, 3.f, 1.f/3.f, 0.25f, 1.f/6.f};
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
origV[i] = r[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
int regnum = (data >> (i*2)) & 3;
|
||||
int abs = (data >> (8+i)) & 1;
|
||||
int negate = (data >> (16+i)) & 1;
|
||||
int constants = (data >> (12+i)) & 1;
|
||||
|
||||
if (!constants)
|
||||
{
|
||||
if (!constants) {
|
||||
if (regnum >= n) {
|
||||
// We mostly handle this now, but still worth reporting.
|
||||
ERROR_LOG_REPORT(CPU, "Invalid VFPU swizzle: %08x: %i / %d at PC = %08x (%s)", data, regnum, n, currentMIPS->pc, MIPSDisasmAt(currentMIPS->pc));
|
||||
}
|
||||
r[i] = origV[regnum];
|
||||
if (abs)
|
||||
((u32 *)r)[i] = ((u32 *)r)[i] & 0x7FFFFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
r[i] = constantArray[regnum + (abs<<2)];
|
||||
}
|
||||
|
||||
@@ -348,11 +346,23 @@ namespace MIPSInt
|
||||
|
||||
int off = GetMatrixSide(sz) - 1;
|
||||
u32 sprefixRemove = VFPU_ANY_SWIZZLE();
|
||||
u32 sprefixAdd = VFPU_CONST(1, 1, 1, 1);
|
||||
u32 sprefixAdd;
|
||||
switch ((op >> 16) & 0xF) {
|
||||
case 3: sprefixAdd |= VFPU_SWIZZLE(off == 0, off == 1, off == 2, off == 3); break;
|
||||
case 6: sprefixAdd |= VFPU_SWIZZLE(0, 0, 0, 0); break;
|
||||
case 7: sprefixAdd |= VFPU_SWIZZLE(1, 1, 1, 1); break;
|
||||
case 3:
|
||||
{
|
||||
VFPUConst constX = off == 0 ? VFPUConst::ONE : VFPUConst::ZERO;
|
||||
VFPUConst constY = off == 1 ? VFPUConst::ONE : VFPUConst::ZERO;
|
||||
VFPUConst constZ = off == 2 ? VFPUConst::ONE : VFPUConst::ZERO;
|
||||
VFPUConst constW = off == 3 ? VFPUConst::ONE : VFPUConst::ZERO;
|
||||
sprefixAdd = VFPU_MAKE_CONSTANTS(constX, constY, constZ, constW);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
sprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::ZERO, VFPUConst::ZERO, VFPUConst::ZERO, VFPUConst::ZERO);
|
||||
break;
|
||||
case 7:
|
||||
sprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::ONE, VFPUConst::ONE, VFPUConst::ONE, VFPUConst::ONE);
|
||||
break;
|
||||
}
|
||||
ApplyPrefixST(&prefixed[off * 4], VFPURewritePrefix(VFPU_CTRL_SPREFIX, sprefixRemove, sprefixAdd), V_Quad);
|
||||
WriteMatrix(prefixed, sz, vd);
|
||||
@@ -370,10 +380,10 @@ namespace MIPSInt
|
||||
VectorSize sz = GetVecSize(op);
|
||||
float d[4];
|
||||
|
||||
int constant = 0;
|
||||
VFPUConst constant = VFPUConst::ZERO;
|
||||
switch ((op >> 16) & 0xF) {
|
||||
case 6: constant = 0; break; //vzero
|
||||
case 7: constant = 1; break; //vone
|
||||
case 6: constant = VFPUConst::ZERO; break; //vzero
|
||||
case 7: constant = VFPUConst::ONE; break; //vone
|
||||
default:
|
||||
_dbg_assert_msg_(CPU, 0, "Trying to interpret instruction that can't be interpreted");
|
||||
PC += 4;
|
||||
@@ -383,7 +393,7 @@ namespace MIPSInt
|
||||
|
||||
// The S prefix generates constants, but negate is still respected.
|
||||
u32 sprefixRemove = VFPU_ANY_SWIZZLE();
|
||||
u32 sprefixAdd = VFPU_CONST(1, 1, 1, 1) | VFPU_SWIZZLE(constant, constant, constant, constant);
|
||||
u32 sprefixAdd = VFPU_MAKE_CONSTANTS(constant, constant, constant, constant);
|
||||
ApplyPrefixST(d, VFPURewritePrefix(VFPU_CTRL_SPREFIX, sprefixRemove, sprefixAdd), sz);
|
||||
|
||||
ApplyPrefixD(d, sz);
|
||||
@@ -422,8 +432,14 @@ namespace MIPSInt
|
||||
// The S prefix generates constants, but negate is still respected.
|
||||
int offmask = sz == V_Quad || sz == V_Triple ? 3 : 1;
|
||||
int off = vd & offmask;
|
||||
// If it's a pair, the identity starts in a different position.
|
||||
VFPUConst constX = off == (0 & offmask) ? VFPUConst::ONE : VFPUConst::ZERO;
|
||||
VFPUConst constY = off == (1 & offmask) ? VFPUConst::ONE : VFPUConst::ZERO;
|
||||
VFPUConst constZ = off == (2 & offmask) ? VFPUConst::ONE : VFPUConst::ZERO;
|
||||
VFPUConst constW = off == (3 & offmask) ? VFPUConst::ONE : VFPUConst::ZERO;
|
||||
|
||||
u32 sprefixRemove = VFPU_ANY_SWIZZLE();
|
||||
u32 sprefixAdd = VFPU_CONST(1, 1, 1, 1) | VFPU_SWIZZLE(off == 0, off == 1, off == (2 & offmask), off == (3 & offmask));
|
||||
u32 sprefixAdd = VFPU_MAKE_CONSTANTS(constX, constY, constZ, constW);
|
||||
ApplyPrefixST(f, VFPURewritePrefix(VFPU_CTRL_SPREFIX, sprefixRemove, sprefixAdd), sz);
|
||||
|
||||
ApplyPrefixD(f, sz);
|
||||
@@ -645,7 +661,7 @@ namespace MIPSInt
|
||||
// T prefix forces constants on and regnum to 1.
|
||||
// That means negate still works, and abs activates a different constant.
|
||||
u32 tprefixRemove = VFPU_ANY_SWIZZLE();
|
||||
u32 tprefixAdd = VFPU_SWIZZLE(1, 1, 1, 1) | VFPU_CONST(1, 1, 1, 1);
|
||||
u32 tprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::ONE, VFPUConst::ONE, VFPUConst::ONE, VFPUConst::ONE);
|
||||
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz);
|
||||
|
||||
for (int i = 0; i < GetNumVectorElements(sz); i++) {
|
||||
@@ -675,10 +691,10 @@ namespace MIPSInt
|
||||
u32 sprefixAdd = VFPU_SWIZZLE(0, 0, 1, 1) | VFPU_NEGATE(1, 0, 1, 0);
|
||||
ApplyPrefixST(s, VFPURewritePrefix(VFPU_CTRL_SPREFIX, sprefixRemove, sprefixAdd), outSize);
|
||||
|
||||
// T prefix forces constants on and regnum to 0, 1, 0, 1.
|
||||
// T prefix forces constants on and regnum to 1, 0, 1, 0.
|
||||
// That means negate still works, and abs activates a different constant.
|
||||
u32 tprefixRemove = VFPU_ANY_SWIZZLE();
|
||||
u32 tprefixAdd = VFPU_SWIZZLE(1, 0, 1, 0) | VFPU_CONST(1, 1, 1, 1);
|
||||
u32 tprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::ONE, VFPUConst::ZERO, VFPUConst::ONE, VFPUConst::ZERO);
|
||||
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), outSize);
|
||||
|
||||
int n = GetNumVectorElements(sz);
|
||||
@@ -704,7 +720,7 @@ namespace MIPSInt
|
||||
|
||||
// Not sure who would do this, but using abs/neg allows a compare against 3 or -3.
|
||||
u32 tprefixRemove = VFPU_ANY_SWIZZLE();
|
||||
u32 tprefixAdd = VFPU_CONST(1, 1, 1, 1) | VFPU_SWIZZLE(0, 0, 0, 0);
|
||||
u32 tprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::ZERO, VFPUConst::ZERO, VFPUConst::ZERO, VFPUConst::ZERO);
|
||||
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz);
|
||||
|
||||
int n = GetNumVectorElements(sz);
|
||||
@@ -838,8 +854,9 @@ namespace MIPSInt
|
||||
VectorSize sz = GetVecSize(op);
|
||||
ReadVector(s, sz, vs);
|
||||
// Swizzle can cause V_Single to properly write both components.
|
||||
// TODO: Minor, but negate shouldn't apply to invalid here. Maybe always?
|
||||
ApplySwizzleS(s, V_Quad);
|
||||
// Negate should not actually apply to invalid swizzle.
|
||||
RetainInvalidSwizzleST(s, V_Quad);
|
||||
|
||||
VectorSize outsize = V_Single;
|
||||
switch (sz) {
|
||||
@@ -1135,16 +1152,16 @@ namespace MIPSInt
|
||||
u32 sprefixAdd;
|
||||
if (sz == V_Quad) {
|
||||
sprefixRemove = VFPU_SWIZZLE(0, 0, 0, 3);
|
||||
sprefixAdd = VFPU_CONST(0, 0, 0, 1) | VFPU_SWIZZLE(0, 0, 0, 1);
|
||||
sprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::NONE, VFPUConst::NONE, VFPUConst::NONE, VFPUConst::ONE);
|
||||
} else if (sz == V_Triple) {
|
||||
sprefixRemove = VFPU_SWIZZLE(0, 0, 3, 0);
|
||||
sprefixAdd = VFPU_CONST(0, 0, 1, 0) | VFPU_SWIZZLE(0, 0, 1, 0);
|
||||
sprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::NONE, VFPUConst::NONE, VFPUConst::ONE, VFPUConst::NONE);
|
||||
} else if (sz == V_Pair) {
|
||||
sprefixRemove = VFPU_SWIZZLE(0, 3, 0, 0);
|
||||
sprefixAdd = VFPU_CONST(0, 1, 0, 0) | VFPU_SWIZZLE(0, 1, 0, 0);
|
||||
sprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::NONE, VFPUConst::ONE, VFPUConst::NONE, VFPUConst::NONE);
|
||||
} else {
|
||||
sprefixRemove = VFPU_SWIZZLE(3, 0, 0, 0);
|
||||
sprefixAdd = VFPU_CONST(1, 0, 0, 0) | VFPU_SWIZZLE(1, 0, 0, 0);
|
||||
sprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::ONE, VFPUConst::NONE, VFPUConst::NONE, VFPUConst::NONE);
|
||||
}
|
||||
ApplyPrefixST(s, VFPURewritePrefix(VFPU_CTRL_SPREFIX, sprefixRemove, sprefixAdd), V_Quad);
|
||||
|
||||
@@ -1227,11 +1244,11 @@ namespace MIPSInt
|
||||
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz);
|
||||
|
||||
// TODO: May mishandle NAN / negative zero / etc.
|
||||
// TODO: If S swizzle selects a lane that doesn't exist in sz, the result is always 0.
|
||||
d[0] = std::min(s[0], t[0]);
|
||||
d[1] = std::max(s[1], t[1]);
|
||||
d[2] = std::min(s[2], t[2]);
|
||||
d[3] = std::max(s[3], t[3]);
|
||||
RetainInvalidSwizzleST(d, sz);
|
||||
ApplyPrefixD(d, sz);
|
||||
WriteVector(d, sz, vd);
|
||||
PC += 4;
|
||||
@@ -1253,11 +1270,11 @@ namespace MIPSInt
|
||||
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz);
|
||||
|
||||
// TODO: May mishandle NAN / negative zero / etc.
|
||||
// TODO: If S swizzle selects a lane that doesn't exist in sz, the result is always 0.
|
||||
d[0] = std::min(s[0], t[0]);
|
||||
d[1] = std::min(s[1], t[1]);
|
||||
d[2] = std::max(s[2], t[2]);
|
||||
d[3] = std::max(s[3], t[3]);
|
||||
RetainInvalidSwizzleST(d, sz);
|
||||
ApplyPrefixD(d, sz);
|
||||
WriteVector(d, sz, vd);
|
||||
PC += 4;
|
||||
@@ -1279,11 +1296,11 @@ namespace MIPSInt
|
||||
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz);
|
||||
|
||||
// TODO: May mishandle NAN / negative zero / etc.
|
||||
// TODO: If S swizzle selects a lane that doesn't exist in sz, the result is always 0.
|
||||
d[0] = std::max(s[0], t[0]);
|
||||
d[1] = std::min(s[1], t[1]);
|
||||
d[2] = std::max(s[2], t[2]);
|
||||
d[3] = std::min(s[3], t[3]);
|
||||
RetainInvalidSwizzleST(d, sz);
|
||||
ApplyPrefixD(d, sz);
|
||||
WriteVector(d, sz, vd);
|
||||
PC += 4;
|
||||
@@ -1305,11 +1322,11 @@ namespace MIPSInt
|
||||
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz);
|
||||
|
||||
// TODO: May mishandle NAN / negative zero / etc.
|
||||
// TODO: If S swizzle selects a lane that doesn't exist in sz, the result is always 0.
|
||||
d[0] = std::max(s[0], t[0]);
|
||||
d[1] = std::max(s[1], t[1]);
|
||||
d[2] = std::min(s[2], t[2]);
|
||||
d[3] = std::min(s[3], t[3]);
|
||||
RetainInvalidSwizzleST(d, sz);
|
||||
ApplyPrefixD(d, sz);
|
||||
WriteVector(d, sz, vd);
|
||||
PC += 4;
|
||||
@@ -1384,7 +1401,7 @@ namespace MIPSInt
|
||||
|
||||
// T prefix generates constants, but abs can change the constant.
|
||||
u32 tprefixRemove = VFPU_ANY_SWIZZLE();
|
||||
u32 tprefixAdd = VFPU_CONST(1, 1, 1, 1) | VFPU_SWIZZLE(1, 1, 1, 1);
|
||||
u32 tprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::ONE, VFPUConst::ONE, VFPUConst::ONE, VFPUConst::ONE);
|
||||
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), V_Quad);
|
||||
|
||||
d = 0.0f;
|
||||
@@ -1408,15 +1425,17 @@ namespace MIPSInt
|
||||
|
||||
// T prefix generates constants, but supports negate.
|
||||
u32 tprefixRemove = VFPU_ANY_SWIZZLE() | VFPU_ABS(1, 1, 1, 1);
|
||||
u32 tprefixAdd = VFPU_CONST(1, 1, 1, 1);
|
||||
u32 tprefixAdd;
|
||||
if (sz == V_Single)
|
||||
tprefixAdd |= VFPU_SWIZZLE(0, 0, 0, 0);
|
||||
tprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::ZERO, VFPUConst::ZERO, VFPUConst::ZERO, VFPUConst::ZERO);
|
||||
else if (sz == V_Pair)
|
||||
tprefixAdd |= VFPU_SWIZZLE(3, 3, 3, 3);
|
||||
tprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::HALF, VFPUConst::HALF, VFPUConst::HALF, VFPUConst::HALF);
|
||||
else if (sz == V_Triple)
|
||||
tprefixAdd |= VFPU_SWIZZLE(1, 1, 1, 1) | VFPU_ABS(1, 1, 1, 1);
|
||||
tprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::THIRD, VFPUConst::THIRD, VFPUConst::THIRD, VFPUConst::THIRD);
|
||||
else if (sz == V_Quad)
|
||||
tprefixAdd |= VFPU_SWIZZLE(2, 2, 2, 2) | VFPU_ABS(1, 1, 1, 1);
|
||||
tprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::FOURTH, VFPUConst::FOURTH, VFPUConst::FOURTH, VFPUConst::FOURTH);
|
||||
else
|
||||
tprefixAdd = 0;
|
||||
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), V_Quad);
|
||||
|
||||
d = 0.0f;
|
||||
@@ -1509,13 +1528,17 @@ namespace MIPSInt
|
||||
float s[4]{};
|
||||
ReadVector(s, V_Single, vs);
|
||||
u32 sprefixRemove = VFPU_NEGATE(1, 0, 0, 0);
|
||||
u32 sprefixAdd = VFPU_NEGATE(negSin, 0, 0, 0);
|
||||
// TODO: Minor, but negate shouldn't apply to invalid here. Maybe always?
|
||||
// We apply negSin later, not here. This handles zero a bit better.
|
||||
u32 sprefixAdd = VFPU_NEGATE(0, 0, 0, 0);
|
||||
ApplyPrefixST(s, VFPURewritePrefix(VFPU_CTRL_SPREFIX, sprefixRemove, sprefixAdd), V_Single);
|
||||
|
||||
// Cosine ignores all prefixes, so take the original.
|
||||
cosine = vfpu_cos(V(vs));
|
||||
sine = vfpu_sin(s[0]);
|
||||
|
||||
if (negSin)
|
||||
sine = -sine;
|
||||
RetainInvalidSwizzleST(&sine, V_Single);
|
||||
}
|
||||
|
||||
if (sineLane == cosineLane) {
|
||||
@@ -1562,11 +1585,17 @@ namespace MIPSInt
|
||||
// S and T prefixes apply for the final row only.
|
||||
// The T prefix is used to apply zero/one constants, but abs still changes it.
|
||||
ApplySwizzleS(&s[ins * 4], V_Quad);
|
||||
u32 tprefixRemove = VFPU_SWIZZLE(0, n < 2 ? 3 : 0, n < 3 ? 3 : 0, n < 4 ? 3 : 0);
|
||||
u32 tprefixAdd = VFPU_CONST(0, n < 2, n < 3, n < 4);
|
||||
VFPUConst constX = VFPUConst::NONE;
|
||||
VFPUConst constY = n < 2 ? VFPUConst::ZERO : VFPUConst::NONE;
|
||||
VFPUConst constZ = n < 3 ? VFPUConst::ZERO : VFPUConst::NONE;
|
||||
VFPUConst constW = n < 4 ? VFPUConst::ZERO : VFPUConst::NONE;
|
||||
if (ins >= n) {
|
||||
tprefixAdd |= VFPU_SWIZZLE(0, ins == 1 ? 1 : 0, ins == 2 ? 1 : 0, ins == 3 ? 1 : 0);
|
||||
constY = ins == 1 ? VFPUConst::ONE : VFPUConst::ZERO;
|
||||
constZ = ins == 2 ? VFPUConst::ONE : VFPUConst::ZERO;
|
||||
constW = ins == 3 ? VFPUConst::ONE : VFPUConst::ZERO;
|
||||
}
|
||||
u32 tprefixRemove = VFPU_SWIZZLE(0, n < 2 ? 3 : 0, n < 3 ? 3 : 0, n < 4 ? 3 : 0);
|
||||
u32 tprefixAdd = VFPU_MAKE_CONSTANTS(constX, constY, constZ, constW);
|
||||
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), V_Quad);
|
||||
|
||||
// Really this is the operation all rows probably use (with constant wiring.)
|
||||
@@ -2011,7 +2040,7 @@ namespace MIPSInt
|
||||
d[0] = s[1]*t[2] - s[2]*t[1];
|
||||
d[1] = s[2]*t[0] - s[0]*t[2];
|
||||
|
||||
// T prefix forces siwzzle and negate, can be used to have weird constants.
|
||||
// T prefix forces swizzle and negate, can be used to have weird constants.
|
||||
tprefixAdd = VFPU_SWIZZLE(1, 0, 3, 2) | VFPU_NEGATE(0, 1, 0, 0);
|
||||
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), V_Quad);
|
||||
ApplySwizzleS(s, V_Quad);
|
||||
@@ -2023,7 +2052,7 @@ namespace MIPSInt
|
||||
d[1] = -s[0]*t[2] + s[1]*t[3] + s[2]*t[0] + s[3]*t[1];
|
||||
d[2] = s[0]*t[1] - s[1]*t[0] + s[2]*t[3] + s[3]*t[2];
|
||||
|
||||
// T prefix forces siwzzle and negate, can be used to have weird constants.
|
||||
// T prefix forces swizzle and negate, can be used to have weird constants.
|
||||
tprefixAdd = VFPU_SWIZZLE(0, 1, 2, 3) | VFPU_NEGATE(1, 1, 1, 0);
|
||||
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), V_Quad);
|
||||
ApplySwizzleS(s, sz);
|
||||
@@ -2070,7 +2099,6 @@ namespace MIPSInt
|
||||
VectorSize sz = GetVecSize(op);
|
||||
|
||||
ReadVector(s.f, sz, vs);
|
||||
// TODO: Swizzled outside sz stays zero (no -INF.)
|
||||
ApplySwizzleS(s.f, sz);
|
||||
|
||||
int exp = (s.u[0] & 0x7F800000) >> 23;
|
||||
@@ -2087,14 +2115,13 @@ namespace MIPSInt
|
||||
d.u[i] = s.u[i];
|
||||
}
|
||||
|
||||
RetainInvalidSwizzleST(d.f, sz);
|
||||
ApplyPrefixD(d.f, sz);
|
||||
WriteVector(d.f, sz, vd);
|
||||
PC += 4;
|
||||
EatPrefixes();
|
||||
}
|
||||
|
||||
// There has to be a concise way of expressing this in terms of
|
||||
// bit manipulation on the raw floats.
|
||||
void Int_Vwbn(MIPSOpcode op) {
|
||||
FloatBits d, s;
|
||||
int vd = _VD;
|
||||
@@ -2103,7 +2130,6 @@ namespace MIPSInt
|
||||
u8 exp = (u8)((op >> 16) & 0xFF);
|
||||
|
||||
ReadVector(s.f, sz, vs);
|
||||
// TODO: Swizzled outside sz stays zero (no exp insertion.)
|
||||
ApplySwizzleS(s.f, sz);
|
||||
|
||||
u32 sigbit = s.u[0] & 0x80000000;
|
||||
@@ -2127,6 +2153,7 @@ namespace MIPSInt
|
||||
d.u[i] = s.u[i];
|
||||
}
|
||||
|
||||
RetainInvalidSwizzleST(d.f, sz);
|
||||
ApplyPrefixD(d.f, sz);
|
||||
WriteVector(d.f, sz, vd);
|
||||
PC += 4;
|
||||
|
||||
@@ -35,7 +35,7 @@ inline int Xpose(int v) {
|
||||
|
||||
// Some games depend on exact values, but sinf() and cosf() aren't always precise.
|
||||
// Stepping down to [0, 2pi) helps, but we also check common exact-result values.
|
||||
// TODO: cos(2) and sin(1) should be -0.0, but doing that gives wrong results (possibly from floorf.)
|
||||
// TODO: cos(1) and sin(2) should be -0.0, but doing that gives wrong results (possibly from floorf.)
|
||||
|
||||
inline float vfpu_sin(float angle) {
|
||||
angle -= floorf(angle * 0.25f) * 4.f;
|
||||
@@ -145,6 +145,36 @@ static u32 VFPU_NEGATE(int x, int y, int z, int w) {
|
||||
return VFPU_MASK(x, y, z, w) << 16;
|
||||
}
|
||||
|
||||
enum class VFPUConst {
|
||||
NONE = -1,
|
||||
ZERO,
|
||||
ONE,
|
||||
TWO,
|
||||
HALF,
|
||||
THREE,
|
||||
THIRD,
|
||||
FOURTH,
|
||||
SIXTH,
|
||||
};
|
||||
|
||||
static u32 VFPU_MAKE_CONSTANTS(VFPUConst x, VFPUConst y, VFPUConst z, VFPUConst w) {
|
||||
u32 result = 0;
|
||||
if (x != VFPUConst::NONE) {
|
||||
// This sets the constant flag and the swizzle/abs flags for the right constant.
|
||||
result |= (((int)x & 3) << 0) | (((int)x & 4) << 6) | (1 << 12);
|
||||
}
|
||||
if (y != VFPUConst::NONE) {
|
||||
result |= (((int)y & 3) << 2) | (((int)y & 4) << 7) | (1 << 13);
|
||||
}
|
||||
if (z != VFPUConst::NONE) {
|
||||
result |= (((int)z & 3) << 4) | (((int)z & 4) << 8) | (1 << 14);
|
||||
}
|
||||
if (w != VFPUConst::NONE) {
|
||||
result |= (((int)w & 3) << 6) | (((int)w & 4) << 9) | (1 << 15);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 VFPURewritePrefix(int ctrl, u32 remove, u32 add);
|
||||
|
||||
void ReadMatrix(float *rd, MatrixSize size, int reg);
|
||||
|
||||
@@ -1172,7 +1172,13 @@ void ConvertBlendState(GenericBlendState &blendState, bool allowShaderBlend) {
|
||||
break;
|
||||
}
|
||||
} else if (!IsStencilTestOutputDisabled()) {
|
||||
switch (ReplaceAlphaWithStencilType()) {
|
||||
StencilValueType stencilValue = ReplaceAlphaWithStencilType();
|
||||
if (stencilValue == STENCIL_VALUE_UNIFORM && constantAlpha == 0x00) {
|
||||
stencilValue = STENCIL_VALUE_ZERO;
|
||||
} else if (stencilValue == STENCIL_VALUE_UNIFORM && constantAlpha == 0xFF) {
|
||||
stencilValue = STENCIL_VALUE_ONE;
|
||||
}
|
||||
switch (stencilValue) {
|
||||
case STENCIL_VALUE_KEEP:
|
||||
blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ZERO, BlendFactor::ONE);
|
||||
break;
|
||||
|
||||
@@ -80,6 +80,7 @@ d814000000000000cecf000000000000,MC Cthulhu,platform:Mac OS X,leftx:,lefty:,righ
|
||||
bd1200000000000015d0000000000000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Mac OS X,
|
||||
|
||||
# Linux
|
||||
050000004c0500006802000000000000,Sony PLAYSTATION(R)3 Controller,platform:Linux,a:b14,b:b13,x:b15,y:b12,back:b0,guide:b16,start:b3,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpdown:b6,dpleft:b7,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a12,righttrigger:a13,
|
||||
03000000ff1100004133000010010000,GreenAsia Inc.USB Joystick,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,
|
||||
0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
|
||||
|
||||
+1
-1
Submodule assets/lang updated: 86c62b9a23...152c6893e9.
+1
-1
@@ -5,7 +5,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.3.2'
|
||||
classpath 'com.android.tools.build:gradle:3.4.0'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
Submodule ffmpeg updated: 7472c903ec...4e8e6a1e7a.
+2
-2
@@ -1,6 +1,6 @@
|
||||
#Tue Jan 15 23:30:05 CET 2019
|
||||
#Fri Apr 19 22:49:10 CEST 2019
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
|
||||
+45
-4
@@ -188,6 +188,7 @@ static RetroOption<bool> ppsspp_separate_io_thread("ppsspp_separate_io_thread",
|
||||
static RetroOption<bool> ppsspp_unsafe_func_replacements("ppsspp_unsafe_func_replacements", "Unsafe FuncReplacements", true);
|
||||
static RetroOption<bool> ppsspp_sound_speedhack("ppsspp_sound_speedhack", "Sound Speedhack", false);
|
||||
static RetroOption<bool> ppsspp_cheats("ppsspp_cheats", "Internal Cheats Support", false);
|
||||
static RetroOption<IOTimingMethods> ppsspp_io_timing_method("ppsspp_io_timing_method", "IO Timing Method", { { "Fast", IOTimingMethods::IOTIMING_FAST }, { "Host", IOTimingMethods::IOTIMING_HOST }, { "Simulate UMD delays", IOTimingMethods::IOTIMING_REALISTIC } });
|
||||
|
||||
void retro_set_environment(retro_environment_t cb) {
|
||||
std::vector<retro_variable> vars;
|
||||
@@ -216,6 +217,7 @@ void retro_set_environment(retro_environment_t cb) {
|
||||
vars.push_back(ppsspp_unsafe_func_replacements.GetOptions());
|
||||
vars.push_back(ppsspp_sound_speedhack.GetOptions());
|
||||
vars.push_back(ppsspp_cheats.GetOptions());
|
||||
vars.push_back(ppsspp_io_timing_method.GetOptions());
|
||||
vars.push_back({});
|
||||
|
||||
environ_cb = cb;
|
||||
@@ -283,6 +285,7 @@ static void check_variables(CoreParameter &coreParam) {
|
||||
ppsspp_locked_cpu_speed.Update(&g_Config.iLockedCPUSpeed);
|
||||
ppsspp_rendering_mode.Update(&g_Config.iRenderingMode);
|
||||
ppsspp_cpu_core.Update((CPUCore *)&g_Config.iCpuCore);
|
||||
ppsspp_io_timing_method.Update((IOTimingMethods *)&g_Config.iIOTimingMethod);
|
||||
|
||||
ppsspp_language.Update(&g_Config.iLanguage);
|
||||
if (g_Config.iLanguage < 0) {
|
||||
@@ -453,6 +456,7 @@ void EmuThreadStop() {
|
||||
// Need to keep eating frames to allow the EmuThread to exit correctly.
|
||||
continue;
|
||||
}
|
||||
|
||||
emuThread.join();
|
||||
emuThread = std::thread();
|
||||
ctx->ThreadEnd();
|
||||
@@ -462,8 +466,11 @@ void EmuThreadPause() {
|
||||
if (emuThreadState != EmuThreadState::RUNNING) {
|
||||
return;
|
||||
}
|
||||
|
||||
emuThreadState = EmuThreadState::PAUSE_REQUESTED;
|
||||
ctx->ThreadFrame();
|
||||
|
||||
ctx->ThreadFrame(); // Eat 1 frame
|
||||
|
||||
while (emuThreadState != EmuThreadState::PAUSED) {
|
||||
sleep_ms(1);
|
||||
}
|
||||
@@ -675,6 +682,11 @@ void retro_run(void) {
|
||||
retro_input();
|
||||
|
||||
if (useEmuThread) {
|
||||
if(emuThreadState == EmuThreadState::PAUSED || emuThreadState == EmuThreadState::PAUSE_REQUESTED) {
|
||||
ctx->SwapBuffers();
|
||||
return;
|
||||
}
|
||||
|
||||
if (emuThreadState != EmuThreadState::RUNNING) {
|
||||
EmuThreadStart();
|
||||
}
|
||||
@@ -705,19 +717,48 @@ struct SaveStart {
|
||||
} // namespace SaveState
|
||||
|
||||
size_t retro_serialize_size(void) {
|
||||
// TODO: Libretro API extension to use the savestate queue
|
||||
if (useEmuThread) {
|
||||
EmuThreadPause();
|
||||
}
|
||||
|
||||
SaveState::SaveStart state;
|
||||
return (CChunkFileReader::MeasurePtr(state) + 0x800000) & ~0x7FFFFF;
|
||||
return (CChunkFileReader::MeasurePtr(state) + 0x800000) & ~0x7FFFFF; // We don't unpause intentionally
|
||||
}
|
||||
|
||||
bool retro_serialize(void *data, size_t size) {
|
||||
// TODO: Libretro API extension to use the savestate queue
|
||||
if (useEmuThread) {
|
||||
EmuThreadPause(); // Does nothing if already paused
|
||||
}
|
||||
|
||||
SaveState::SaveStart state;
|
||||
assert(CChunkFileReader::MeasurePtr(state) <= size);
|
||||
return CChunkFileReader::SavePtr((u8 *)data, state) == CChunkFileReader::ERROR_NONE;
|
||||
bool retVal = CChunkFileReader::SavePtr((u8 *)data, state) == CChunkFileReader::ERROR_NONE;
|
||||
|
||||
if (useEmuThread) {
|
||||
EmuThreadStart();
|
||||
sleep_ms(4);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
bool retro_unserialize(const void *data, size_t size) {
|
||||
// TODO: Libretro API extension to use the savestate queue
|
||||
if (useEmuThread) {
|
||||
EmuThreadPause(); // Does nothing if already paused
|
||||
}
|
||||
|
||||
SaveState::SaveStart state;
|
||||
return CChunkFileReader::LoadPtr((u8 *)data, state) == CChunkFileReader::ERROR_NONE;
|
||||
bool retVal = CChunkFileReader::LoadPtr((u8 *)data, state) == CChunkFileReader::ERROR_NONE;
|
||||
|
||||
if (useEmuThread) {
|
||||
EmuThreadStart();
|
||||
sleep_ms(4);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
void *retro_get_memory_data(unsigned id) {
|
||||
|
||||
Reference in new issue
Block a user