diff --git a/ps2xRuntime/src/lib/ps2_runtime.cpp b/ps2xRuntime/src/lib/ps2_runtime.cpp index ff2cecd..cd82a87 100644 --- a/ps2xRuntime/src/lib/ps2_runtime.cpp +++ b/ps2xRuntime/src/lib/ps2_runtime.cpp @@ -10,9 +10,6 @@ #include #include "raylib.h" -// From ps2_syscalls.cpp to help keep the scheduler semaphore sane. -extern std::atomic g_schedulerSemaId; - #define ELF_MAGIC 0x464C457F // "\x7FELF" in little endian #define ET_EXEC 2 // Executable file @@ -168,82 +165,6 @@ static void UploadFrame(Texture2D &tex, PS2Runtime *rt) UpdateTexture(tex, scratch.data()); } -static void DumpFramebufferSample(PS2Memory &mem) -{ - uint32_t base = DEFAULT_FB_ADDR & 0x1FFFFFFF; - uint8_t *ptr = mem.getRDRAM() + base; - uint32_t sum = 0; - for (int i = 0; i < 32; ++i) - { - sum += ptr[i]; - } - std::cout << "[FB] addr=0x" << std::hex << DEFAULT_FB_ADDR << " first32 sum=0x" << sum << std::dec - << " bytes:"; - for (int i = 0; i < 16; ++i) - { - std::cout << " " << (int)ptr[i]; - } - std::cout << std::dec << std::endl; - - // Also dump the thread param block used in InitThread (0x363610 area) - uint32_t tparam = 0x363600 & PS2_RAM_MASK; - uint32_t *tp = reinterpret_cast(mem.getRDRAM() + tparam); - std::cout << "[InitThread params] @0x363600: " - << std::hex << tp[0] << " " << tp[1] << " " << tp[2] << " " << tp[3] - << " " << tp[4] << " " << tp[5] << " " << tp[6] << std::dec << std::endl; -} - -// Trace hook for a suspected thread entry to see what it does. -static PS2Runtime::RecompiledFunction g_entry_10c920 = nullptr; -static void entry_10c920_traced(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) -{ - std::cout << "[trace] enter 0x10c920 sp=0x" << std::hex << ctx->r[29].m128i_u32[0] - << " gp=0x" << ctx->r[28].m128i_u32[0] - << " ra=0x" << ctx->r[31].m128i_u32[0] << std::dec << std::endl; - if (g_entry_10c920) - { - g_entry_10c920(rdram, ctx, runtime); - } - std::cout << "[trace] exit 0x10c920 pc=0x" << std::hex << ctx->pc - << " ra=0x" << ctx->r[31].m128i_u32[0] << std::dec << std::endl; -} - -// Hook for sceGsPutDispEnv to capture display buffer setup. -static PS2Runtime::RecompiledFunction g_putDispEnv = nullptr; -static void sceGsPutDispEnv_hook(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) -{ - uint32_t envPtr = GPR_U32(ctx, 4); - const uint8_t *base = runtime->memory().getRDRAM(); - constexpr uint32_t MASK = PS2_RAM_SIZE - 1; - const uint64_t *env = reinterpret_cast(base + (envPtr & MASK)); - if (env) - { - auto &gs = runtime->memory().gs(); - gs.dispfb1 = env[0]; - gs.display1 = env[1]; - std::cout << "[hook] sceGsPutDispEnv @0x" << std::hex << envPtr - << " dispfb1=0x" << env[0] << " display1=0x" << env[1] << std::dec << std::endl; - } - if (g_putDispEnv) - { - g_putDispEnv(rdram, ctx, runtime); - } -} - -// Hook for sceSifCallRpc to keep IOP RPC loops from stalling the main thread. -static PS2Runtime::RecompiledFunction g_sceSifCallRpc = nullptr; -static void sceSifCallRpc_stub(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) -{ - static int logCount = 0; - if (logCount++ < 5) - { - std::cout << "[stub] sceSifCallRpc fno=0x" << std::hex << GPR_U32(ctx, 5) - << " mode=0x" << GPR_U32(ctx, 6) - << " send=0x" << GPR_U32(ctx, 7) - << " recv=0x" << GPR_U32(ctx, 8) << std::dec << std::endl; - } - SET_GPR_S32(ctx, 2, 0); -} PS2Runtime::PS2Runtime() { @@ -360,30 +281,6 @@ bool PS2Runtime::loadELF(const std::string &elfPath) m_loadedModules.push_back(module); - // acccordind to GPT some titles expect cmd_sem_init to see -1 sentinels before creating semaphores. - const uint32_t semaInitAddrs[] = {0x00302c90u, 0x00302c94u, 0x00302c98u, 0x00302c9cu}; - bool seeded = false; - for (uint32_t addr : semaInitAddrs) - { - uint32_t physAddr = m_memory.translateAddress(addr); - uint32_t *p = reinterpret_cast(m_memory.getRDRAM() + physAddr); - if (*p == 0) - { - *p = 0xFFFFFFFFu; - seeded = true; - } - } - if (seeded) - { - std::cout << "[init] Seeded cmd_sem_init sema IDs to -1" << std::endl; - } - - // Debug: peek at some early globals to verify init state - uint32_t dbg_addr = 0x00300000 + 11240; - uint8_t *dbg_base = m_memory.getRDRAM(); - uint32_t dbg_val = *reinterpret_cast(dbg_base + (dbg_addr & PS2_RAM_MASK)); - std::cout << "Debug: [0x" << std::hex << dbg_addr << "] = 0x" << dbg_val << std::dec << std::endl; - std::cout << "ELF file loaded successfully. Entry point: 0x" << std::hex << m_cpuContext.pc << std::dec << std::endl; return true; } @@ -425,53 +322,6 @@ void PS2Runtime::SignalException(R5900Context *ctx, PS2Exception exception) } } -static PS2Runtime::RecompiledFunction g_entry_10cb00 = nullptr; -static void entry_10cb00_hook(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) -{ - static int logCount = 0; - if (logCount < 16) - { - std::cout << "[cmdq] enqueue cmd=0 tid=" << GPR_U32(ctx, 16) - << " a0=0x" << std::hex << GPR_U32(ctx, 4) << std::dec << std::endl; - ++logCount; - } - if (g_entry_10cb00) - { - g_entry_10cb00(rdram, ctx, runtime); - } -} - -static PS2Runtime::RecompiledFunction g_entry_10cb98 = nullptr; -static void entry_10cb98_hook(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) -{ - static int logCount = 0; - if (logCount < 16) - { - std::cout << "[cmdq] enqueue cmd=1 tid=" << GPR_U32(ctx, 16) - << " a0=0x" << std::hex << GPR_U32(ctx, 4) << std::dec << std::endl; - ++logCount; - } - if (g_entry_10cb98) - { - g_entry_10cb98(rdram, ctx, runtime); - } -} - -static PS2Runtime::RecompiledFunction g_entry_10cc34 = nullptr; -static void entry_10cc34_hook(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) -{ - static int logCount = 0; - if (logCount < 16) - { - std::cout << "[cmdq] enqueue cmd=2 tid=" << GPR_U32(ctx, 16) - << " a0=0x" << std::hex << GPR_U32(ctx, 4) << std::dec << std::endl; - ++logCount; - } - if (g_entry_10cc34) - { - g_entry_10cc34(rdram, ctx, runtime); - } -} void PS2Runtime::executeVU0Microprogram(uint8_t *rdram, R5900Context *ctx, uint32_t address) { @@ -572,118 +422,8 @@ void PS2Runtime::run() Texture2D frameTex = LoadTextureFromImage(blank); UnloadImage(blank); - if (hasFunction(0x10c920)) - { - g_entry_10c920 = lookupFunction(0x10c920); - registerFunction(0x10c920, entry_10c920_traced); - std::cout << "[trace] hooked entry 0x10c920 for logging" << std::endl; - } - else - { - std::cout << "[trace] entry 0x10c920 not registered" << std::endl; - } - if (hasFunction(0x1004b8)) - { - g_putDispEnv = lookupFunction(0x1004b8); - registerFunction(0x1004b8, sceGsPutDispEnv_hook); - std::cout << "[hook] wrapped sceGsPutDispEnv at 0x1004b8" << std::endl; - } - if (hasFunction(0x10ed80)) - { - g_sceSifCallRpc = lookupFunction(0x10ed80); - registerFunction(0x10ed80, sceSifCallRpc_stub); - std::cout << "[hook] wrapped sceSifCallRpc at 0x10ed80" << std::endl; - } - if (hasFunction(0x10cb00)) - { - g_entry_10cb00 = lookupFunction(0x10cb00); - registerFunction(0x10cb00, entry_10cb00_hook); - std::cout << "[hook] wrapped cmd queue (cmd=0) at 0x10cb00" << std::endl; - } - if (hasFunction(0x10cb98)) - { - g_entry_10cb98 = lookupFunction(0x10cb98); - registerFunction(0x10cb98, entry_10cb98_hook); - std::cout << "[hook] wrapped cmd queue (cmd=1) at 0x10cb98" << std::endl; - } - if (hasFunction(0x10cc34)) - { - g_entry_10cc34 = lookupFunction(0x10cc34); - registerFunction(0x10cc34, entry_10cc34_hook); - std::cout << "[hook] wrapped cmd queue (cmd=2) at 0x10cc34" << std::endl; - } - g_activeThreads.store(1, std::memory_order_relaxed); - // for now if the scheduler sema hasn't been created yet, force InitThread to set it up. - if (hasFunction(0x10c9f8)) - { - uint32_t *sched = reinterpret_cast(m_memory.getRDRAM() + (0x363a10 & PS2_RAM_MASK)); - if (!sched || sched[0] == 0) - { - RecompiledFunction initThread = lookupFunction(0x10c9f8); - R5900Context initCtx{}; - std::memset(&initCtx, 0, sizeof(initCtx)); - initCtx.r[0] = _mm_set1_epi32(0); - initCtx.r[29] = _mm_set1_epi32(0x02000000); - initCtx.r[28] = _mm_set1_epi32(0x36a7f0); - initCtx.pc = 0x10c9f8; - std::cout << "[autorun] running InitThread pc=0x10c9f8" << std::endl; - initThread(m_memory.getRDRAM(), &initCtx, this); - } - } - - // Fallback: if the game's main entry (ps2_main at 0x12b0a0) is registered, start it on a separate host thread. - // The normal bootstrap thread seems to stall before spawning it, so we kick it off manually. - if (hasFunction(0x12b0a0)) - { - RecompiledFunction ps2Main = lookupFunction(0x12b0a0); - g_activeThreads.fetch_add(1, std::memory_order_relaxed); - std::thread([=]() mutable - { - R5900Context localCtx{}; - std::memset(&localCtx, 0, sizeof(localCtx)); - // Set baseline registers similar to the primary thread. - localCtx.r[0] = _mm_set1_epi32(0); - localCtx.r[29] = _mm_set1_epi32(0x02000000); // SP top of RAM - localCtx.r[28] = _mm_set1_epi32(0x36a7f0); // GP from ELF bootstrap - localCtx.pc = 0x12b0a0; - - std::cout << "[autorun] starting ps2_main fallback pc=0x12b0a0 sp=0x02000000 gp=0x36a7f0" << std::endl; - try - { - ps2Main(m_memory.getRDRAM(), &localCtx, this); - std::cout << "[autorun] ps2_main returned pc=0x" << std::hex << localCtx.pc - << " ra=0x" << localCtx.r[31].m128i_u32[0] << std::dec << std::endl; - } - catch (const std::exception &e) - { - std::cerr << "[autorun] ps2_main exception: " << e.what() << std::endl; - } - g_activeThreads.fetch_sub(1, std::memory_order_relaxed); }) - .detach(); - } - else - { - std::cout << "[autorun] ps2_main not registered; skipping fallback launch" << std::endl; - } - - // Dump a small sample - { - uint32_t base = DEFAULT_FB_ADDR & 0x1FFFFFFF; - uint8_t *ptr = m_memory.getRDRAM() + base; - uint32_t sum = 0; - for (int i = 0; i < 32; ++i) - sum += ptr[i]; - std::cout << "[FB] addr=0x" << std::hex << DEFAULT_FB_ADDR - << " first32 sum=0x" << sum << " bytes:"; - for (int i = 0; i < 16; ++i) - { - std::cout << " " << (int)ptr[i]; - } - std::cout << std::dec << std::endl; - } - std::thread gameThread([&, entryPoint]() { try @@ -698,66 +438,9 @@ void PS2Runtime::run() } g_activeThreads.fetch_sub(1, std::memory_order_relaxed); }); - static uint32_t lastSchedId = 0; uint64_t tick = 0; while (g_activeThreads.load(std::memory_order_relaxed) > 0) { - { - uint32_t *sched = reinterpret_cast(m_memory.getRDRAM() + (0x363a10 & PS2_RAM_MASK)); - int known = g_schedulerSemaId.load(std::memory_order_relaxed); - if (sched) - { - if ((sched[0] == 0 || sched[0] > 1000) && known > 0) - sched[0] = static_cast(known); - // head/tail indices - if (sched[2] > 511) - sched[2] = 0; - if (sched[3] > 511) - sched[3] = 0; - } - } - - { - constexpr uint32_t kSchedSpan = 0x420; - static std::vector schedSnapshot; - static int schedDeltaLogs = 0; - - uint8_t *rdram = m_memory.getRDRAM(); - uint32_t base = 0x363a10 & PS2_RAM_MASK; - - if (schedSnapshot.empty()) - { - schedSnapshot.resize(kSchedSpan); - std::memcpy(schedSnapshot.data(), rdram + base, kSchedSpan); - } - else - { - int diffCount = 0; - int detailCount = 0; - for (uint32_t i = 0; i < kSchedSpan; ++i) - { - uint8_t cur = rdram[(base + i) & PS2_RAM_MASK]; - uint8_t prev = schedSnapshot[i]; - if (cur != prev) - { - schedSnapshot[i] = cur; - ++diffCount; - if (schedDeltaLogs < 32 && detailCount < 8) - { - std::cout << "[sched delta] off=0x" << std::hex << i - << " " << (int)prev << "->" << (int)cur << std::dec << std::endl; - ++detailCount; - } - } - } - if (diffCount > 0 && schedDeltaLogs < 32) - { - std::cout << "[sched delta] changed=" << diffCount << std::endl; - ++schedDeltaLogs; - } - } - } - if ((tick++ % 120) == 0) { std::cout << "[run] activeThreads=" << g_activeThreads.load(std::memory_order_relaxed); @@ -768,27 +451,6 @@ void PS2Runtime::run() } if ((tick % 600) == 0) { - static int schedLog = 0; - if (schedLog < 5) - { - uint8_t *rdram = m_memory.getRDRAM(); - uint32_t base = 0x363a10 & PS2_RAM_MASK; - uint32_t *p = reinterpret_cast(rdram + base); - uint32_t argPtr = 0x363a18 & PS2_RAM_MASK; - uint32_t idx = *reinterpret_cast(rdram + argPtr) & 0x1FF; - uint32_t cmdBase = (argPtr + 8) & PS2_RAM_MASK; - uint32_t tidBase = (argPtr + 9) & PS2_RAM_MASK; - uint8_t cmd0 = rdram[cmdBase & PS2_RAM_MASK]; - uint8_t tid0 = rdram[tidBase & PS2_RAM_MASK]; - uint8_t cmdIdx = rdram[(cmdBase + (idx << 1)) & PS2_RAM_MASK]; - uint8_t tidIdx = rdram[(tidBase + (idx << 1)) & PS2_RAM_MASK]; - std::cout << "[sched] sema=" << p[0] << " q1=" << p[1] << " head=" << p[2] << " tail=" << p[3] - << " cmd0=" << (int)cmd0 << "/" << (int)tid0 - << " cmd[idx=" << idx << "]=" << (int)cmdIdx << "/" << (int)tidIdx - << " lastId=" << lastSchedId << std::endl; - ++schedLog; - } - static uint64_t lastDma = 0, lastGif = 0, lastGs = 0, lastVif = 0; uint64_t curDma = m_memory.dmaStartCount(); uint64_t curGif = m_memory.gifCopyCount(); @@ -806,30 +468,6 @@ void PS2Runtime::run() lastVif = curVif; } } - // Kick the scheduler semaphore (stored at 0x363a10) to simulate VBlank-style ticks. - { - uint32_t schedId = *reinterpret_cast(m_memory.getRDRAM() + (0x363a10 & PS2_RAM_MASK)); - if (schedId && schedId < 0x1000) - { - lastSchedId = schedId; - } - if (schedId == 0 && lastSchedId != 0) - { - schedId = lastSchedId; // fall back to the last seen non-zero id - } - else if (schedId >= 0x1000 && lastSchedId != 0) - { - // Ignore obviously bogus ids that are likely other data scribbling over the struct. - schedId = lastSchedId; - } - if (schedId) - { - R5900Context semaCtx{}; - R5900Context *semaCtxPtr = &semaCtx; - SET_GPR_U32(semaCtxPtr, 4, schedId); - ps2_syscalls::SignalSema(m_memory.getRDRAM(), semaCtxPtr, this); - } - } UploadFrame(frameTex, this); BeginDrawing(); diff --git a/ps2xRuntime/src/lib/ps2_syscalls.cpp b/ps2xRuntime/src/lib/ps2_syscalls.cpp index b945ae0..f7ec65b 100644 --- a/ps2xRuntime/src/lib/ps2_syscalls.cpp +++ b/ps2xRuntime/src/lib/ps2_syscalls.cpp @@ -46,7 +46,6 @@ static thread_local int g_currentThreadId = 1; static std::unordered_map> g_semas; static int g_nextSemaId = 1; std::atomic g_activeThreads{0}; -std::atomic g_schedulerSemaId{0}; // best guess of the game's scheduler semaphore id int allocatePs2Fd(FILE *file) { @@ -130,62 +129,6 @@ std::string translatePs2Path(const char *ps2Path) namespace ps2_syscalls { - namespace - { - constexpr uint32_t kCmdqWakeupAddr = 0x10cb00; - constexpr uint32_t kCmdqRotateAddr = 0x10cb98; - constexpr uint32_t kCmdqSuspendAddr = 0x10cc34; - - bool isSchedulerReturn(uint32_t ra) - { - if (g_currentThreadId == 2) - { - return true; - } - return ra >= 0x10c920 && ra <= 0x10ca00; - } - - bool enqueueSchedulerCmd(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime, - uint32_t funcAddr, uint32_t arg, const char *name) - { - if (!runtime || !runtime->hasFunction(funcAddr)) - { - static int missCount = 0; - if (missCount < 4) - { - std::cout << "[" << name << "] missing cmdq function @0x" - << std::hex << funcAddr << std::dec << std::endl; - ++missCount; - } - return false; - } - - uint32_t sp = GPR_U32(ctx, 29); - if (sp < 32) - { - return false; - } - uint32_t frame = sp - 32; - WRITE64(frame + 0, GPR_U64(ctx, 16)); - WRITE64(frame + 16, GPR_U64(ctx, 31)); - - uint32_t savedPc = ctx->pc; - SET_GPR_U32(ctx, 29, frame); - SET_GPR_U32(ctx, 16, arg); - - auto func = runtime->lookupFunction(funcAddr); - func(rdram, ctx, runtime); - - ctx->pc = savedPc; - if (GPR_U32(ctx, 29) != sp) - { - SET_GPR_U32(ctx, 29, sp); - SET_GPR_U64(ctx, 16, READ64(frame + 0)); - SET_GPR_U64(ctx, 31, READ64(frame + 16)); - } - return true; - } - } // namespace void FlushCache(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) { @@ -321,9 +264,6 @@ namespace ps2_syscalls g_activeThreads.fetch_sub(1, std::memory_order_relaxed); }) .detach(); - // for now kick sema 1 if it was created empty to let render thread proceed. - ps2_syscalls::SignalSema(rdram, ctx, runtime); - // for now report success to the caller. setReturnS32(ctx, 0); } @@ -357,15 +297,6 @@ namespace ps2_syscalls std::cout << "[SuspendThread] tid=" << tid << std::endl; ++logCount; } - if (isSchedulerReturn(GPR_U32(ctx, 31))) - { - setReturnS32(ctx, 0); - return; - } - if (enqueueSchedulerCmd(rdram, ctx, runtime, kCmdqSuspendAddr, static_cast(tid), "SuspendThread")) - { - return; - } setReturnS32(ctx, 0); } @@ -404,15 +335,6 @@ namespace ps2_syscalls std::cout << "[WakeupThread] tid=" << tid << std::endl; ++logCount; } - if (isSchedulerReturn(GPR_U32(ctx, 31))) - { - setReturnS32(ctx, 0); - return; - } - if (enqueueSchedulerCmd(rdram, ctx, runtime, kCmdqWakeupAddr, static_cast(tid), "WakeupThread")) - { - return; - } setReturnS32(ctx, 0); } @@ -425,10 +347,6 @@ namespace ps2_syscalls std::cout << "[iWakeupThread] tid=" << tid << std::endl; ++logCount; } - if (enqueueSchedulerCmd(rdram, ctx, runtime, kCmdqWakeupAddr, static_cast(tid), "iWakeupThread")) - { - return; - } setReturnS32(ctx, 0); } @@ -458,15 +376,6 @@ namespace ps2_syscalls setReturnS32(ctx, -1); return; } - if (isSchedulerReturn(GPR_U32(ctx, 31))) - { - setReturnS32(ctx, 0); - return; - } - if (enqueueSchedulerCmd(rdram, ctx, runtime, kCmdqRotateAddr, static_cast(prio), "RotateThreadReadyQueue")) - { - return; - } setReturnS32(ctx, 0); } @@ -521,15 +430,6 @@ namespace ps2_syscalls { int sid = static_cast(getRegU32(ctx, 4)); auto it = g_semas.find(sid); - if (it == g_semas.end() && sid > 1000) - { - int fallback = g_schedulerSemaId.load(std::memory_order_relaxed); - if (fallback > 0) - { - sid = fallback; - it = g_semas.find(sid); - } - } if (it != g_semas.end()) { auto sema = it->second; @@ -552,51 +452,16 @@ namespace ps2_syscalls { int sid = static_cast(getRegU32(ctx, 4)); auto it = g_semas.find(sid); - if (it == g_semas.end() && sid > 1000) - { - int fallback = g_schedulerSemaId.load(std::memory_order_relaxed); - if (fallback > 0) - { - sid = fallback; - it = g_semas.find(sid); - } - } if (it != g_semas.end()) { auto sema = it->second; std::unique_lock lock(sema->m); - uint32_t schedSid = *reinterpret_cast(runtime->memory().getRDRAM() + (0x363a10 & PS2_RAM_MASK)); static int globalLog = 0; if (globalLog < 5) { std::cout << "[WaitSema] sid=" << sid << " count=" << sema->count << std::endl; ++globalLog; } - if (sid == schedSid) - { - static thread_local int queueLog = 0; - if (queueLog < 3) - { - uint32_t off = 0x363a10 & PS2_RAM_MASK; - uint32_t *p = reinterpret_cast(runtime->memory().getRDRAM() + off); - std::cout << "[WaitSema] sid=" << sid << " count=" << sema->count - << " queue[0..3]=" << std::hex << p[0] << " " << p[1] << " " << p[2] << " " << p[3] << std::dec << std::endl; - - // Dump data - uint32_t argPtr = getRegU32(ctx, 17); - uint32_t idx = 0; - if (argPtr) - { - idx = READ32(ADD32(argPtr, 0)) & 0x1FF; - uint32_t cmdBase = (argPtr + 8) & PS2_RAM_MASK; - uint32_t tidBase = (argPtr + 9) & PS2_RAM_MASK; - uint32_t cmd = runtime->memory().getRDRAM()[(cmdBase + (idx << 1)) & PS2_RAM_MASK]; - uint32_t tid = runtime->memory().getRDRAM()[(tidBase + (idx << 1)) & PS2_RAM_MASK]; - std::cout << "[WaitSema] sched idx=" << idx << " cmd=" << cmd << " tid=" << tid << std::endl; - } - ++queueLog; - } - } if (sema->count == 0) { static thread_local int logCount = 0; @@ -612,10 +477,6 @@ namespace ps2_syscalls { sema->count--; } - if (sid < 32) - { - g_schedulerSemaId.store(sid, std::memory_order_relaxed); - } } setReturnS32(ctx, 0); } @@ -900,11 +761,6 @@ namespace ps2_syscalls void _sceRpcGetPacket(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) { uint32_t queuePtr = getRegU32(ctx, 4); - if (queuePtr == 0) - { - // Fall back to a safe, writable address in RDRAM. - queuePtr = 0x00370000; - } setReturnS32(ctx, static_cast(queuePtr)); } @@ -1439,151 +1295,14 @@ namespace ps2_syscalls uint32_t syscall_num = getRegU32(ctx, 3); // Syscall number usually in $v1 ($r3) for SYSCALL instr uint32_t caller_ra = getRegU32(ctx, 31); // $ra - // Many recompiled libc helper stubs land here without setting $v1. - if (syscall_num == 0) - { - static int logCount = 0; - if (logCount++ < 5) - { - std::cout << "[stub] Treating syscall #0 as no-op success PC=0x" << std::hex << ctx->pc - << " RA=0x" << caller_ra << std::dec << std::endl; - } - setReturnS32(ctx, 0); - return; - } - - if (syscall_num > 0x1FFF) - { - static int logCount = 0; - if (logCount++ < 5) - { - std::cout << "[stub] Suspicious syscall id 0x" << std::hex << syscall_num - << " treated as success PC=0x" << ctx->pc - << " RA=0x" << caller_ra << std::dec << std::endl; - } - setReturnS32(ctx, 0); - return; - } - - if (syscall_num == 0xff) - { - // InitGdSystemEx: graphics driver bootstrap. Treat as success. - static int logCount = 0; - if (logCount++ < 3) - { - std::cout << "[stub] InitGdSystemEx (syscall 0xff) PC=0x" << std::hex << ctx->pc - << " RA=0x" << caller_ra - << " args a0=0x" << getRegU32(ctx, 4) - << " a1=0x" << getRegU32(ctx, 5) - << " a2=0x" << getRegU32(ctx, 6) - << " a3=0x" << getRegU32(ctx, 7) << std::dec << std::endl; - } - // For now Seed GS display registers to a sane default 640x448 @ PSMCT32 so the blitter has something to show. - PS2Memory &mem = runtime->memory(); - constexpr uint32_t fbWidth = 640; - constexpr uint32_t fbHeight = 448; - constexpr uint32_t defaultFbAddr = 0x00100000; - uint64_t dispfb = 0; - uint32_t fbp = (defaultFbAddr & 0x1FFFFFFF) / 2048; - uint32_t fbw = fbWidth / 64; - uint32_t psm = 0; // PSMCT32 - dispfb |= (fbp & 0x1FF); - dispfb |= (static_cast(fbw & 0x3F) << 10); - dispfb |= (static_cast(psm & 0x1F) << 16); - mem.gs().dispfb1 = dispfb; - uint64_t display = 0; - uint64_t dw = fbWidth - 1; - uint64_t dh = fbHeight - 1; - display |= (dw & 0x7FF) << 23; - display |= (dh & 0x7FF) << 34; - mem.gs().display1 = display; - - // Fill a visible test pattern only until we see a real GIF copy. - if (!mem.hasSeenGifCopy()) - { - uint8_t *vram = mem.getGSVRAM(); - if (vram) - { - size_t base = static_cast(fbp) * 2048; - size_t bytes = static_cast(fbWidth) * fbHeight * 4; - if (base + bytes <= PS2_GS_VRAM_SIZE) - { - for (uint32_t y = 0; y < fbHeight; ++y) - { - for (uint32_t x = 0; x < fbWidth; ++x) - { - size_t idx = base + (static_cast(y) * fbWidth + x) * 4; - vram[idx + 0] = static_cast(x); // B - vram[idx + 1] = static_cast(y); // G - vram[idx + 2] = static_cast(x ^ y); // R - vram[idx + 3] = 0xFF; // A - } - } - uint32_t sum = 0; - for (int i = 0; i < 32; ++i) - { - sum += vram[base + i]; - } - std::cout << "[stub] InitGdSystemEx filled VRAM sum=0x" << std::hex << sum << std::dec << std::endl; - } - } - } - - setReturnS32(ctx, 0); - return; - } - - if (syscall_num == 0x41) - { - // njInitView: initialise a view matrix block; seed with identity so later math has sane defaults. - static int logCount = 0; - uint32_t viewPtr = getRegU32(ctx, 4); - float *dst = reinterpret_cast(getMemPtr(rdram, viewPtr)); - - if (dst) - { - const float identity[16] = { - 1.f, 0.f, 0.f, 0.f, - 0.f, 1.f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - 0.f, 0.f, 0.f, 1.f}; - std::memcpy(dst, identity, sizeof(identity)); - } - - if (logCount++ < 3) - { - std::cout << "[stub] njInitView (syscall 0x41) PC=0x" << std::hex << ctx->pc - << " RA=0x" << caller_ra - << " viewPtr=0x" << viewPtr - << (dst ? "" : " (invalid)") << std::dec << std::endl; - } - - setReturnS32(ctx, 0); - return; - } - - if (syscall_num == 0x06 || syscall_num == 0x14 || syscall_num == 0x20) - { - // Treat frequent boot/runtime syscalls as success to avoid tight loops. - static int logCount = 0; - if (logCount++ < 5) - { - std::cout << "[stub] Syscall 0x" << std::hex << syscall_num - << " treated as success PC=0x" << ctx->pc - << " RA=0x" << caller_ra << std::dec << std::endl; - } - setReturnS32(ctx, 0); - return; - } - std::cerr << "Warning: Unimplemented PS2 syscall called. PC=0x" << std::hex << ctx->pc - << ", RA=0x" << caller_ra - << ", Syscall # (from $v1)=0x" << syscall_num << std::dec << std::endl; + << ", RA=0x" << caller_ra + << ", Syscall # (from $v1)=0x" << syscall_num << std::dec << std::endl; std::cerr << " Args: $a0=0x" << std::hex << getRegU32(ctx, 4) - << ", $a1=0x" << getRegU32(ctx, 5) - << ", $a2=0x" << getRegU32(ctx, 6) - << ", $a3=0x" << getRegU32(ctx, 7) << std::dec << std::endl; + << ", $a1=0x" << getRegU32(ctx, 5) + << ", $a2=0x" << getRegU32(ctx, 6) + << ", $a3=0x" << getRegU32(ctx, 7) << std::dec << std::endl; // Common syscalls: // 0x04: Exit @@ -1597,7 +1316,7 @@ namespace ps2_syscalls } // Return generic error for unimplemented ones - setReturnS32(ctx, -1); + setReturnS32(ctx, -1); // Return -ENOSYS or similar? Use -1 for simplicity. } // 0x3C SetupThread: returns stack pointer (stack + stack_size)