refactor: remove re code veronica hacks

This commit is contained in:
Ran-j
2026-01-27 17:06:22 -03:00
parent ff8d354259
commit 7b3fee9247
2 changed files with 6 additions and 649 deletions
-362
View File
@@ -10,9 +10,6 @@
#include <unordered_map>
#include "raylib.h"
// From ps2_syscalls.cpp to help keep the scheduler semaphore sane.
extern std::atomic<int> 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<uint32_t *>(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<const uint64_t *>(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<uint32_t *>(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<uint32_t *>(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<uint32_t *>(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<uint32_t *>(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<uint32_t>(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<uint8_t> 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<uint32_t *>(rdram + base);
uint32_t argPtr = 0x363a18 & PS2_RAM_MASK;
uint32_t idx = *reinterpret_cast<uint32_t *>(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<uint32_t *>(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();
+6 -287
View File
@@ -46,7 +46,6 @@ static thread_local int g_currentThreadId = 1;
static std::unordered_map<int, std::shared_ptr<SemaInfo>> g_semas;
static int g_nextSemaId = 1;
std::atomic<int> g_activeThreads{0};
std::atomic<int> 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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint32_t>(prio), "RotateThreadReadyQueue"))
{
return;
}
setReturnS32(ctx, 0);
}
@@ -521,15 +430,6 @@ namespace ps2_syscalls
{
int sid = static_cast<int>(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<int>(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<std::mutex> lock(sema->m);
uint32_t schedSid = *reinterpret_cast<uint32_t *>(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<uint32_t *>(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<int32_t>(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<uint64_t>(fbw & 0x3F) << 10);
dispfb |= (static_cast<uint64_t>(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<size_t>(fbp) * 2048;
size_t bytes = static_cast<size_t>(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<size_t>(y) * fbWidth + x) * 4;
vram[idx + 0] = static_cast<uint8_t>(x); // B
vram[idx + 1] = static_cast<uint8_t>(y); // G
vram[idx + 2] = static_cast<uint8_t>(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<float *>(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)