Merge branch 'master' into TemporaryHackishBranch

# Conflicts:
#	Core/MIPS/ARM64/Arm64CompVFPU.cpp
#	Core/MIPS/MIPSIntVFPU.cpp
#	Core/MIPS/MIPSVFPUUtils.h
This commit is contained in:
LunaMoo committed 2019-04-25 02:35:25 +02:00
commit e136416ffd
20 files changed
+378 -162

No files matched your search

+15 -18
View File
@@ -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
View File
@@ -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
+2 -2
View File
@@ -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
View File
@@ -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;
}
+3
View File
@@ -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);
+1 -1
View File
@@ -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; }
+9 -1
View File
@@ -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);
+18 -5
View File
@@ -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 {
+18 -2
View File
@@ -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);
}
}
+3
View File
@@ -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) {
+1
View File
@@ -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
View File
@@ -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;
+31 -1
View File
@@ -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);
+7 -1
View File
@@ -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;
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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) {