mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-09-26 08:51:05 -04:00
feat: added ps2 syscall
This commit is contained in:
@@ -21,6 +21,21 @@ constexpr uint32_t PS2_VU1_CODE_BASE = 0x11008000;
|
||||
constexpr uint32_t PS2_VU1_DATA_BASE = 0x1100C000;
|
||||
constexpr uint32_t PS2_GS_BASE = 0x12000000;
|
||||
|
||||
#define PS2_FIO_O_RDONLY 0x0001
|
||||
#define PS2_FIO_O_WRONLY 0x0002
|
||||
#define PS2_FIO_O_RDWR 0x0003
|
||||
#define PS2_FIO_O_APPEND 0x0100
|
||||
#define PS2_FIO_O_CREAT 0x0200
|
||||
#define PS2_FIO_O_TRUNC 0x0400
|
||||
#define PS2_FIO_O_EXCL 0x0800
|
||||
|
||||
#define PS2_FIO_SEEK_SET 0
|
||||
#define PS2_FIO_SEEK_CUR 1
|
||||
#define PS2_FIO_SEEK_END 2
|
||||
|
||||
#define PS2_FIO_S_IFDIR 0x1000
|
||||
#define PS2_FIO_S_IFREG 0x2000
|
||||
|
||||
// PS2 CPU context (R5900)
|
||||
struct R5900Context
|
||||
{
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
#include <unordered_map>
|
||||
#include <filesystem>
|
||||
|
||||
std::unordered_map<int, FILE*> g_fileDescriptors;
|
||||
std::unordered_map<int, FILE *> g_fileDescriptors;
|
||||
int g_nextFd = 3; // Start after stdin, stdout, stderr
|
||||
|
||||
int allocatePs2Fd(FILE* file)
|
||||
int allocatePs2Fd(FILE *file)
|
||||
{
|
||||
if (!file)
|
||||
return -1;
|
||||
@@ -23,7 +23,7 @@ int allocatePs2Fd(FILE* file)
|
||||
return fd;
|
||||
}
|
||||
|
||||
FILE* getHostFile(int ps2Fd)
|
||||
FILE *getHostFile(int ps2Fd)
|
||||
{
|
||||
auto it = g_fileDescriptors.find(ps2Fd);
|
||||
if (it != g_fileDescriptors.end())
|
||||
@@ -38,7 +38,6 @@ void releasePs2Fd(int ps2Fd)
|
||||
g_fileDescriptors.erase(ps2Fd);
|
||||
}
|
||||
|
||||
|
||||
const char *translateFioMode(int ps2Flags)
|
||||
{
|
||||
bool read = (ps2Flags & PS2_FIO_O_RDONLY) || (ps2Flags & PS2_FIO_O_RDWR);
|
||||
@@ -89,7 +88,6 @@ std::string translatePs2Path(const char *ps2Path)
|
||||
std::filesystem::create_directories(cdBasePath); // Ensure it exists
|
||||
return (cdBasePath / pathStr.substr(7)).string();
|
||||
}
|
||||
// Add other mappings (mc0:, hdd0:, etc.) as needed
|
||||
std::cerr << "Warning: Unsupported PS2 path prefix: " << pathStr << std::endl;
|
||||
return "";
|
||||
}
|
||||
@@ -100,17 +98,22 @@ namespace ps2_syscalls
|
||||
{
|
||||
void FlushCache(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
std::cout << "Syscall: FlushCache (No-op)" << std::endl;
|
||||
// No-op for now
|
||||
setReturnS32(ctx, 0);
|
||||
}
|
||||
|
||||
void ResetEE(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
std::cerr << "Syscall: ResetEE - Halting Execution (Not fully implemented)" << std::endl;
|
||||
exit(0); // Should we exit or just halt the execution?
|
||||
}
|
||||
|
||||
void SetMemoryMode(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
// Affects memory mapping / TLB behavior.
|
||||
// std::cout << "Syscall: SetMemoryMode (No-op)" << std::endl;
|
||||
setReturnS32(ctx, 0); // Success
|
||||
}
|
||||
|
||||
void CreateThread(uint8_t *rdram, R5900Context *ctx)
|
||||
@@ -131,6 +134,7 @@ namespace ps2_syscalls
|
||||
void ExitThread(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
std::cout << "PS2 ExitThread: Thread is exiting (PC=0x" << std::hex << ctx->pc << std::dec << ")" << std::endl;
|
||||
}
|
||||
|
||||
void ExitDeleteThread(uint8_t *rdram, R5900Context *ctx)
|
||||
@@ -390,110 +394,553 @@ namespace ps2_syscalls
|
||||
|
||||
void fioOpen(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
uint32_t pathAddr = getRegU32(ctx, 4); // $a0
|
||||
int flags = (int)getRegU32(ctx, 5); // $a1 (PS2 FIO flags)
|
||||
|
||||
const char *ps2Path = reinterpret_cast<const char *>(getConstMemPtr(rdram, pathAddr));
|
||||
if (!ps2Path)
|
||||
{
|
||||
std::cerr << "fioOpen error: Invalid path address" << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string hostPath = translatePs2Path(ps2Path);
|
||||
if (hostPath.empty())
|
||||
{
|
||||
std::cerr << "fioOpen error: Failed to translate path '" << ps2Path << "'" << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *mode = translateFioMode(flags);
|
||||
std::cout << "fioOpen: '" << hostPath << "' flags=0x" << std::hex << flags << std::dec << " mode='" << mode << "'" << std::endl;
|
||||
|
||||
FILE *fp = ::fopen(hostPath.c_str(), mode);
|
||||
if (!fp)
|
||||
{
|
||||
std::cerr << "fioOpen error: fopen failed for '" << hostPath << "': " << strerror(errno) << std::endl;
|
||||
setReturnS32(ctx, -1); // e.g., -ENOENT, -EACCES
|
||||
return;
|
||||
}
|
||||
|
||||
int ps2Fd = allocatePs2Fd(fp);
|
||||
if (ps2Fd < 0)
|
||||
{
|
||||
std::cerr << "fioOpen error: Failed to allocate PS2 file descriptor" << std::endl;
|
||||
::fclose(fp);
|
||||
setReturnS32(ctx, -1); // e.g., -EMFILE
|
||||
return;
|
||||
}
|
||||
|
||||
// returns the PS2 file descriptor
|
||||
setReturnS32(ctx, ps2Fd);
|
||||
}
|
||||
|
||||
void fioClose(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
int ps2Fd = (int)getRegU32(ctx, 4); // $a0
|
||||
std::cout << "fioClose: fd=" << ps2Fd << std::endl;
|
||||
|
||||
FILE *fp = getHostFile(ps2Fd);
|
||||
if (!fp)
|
||||
{
|
||||
std::cerr << "fioClose warning: Invalid PS2 file descriptor " << ps2Fd << std::endl;
|
||||
setReturnS32(ctx, -1); // e.g., -EBADF
|
||||
return;
|
||||
}
|
||||
|
||||
int ret = ::fclose(fp);
|
||||
releasePs2Fd(ps2Fd);
|
||||
|
||||
// returns 0 on success, -1 on error
|
||||
setReturnS32(ctx, ret == 0 ? 0 : -1);
|
||||
}
|
||||
|
||||
void fioRead(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
int ps2Fd = (int)getRegU32(ctx, 4); // $a0
|
||||
uint32_t bufAddr = getRegU32(ctx, 5); // $a1
|
||||
size_t size = getRegU32(ctx, 6); // $a2
|
||||
|
||||
uint8_t *hostBuf = getMemPtr(rdram, bufAddr);
|
||||
FILE *fp = getHostFile(ps2Fd);
|
||||
|
||||
if (!hostBuf)
|
||||
{
|
||||
std::cerr << "fioRead error: Invalid buffer address for fd " << ps2Fd << std::endl;
|
||||
setReturnS32(ctx, -1); // -EFAULT
|
||||
return;
|
||||
}
|
||||
if (!fp)
|
||||
{
|
||||
std::cerr << "fioRead error: Invalid file descriptor " << ps2Fd << std::endl;
|
||||
setReturnS32(ctx, -1); // -EBADF
|
||||
return;
|
||||
}
|
||||
if (size == 0)
|
||||
{
|
||||
setReturnS32(ctx, 0); // Read 0 bytes
|
||||
return;
|
||||
}
|
||||
|
||||
size_t bytesRead = ::fread(hostBuf, 1, size, fp);
|
||||
|
||||
if (bytesRead < size && ferror(fp))
|
||||
{
|
||||
std::cerr << "fioRead error: fread failed for fd " << ps2Fd << ": " << strerror(errno) << std::endl;
|
||||
clearerr(fp);
|
||||
setReturnS32(ctx, -1); // -EIO or other appropriate error
|
||||
return;
|
||||
}
|
||||
|
||||
// returns number of bytes read (can be 0 for EOF)
|
||||
setReturnS32(ctx, (int32_t)bytesRead);
|
||||
}
|
||||
|
||||
void fioWrite(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
int ps2Fd = (int)getRegU32(ctx, 4); // $a0
|
||||
uint32_t bufAddr = getRegU32(ctx, 5); // $a1
|
||||
size_t size = getRegU32(ctx, 6); // $a2
|
||||
|
||||
const uint8_t *hostBuf = getConstMemPtr(rdram, bufAddr);
|
||||
FILE *fp = getHostFile(ps2Fd);
|
||||
|
||||
if (!hostBuf)
|
||||
{
|
||||
std::cerr << "fioWrite error: Invalid buffer address for fd " << ps2Fd << std::endl;
|
||||
setReturnS32(ctx, -1); // -EFAULT
|
||||
return;
|
||||
}
|
||||
if (!fp)
|
||||
{
|
||||
std::cerr << "fioWrite error: Invalid file descriptor " << ps2Fd << std::endl;
|
||||
setReturnS32(ctx, -1); // -EBADF
|
||||
return;
|
||||
}
|
||||
if (size == 0)
|
||||
{
|
||||
setReturnS32(ctx, 0); // Wrote 0 bytes
|
||||
return;
|
||||
}
|
||||
|
||||
size_t bytesWritten = ::fwrite(hostBuf, 1, size, fp);
|
||||
|
||||
if (bytesWritten < size)
|
||||
{
|
||||
if (ferror(fp))
|
||||
{
|
||||
std::cerr << "fioWrite error: fwrite failed for fd " << ps2Fd << ": " << strerror(errno) << std::endl;
|
||||
clearerr(fp);
|
||||
setReturnS32(ctx, -1); // -EIO, -ENOSPC etc.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Partial write without error? Possible but idk.
|
||||
setReturnS32(ctx, (int32_t)bytesWritten);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// returns number of bytes written
|
||||
setReturnS32(ctx, (int32_t)bytesWritten);
|
||||
}
|
||||
|
||||
void fioLseek(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
int ps2Fd = (int)getRegU32(ctx, 4); // $a0
|
||||
int32_t offset = getRegU32(ctx, 5); // $a1 (PS2 seems to use 32-bit offset here commonly)
|
||||
int whence = (int)getRegU32(ctx, 6); // $a2 (PS2 FIO_SEEK constants)
|
||||
|
||||
FILE *fp = getHostFile(ps2Fd);
|
||||
if (!fp)
|
||||
{
|
||||
std::cerr << "fioLseek error: Invalid file descriptor " << ps2Fd << std::endl;
|
||||
setReturnS32(ctx, -1); // -EBADF
|
||||
return;
|
||||
}
|
||||
|
||||
int hostWhence;
|
||||
switch (whence)
|
||||
{
|
||||
case PS2_FIO_SEEK_SET:
|
||||
hostWhence = SEEK_SET;
|
||||
break;
|
||||
case PS2_FIO_SEEK_CUR:
|
||||
hostWhence = SEEK_CUR;
|
||||
break;
|
||||
case PS2_FIO_SEEK_END:
|
||||
hostWhence = SEEK_END;
|
||||
break;
|
||||
default:
|
||||
std::cerr << "fioLseek error: Invalid whence value " << whence << " for fd " << ps2Fd << std::endl;
|
||||
setReturnS32(ctx, -1); // -EINVAL
|
||||
return;
|
||||
}
|
||||
|
||||
if (::fseek(fp, static_cast<long>(offset), hostWhence) != 0)
|
||||
{
|
||||
std::cerr << "fioLseek error: fseek failed for fd " << ps2Fd << ": " << strerror(errno) << std::endl;
|
||||
setReturnS32(ctx, -1); // Return error code
|
||||
return;
|
||||
}
|
||||
|
||||
long newPos = ::ftell(fp);
|
||||
if (newPos < 0)
|
||||
{
|
||||
std::cerr << "fioLseek error: ftell failed after fseek for fd " << ps2Fd << ": " << strerror(errno) << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// maybe we dont need this check. if position fits in 32 bits
|
||||
if (newPos > 0xFFFFFFFFL)
|
||||
{
|
||||
std::cerr << "fioLseek warning: New position exceeds 32-bit for fd " << ps2Fd << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
setReturnS32(ctx, (int32_t)newPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fioMkdir(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
// TODO maybe we dont need this.
|
||||
uint32_t pathAddr = getRegU32(ctx, 4); // $a0
|
||||
// int mode = (int)getRegU32(ctx, 5);
|
||||
|
||||
const char *ps2Path = reinterpret_cast<const char *>(getConstMemPtr(rdram, pathAddr));
|
||||
if (!ps2Path)
|
||||
{
|
||||
std::cerr << "fioMkdir error: Invalid path address" << std::endl;
|
||||
setReturnS32(ctx, -1); // -EFAULT
|
||||
return;
|
||||
}
|
||||
std::string hostPath = translatePs2Path(ps2Path);
|
||||
if (hostPath.empty())
|
||||
{
|
||||
std::cerr << "fioMkdir error: Failed to translate path '" << ps2Path << "'" << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int ret = -1;
|
||||
#else
|
||||
int ret = ::mkdir(hostPath.c_str(), 0775);
|
||||
#endif
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
std::cerr << "fioMkdir error: mkdir failed for '" << hostPath << "': " << strerror(errno) << std::endl;
|
||||
setReturnS32(ctx, -1); // errno
|
||||
}
|
||||
else
|
||||
{
|
||||
setReturnS32(ctx, 0); // Success
|
||||
}
|
||||
}
|
||||
|
||||
void fioChdir(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
// TODO maybe we dont need this as well.
|
||||
uint32_t pathAddr = getRegU32(ctx, 4); // $a0
|
||||
const char *ps2Path = reinterpret_cast<const char *>(getConstMemPtr(rdram, pathAddr));
|
||||
if (!ps2Path)
|
||||
{
|
||||
std::cerr << "fioChdir error: Invalid path address" << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string hostPath = translatePs2Path(ps2Path);
|
||||
if (hostPath.empty())
|
||||
{
|
||||
std::cerr << "fioChdir error: Failed to translate path '" << ps2Path << "'" << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
std::cerr << "fioChdir: Attempting host chdir to '" << hostPath << "' (Stub - Check side effects)" << std::endl;
|
||||
|
||||
#ifdef _WIN32
|
||||
int ret = -1;
|
||||
#else
|
||||
int ret = ::chdir(hostPath.c_str());
|
||||
#endif
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
std::cerr << "fioChdir error: chdir failed for '" << hostPath << "': " << strerror(errno) << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
setReturnS32(ctx, 0); // Success
|
||||
}
|
||||
}
|
||||
|
||||
void fioRmdir(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
uint32_t pathAddr = getRegU32(ctx, 4); // $a0
|
||||
const char *ps2Path = reinterpret_cast<const char *>(getConstMemPtr(rdram, pathAddr));
|
||||
if (!ps2Path)
|
||||
{
|
||||
std::cerr << "fioRmdir error: Invalid path address" << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
return;
|
||||
}
|
||||
std::string hostPath = translatePs2Path(ps2Path);
|
||||
if (hostPath.empty())
|
||||
{
|
||||
std::cerr << "fioRmdir error: Failed to translate path '" << ps2Path << "'" << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int ret = -1;
|
||||
#else
|
||||
int ret = ::rmdir(hostPath.c_str());
|
||||
#endif
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
std::cerr << "fioRmdir error: rmdir failed for '" << hostPath << "': " << strerror(errno) << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
setReturnS32(ctx, 0); // Success
|
||||
}
|
||||
}
|
||||
|
||||
void fioGetstat(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
// we wont implement this for now.
|
||||
uint32_t pathAddr = getRegU32(ctx, 4); // $a0
|
||||
uint32_t statBufAddr = getRegU32(ctx, 5); // $a1
|
||||
|
||||
const char *ps2Path = reinterpret_cast<const char *>(getConstMemPtr(rdram, pathAddr));
|
||||
uint8_t *ps2StatBuf = getMemPtr(rdram, statBufAddr);
|
||||
|
||||
if (!ps2Path)
|
||||
{
|
||||
std::cerr << "fioGetstat error: Invalid path addr" << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
return;
|
||||
}
|
||||
if (!ps2StatBuf)
|
||||
{
|
||||
std::cerr << "fioGetstat error: Invalid buffer addr" << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string hostPath = translatePs2Path(ps2Path);
|
||||
if (hostPath.empty())
|
||||
{
|
||||
std::cerr << "fioGetstat error: Bad path translate" << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
setReturnS32(ctx, -1);
|
||||
}
|
||||
|
||||
void fioRemove(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
uint32_t pathAddr = getRegU32(ctx, 4); // $a0
|
||||
const char *ps2Path = reinterpret_cast<const char *>(getConstMemPtr(rdram, pathAddr));
|
||||
if (!ps2Path)
|
||||
{
|
||||
std::cerr << "fioRemove error: Invalid path" << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string hostPath = translatePs2Path(ps2Path);
|
||||
if (hostPath.empty())
|
||||
{
|
||||
std::cerr << "fioRemove error: Path translate fail" << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int ret = -1;
|
||||
#else
|
||||
int ret = ::unlink(hostPath.c_str());
|
||||
#endif
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
std::cerr << "fioRemove error: unlink failed for '" << hostPath << "': " << strerror(errno) << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
setReturnS32(ctx, 0); // Success
|
||||
}
|
||||
}
|
||||
|
||||
void GsSetCrt(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
int interlaced = getRegU32(ctx, 4); // $a0 - 0=non-interlaced, 1=interlaced
|
||||
int videoMode = getRegU32(ctx, 5); // $a1 - 0=NTSC, 1=PAL, 2=VESA, 3=HiVision
|
||||
int frameMode = getRegU32(ctx, 6); // $a2 - 0=field, 1=frame
|
||||
|
||||
std::cout << "PS2 GsSetCrt: interlaced=" << interlaced
|
||||
<< ", videoMode=" << videoMode
|
||||
<< ", frameMode=" << frameMode << std::endl;
|
||||
}
|
||||
|
||||
void GsGetIMR(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
// TODO return IMR value from the Gs hardware this is just a stub.
|
||||
// The IMR (Interrupt Mask Register) is a 64-bit register that controls which interrupts are enabled.
|
||||
uint64_t imr = 0x0000000000000000ULL;
|
||||
|
||||
std::cout << "PS2 GsGetIMR: Returning IMR=0x" << std::hex << imr << std::dec << std::endl;
|
||||
|
||||
setReturnS32(ctx, (int32_t)(imr & 0xFFFFFFFF)); // Return lower 32 bits
|
||||
setReturnS32(ctx, (int32_t)(imr >> 32)); // Return upper 32 bits
|
||||
}
|
||||
|
||||
void GsPutIMR(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
uint64_t imr = getRegU32(ctx, 4) | ((uint64_t)getRegU32(ctx, 5) << 32); // $a0 = lower 32 bits, $a1 = upper 32 bits
|
||||
std::cout << "PS2 GsPutIMR: Setting IMR=0x" << std::hex << imr << std::dec << std::endl;
|
||||
// Do nothing for now.
|
||||
}
|
||||
|
||||
void GsSetVideoMode(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
int mode = getRegU32(ctx, 4); // $a0 - video mode (various flags)
|
||||
|
||||
std::cout << "PS2 GsSetVideoMode: mode=0x" << std::hex << mode << std::dec << std::endl;
|
||||
|
||||
// Do nothing for now.
|
||||
}
|
||||
|
||||
void GetOsdConfigParam(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
uint32_t paramAddr = getRegU32(ctx, 4); // $a0 - pointer to parameter structure
|
||||
|
||||
if (!getMemPtr(rdram, paramAddr))
|
||||
{
|
||||
std::cerr << "PS2 GetOsdConfigParam error: Invalid parameter address: 0x"
|
||||
<< std::hex << paramAddr << std::dec << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t *param = reinterpret_cast<uint32_t *>(getMemPtr(rdram, paramAddr));
|
||||
|
||||
// Default to English language, USA region
|
||||
*param = 0x00000000;
|
||||
|
||||
std::cout << "PS2 GetOsdConfigParam: Retrieved OSD parameters" << std::endl;
|
||||
|
||||
setReturnS32(ctx, 0);
|
||||
}
|
||||
|
||||
void SetOsdConfigParam(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
uint32_t paramAddr = getRegU32(ctx, 4); // $a0 - pointer to parameter structure
|
||||
|
||||
if (!getConstMemPtr(rdram, paramAddr))
|
||||
{
|
||||
std::cerr << "PS2 SetOsdConfigParam error: Invalid parameter address: 0x"
|
||||
<< std::hex << paramAddr << std::dec << std::endl;
|
||||
setReturnS32(ctx, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO save user preferences
|
||||
std::cout << "PS2 SetOsdConfigParam: Set OSD parameters" << std::endl;
|
||||
|
||||
setReturnS32(ctx, 0);
|
||||
}
|
||||
|
||||
void GetRomName(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
uint32_t bufAddr = getRegU32(ctx, 4); // $a0
|
||||
size_t bufSize = getRegU32(ctx, 5); // $a1
|
||||
char *hostBuf = reinterpret_cast<char *>(getMemPtr(rdram, bufAddr));
|
||||
const char *romName = "ROMVER 0100";
|
||||
|
||||
if (!hostBuf)
|
||||
{
|
||||
std::cerr << "GetRomName error: Invalid buffer address" << std::endl;
|
||||
setReturnS32(ctx, -1); // Error
|
||||
return;
|
||||
}
|
||||
if (bufSize == 0)
|
||||
{
|
||||
setReturnS32(ctx, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
strncpy(hostBuf, romName, bufSize - 1);
|
||||
hostBuf[bufSize - 1] = '\0';
|
||||
|
||||
// returns the length of the string (excluding null?) or error
|
||||
setReturnS32(ctx, (int32_t)strlen(hostBuf));
|
||||
}
|
||||
|
||||
void SifLoadElfPart(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
uint32_t pathAddr = getRegU32(ctx, 4); // $a0 - pointer to ELF path
|
||||
|
||||
const char *elfPath = reinterpret_cast<const char *>(getConstMemPtr(rdram, pathAddr));
|
||||
|
||||
std::cout << "PS2 SifLoadElfPart: Would load ELF from " << elfPath << std::endl;
|
||||
setReturnS32(ctx, 1); // dummy return value for success
|
||||
}
|
||||
|
||||
void sceSifLoadModule(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
// TODO
|
||||
uint32_t moduePath = getRegU32(ctx, 4); // $a0 - pointer to module path
|
||||
|
||||
// Extract path
|
||||
const char *modulePath = reinterpret_cast<const char *>(getConstMemPtr(rdram, moduePath));
|
||||
|
||||
std::cout << "PS2 SifLoadModule: Would load module from " << moduePath << std::endl;
|
||||
|
||||
setReturnS32(ctx, 1);
|
||||
}
|
||||
|
||||
void TODO(uint8_t *rdram, R5900Context *ctx)
|
||||
{
|
||||
uint32_t syscall_num = getRegU32(ctx, 2); // $v0 often holds syscall num before call
|
||||
std::cerr << "Warning: Unimplemented syscall called. PC=0x" << std::hex << ctx->pc
|
||||
<< " Syscall # (approx): 0x" << syscall_num << std::dec << std::endl;
|
||||
setReturnS32(ctx, -1); // Return error
|
||||
}
|
||||
uint32_t syscall_num = getRegU32(ctx, 3); // Syscall number usually in $v1 ($r3) for SYSCALL instr
|
||||
uint32_t caller_ra = getRegU32(ctx, 31); // $ra
|
||||
|
||||
// Helper functions
|
||||
void RenderFrame(uint8_t *rdram)
|
||||
{
|
||||
// TODO
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
// Common syscalls:
|
||||
// 0x04: Exit
|
||||
// 0x06: LoadExecPS2
|
||||
// 0x07: ExecPS2
|
||||
if (syscall_num == 0x04)
|
||||
{
|
||||
std::cerr << " -> Syscall is Exit(), calling ExitThread stub." << std::endl;
|
||||
ExitThread(rdram, ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
// Return generic error for unimplemented ones
|
||||
setReturnS32(ctx, -1); // Return -ENOSYS or similar? Use -1 for simplicity.
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user