mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-09-11 15:13:37 +02:00
Merge pull request #22090 from hrydgard/more-stuff
Simplify file system mounting slightly, more MIPS context plumbing
This commit is contained in:
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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/
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user