Merge pull request #22090 from hrydgard/more-stuff

Simplify file system mounting slightly, more MIPS context plumbing
This commit is contained in:
Henrik Rydgård
2026-08-13 08:34:27 +02:00
committed by GitHub
26 changed files with 220 additions and 163 deletions
+13 -2
View File
@@ -40,8 +40,19 @@ necessarily after every edit), run these too:
- Windows: build the `UnitTest` project (unittest/UnitTests.vcxproj), then run `Windows/x64/Debug/UnitTest.exe all`
- Linux/Mac: configure with `-DUNITTEST=ON`, then run `build/PPSSPPUnitTest all`
This runs all tests in `availableTests` in unittest/UnitTest.cpp. You can run a single test by
passing its name instead of `all`; no arguments lists the available tests.
This runs all tests in `availableTests` in unittest/UnitTest.cpp. You can run one or more
specific tests by passing their names instead of `all` (space-separated, e.g. `UnitTest.exe
CmdLine Path Utf8`); no arguments lists the available tests.
Known environment-specific issue: in at least one sandboxed dev environment, the `Jit` test
(`unittest/JitHarness.cpp`) hangs indefinitely specifically during the `CPUCore::JIT_IR`
phase - confirmed unrelated to source changes (reproduces identically on unmodified checkouts)
and not a memory-access fault (`Memory::HandleFault` is never entered). Root cause wasn't
pinned down further (would need a native debugger attached to the hung process, not available
in that environment) but is very likely specific to that sandbox rather than a real PPSSPP
bug, since CI runs the equivalent of `UnitTest.exe all` on every commit across multiple
platforms without apparent issue. If `all`/`Jit` hangs in your environment, run every other
test by name instead (skip `Jit`) to still get real coverage.
## Multiplatform considerations
+1 -1
View File
@@ -442,7 +442,7 @@ void XEmitter::ABI_CallFunctionPPC(const void *func, void *param1, void *param2,
// Pass a register as a parameter.
void XEmitter::ABI_CallFunctionR(const void *func, X64Reg reg1) {
if (reg1 != ABI_PARAM1)
MOV(32, R(ABI_PARAM1), R(reg1));
MOV(64, R(ABI_PARAM1), R(reg1));
u64 distance = u64(func) - (u64(code) + 5);
if (distance >= 0x0000000080000000ULL
&& distance < 0xFFFFFFFF80000000ULL) {
+15 -2
View File
@@ -1044,8 +1044,21 @@ void ARM64XEmitter::BL(const void* ptr)
}
void ARM64XEmitter::QuickCallFunction(ARM64Reg scratchreg, const void *func) {
s64 distance = (s64)func - (s64)m_code;
distance >>= 2; // Can only branch to opcode-aligned (4) addresses
s64 distance = ((s64)func - (s64)m_code) >> 2;
if (!IsInRangeImm26(distance)) {
// WARN_LOG(Log::JIT, "Distance too far in function call (%p to %p)! Using scratch.", m_code, func);
MOVI2R(scratchreg, (uintptr_t)func);
BLR(scratchreg);
} else {
BL(func);
}
}
void ARM64XEmitter::QuickCallFunctionR(ARM64Reg scratchreg, const void *func, ARM64Reg arg) {
s64 distance = ((s64)func - (s64)m_code) >> 2;
if (arg != X0) {
MOV(X0, arg);
}
if (!IsInRangeImm26(distance)) {
// WARN_LOG(Log::JIT, "Distance too far in function call (%p to %p)! Using scratch.", m_code, func);
MOVI2R(scratchreg, (uintptr_t)func);
+5
View File
@@ -776,6 +776,11 @@ public:
template <typename T> void QuickCallFunction(ARM64Reg scratchreg, T func) {
QuickCallFunction(scratchreg, (const void *)func);
}
void QuickCallFunctionR(ARM64Reg scratchreg, const void *func, ARM64Reg arg);
template <typename T> void QuickCallFunctionR(ARM64Reg scratchreg, T func, ARM64Reg arg) {
QuickCallFunctionR(scratchreg, (const void *)func, arg);
}
};
class ARM64FloatEmitter
+12
View File
@@ -557,6 +557,18 @@ void ARMXEmitter::QuickCallFunction(ARMReg reg, const void *func) {
}
}
void ARMXEmitter::QuickCallFunctionR(ARMReg reg, const void *func, ARMReg arg) {
if (arg != R0) {
MOV(R0, arg);
}
if (BLInRange(func)) {
BL(func);
} else {
MOVP2R(reg, func);
BL(reg);
}
}
void ARMXEmitter::SetCodePointer(u8 *ptr, u8 *writePtr)
{
code = ptr;
+4
View File
@@ -854,6 +854,10 @@ public:
template <typename T> void QuickCallFunction(ARMReg scratchreg, T func) {
QuickCallFunction(scratchreg, (const void *)func);
}
void QuickCallFunctionR(ARMReg scratchreg, const void *func, ARMReg arg);
template <typename T> void QuickCallFunctionR(ARMReg scratchreg, T func, ARMReg arg) {
QuickCallFunctionR(scratchreg, (const void *)func, arg);
}
// Wrapper around MOVT/MOVW with fallbacks.
void MOVI2R(ARMReg reg, u32 val, bool optimize = true);
+9 -1
View File
@@ -165,7 +165,15 @@ public:
static_assert(std::is_function<T>::value, "QuickCallFunction without function");
QuickCallFunction((const u8 *)func, scratchreg);
}
void QuickCallFunctionR(const u8 *func, LoongArch64Reg arg, LoongArch64Reg scratchreg = R_RA) {
MOVE(LoongArch64Reg::X4, arg);
QuickJump(scratchreg, R_RA, func);
}
template <typename T>
void QuickCallFunctionR(T *func, LoongArch64Reg arg, LoongArch64Reg scratchreg = R_RA) {
static_assert(std::is_function<T>::value, "QuickCallFunction without function");
QuickCallFunctionR((const u8 *)func, arg, scratchreg);
}
// https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html
// https://github.com/loongson-community/loongarch-opcodes/
+11
View File
@@ -226,6 +226,17 @@ public:
QuickCallFunction((const u8 *)func, scratchreg);
}
void QuickCallFunctionR(const u8 *func, RiscVReg arg, RiscVReg scratchreg = R_RA) {
if (arg != RiscVReg::X10) { // A0
MV(RiscVReg::X10, arg);
}
QuickJAL(scratchreg, R_RA, func);
}
template <typename T>
void QuickCallFunctionR(T *func, RiscVReg arg, RiscVReg scratchreg = R_RA) {
static_assert(std::is_function<T>::value, "QuickCallFunction without function");
QuickCallFunctionR((const u8 *)func, arg, scratchreg);
}
void LUI(RiscVReg rd, s32 simm32);
void AUIPC(RiscVReg rd, s32 simm32);
+1 -2
View File
@@ -379,8 +379,7 @@ void ForceCheck(MIPSState *mips) {
#endif
}
void Advance() {
MIPSState *mips = currentMIPS; // TODO: Move to parameter
void Advance(MIPSState *mips) {
PROFILE_THIS_SCOPE("advance");
int cyclesExecuted = slicelength - mips->downcount;
globalTimer += cyclesExecuted;
+1 -1
View File
@@ -113,7 +113,7 @@ namespace CoreTiming {
const Event *GetFirstEvent();
void RemoveEvent(int event_type);
bool IsScheduled(int event_type);
void Advance();
void Advance(MIPSState *mips);
void ForceCheck(MIPSState *mips);
// Pretend that the main CPU has executed enough cycles to reach the next event.
+16 -22
View File
@@ -605,8 +605,8 @@ void hleEnqueueCall(u32 func, int argc, const u32 *argv, PSPAction *afterAction)
hleAfterSyscall |= HLE_AFTER_QUEUED_CALLS;
}
void hleFlushCalls() {
u32 &sp = currentMIPS->r[MIPS_REG_SP];
static void hleFlushCalls(MIPSState *mips) {
u32 &sp = mips->r[MIPS_REG_SP];
PSPPointer<HLEMipsCallStack> stackData;
_dbg_assert_(g_stackSize == 0);
VERBOSE_LOG(Log::HLE, "Flushing %d HLE mips calls from %s, sp=%08x", (int)enqueuedMipsCalls.size(), g_stackSize ? g_stack[0]->name : "?", sp);
@@ -615,15 +615,15 @@ void hleFlushCalls() {
sp -= sizeof(HLEMipsCallStack);
stackData.ptr = sp;
stackData->nextOff = 0xFFFFFFFF;
stackData->ra = currentMIPS->pc;
stackData->v0 = currentMIPS->r[MIPS_REG_V0];
stackData->v1 = currentMIPS->r[MIPS_REG_V1];
stackData->ra = mips->pc;
stackData->v0 = mips->r[MIPS_REG_V0];
stackData->v1 = mips->r[MIPS_REG_V1];
// Now we'll set up the first in the chain.
currentMIPS->pc = enqueuedMipsCalls[0].func;
currentMIPS->r[MIPS_REG_RA] = HLEMipsCallReturnAddress();
mips->pc = enqueuedMipsCalls[0].func;
mips->r[MIPS_REG_RA] = HLEMipsCallReturnAddress();
for (int i = 0; i < (int)enqueuedMipsCalls[0].args.size(); i++) {
currentMIPS->r[MIPS_REG_A0 + i] = enqueuedMipsCalls[0].args[i];
mips->r[MIPS_REG_A0 + i] = enqueuedMipsCalls[0].args[i];
}
// For stack info, process the first enqueued call last, so we run it first.
@@ -653,6 +653,7 @@ void hleFlushCalls() {
DEBUG_LOG(Log::HLE, "Executing HLE mips call at %08x, sp=%08x", currentMIPS->pc, sp);
}
// This is a HLE function.
void HLEReturnFromMipsCall() {
u32 &sp = currentMIPS->r[MIPS_REG_SP];
PSPPointer<HLEMipsCallStack> stackData;
@@ -777,7 +778,7 @@ static void hleFinishSyscall(const HLEFunction *info) {
SetDeadbeefRegs();
if ((hleAfterSyscall & HLE_AFTER_QUEUED_CALLS) != 0)
hleFlushCalls();
hleFlushCalls(currentMIPS);
if ((hleAfterSyscall & HLE_AFTER_CURRENT_CALLBACKS) != 0 && (hleAfterSyscall & HLE_AFTER_RESCHED_CALLBACKS) == 0)
__KernelForceCallbacks();
@@ -806,15 +807,13 @@ void hleFinishSyscallAfterGe() {
hleFinishSyscall(nullptr);
}
static void updateSyscallStats(int modulenum, int funcnum, double total)
{
static void updateSyscallStats(int modulenum, int funcnum, double total) {
const char *name = moduleDB[modulenum].funcTable[funcnum].name;
// Ignore this one, especially for msInSyscalls (although that ignores CoreTiming events.)
if (0 == strcmp(name, "_sceKernelIdle"))
return;
if (total > kernelStats.slowestSyscallTime)
{
if (total > kernelStats.slowestSyscallTime) {
kernelStats.slowestSyscallTime = total;
kernelStats.slowestSyscallName = name;
}
@@ -822,20 +821,15 @@ static void updateSyscallStats(int modulenum, int funcnum, double total)
KernelStatsSyscall statCall(modulenum, funcnum);
auto summedStat = kernelStats.summedMsInSyscalls.find(statCall);
if (summedStat == kernelStats.summedMsInSyscalls.end())
{
if (summedStat == kernelStats.summedMsInSyscalls.end()) {
kernelStats.summedMsInSyscalls[statCall] = total;
if (total > kernelStats.summedSlowestSyscallTime)
{
if (total > kernelStats.summedSlowestSyscallTime) {
kernelStats.summedSlowestSyscallTime = total;
kernelStats.summedSlowestSyscallName = name;
}
}
else
{
} else {
double newTotal = kernelStats.summedMsInSyscalls[statCall] += total;
if (newTotal > kernelStats.summedSlowestSyscallTime)
{
if (newTotal > kernelStats.summedSlowestSyscallTime) {
kernelStats.summedSlowestSyscallTime = newTotal;
kernelStats.summedSlowestSyscallName = name;
}
+24 -67
View File
@@ -651,42 +651,6 @@ void __IoInit() {
asyncNotifyEvent = CoreTiming::RegisterEvent("IoAsyncNotify", __IoAsyncNotify);
syncNotifyEvent = CoreTiming::RegisterEvent("IoSyncNotify", __IoSyncNotify);
// TODO(scoped): This won't work if memStickDirectory points at the contents of /PSP...
#if defined(USING_WIN_UI) || defined(APPLE)
auto flash0System = std::make_shared<DirectoryFileSystem>(&pspFileSystem, g_Config.flash0Directory, FileSystemFlags::FLASH);
#else
auto flash0System = std::make_shared<VFSFileSystem>(&pspFileSystem, "flash0");
#endif
FileSystemFlags memstickFlags = FileSystemFlags::SIMULATE_FAT32 | FileSystemFlags::CARD;
Path pspDir = GetSysDirectory(DIRECTORY_PSP);
if (pspDir == g_Config.memStickDirectory) {
// Initially tried to do this with dual mounts, but failed due to save state compatibility issues.
INFO_LOG(Log::sceIo, "Enabling /PSP compatibility mode");
memstickFlags |= FileSystemFlags::STRIP_PSP;
}
auto memstickSystem = std::make_shared<DirectoryFileSystem>(&pspFileSystem, g_Config.memStickDirectory, memstickFlags);
pspFileSystem.Mount("ms0:", memstickSystem);
pspFileSystem.Mount("fatms0:", memstickSystem);
pspFileSystem.Mount("fatms:", memstickSystem);
pspFileSystem.Mount("pfat0:", memstickSystem);
pspFileSystem.Mount("flash0:", flash0System);
if (g_RemasterMode) {
const std::string gameId = g_paramSFO.GetDiscID();
const Path exdataPath = GetSysDirectory(DIRECTORY_EXDATA) / gameId;
if (File::Exists(exdataPath)) {
auto exdataSystem = std::make_shared<DirectoryFileSystem>(&pspFileSystem, exdataPath, FileSystemFlags::SIMULATE_FAT32 | FileSystemFlags::CARD);
pspFileSystem.Mount("exdata0:", exdataSystem);
INFO_LOG(Log::sceIo, "Mounted exdata/%s/ under memstick for exdata0:/", gameId.c_str());
} else {
INFO_LOG(Log::sceIo, "Did not find exdata/%s/ under memstick for exdata0:/", gameId.c_str());
}
}
__KernelListenThreadEnd(&TellFsThreadEnded);
memset(fds, 0, sizeof(fds));
@@ -703,6 +667,30 @@ void __IoInit() {
lastMemStickFatState = MemoryStick_FatState();
}
void __IoShutdown() {
ioManagerThreadEnabled = false;
ioManager.SyncThread();
ioManager.FinishEventLoop();
if (ioManagerThread.joinable()) {
ioManagerThread.join();
ioManager.Shutdown();
}
for (int i = 0; i < PSP_COUNT_FDS; ++i) {
asyncParams[i].op = IoAsyncOp::NONE;
asyncParams[i].priority = -1;
if (asyncThreads[i])
asyncThreads[i]->Forget();
delete asyncThreads[i];
asyncThreads[i] = nullptr;
}
asyncDefaultPriority = -1;
MemoryStick_Shutdown();
memStickCallbacks.clear();
memStickFatCallbacks.clear();
}
void __IoDoState(PointerWrap &p) {
auto s = p.Section("sceIo", 1, 5);
if (!s)
@@ -771,37 +759,6 @@ void __IoDoState(PointerWrap &p) {
}
}
void __IoShutdown() {
ioManagerThreadEnabled = false;
ioManager.SyncThread();
ioManager.FinishEventLoop();
if (ioManagerThread.joinable()) {
ioManagerThread.join();
ioManager.Shutdown();
}
for (int i = 0; i < PSP_COUNT_FDS; ++i) {
asyncParams[i].op = IoAsyncOp::NONE;
asyncParams[i].priority = -1;
if (asyncThreads[i])
asyncThreads[i]->Forget();
delete asyncThreads[i];
asyncThreads[i] = nullptr;
}
asyncDefaultPriority = -1;
pspFileSystem.Unmount("ms0:");
pspFileSystem.Unmount("fatms0:");
pspFileSystem.Unmount("fatms:");
pspFileSystem.Unmount("pfat0:");
pspFileSystem.Unmount("flash0:");
pspFileSystem.Unmount("exdata0:");
MemoryStick_Shutdown();
memStickCallbacks.clear();
memStickFatCallbacks.clear();
}
static std::string IODetermineFilename(const FileNode *f) {
uint64_t offset = pspFileSystem.GetSeekPos(f->handle);
if ((pspFileSystem.DevType(f->handle) & PSPDevType::BLOCK) != 0) {
+1 -1
View File
@@ -1638,7 +1638,7 @@ void __KernelReSchedule(const char *reason)
__KernelCheckCallbacks();
// Execute any pending events while we're doing scheduling.
CoreTiming::Advance();
CoreTiming::Advance(currentMIPS);
if (__IsInInterrupt() || !__KernelIsDispatchEnabled()) {
// Threads don't get changed within interrupts or while dispatch is disabled.
reason = "In Interrupt Or Callback";
+1 -1
View File
@@ -159,7 +159,7 @@ void ArmJit::GenerateFixedCode() {
outerLoop = GetCodePtr();
SaveDowncount();
RestoreRoundingMode(true);
QuickCallFunction(R0, &CoreTiming::Advance);
QuickCallFunctionR(R1, &CoreTiming::Advance, CTXREG);
ApplyRoundingMode(true);
RestoreDowncount();
FixupBranch skipToCoreStateCheck = B(); //skip the downcount check
+1 -1
View File
@@ -204,7 +204,7 @@ void Arm64Jit::GenerateFixedCode(const JitOptions &jo) {
outerLoop = GetCodePtr();
SaveStaticRegisters(); // Advance can change the downcount, so must save/restore
RestoreRoundingMode(true);
QuickCallFunction(SCRATCH1_64, &CoreTiming::Advance);
QuickCallFunctionR(SCRATCH1_64, &CoreTiming::Advance, CTXREG);
ApplyRoundingMode(true);
LoadStaticRegisters();
FixupBranch skipToCoreStateCheck = B(); //skip the downcount check
+1 -1
View File
@@ -169,7 +169,7 @@ void Arm64JitBackend::GenerateFixedCode(MIPSState *mipsState) {
SaveStaticRegisters(); // Advance can change the downcount, so must save/restore
RestoreRoundingMode(true);
WriteDebugProfilerStatus(IRProfilerStatus::TIMER_ADVANCE);
QuickCallFunction(SCRATCH1_64, &CoreTiming::Advance);
QuickCallFunctionR(SCRATCH1_64, &CoreTiming::Advance, CTXREG);
WriteDebugProfilerStatus(IRProfilerStatus::IN_JIT);
ApplyRoundingMode(true);
LoadStaticRegisters();
+1 -1
View File
@@ -175,7 +175,7 @@ void IRJit::RunLoopUntil(u64 globalticks) {
MIPSState *mips = mips_;
while (true) {
// RestoreRoundingMode(true);
CoreTiming::Advance();
CoreTiming::Advance(currentMIPS);
// ApplyRoundingMode(true);
if (coreState != 0) {
break;
+1 -1
View File
@@ -134,7 +134,7 @@ void LoongArch64JitBackend::GenerateFixedCode(MIPSState *mipsState) {
SaveStaticRegisters();
RestoreRoundingMode(true);
WriteDebugProfilerStatus(IRProfilerStatus::TIMER_ADVANCE);
QuickCallFunction(&CoreTiming::Advance, R20);
QuickCallFunctionR(&CoreTiming::Advance, CTXREG, R20);
WriteDebugProfilerStatus(IRProfilerStatus::IN_JIT);
ApplyRoundingMode(true);
LoadStaticRegisters();
+1 -1
View File
@@ -325,7 +325,7 @@ void MIPSState::DoState(PointerWrap &p) {
void MIPSState::SingleStep() {
int cycles = MIPS_SingleStep(this);
downcount -= cycles;
CoreTiming::Advance();
CoreTiming::Advance(currentMIPS);
}
// returns 1 if reached ticks limit
+2 -2
View File
@@ -1197,9 +1197,9 @@ static void RunUntilDowncountZeroWithChecks(MIPSState *mips, u64 globalTicks) {
int MIPSInterpret_RunUntil(MIPSState *mips, u64 globalTicks) {
while (coreState == CORE_RUNNING_CPU) {
CoreTiming::Advance();
CoreTiming::Advance(mips);
uint64_t ticksLeft = globalTicks - CoreTiming::GetTicks(currentMIPS);
uint64_t ticksLeft = globalTicks - CoreTiming::GetTicks(mips);
if (g_breakpoints.HasBreakPoints() || g_breakpoints.HasMemChecks() || ticksLeft <= mips->downcount) {
RunUntilDowncountZeroWithChecks(mips, globalTicks);
} else {
+1 -1
View File
@@ -143,7 +143,7 @@ void RiscVJitBackend::GenerateFixedCode(MIPSState *mipsState) {
SaveStaticRegisters();
RestoreRoundingMode(true);
WriteDebugProfilerStatus(IRProfilerStatus::TIMER_ADVANCE);
QuickCallFunction(&CoreTiming::Advance, X7);
QuickCallFunctionR(&CoreTiming::Advance, CTXREG, X7);
WriteDebugProfilerStatus(IRProfilerStatus::IN_JIT);
ApplyRoundingMode(true);
LoadStaticRegisters();
+2 -1
View File
@@ -125,7 +125,8 @@ void Jit::GenerateFixedCode(JitOptions &jo) {
outerLoop = GetCodePtr();
RestoreRoundingMode(true);
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
LEA(PTRBITS, ECX, MDisp(CTXREG, -(s32)offsetof(MIPSState, f[0]))); // Adjust to get the real pointer.
ABI_CallFunctionR(reinterpret_cast<void *>(&CoreTiming::Advance), ECX);
ApplyRoundingMode(true);
FixupBranch skipToCoreStateCheck = J(); //skip the downcount check
+2 -1
View File
@@ -167,7 +167,8 @@ void X64JitBackend::GenerateFixedCode(MIPSState *mipsState) {
SaveStaticRegisters();
RestoreRoundingMode(true);
WriteDebugProfilerStatus(IRProfilerStatus::TIMER_ADVANCE);
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
LEA(PTRBITS, ECX, MDisp(CTXREG, -(s32)offsetof(MIPSState, f[0]))); // Adjust to get the real pointer.
ABI_CallFunctionR(reinterpret_cast<void *>(&CoreTiming::Advance), ECX);
WriteDebugProfilerStatus(IRProfilerStatus::IN_JIT);
ApplyRoundingMode(true);
LoadStaticRegisters();
+45 -4
View File
@@ -63,15 +63,15 @@
#include "Core/CoreTiming.h"
#include "Core/CoreParameter.h"
#include "Core/FileLoaders/RamCachingFileLoader.h"
#include "Core/LuaContext.h"
#include "Core/FileSystems/MetaFileSystem.h"
#include "Core/FileSystems/ISOFileSystem.h"
#include "Core/FileSystems/DirectoryFileSystem.h"
#include "Core/LuaContext.h"
#include "Core/Loaders.h"
#include "Core/PSPLoaders.h"
#include "Core/FileSystems/ISOFileSystem.h"
#include "Core/ELF/ParamSFO.h"
#include "Core/SaveState.h"
#include "Core/Util/RecentFiles.h"
#include "Common/StringUtils.h"
#include "Common/ExceptionHandlerSetup.h"
#include "GPU/GPUCommon.h"
#include "GPU/Debugger/Playback.h"
@@ -276,6 +276,44 @@ static void ShowCompatWarnings(const Compatibility &compat) {
extern const std::string INDEX_FILENAME;
static void MountFileSystems() {
// TODO(scoped): This won't work if memStickDirectory points at the contents of /PSP...
#if defined(USING_WIN_UI) || defined(APPLE)
auto flash0System = std::make_shared<DirectoryFileSystem>(&pspFileSystem, g_Config.flash0Directory, FileSystemFlags::FLASH);
#else
auto flash0System = std::make_shared<VFSFileSystem>(&pspFileSystem, "flash0");
#endif
FileSystemFlags memstickFlags = FileSystemFlags::SIMULATE_FAT32 | FileSystemFlags::CARD;
Path pspDir = GetSysDirectory(DIRECTORY_PSP);
if (pspDir == g_Config.memStickDirectory) {
// Initially tried to do this with dual mounts, but failed due to save state compatibility issues.
INFO_LOG(Log::sceIo, "Enabling /PSP compatibility mode");
memstickFlags |= FileSystemFlags::STRIP_PSP;
}
auto memstickSystem = std::make_shared<DirectoryFileSystem>(&pspFileSystem, g_Config.memStickDirectory, memstickFlags);
pspFileSystem.Mount("ms0:", memstickSystem);
pspFileSystem.Mount("fatms0:", memstickSystem);
pspFileSystem.Mount("fatms:", memstickSystem);
pspFileSystem.Mount("pfat0:", memstickSystem);
pspFileSystem.Mount("flash0:", flash0System);
if (g_RemasterMode) {
const std::string gameId = g_paramSFO.GetDiscID();
const Path exdataPath = GetSysDirectory(DIRECTORY_EXDATA) / gameId;
if (File::Exists(exdataPath)) {
auto exdataSystem = std::make_shared<DirectoryFileSystem>(&pspFileSystem, exdataPath, FileSystemFlags::SIMULATE_FAT32 | FileSystemFlags::CARD);
pspFileSystem.Mount("exdata0:", exdataSystem);
INFO_LOG(Log::sceIo, "Mounted exdata/%s/ under memstick for exdata0:/", gameId.c_str());
} else {
INFO_LOG(Log::sceIo, "Did not find exdata/%s/ under memstick for exdata0:/", gameId.c_str());
}
}
}
// NOTE: The loader has already been fully resolved (ResolveFileLoaderTarget) and identified here.
static bool CPU_Init(FileLoader *fileLoader, IdentifiedFileType type, std::string *errorString) {
// Default memory settings
@@ -449,6 +487,8 @@ static bool CPU_Init(FileLoader *fileLoader, IdentifiedFileType type, std::strin
g_CoreParameter.mountIsoLoader = ConstructFileLoader(g_CoreParameter.mountIso);
}
MountFileSystems();
// Game-specific settings are load from for example Load_PSP_ISO (which calls g_Config.LoadGameConfig).
// We can't do things that depend on these before the below switch. So for example, the adjustment of the GPU core
// to software has now been moved below it.
@@ -541,7 +581,8 @@ void CPU_Shutdown(bool success) {
DisplayHWShutdown();
pspFileSystem.Shutdown();
pspFileSystem.Shutdown(); // This unmounts all filesystems.
mipsr4k.Shutdown();
Memory::Shutdown();
HLEPlugins::Shutdown();
+1 -11
View File
@@ -147,16 +147,6 @@ bool TestJit() {
u32 addr = currentMIPS->pc;
DebugInterface *dbg = currentDebugMIPS;
for (int i = 0; i < 100; ++i) {
/*
// VFPU ops aren't supported by MIPSAsm yet.
*p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8);
*p++ = 0xD03C0000 | (1 << 7) | (1 << 15);
*p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8);
*p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8);
*p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8);
*p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8);
*p++ = 0xD03C0000 | (1 << 7) | (1 << 15) | (7 << 8);
*/
std::string error;
for (size_t j = 0; j < ARRAY_SIZE(lines); ++j) {
p++;
@@ -192,7 +182,7 @@ bool TestJit() {
jit_speed = ExecCPUTest();
#if !PPSSPP_PLATFORM(MAC)
mipsr4k.UpdateCore(CPUCore::JIT_IR);
jit_ir_speed = ExecCPUTest(false);
jit_ir_speed = ExecCPUTest(false); // not clearing, so the below can do things.
#endif
// Disassemble
+48 -38
View File
@@ -1617,57 +1617,67 @@ int main(int argc, const char *argv[]) {
g_Config.bEnableLogging = true;
g_logManager.DisableOutput(LogOutput::DebugString); // not really needed
bool allTests = false;
TestFunc testFunc = nullptr;
if (argc >= 2) {
if (!strcasecmp(argv[1], "all")) {
allTests = true;
// Collect the set of tests to run: "all", or one or more test names by
// (case-insensitive) name. Every non-"all" argument must match a known test name, or we
// bail out with the usage text - a silent partial run (e.g. from a typo) would be worse
// than an error.
std::vector<TestItem> testsToRun;
bool badArg = false;
if (argc == 2 && !strcasecmp(argv[1], "all")) {
for (const auto &f : availableTests) {
testsToRun.push_back(f);
}
for (auto f : availableTests) {
if (!strcasecmp(argv[1], f.name)) {
testFunc = f.func;
break;
} else {
for (int i = 1; i < argc; ++i) {
const TestItem *found = nullptr;
for (const auto &f : availableTests) {
if (!strcasecmp(argv[i], f.name)) {
found = &f;
break;
}
}
if (found) {
testsToRun.push_back(*found);
} else {
fprintf(stderr, "Unknown test: %s\n", argv[i]);
badArg = true;
}
}
}
if (allTests) {
int passes = 0;
int fails = 0;
std::vector<const char *> failedTests;
for (const auto &f : availableTests) {
printf("\n**** Running test %s ****\n", f.name);
if (f.func()) {
++passes;
} else {
printf("%s: FAILED\n", f.name);
failedTests.push_back(f.name);
++fails;
}
}
if (passes > 0) {
printf("%d tests passed.\n", passes);
}
if (fails > 0) {
printf("%d tests failed!\n", fails);
for (auto testName : failedTests) {
printf(" * %s\n", testName);
}
return 2;
}
} else if (!testFunc) {
fprintf(stderr, "You may select a test to run by passing an argument, either \"all\" or one or more of the below.\n");
if (testsToRun.empty() || badArg) {
fprintf(stderr, "You may select tests to run by passing one or more arguments, either \"all\" or one or more of the below.\n");
fprintf(stderr, "\n");
fprintf(stderr, "Available tests:\n");
for (auto f : availableTests) {
fprintf(stderr, " * %s\n", f.name);
}
return 1;
} else {
if (!testFunc()) {
return 2;
}
int passes = 0;
int fails = 0;
std::vector<const char *> failedTests;
for (const auto &f : testsToRun) {
printf("\n**** Running test %s ****\n", f.name);
if (f.func()) {
++passes;
} else {
printf("%s: FAILED\n", f.name);
failedTests.push_back(f.name);
++fails;
}
}
if (passes > 0) {
printf("%d tests passed.\n", passes);
}
if (fails > 0) {
printf("%d tests failed!\n", fails);
for (auto testName : failedTests) {
printf(" * %s\n", testName);
}
return 2;
}
return 0;
}