mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-09-26 08:51:05 -04:00
feat: misc runtime changes
This commit is contained in:
@@ -38,6 +38,11 @@ target_link_libraries(ps2_runtime PRIVATE raylib)
|
||||
target_link_libraries(ps2EntryRunner PRIVATE raylib)
|
||||
target_link_libraries(ps2EntryRunner PRIVATE ps2_runtime)
|
||||
|
||||
# Work around WinAPI vs raylib symbol clash for CloseWindow on x64
|
||||
if (MSVC)
|
||||
target_link_options(ps2EntryRunner PRIVATE "/FORCE:MULTIPLE")
|
||||
endif()
|
||||
|
||||
install(TARGETS ps2_runtime
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
@@ -45,4 +50,4 @@ install(TARGETS ps2_runtime
|
||||
|
||||
install(DIRECTORY include/
|
||||
DESTINATION include
|
||||
)
|
||||
)
|
||||
|
||||
@@ -216,6 +216,13 @@ inline void setReturnS32(R5900Context *ctx, int32_t value)
|
||||
ctx->r[2] = _mm_set_epi32(0, 0, 0, value); // $v0 Sign extension handled by cast? TODO Check MIPS ABI.
|
||||
}
|
||||
|
||||
inline void setReturnU64(R5900Context *ctx, uint64_t value)
|
||||
{
|
||||
// 64-bit returns use $v0/$v1 (r2/r3)
|
||||
ctx->r[2] = _mm_set_epi32(0, 0, 0, static_cast<uint32_t>(value));
|
||||
ctx->r[3] = _mm_set_epi32(0, 0, 0, static_cast<uint32_t>(value >> 32));
|
||||
}
|
||||
|
||||
inline uint8_t *getMemPtr(uint8_t *rdram, uint32_t addr)
|
||||
{
|
||||
constexpr uint32_t PS2_RAM_MASK = PS2_RAM_SIZE - 1;
|
||||
@@ -372,6 +379,7 @@ private:
|
||||
|
||||
bool isAddressInRegion(uint32_t address, const CodeRegion ®ion);
|
||||
void markModified(uint32_t address, uint32_t size);
|
||||
bool isScratchpad(uint32_t address) const;
|
||||
};
|
||||
|
||||
class PS2Runtime
|
||||
@@ -435,4 +443,4 @@ private:
|
||||
std::vector<LoadedModule> m_loadedModules;
|
||||
};
|
||||
|
||||
#endif // PS2_RUNTIME_H
|
||||
#endif // PS2_RUNTIME_H
|
||||
|
||||
@@ -86,10 +86,16 @@ bool PS2Memory::initialize(size_t ramSize)
|
||||
}
|
||||
}
|
||||
|
||||
bool PS2Memory::isScratchpad(uint32_t address) const
|
||||
{
|
||||
return address >= PS2_SCRATCHPAD_BASE &&
|
||||
address < PS2_SCRATCHPAD_BASE + PS2_SCRATCHPAD_SIZE;
|
||||
}
|
||||
|
||||
uint32_t PS2Memory::translateAddress(uint32_t virtualAddress)
|
||||
{
|
||||
// Handle special memory regions
|
||||
if (virtualAddress >= PS2_SCRATCHPAD_BASE && virtualAddress < PS2_SCRATCHPAD_BASE + PS2_SCRATCHPAD_SIZE)
|
||||
if (isScratchpad(virtualAddress))
|
||||
{
|
||||
// Scratchpad is directly mapped
|
||||
return virtualAddress - PS2_SCRATCHPAD_BASE;
|
||||
@@ -132,16 +138,17 @@ uint32_t PS2Memory::translateAddress(uint32_t virtualAddress)
|
||||
|
||||
uint8_t PS2Memory::read8(uint32_t address)
|
||||
{
|
||||
const bool scratch = isScratchpad(address);
|
||||
uint32_t physAddr = translateAddress(address);
|
||||
|
||||
if (scratch)
|
||||
{
|
||||
return m_scratchpad[physAddr];
|
||||
}
|
||||
if (physAddr < PS2_RAM_SIZE)
|
||||
{
|
||||
return m_rdram[physAddr];
|
||||
}
|
||||
else if (physAddr >= PS2_SCRATCHPAD_BASE && physAddr < PS2_SCRATCHPAD_BASE + PS2_SCRATCHPAD_SIZE)
|
||||
{
|
||||
return m_scratchpad[physAddr - PS2_SCRATCHPAD_BASE];
|
||||
}
|
||||
else if (physAddr >= PS2_IO_BASE && physAddr < PS2_IO_BASE + PS2_IO_SIZE)
|
||||
{
|
||||
// IO registers - often not handled byte by byte
|
||||
@@ -167,16 +174,17 @@ uint16_t PS2Memory::read16(uint32_t address)
|
||||
throw std::runtime_error("Unaligned 16-bit read at address: 0x" + std::to_string(address));
|
||||
}
|
||||
|
||||
const bool scratch = isScratchpad(address);
|
||||
uint32_t physAddr = translateAddress(address);
|
||||
|
||||
if (scratch)
|
||||
{
|
||||
return *reinterpret_cast<uint16_t *>(&m_scratchpad[physAddr]);
|
||||
}
|
||||
if (physAddr < PS2_RAM_SIZE)
|
||||
{
|
||||
return *reinterpret_cast<uint16_t *>(&m_rdram[physAddr]);
|
||||
}
|
||||
else if (physAddr >= PS2_SCRATCHPAD_BASE && physAddr < PS2_SCRATCHPAD_BASE + PS2_SCRATCHPAD_SIZE)
|
||||
{
|
||||
return *reinterpret_cast<uint16_t *>(&m_scratchpad[physAddr - PS2_SCRATCHPAD_BASE]);
|
||||
}
|
||||
else if (physAddr >= PS2_IO_BASE && physAddr < PS2_IO_BASE + PS2_IO_SIZE)
|
||||
{
|
||||
// IO registers - align to word boundary and extract relevant bits
|
||||
@@ -201,16 +209,17 @@ uint32_t PS2Memory::read32(uint32_t address)
|
||||
throw std::runtime_error("Unaligned 32-bit read at address: 0x" + std::to_string(address));
|
||||
}
|
||||
|
||||
const bool scratch = isScratchpad(address);
|
||||
uint32_t physAddr = translateAddress(address);
|
||||
|
||||
if (scratch)
|
||||
{
|
||||
return *reinterpret_cast<uint32_t *>(&m_scratchpad[physAddr]);
|
||||
}
|
||||
if (physAddr < PS2_RAM_SIZE)
|
||||
{
|
||||
return *reinterpret_cast<uint32_t *>(&m_rdram[physAddr]);
|
||||
}
|
||||
else if (physAddr >= PS2_SCRATCHPAD_BASE && physAddr < PS2_SCRATCHPAD_BASE + PS2_SCRATCHPAD_SIZE)
|
||||
{
|
||||
return *reinterpret_cast<uint32_t *>(&m_scratchpad[physAddr - PS2_SCRATCHPAD_BASE]);
|
||||
}
|
||||
else if (physAddr >= PS2_IO_BASE && physAddr < PS2_IO_BASE + PS2_IO_SIZE)
|
||||
{
|
||||
// IO registers
|
||||
@@ -232,16 +241,17 @@ uint64_t PS2Memory::read64(uint32_t address)
|
||||
throw std::runtime_error("Unaligned 64-bit read at address: 0x" + std::to_string(address));
|
||||
}
|
||||
|
||||
const bool scratch = isScratchpad(address);
|
||||
uint32_t physAddr = translateAddress(address);
|
||||
|
||||
if (scratch)
|
||||
{
|
||||
return *reinterpret_cast<uint64_t *>(&m_scratchpad[physAddr]);
|
||||
}
|
||||
if (physAddr < PS2_RAM_SIZE)
|
||||
{
|
||||
return *reinterpret_cast<uint64_t *>(&m_rdram[physAddr]);
|
||||
}
|
||||
else if (physAddr >= PS2_SCRATCHPAD_BASE && physAddr < PS2_SCRATCHPAD_BASE + PS2_SCRATCHPAD_SIZE)
|
||||
{
|
||||
return *reinterpret_cast<uint64_t *>(&m_scratchpad[physAddr - PS2_SCRATCHPAD_BASE]);
|
||||
}
|
||||
|
||||
// 64-bit IO operations are not common, but who knows
|
||||
return (uint64_t)read32(address) | ((uint64_t)read32(address + 4) << 32);
|
||||
@@ -255,16 +265,17 @@ __m128i PS2Memory::read128(uint32_t address)
|
||||
throw std::runtime_error("Unaligned 128-bit read at address: 0x" + std::to_string(address));
|
||||
}
|
||||
|
||||
const bool scratch = isScratchpad(address);
|
||||
uint32_t physAddr = translateAddress(address);
|
||||
|
||||
if (scratch)
|
||||
{
|
||||
return _mm_loadu_si128(reinterpret_cast<__m128i *>(&m_scratchpad[physAddr]));
|
||||
}
|
||||
if (physAddr < PS2_RAM_SIZE)
|
||||
{
|
||||
return _mm_loadu_si128(reinterpret_cast<__m128i *>(&m_rdram[physAddr]));
|
||||
}
|
||||
else if (physAddr >= PS2_SCRATCHPAD_BASE && physAddr < PS2_SCRATCHPAD_BASE + PS2_SCRATCHPAD_SIZE)
|
||||
{
|
||||
return _mm_loadu_si128(reinterpret_cast<__m128i *>(&m_scratchpad[physAddr - PS2_SCRATCHPAD_BASE]));
|
||||
}
|
||||
|
||||
// 128-bit reads are primarily for quad-word loads in the EE, which are only valid for RAM areas
|
||||
// Return zeroes for unsupported areas
|
||||
@@ -273,16 +284,17 @@ __m128i PS2Memory::read128(uint32_t address)
|
||||
|
||||
void PS2Memory::write8(uint32_t address, uint8_t value)
|
||||
{
|
||||
const bool scratch = isScratchpad(address);
|
||||
uint32_t physAddr = translateAddress(address);
|
||||
|
||||
if (physAddr < PS2_RAM_SIZE)
|
||||
if (scratch)
|
||||
{
|
||||
m_scratchpad[physAddr] = value;
|
||||
}
|
||||
else if (physAddr < PS2_RAM_SIZE)
|
||||
{
|
||||
m_rdram[physAddr] = value;
|
||||
}
|
||||
else if (physAddr >= PS2_SCRATCHPAD_BASE && physAddr < PS2_SCRATCHPAD_BASE + PS2_SCRATCHPAD_SIZE)
|
||||
{
|
||||
m_scratchpad[physAddr - PS2_SCRATCHPAD_BASE] = value;
|
||||
}
|
||||
else if (physAddr >= PS2_IO_BASE && physAddr < PS2_IO_BASE + PS2_IO_SIZE)
|
||||
{
|
||||
// IO registers - handle byte writes by modifying the appropriate byte in the word
|
||||
@@ -304,16 +316,17 @@ void PS2Memory::write16(uint32_t address, uint16_t value)
|
||||
throw std::runtime_error("Unaligned 16-bit write at address: 0x" + std::to_string(address));
|
||||
}
|
||||
|
||||
const bool scratch = isScratchpad(address);
|
||||
uint32_t physAddr = translateAddress(address);
|
||||
|
||||
if (physAddr < PS2_RAM_SIZE)
|
||||
if (scratch)
|
||||
{
|
||||
*reinterpret_cast<uint16_t *>(&m_scratchpad[physAddr]) = value;
|
||||
}
|
||||
else if (physAddr < PS2_RAM_SIZE)
|
||||
{
|
||||
*reinterpret_cast<uint16_t *>(&m_rdram[physAddr]) = value;
|
||||
}
|
||||
else if (physAddr >= PS2_SCRATCHPAD_BASE && physAddr < PS2_SCRATCHPAD_BASE + PS2_SCRATCHPAD_SIZE)
|
||||
{
|
||||
*reinterpret_cast<uint16_t *>(&m_scratchpad[physAddr - PS2_SCRATCHPAD_BASE]) = value;
|
||||
}
|
||||
else if (physAddr >= PS2_IO_BASE && physAddr < PS2_IO_BASE + PS2_IO_SIZE)
|
||||
{
|
||||
// IO registers - handle halfword writes
|
||||
@@ -335,20 +348,21 @@ void PS2Memory::write32(uint32_t address, uint32_t value)
|
||||
throw std::runtime_error("Unaligned 32-bit write at address: 0x" + std::to_string(address));
|
||||
}
|
||||
|
||||
const bool scratch = isScratchpad(address);
|
||||
uint32_t physAddr = translateAddress(address);
|
||||
|
||||
if (physAddr < PS2_RAM_SIZE)
|
||||
if (scratch)
|
||||
{
|
||||
*reinterpret_cast<uint32_t *>(&m_scratchpad[physAddr]) = value;
|
||||
}
|
||||
else if (physAddr < PS2_RAM_SIZE)
|
||||
{
|
||||
// Check if this might be code modification
|
||||
markModified(address, 4);
|
||||
|
||||
*reinterpret_cast<uint32_t *>(&m_rdram[physAddr]) = value;
|
||||
}
|
||||
else if (physAddr >= 0x70000000 && physAddr < 0x70004000)
|
||||
{ // Scratchpad
|
||||
*reinterpret_cast<uint32_t *>(&m_scratchpad[physAddr - 0x70000000]) = value;
|
||||
}
|
||||
else if (physAddr >= 0x10000000 && physAddr < 0x10010000)
|
||||
else if (physAddr >= PS2_IO_BASE && physAddr < PS2_IO_BASE + PS2_IO_SIZE)
|
||||
{
|
||||
// Handle IO register writes with potential side effects
|
||||
writeIORegister(physAddr, value);
|
||||
@@ -363,16 +377,17 @@ void PS2Memory::write64(uint32_t address, uint64_t value)
|
||||
throw std::runtime_error("Unaligned 64-bit write at address: 0x" + std::to_string(address));
|
||||
}
|
||||
|
||||
const bool scratch = isScratchpad(address);
|
||||
uint32_t physAddr = translateAddress(address);
|
||||
|
||||
if (physAddr < PS2_RAM_SIZE)
|
||||
if (scratch)
|
||||
{
|
||||
*reinterpret_cast<uint64_t *>(&m_scratchpad[physAddr]) = value;
|
||||
}
|
||||
else if (physAddr < PS2_RAM_SIZE)
|
||||
{
|
||||
*reinterpret_cast<uint64_t *>(&m_rdram[physAddr]) = value;
|
||||
}
|
||||
else if (physAddr >= PS2_SCRATCHPAD_BASE && physAddr < PS2_SCRATCHPAD_BASE + PS2_SCRATCHPAD_SIZE)
|
||||
{
|
||||
*reinterpret_cast<uint64_t *>(&m_scratchpad[physAddr - PS2_SCRATCHPAD_BASE]) = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Split into two 32-bit writes for other memory regions
|
||||
@@ -389,16 +404,17 @@ void PS2Memory::write128(uint32_t address, __m128i value)
|
||||
throw std::runtime_error("Unaligned 128-bit write at address: 0x" + std::to_string(address));
|
||||
}
|
||||
|
||||
const bool scratch = isScratchpad(address);
|
||||
uint32_t physAddr = translateAddress(address);
|
||||
|
||||
if (physAddr < PS2_RAM_SIZE)
|
||||
if (scratch)
|
||||
{
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i *>(&m_scratchpad[physAddr]), value);
|
||||
}
|
||||
else if (physAddr < PS2_RAM_SIZE)
|
||||
{
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i *>(&m_rdram[physAddr]), value);
|
||||
}
|
||||
else if (physAddr >= PS2_SCRATCHPAD_BASE && physAddr < PS2_SCRATCHPAD_BASE + PS2_SCRATCHPAD_SIZE)
|
||||
{
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i *>(&m_scratchpad[physAddr - PS2_SCRATCHPAD_BASE]), value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Split into smaller writes for other memory regions
|
||||
@@ -607,4 +623,4 @@ void PS2Memory::clearModifiedFlag(uint32_t address, uint32_t size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include "raylib.h"
|
||||
|
||||
#define ELF_MAGIC 0x464C457F // "\x7FELF" in little endian
|
||||
@@ -141,13 +143,27 @@ bool PS2Runtime::loadELF(const std::string &elfPath)
|
||||
|
||||
// Copy to memory
|
||||
uint32_t physAddr = m_memory.translateAddress(ph.vaddr);
|
||||
uint8_t *dest = m_memory.getRDRAM() + physAddr;
|
||||
uint8_t *dest = nullptr;
|
||||
if (ph.vaddr >= PS2_SCRATCHPAD_BASE && ph.vaddr < PS2_SCRATCHPAD_BASE + PS2_SCRATCHPAD_SIZE)
|
||||
{
|
||||
dest = m_memory.getScratchpad() + physAddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest = m_memory.getRDRAM() + physAddr;
|
||||
}
|
||||
std::memcpy(dest, buffer.data(), ph.filesz);
|
||||
|
||||
if (ph.memsz > ph.filesz)
|
||||
{
|
||||
std::memset(dest + ph.filesz, 0, ph.memsz - ph.filesz);
|
||||
}
|
||||
|
||||
// Track executable regions for self-modifying code invalidation
|
||||
if (ph.flags & 0x1) // PF_X
|
||||
{
|
||||
m_memory.registerCodeRegion(ph.vaddr, ph.vaddr + ph.memsz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,39 +293,52 @@ void PS2Runtime::run()
|
||||
|
||||
std::cout << "Starting execution at address 0x" << std::hex << m_cpuContext.pc << std::dec << std::endl;
|
||||
|
||||
try
|
||||
{
|
||||
// Call the entry point function
|
||||
entryPoint(m_memory.getRDRAM(), &m_cpuContext, this);
|
||||
// A blank image to use as a framebuffer
|
||||
Image blank = GenImageColor(FB_WIDTH, FB_HEIGHT, BLANK);
|
||||
Texture2D frameTex = LoadTextureFromImage(blank);
|
||||
UnloadImage(blank);
|
||||
|
||||
std::cout << "Program execution completed successfully" << std::endl;
|
||||
std::atomic<bool> running{true};
|
||||
|
||||
// A blank image to use as a framebuffer
|
||||
Image blank = GenImageColor(FB_WIDTH, FB_HEIGHT, BLANK);
|
||||
Texture2D frameTex = LoadTextureFromImage(blank);
|
||||
UnloadImage(blank);
|
||||
|
||||
while (!WindowShouldClose())
|
||||
std::thread gameThread([&, entryPoint]() {
|
||||
try
|
||||
{
|
||||
// TODO step only a small slice each host
|
||||
auto self = this;
|
||||
lookupFunction(memory().read32(0))(
|
||||
memory().getRDRAM(),
|
||||
&cpu(),
|
||||
self);
|
||||
|
||||
UploadFrame(frameTex, self);
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(BLACK);
|
||||
DrawTexture(frameTex, 0, 0, WHITE);
|
||||
EndDrawing();
|
||||
entryPoint(m_memory.getRDRAM(), &m_cpuContext, this);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "Error during program execution: " << e.what() << std::endl;
|
||||
}
|
||||
running = false;
|
||||
});
|
||||
|
||||
CloseWindow();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
while (running && !WindowShouldClose())
|
||||
{
|
||||
std::cerr << "Error during program execution: " << e.what() << std::endl;
|
||||
UploadFrame(frameTex, this);
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(BLACK);
|
||||
DrawTexture(frameTex, 0, 0, WHITE);
|
||||
EndDrawing();
|
||||
}
|
||||
}
|
||||
|
||||
if (!running)
|
||||
{
|
||||
// Game thread finished on its own
|
||||
if (gameThread.joinable())
|
||||
{
|
||||
gameThread.join();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Window was closed while the game thread is still running
|
||||
if (gameThread.joinable())
|
||||
{
|
||||
gameThread.detach();
|
||||
}
|
||||
}
|
||||
|
||||
UnloadTexture(frameTex);
|
||||
CloseWindow();
|
||||
}
|
||||
|
||||
@@ -811,8 +811,7 @@ namespace ps2_syscalls
|
||||
|
||||
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
|
||||
setReturnU64(ctx, imr); // Return in $v0/$v1
|
||||
}
|
||||
|
||||
void GsPutIMR(uint8_t *rdram, R5900Context *ctx)
|
||||
@@ -947,4 +946,4 @@ namespace ps2_syscalls
|
||||
// Return generic error for unimplemented ones
|
||||
setReturnS32(ctx, -1); // Return -ENOSYS or similar? Use -1 for simplicity.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user