mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-09-26 08:51:05 -04:00
refactor: remove re code veronica hacks
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user