From a35f5854d8ed56eb52ec3292c1c892383991dcb4 Mon Sep 17 00:00:00 2001 From: Lucas Ribeiro Date: Thu, 29 Jan 2026 04:09:33 -0300 Subject: [PATCH 1/2] feat: integrate Rabbitizer via FetchContent --- ps2xAnalyzer/CMakeLists.txt | 1 + ps2xAnalyzer/include/ps2recomp/elf_analyzer.h | 15 +++--- ps2xAnalyzer/src/elf_analyzer.cpp | 49 +++++++++++++------ ps2xRecomp/CMakeLists.txt | 24 +++++++++ ps2xRecomp/include/ps2recomp/code_generator.h | 1 + ps2xRecomp/src/code_generator.cpp | 13 +++-- 6 files changed, 74 insertions(+), 29 deletions(-) diff --git a/ps2xAnalyzer/CMakeLists.txt b/ps2xAnalyzer/CMakeLists.txt index 2b8afdf..0d939c3 100644 --- a/ps2xAnalyzer/CMakeLists.txt +++ b/ps2xAnalyzer/CMakeLists.txt @@ -18,6 +18,7 @@ target_include_directories(ps2_analyzer PRIVATE target_link_libraries(ps2_analyzer PRIVATE fmt::fmt ps2_recomp + rabbitizer ) install(TARGETS ps2_analyzer diff --git a/ps2xAnalyzer/include/ps2recomp/elf_analyzer.h b/ps2xAnalyzer/include/ps2recomp/elf_analyzer.h index ab3c02b..ecefc04 100644 --- a/ps2xAnalyzer/include/ps2recomp/elf_analyzer.h +++ b/ps2xAnalyzer/include/ps2recomp/elf_analyzer.h @@ -2,8 +2,8 @@ #define PS2RECOMP_ELF_ANALYZER_H #include "ps2recomp/elf_parser.h" -#include "ps2recomp/r5900_decoder.h" #include "ps2recomp/types.h" +#include "ps2recomp/instructions.h" #include #include #include @@ -26,25 +26,24 @@ namespace ps2recomp private: std::string m_elfPath; std::unique_ptr m_elfParser; - std::unique_ptr m_decoder; std::vector m_functions; std::vector m_symbols; std::vector
m_sections; std::vector m_relocations; - + std::unordered_set m_libFunctions; std::unordered_set m_skipFunctions; std::unordered_map> m_functionDataUsage; std::unordered_map m_commonDataAccess; - + std::map m_patches; std::map m_patchReasons; - + std::unordered_map m_functionCFGs; std::vector m_jumpTables; std::unordered_map> m_functionCalls; - + void initializeLibraryFunctions(); void analyzeEntryPoint(); void analyzeLibraryFunctions(); @@ -57,12 +56,12 @@ namespace ps2recomp void analyzeRegisterUsage(); void analyzeFunctionSignatures(); void optimizePatches(); - + bool identifyMemcpyPattern(const Function &func); bool identifyMemsetPattern(const Function &func); bool identifyStringOperationPattern(const Function &func); bool identifyMathPattern(const Function &func); - + bool isSystemFunction(const std::string &name) const; bool isLibraryFunction(const std::string &name) const; std::vector decodeFunction(const Function &function); diff --git a/ps2xAnalyzer/src/elf_analyzer.cpp b/ps2xAnalyzer/src/elf_analyzer.cpp index 6552b66..d815607 100644 --- a/ps2xAnalyzer/src/elf_analyzer.cpp +++ b/ps2xAnalyzer/src/elf_analyzer.cpp @@ -1,4 +1,5 @@ #include "ps2recomp/elf_analyzer.h" +#include #include #include #include @@ -20,7 +21,6 @@ namespace ps2recomp : m_elfPath(elfPath) { m_elfParser = std::make_unique(elfPath); - m_decoder = std::make_unique(); initializeLibraryFunctions(); } @@ -255,7 +255,7 @@ namespace ps2recomp { if (inst.opcode == OPCODE_JAL) { - uint32_t target = (inst.address & 0xF0000000) | (inst.target << 2); + uint32_t target = inst.target; for (const auto &func : m_functions) { @@ -537,7 +537,7 @@ namespace ps2recomp if (nextInst.opcode == OPCODE_J || nextInst.opcode == OPCODE_JAL) { - uint32_t jumpTarget = (nextInst.address & 0xF0000000) | (nextInst.target << 2); + uint32_t jumpTarget = nextInst.target; for (const auto §ion : m_sections) { @@ -652,7 +652,7 @@ namespace ps2recomp if (inst.opcode == OPCODE_JAL) { - targetAddr = (inst.address & 0xF0000000) | (inst.target << 2); + targetAddr = inst.target; } else { @@ -1358,7 +1358,7 @@ namespace ps2recomp // Jump target for J/JAL if ((inst.opcode == OPCODE_J || inst.opcode == OPCODE_JAL) && !inst.isCall) { - uint32_t target = (inst.address & 0xF0000000) | (inst.target << 2); + uint32_t target = inst.target; leaders.insert(target); } } @@ -1439,7 +1439,7 @@ namespace ps2recomp if (lastInst.opcode == OPCODE_J || lastInst.opcode == OPCODE_JAL) { // Direct jump - uint32_t targetAddr = (lastInst.address & 0xF0000000) | (lastInst.target << 2); + uint32_t targetAddr = lastInst.target; // Only add successor if it's within this function if (targetAddr >= function.start && targetAddr < function.end && @@ -1580,16 +1580,33 @@ namespace ps2recomp uint32_t rawInstruction = m_elfParser->readWord(addr); - try - { - Instruction inst = m_decoder->decodeInstruction(addr, rawInstruction); - instructions.push_back(inst); - } - catch (const std::exception &e) - { - std::cerr << "Error decoding instruction at " << formatAddress(addr) - << ": " << e.what() << std::endl; - } + RabbitizerInstruction instr; + RabbitizerInstruction_init(&instr, rawInstruction, addr); + + Instruction inst; + inst.address = addr; + inst.raw = rawInstruction; + inst.opcode = RAB_INSTR_GET_opcode(&instr); + inst.rs = RAB_INSTR_GET_rs(&instr); + inst.rt = RAB_INSTR_GET_rt(&instr); + inst.rd = RAB_INSTR_GET_rd(&instr); + inst.sa = RAB_INSTR_GET_sa(&instr); + inst.function = RAB_INSTR_GET_function(&instr); + inst.immediate = RAB_INSTR_GET_immediate(&instr); + inst.simmediate = static_cast(RabbitizerInstruction_getProcessedImmediate(&instr)); + inst.target = RabbitizerInstruction_getInstrIndexAsVram(&instr); + inst.hasDelaySlot = RabbitizerInstruction_hasDelaySlot(&instr); + inst.isCall = RabbitizerInstruction_isFunctionCall(&instr); + inst.isReturn = RabbitizerInstruction_isReturn(&instr); + inst.isBranch = (RabbitizerInstruction_getBranchOffsetGeneric(&instr) != 0) || + RabbitizerInstruction_isJumptableJump(&instr); + inst.isJump = RabbitizerInstruction_isUnconditionalBranch(&instr) || + RabbitizerInstruction_isJumptableJump(&instr); + inst.isMMI = (inst.opcode == OPCODE_MMI); + inst.isVU = (inst.opcode == OPCODE_COP2); + + instructions.push_back(inst); + RabbitizerInstruction_destroy(&instr); } return instructions; diff --git a/ps2xRecomp/CMakeLists.txt b/ps2xRecomp/CMakeLists.txt index 93f7e6e..bb56101 100644 --- a/ps2xRecomp/CMakeLists.txt +++ b/ps2xRecomp/CMakeLists.txt @@ -29,6 +29,28 @@ FetchContent_Declare( ) FetchContent_MakeAvailable(fmt) +FetchContent_Declare( + rabbitizer + GIT_REPOSITORY https://github.com/Decompollaborate/rabbitizer.git + GIT_TAG 1.x +) +FetchContent_MakeAvailable(rabbitizer) + +file(GLOB_RECURSE RABBITIZER_SOURCES CONFIGURE_DEPENDS + "${rabbitizer_SOURCE_DIR}/src/analysis/*.c" + "${rabbitizer_SOURCE_DIR}/src/common/*.c" + "${rabbitizer_SOURCE_DIR}/src/instructions/*.c" + "${rabbitizer_SOURCE_DIR}/src/instructions/*/*.c" +) + +add_library(rabbitizer STATIC ${RABBITIZER_SOURCES}) + +target_include_directories(rabbitizer PUBLIC + "${rabbitizer_SOURCE_DIR}/include" + "${rabbitizer_SOURCE_DIR}/tables" + "${rabbitizer_SOURCE_DIR}/tables/tables" +) + file(GLOB_RECURSE PS2RECOMP_SOURCES "src/*.cpp" ) @@ -60,11 +82,13 @@ target_include_directories(ps2_recomp PRIVATE target_link_libraries(ps2recomp PRIVATE fmt::fmt toml11::toml11 + rabbitizer ) target_link_libraries(ps2_recomp PUBLIC fmt::fmt toml11::toml11 + rabbitizer ) install(TARGETS ps2recomp ps2_recomp diff --git a/ps2xRecomp/include/ps2recomp/code_generator.h b/ps2xRecomp/include/ps2recomp/code_generator.h index 1a3ff02..a1a61e7 100644 --- a/ps2xRecomp/include/ps2recomp/code_generator.h +++ b/ps2xRecomp/include/ps2recomp/code_generator.h @@ -120,6 +120,7 @@ namespace ps2recomp Symbol *findSymbolByAddress(uint32_t address); std::string getFunctionName(uint32_t address); + std::string sanitizeFunctionName(const std::string &name); std::string getGeneratedFunctionName(const Function &function); }; diff --git a/ps2xRecomp/src/code_generator.cpp b/ps2xRecomp/src/code_generator.cpp index 111e3e5..9bca831 100644 --- a/ps2xRecomp/src/code_generator.cpp +++ b/ps2xRecomp/src/code_generator.cpp @@ -55,7 +55,7 @@ namespace ps2recomp Symbol *sym = findSymbolByAddress(address); if (sym && sym->isFunction) { - return sym->name; + return CodeGenerator::sanitizeFunctionName(sym->name); } return ""; @@ -75,7 +75,7 @@ namespace ps2recomp return kKeywords.find(name) != kKeywords.end(); } - static std::string sanitizeFunctionName(const std::string& name) + std::string CodeGenerator::sanitizeFunctionName(const std::string &name) { std::string sanitized = name; @@ -99,7 +99,7 @@ namespace ps2recomp std::string name = getFunctionName(function.start); if (name.empty()) { - name = sanitizeFunctionName(function.name); + name = CodeGenerator::sanitizeFunctionName(function.name); } return name; } @@ -129,10 +129,13 @@ namespace ps2recomp std::string funcName = getFunctionName(target); if (!funcName.empty()) { - ss << " " << funcName << "(rdram, ctx, runtime);\n"; if (branchInst.opcode == OPCODE_J) { - ss << " return;\n"; + ss << " " << funcName << "(rdram, ctx, runtime); return;\n"; + } + else + { + ss << " " << funcName << "(rdram, ctx, runtime);\n"; } } else From b4c7b108ed2ca3fde25ce339a746ade25a7e80e7 Mon Sep 17 00:00:00 2001 From: Lucas Ribeiro Date: Fri, 30 Jan 2026 13:58:42 -0300 Subject: [PATCH 2/2] feat: deprecate R5900_decoder code in favor of Rabbitizer on the entire codebase --- ps2xAnalyzer/CMakeLists.txt | 10 +- ps2xAnalyzer/src/elf_analyzer.cpp | 2 +- ps2xRecomp/example_config.toml | 4 +- ps2xRecomp/include/ps2recomp/decoder.h | 15 + ps2xRecomp/include/ps2recomp/ps2_recompiler.h | 2 - ps2xRecomp/include/ps2recomp/r5900_decoder.h | 55 - ps2xRecomp/src/code_generator.cpp | 26 +- ps2xRecomp/src/decoder.cpp | 651 ++++++++++ ps2xRecomp/src/ps2_recompiler.cpp | 16 +- ps2xRecomp/src/r5900_decoder.cpp | 1105 ----------------- ps2xRuntime/Readme.md | 2 +- ps2xRuntime/include/ps2_runtime.h | 53 +- ps2xRuntime/include/ps2_stubs.h | 6 +- ps2xRuntime/include/ps2_syscalls.h | 4 +- ps2xRuntime/main_example.cpp | 6 +- ps2xRuntime/output/ps2_runtime_macros.h | 126 +- ps2xRuntime/src/lib/ps2_runtime.cpp | 28 +- ps2xRuntime/src/lib/ps2_stubs.cpp | 174 +-- ps2xRuntime/src/lib/ps2_syscalls.cpp | 188 +-- ps2xTest/CMakeLists.txt | 2 +- ps2xTest/src/code_generator_tests.cpp | 4 +- ...00_decoder_tests.cpp => decoder_tests.cpp} | 65 +- ps2xTest/src/main.cpp | 4 +- 23 files changed, 1031 insertions(+), 1517 deletions(-) create mode 100644 ps2xRecomp/include/ps2recomp/decoder.h delete mode 100644 ps2xRecomp/include/ps2recomp/r5900_decoder.h create mode 100644 ps2xRecomp/src/decoder.cpp delete mode 100644 ps2xRecomp/src/r5900_decoder.cpp rename ps2xTest/src/{r5900_decoder_tests.cpp => decoder_tests.cpp} (74%) diff --git a/ps2xAnalyzer/CMakeLists.txt b/ps2xAnalyzer/CMakeLists.txt index 0d939c3..9b90658 100644 --- a/ps2xAnalyzer/CMakeLists.txt +++ b/ps2xAnalyzer/CMakeLists.txt @@ -3,24 +3,24 @@ project(PS2Analyzer VERSION 0.1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) - + file(GLOB_RECURSE PS2ANALYZER_SOURCES "src/*.cpp" ) - + add_executable(ps2_analyzer ${PS2ANALYZER_SOURCES}) - + target_include_directories(ps2_analyzer PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/ps2xRecomp/include ) - + target_link_libraries(ps2_analyzer PRIVATE fmt::fmt ps2_recomp rabbitizer ) - + install(TARGETS ps2_analyzer RUNTIME DESTINATION bin ) \ No newline at end of file diff --git a/ps2xAnalyzer/src/elf_analyzer.cpp b/ps2xAnalyzer/src/elf_analyzer.cpp index d815607..c7ec4f7 100644 --- a/ps2xAnalyzer/src/elf_analyzer.cpp +++ b/ps2xAnalyzer/src/elf_analyzer.cpp @@ -192,7 +192,7 @@ namespace ps2recomp const std::vector stdLibFuncs = { // I/O functions "printf", "sprintf", "snprintf", "fprintf", "vprintf", "vfprintf", "vsprintf", "vsnprintf", - "puts", "putchar", "getchar", "gets", "fgets", "fputs", "scanf", "fscanf", "sscanf", + "puts", "putchar", "getchar", "gets", "fgets", "fputs", "scanf", "fscanf", "sscanf", "sprint", "sbprintf", // Memory management diff --git a/ps2xRecomp/example_config.toml b/ps2xRecomp/example_config.toml index 3a1ab81..b3df816 100644 --- a/ps2xRecomp/example_config.toml +++ b/ps2xRecomp/example_config.toml @@ -30,7 +30,7 @@ instructions = [ function = "printf" code = ''' // Custom printf implementation -void printf(uint8_t* rdram, R5900Context* ctx) { +void printf(uint8_t* rdram, Ps2CpuContext* ctx) { // Implementation here } ''' @@ -40,7 +40,7 @@ void printf(uint8_t* rdram, R5900Context* ctx) { address = "0x100000" code = ''' // Custom implementation for function at 0x100000 -void func_00100000(uint8_t* rdram, R5900Context* ctx) { +void func_00100000(uint8_t* rdram, Ps2CpuContext* ctx) { // Implementation here } ''' diff --git a/ps2xRecomp/include/ps2recomp/decoder.h b/ps2xRecomp/include/ps2recomp/decoder.h new file mode 100644 index 0000000..27cb350 --- /dev/null +++ b/ps2xRecomp/include/ps2recomp/decoder.h @@ -0,0 +1,15 @@ +#ifndef PS2RECOMP_DECODER_H +#define PS2RECOMP_DECODER_H + +#include "ps2recomp/types.h" +#include "ps2recomp/instructions.h" +#include + +namespace ps2recomp +{ + Instruction decodeInstruction(uint32_t address, uint32_t rawInstruction); + uint32_t getBranchTarget(const Instruction &inst); + uint32_t getJumpTarget(const Instruction &inst); +} + +#endif // PS2RECOMP_DECODER_H diff --git a/ps2xRecomp/include/ps2recomp/ps2_recompiler.h b/ps2xRecomp/include/ps2recomp/ps2_recompiler.h index 049e241..46b4f4d 100644 --- a/ps2xRecomp/include/ps2recomp/ps2_recompiler.h +++ b/ps2xRecomp/include/ps2recomp/ps2_recompiler.h @@ -3,7 +3,6 @@ #include "ps2recomp/types.h" #include "ps2recomp/elf_parser.h" -#include "ps2recomp/r5900_decoder.h" #include "ps2recomp/code_generator.h" #include "ps2recomp/config_manager.h" #include @@ -28,7 +27,6 @@ namespace ps2recomp private: ConfigManager m_configManager; std::unique_ptr m_elfParser; - std::unique_ptr m_decoder; std::unique_ptr m_codeGenerator; RecompilerConfig m_config; diff --git a/ps2xRecomp/include/ps2recomp/r5900_decoder.h b/ps2xRecomp/include/ps2recomp/r5900_decoder.h deleted file mode 100644 index 80f0fa7..0000000 --- a/ps2xRecomp/include/ps2recomp/r5900_decoder.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef PS2RECOMP_R5900_DECODER_H -#define PS2RECOMP_R5900_DECODER_H - -#include "ps2recomp/types.h" -#include "ps2recomp/instructions.h" -#include - -namespace ps2recomp -{ - - class R5900Decoder - { - public: - R5900Decoder(); - ~R5900Decoder(); - - Instruction decodeInstruction(uint32_t address, uint32_t rawInstruction); - - bool isBranchInstruction(const Instruction &inst) const; - bool isJumpInstruction(const Instruction &inst) const; - bool isCallInstruction(const Instruction &inst) const; - bool isReturnInstruction(const Instruction &inst) const; - bool isMMIInstruction(const Instruction &inst) const; - bool isVUInstruction(const Instruction &inst) const; - bool isStore(const Instruction &inst) const; - bool isLoad(const Instruction &inst) const; - bool hasDelaySlot(const Instruction &inst) const; - - uint32_t getBranchTarget(const Instruction &inst) const; - uint32_t getJumpTarget(const Instruction &inst) const; - - private: - void decodeRType(Instruction &inst) const; - void decodeIType(Instruction &inst) const; - void decodeJType(Instruction &inst) const; - - void decodeSpecial(Instruction &inst) const; - void decodeRegimm(Instruction &inst) const; - - void decodeCOP0(Instruction& inst) const; - void decodeCOP1(Instruction &inst) const; - void decodeCOP2(Instruction &inst) const; - - void decodeMMI(Instruction &inst) const; - void decodeMMI0(Instruction &inst) const; - void decodeMMI1(Instruction &inst) const; - void decodeMMI2(Instruction &inst) const; - void decodeMMI3(Instruction &inst) const; - - void decodePMFHL(Instruction &inst) const; - }; - -} // namespace ps2recomp - -#endif // PS2RECOMP_R5900_DECODER_H \ No newline at end of file diff --git a/ps2xRecomp/src/code_generator.cpp b/ps2xRecomp/src/code_generator.cpp index 9bca831..5da72f2 100644 --- a/ps2xRecomp/src/code_generator.cpp +++ b/ps2xRecomp/src/code_generator.cpp @@ -29,9 +29,10 @@ namespace ps2recomp { CodeGenerator::CodeGenerator(const std::vector &symbols) { - for (auto& symbol : symbols) { - m_symbols.emplace(symbol.address, symbol); - } + for (auto &symbol : symbols) + { + m_symbols.emplace(symbol.address, symbol); + } } void CodeGenerator::setRenamedFunctions(const std::unordered_map &renames) @@ -125,7 +126,7 @@ namespace ps2recomp { ss << " " << delaySlotCode << "\n"; } - uint32_t target = (branchInst.address & 0xF0000000) | (branchInst.target << 2); + uint32_t target = branchInst.target; std::string funcName = getFunctionName(target); if (!funcName.empty()) { @@ -604,7 +605,7 @@ namespace ps2recomp } else if (isStaticJump) { - uint32_t target = (inst.address & 0xF0000000) | (inst.target << 2); + uint32_t target = inst.target; if (target >= function.start && target < function.end) { std::string funcName = getFunctionName(target); @@ -647,7 +648,7 @@ namespace ps2recomp { std::string sanitizedName = sanitizeFunctionName(function.name); ss << "// System call wrapper for " << function.name << "\n"; - ss << "void " << sanitizedName << "(uint8_t* rdram, R5900Context* ctx, PS2Runtime *runtime) {\n"; + ss << "void " << sanitizedName << "(uint8_t* rdram, Ps2CpuContext* ctx, PS2Runtime *runtime) {\n"; ss << " ps2_syscalls::" << function.name << "(rdram, ctx, runtime);\n"; ss << "}\n"; return ss.str(); @@ -666,7 +667,7 @@ namespace ps2recomp ss << "// Function: " << function.name << "\n"; ss << "// Address: 0x" << std::hex << function.start << " - 0x" << function.end << std::dec << "\n"; std::string sanitizedName = getGeneratedFunctionName(function); - ss << "void " << sanitizedName << "(uint8_t* rdram, R5900Context* ctx, PS2Runtime *runtime) {\n\n"; + ss << "void " << sanitizedName << "(uint8_t* rdram, Ps2CpuContext* ctx, PS2Runtime *runtime) {\n\n"; for (size_t i = 0; i < instructions.size(); ++i) { @@ -813,9 +814,9 @@ namespace ps2recomp "SET_GPR_S64(ctx, {}, (int64_t)GPR_S64(ctx, {}) + (int64_t){});", inst.rt, inst.rs, inst.simmediate); case OPCODE_J: - return fmt::format("// JAL 0x{:X} - Handled by branch logic", (inst.address & 0xF0000000) | (inst.target << 2)); + return fmt::format("// JAL 0x{:X} - Handled by branch logic", inst.target); case OPCODE_JAL: - return fmt::format("// JAL 0x{:X} - Handled by branch logic", (inst.address & 0xF0000000) | (inst.target << 2)); + return fmt::format("// JAL 0x{:X} - Handled by branch logic", inst.target); case OPCODE_BEQ: case OPCODE_BNE: case OPCODE_BLEZ: @@ -2579,8 +2580,9 @@ namespace ps2recomp Symbol *CodeGenerator::findSymbolByAddress(uint32_t address) { auto it = m_symbols.find(address); - if (it != m_symbols.end()) { - return &it->second; + if (it != m_symbols.end()) + { + return &it->second; } return nullptr; @@ -2594,7 +2596,7 @@ namespace ps2recomp std::stringstream ss; ss << "// Auto-generated bootstrap for ELF entry point\n"; ss << "void entry_" << std::hex << m_bootstrapInfo.entry << std::dec - << "(uint8_t* rdram, R5900Context* ctx, PS2Runtime *runtime) {\n"; + << "(uint8_t* rdram, Ps2CpuContext* ctx, PS2Runtime *runtime) {\n"; if (m_bootstrapInfo.bssEnd > m_bootstrapInfo.bssStart) { ss << " const uint32_t bss_start = 0x" << std::hex << m_bootstrapInfo.bssStart << ";\n"; diff --git a/ps2xRecomp/src/decoder.cpp b/ps2xRecomp/src/decoder.cpp new file mode 100644 index 0000000..2ceab7f --- /dev/null +++ b/ps2xRecomp/src/decoder.cpp @@ -0,0 +1,651 @@ +#include "ps2recomp/decoder.h" + +#include +#include + +namespace ps2recomp +{ + namespace + { + void decodeRType(Instruction &inst) + { + if (inst.rd != 0) + { + inst.modificationInfo.modifiesGPR = true; + } + } + + void decodeIType(Instruction &inst) + { + if (!inst.isStore && !inst.isBranch && inst.rt != 0) + { + inst.modificationInfo.modifiesGPR = true; + } + } + + void decodeJType(Instruction &inst) + { + inst.isJump = true; + inst.hasDelaySlot = true; + inst.modificationInfo.modifiesControl = true; // PC + if (inst.opcode == OPCODE_JAL) + { + inst.isCall = true; + inst.modificationInfo.modifiesGPR = true; // $ra (r[31]) + } + } + + void decodeSpecial(Instruction &inst) + { + switch (inst.function) + { + case SPECIAL_JR: + inst.isJump = true; + inst.hasDelaySlot = true; + inst.modificationInfo.modifiesControl = true; // PC + if (inst.rs == 31) + { + inst.isReturn = true; + } + break; + case SPECIAL_JALR: + inst.isJump = true; + inst.isCall = true; + inst.hasDelaySlot = true; + inst.modificationInfo.modifiesControl = true; + if (inst.rd != 0) + { + inst.modificationInfo.modifiesGPR = true; // Link register + } + break; + case SPECIAL_SYSCALL: + case SPECIAL_BREAK: + inst.modificationInfo.modifiesControl = true; // Control flow changes + break; + case SPECIAL_MFHI: + case SPECIAL_MFLO: + if (inst.rd != 0) + { + inst.modificationInfo.modifiesGPR = true; + } + break; + case SPECIAL_MTHI: + case SPECIAL_MTLO: + inst.modificationInfo.modifiesControl = true; + break; + case SPECIAL_MULT: + case SPECIAL_MULTU: + case SPECIAL_DIV: + case SPECIAL_DIVU: + inst.modificationInfo.modifiesControl = true; + break; + default: + decodeRType(inst); + break; + } + } + + void decodeRegimm(Instruction &inst) + { + inst.isBranch = true; + inst.hasDelaySlot = true; + inst.modificationInfo.modifiesControl = true; // PC potentially + if (inst.rt == REGIMM_BGEZAL || inst.rt == REGIMM_BLTZAL || + inst.rt == REGIMM_BGEZALL || inst.rt == REGIMM_BLTZALL) + { + inst.isCall = true; + inst.modificationInfo.modifiesGPR = true; // Link register ($ra) + } + } + + void decodeMMI0(Instruction &inst) + { + inst.mmiType = 0; + inst.mmiFunction = static_cast(inst.sa); + } + + void decodeMMI1(Instruction &inst) + { + inst.mmiType = 1; + inst.mmiFunction = static_cast(inst.sa); + } + + void decodeMMI2(Instruction &inst) + { + inst.mmiType = 2; + inst.mmiFunction = static_cast(inst.sa); + } + + void decodeMMI3(Instruction &inst) + { + inst.mmiType = 3; + inst.mmiFunction = static_cast(inst.sa); + } + + void decodePMFHL(Instruction &inst) + { + uint32_t saField = inst.sa; + + switch (saField) + { + case PMFHL_LW: + inst.pmfhlVariation = PMFHL_LW; + break; + case PMFHL_UW: + inst.pmfhlVariation = PMFHL_UW; + break; + case PMFHL_SLW: + inst.pmfhlVariation = PMFHL_SLW; + break; + case PMFHL_LH: + inst.pmfhlVariation = PMFHL_LH; + break; + case PMFHL_SH: + inst.pmfhlVariation = PMFHL_SH; + break; + default: + inst.pmfhlVariation = 0xFF; + break; + } + } + + void decodeMMI(Instruction &inst) + { + inst.isMMI = true; + inst.isMultimedia = true; + + inst.isMMI = true; + inst.isMultimedia = true; + inst.mmiFunction = static_cast(inst.sa); + + // Determine MMI type groups + if (inst.function == MMI_MMI0) + { + inst.mmiType = 0; + decodeMMI0(inst); + } + else if (inst.function == MMI_MMI1) + { + inst.mmiType = 1; + decodeMMI1(inst); + } + else if (inst.function == MMI_MMI2) + { + inst.mmiType = 2; + decodeMMI2(inst); + } + else if (inst.function == MMI_MMI3) + { + inst.mmiType = 3; + decodeMMI3(inst); + } + else + { + // Default to MMI0 semantics for standalone ops like PADDW + inst.mmiType = 0; + decodeRType(inst); + } + + // Mark HI/LO touching ops as control modifications + switch (inst.function) + { + case MMI_MADD: + case MMI_MADDU: + case MMI_MSUB: + case MMI_MSUBU: + case MMI_MADD1: + case MMI_MADDU1: + case MMI_MULT1: + case MMI_MULTU1: + case MMI_DIV1: + case MMI_DIVU1: + case MMI_PMTHL: + inst.modificationInfo.modifiesControl = true; + break; + default: + break; + } + } + + void decodeCOP0(Instruction &inst) + { + uint8_t format = inst.rs; + inst.modificationInfo.modifiesControl = true; // Assume COP0 always modifies some control state + if (format == COP0_MF && inst.rt != 0) + { + inst.modificationInfo.modifiesGPR = true; + } + else if (format == COP0_CO && inst.function == COP0_CO_ERET) + { + inst.isReturn = true; + inst.hasDelaySlot = false; + } + else if (format == COP0_BC) + { + inst.isBranch = true; + inst.hasDelaySlot = true; + } + } + + void decodeCOP1(Instruction &inst) + { + uint8_t format = inst.rs; + if (format == COP1_MF || format == COP1_CF) + { + if (inst.rt != 0) + inst.modificationInfo.modifiesGPR = true; + } + else if (format == COP1_BC) + { + inst.isBranch = true; + inst.hasDelaySlot = true; + inst.modificationInfo.modifiesControl = true; + } + else if (format == COP1_S || format == COP1_W || format == COP1_L) + { + inst.modificationInfo.modifiesFPR = true; + } + if (format == COP1_CT || (format == COP1_S && inst.function >= COP1_S_C_F)) + { + inst.modificationInfo.modifiesControl = true; + } + } + + void decodeCOP2(Instruction &inst) + { + uint8_t format = inst.rs; + inst.isVU = true; + inst.isMultimedia = true; + + switch (format) + { + case COP2_QMFC2: + case COP2_CFC2: + if (inst.rt != 0) + inst.modificationInfo.modifiesGPR = true; + break; + case COP2_QMTC2: + inst.modificationInfo.modifiesVFR = true; + break; + case COP2_CTC2: + inst.modificationInfo.modifiesControl = true; + break; + case COP2_BC: + inst.isBranch = true; + inst.hasDelaySlot = true; + inst.modificationInfo.modifiesControl = true; + break; + case COP2_CO: + case COP2_CO + 1: + case COP2_CO + 2: + case COP2_CO + 3: + case COP2_CO + 4: + case COP2_CO + 5: + case COP2_CO + 6: + case COP2_CO + 7: + case COP2_CO + 8: + case COP2_CO + 9: + case COP2_CO + 10: + case COP2_CO + 11: + case COP2_CO + 12: + case COP2_CO + 13: + case COP2_CO + 14: + case COP2_CO + 15: + { + uint8_t vu_func = inst.function; + + if (vu_func == VU0_S2_VDIV || vu_func == VU0_S2_VSQRT || vu_func == VU0_S2_VRSQRT) + { + inst.vectorInfo.fsf = (inst.raw >> 10) & 0x3; // Extract bits 10-11 + inst.vectorInfo.ftf = (inst.raw >> 8) & 0x3; // Extract bits 8-9 + } + + inst.vectorInfo.vectorField = (inst.raw >> 21) & 0xF; + + inst.modificationInfo.modifiesVFR = true; // Default: Modifies Vector Float Reg + inst.modificationInfo.modifiesControl = true; // Default: Modifies Flags/Special Regs (Q, P, I, MAC, Clip...) + + if (vu_func >= 0x3C) // Special2 Table + { + switch (vu_func) + { + case VU0_S2_VDIV: + case VU0_S2_VSQRT: + case VU0_S2_VRSQRT: + inst.vectorInfo.usesQReg = true; + break; + case VU0_S2_VMTIR: + inst.modificationInfo.modifiesVFR = false; + inst.modificationInfo.modifiesVIC = true; + break; + case VU0_S2_VMFIR: + inst.modificationInfo.modifiesVIR = false; + break; + case VU0_S2_VILWR: + inst.modificationInfo.modifiesVFR = false; + inst.modificationInfo.modifiesVIR = true; + inst.isLoad = true; + break; + case VU0_S2_VISWR: + inst.modificationInfo.modifiesVFR = false; + inst.modificationInfo.modifiesVIR = false; + inst.isStore = true; + inst.modificationInfo.modifiesMemory = true; + break; + + case VU0_S2_VRINIT: + case VU0_S2_VRXOR: + inst.modificationInfo.modifiesVFR = false; + break; + case VU0_S2_VRGET: + inst.modificationInfo.modifiesControl = false; + break; + case VU0_S2_VRNEXT: + inst.modificationInfo.modifiesControl = true; + inst.modificationInfo.modifiesVFR = false; + break; + case VU0_S2_VABS: + case VU0_S2_VMOVE: + case VU0_S2_VMR32: + inst.modificationInfo.modifiesControl = false; + break; + case VU0_S2_VNOP: + inst.modificationInfo.modifiesVFR = false; + inst.modificationInfo.modifiesControl = false; + break; + case VU0_S2_VCLIPw: + inst.modificationInfo.modifiesVFR = false; + break; + } + } + else // Special1 Table + { + if (vu_func >= VU0_S1_VIADD && vu_func <= VU0_S1_VIOR) + { + inst.modificationInfo.modifiesVFR = false; + inst.modificationInfo.modifiesVIR = true; + } + if (vu_func == VU0_S1_VIADDI) + { + inst.modificationInfo.modifiesVFR = false; + inst.modificationInfo.modifiesVIR = true; + } + if (vu_func == VU0_S2_VMFIR) + { + inst.modificationInfo.modifiesVIR = false; + } + if (vu_func == VU0_S2_VMTIR) + { + inst.modificationInfo.modifiesVFR = false; + inst.modificationInfo.modifiesVIC = true; + } + if (vu_func == VU0_S2_VILWR) + { + inst.modificationInfo.modifiesVFR = false; + inst.modificationInfo.modifiesVIR = true; + inst.isLoad = true; + } + if (vu_func == VU0_S2_VISWR) + { + inst.modificationInfo.modifiesVFR = false; + inst.modificationInfo.modifiesVIR = false; + inst.isStore = true; + inst.modificationInfo.modifiesMemory = true; + } + if (vu_func == VU0_S2_VDIV || vu_func == VU0_S2_VSQRT || vu_func == VU0_S2_VRSQRT) + { + inst.vectorInfo.usesQReg = true; + } + } + break; + } + } + } + + } // namespace + + Instruction decodeInstruction(uint32_t address, uint32_t rawInstruction) + { + Instruction inst{}; + + RabbitizerInstruction rabInstr; + RabbitizerInstruction_init(&rabInstr, rawInstruction, address); + + inst.address = address; + inst.raw = rawInstruction; + inst.opcode = RAB_INSTR_GET_opcode(&rabInstr); + inst.rs = RAB_INSTR_GET_rs(&rabInstr); + inst.rt = RAB_INSTR_GET_rt(&rabInstr); + inst.rd = RAB_INSTR_GET_rd(&rabInstr); + inst.sa = RAB_INSTR_GET_sa(&rabInstr); + inst.function = RAB_INSTR_GET_function(&rabInstr); + inst.immediate = RAB_INSTR_GET_immediate(&rabInstr); + inst.simmediate = static_cast(RabbitizerInstruction_getProcessedImmediate(&rabInstr)); + inst.target = RabbitizerInstruction_getInstrIndexAsVram(&rabInstr); + + inst.vectorInfo.vectorField = 0xF; // All fields (xyzw) + inst.hasDelaySlot = RabbitizerInstruction_hasDelaySlot(&rabInstr); + inst.isCall = RabbitizerInstruction_isFunctionCall(&rabInstr); + inst.isReturn = RabbitizerInstruction_isReturn(&rabInstr); + inst.isMMI = (inst.opcode == OPCODE_MMI); + inst.isVU = (inst.opcode == OPCODE_COP2); + + switch (inst.opcode) + { + case OPCODE_SPECIAL: + decodeSpecial(inst); + break; + + case OPCODE_REGIMM: + decodeRegimm(inst); + break; + + case OPCODE_J: + case OPCODE_JAL: + decodeJType(inst); + break; + + case OPCODE_BEQ: + case OPCODE_BNE: + case OPCODE_BLEZ: + case OPCODE_BGTZ: + case OPCODE_BEQL: + case OPCODE_BNEL: + case OPCODE_BLEZL: + case OPCODE_BGTZL: + decodeIType(inst); + inst.isBranch = true; + inst.hasDelaySlot = true; + inst.modificationInfo.modifiesControl = true; // PC potentially + break; + + case OPCODE_DADDI: + case OPCODE_DADDIU: + decodeIType(inst); + if (inst.rt != 0) + inst.modificationInfo.modifiesGPR = true; + break; + + case OPCODE_MMI: + decodeMMI(inst); + break; + + case OPCODE_LQ: + decodeIType(inst); + inst.isLoad = true; + inst.isMultimedia = true; + break; + + case OPCODE_SQ: + decodeIType(inst); + inst.isStore = true; + inst.isMultimedia = true; + inst.modificationInfo.modifiesMemory = true; + break; + + case OPCODE_LB: + case OPCODE_LH: + case OPCODE_LW: + case OPCODE_LBU: + case OPCODE_LHU: + case OPCODE_LWU: + case OPCODE_LD: + inst.isLoad = true; + if (inst.rt != 0) + inst.modificationInfo.modifiesGPR = true; + break; + + case OPCODE_LWL: + case OPCODE_LWR: + case OPCODE_LDL: + case OPCODE_LDR: + inst.isLoad = true; + if (inst.rt != 0) + inst.modificationInfo.modifiesGPR = true; + inst.modificationInfo.modifiesMemory = true; + break; + + case OPCODE_LL: + case OPCODE_LLD: + decodeIType(inst); + inst.isLoad = true; + if (inst.rt != 0) + { + inst.modificationInfo.modifiesGPR = true; + } + inst.modificationInfo.modifiesControl = true; + break; + + case OPCODE_LWC1: + inst.isLoad = true; + inst.modificationInfo.modifiesFPR = true; + break; + + case OPCODE_LDC1: + case OPCODE_LWC2: + case OPCODE_LDC2: + inst.isLoad = true; + inst.isVU = true; + inst.modificationInfo.modifiesVFR = true; + break; + + case OPCODE_SB: + case OPCODE_SH: + case OPCODE_SW: + case OPCODE_SD: + inst.isStore = true; + inst.modificationInfo.modifiesMemory = true; + break; + + case OPCODE_SWL: + case OPCODE_SWR: + case OPCODE_SDL: + case OPCODE_SDR: + inst.isStore = true; + inst.modificationInfo.modifiesMemory = true; + break; + + case OPCODE_SWC1: + inst.isStore = true; + inst.modificationInfo.modifiesMemory = true; + break; + + case OPCODE_SDC1: + case OPCODE_SWC2: + case OPCODE_SDC2: + inst.isStore = true; + inst.isVU = true; + inst.modificationInfo.modifiesMemory = true; + break; + + case OPCODE_SC: + case OPCODE_SCD: + inst.isStore = true; + inst.modificationInfo.modifiesMemory = true; + if (inst.rt != 0) + inst.modificationInfo.modifiesGPR = true; + inst.modificationInfo.modifiesControl = true; + break; + + case OPCODE_ADDI: + case OPCODE_ADDIU: + case OPCODE_SLTI: + case OPCODE_SLTIU: + case OPCODE_ANDI: + case OPCODE_ORI: + case OPCODE_XORI: + case OPCODE_LUI: + decodeIType(inst); + if (inst.rt != 0) + inst.modificationInfo.modifiesGPR = true; + break; + + case OPCODE_CACHE: + decodeIType(inst); + inst.modificationInfo.modifiesControl = true; + break; + + case OPCODE_PREF: + decodeIType(inst); + break; + + case OPCODE_COP0: + decodeCOP0(inst); + break; + + case OPCODE_COP1: + decodeCOP1(inst); + break; + + case OPCODE_COP2: + decodeCOP2(inst); + break; + + default: + decodeIType(inst); + break; + } + + if (inst.isMMI || inst.isVU) + { + inst.isMultimedia = true; + inst.vectorInfo.isVector = inst.isVU; + } + + RabbitizerInstruction_destroy(&rabInstr); + return inst; + } + + uint32_t getBranchTarget(const Instruction &inst) + { + if (!inst.isBranch) + { + return 0; + } + + int32_t offset = inst.simmediate << 2; + return inst.address + 4 + offset; + } + + uint32_t getJumpTarget(const Instruction &inst) + { + if (!inst.isJump) + { + return 0; + } + + if (inst.opcode == OPCODE_SPECIAL && + (inst.function == SPECIAL_JR || inst.function == SPECIAL_JALR)) + { + return 0; + } + + if (inst.opcode == OPCODE_J || inst.opcode == OPCODE_JAL) + { + return inst.target; + } + + return 0; + } + +} // namespace ps2recomp diff --git a/ps2xRecomp/src/ps2_recompiler.cpp b/ps2xRecomp/src/ps2_recompiler.cpp index 6c8b354..f6051ef 100644 --- a/ps2xRecomp/src/ps2_recompiler.cpp +++ b/ps2xRecomp/src/ps2_recompiler.cpp @@ -1,5 +1,6 @@ #include "ps2recomp/ps2_recompiler.h" #include "ps2recomp/instructions.h" +#include "ps2recomp/decoder.h" #include "ps2_runtime_calls.h" #include #include @@ -135,7 +136,6 @@ namespace ps2recomp << m_sections.size() << " sections, " << m_relocations.size() << " relocations." << std::endl; - m_decoder = std::make_unique(); m_codeGenerator = std::make_unique(m_symbols); m_codeGenerator->setBootstrapInfo(m_bootstrapInfo); @@ -258,7 +258,7 @@ namespace ps2recomp std::string generatedName = m_codeGenerator->getGeneratedFunctionName(function); std::stringstream stub; stub << "void " << generatedName - << "(uint8_t* rdram, R5900Context* ctx, PS2Runtime *runtime) { "; + << "(uint8_t* rdram, Ps2CpuContext* ctx, PS2Runtime *runtime) { "; switch (resolveStubTarget(function.name)) { @@ -418,7 +418,7 @@ namespace ps2recomp for (const auto &funcName : stubNames) { - ss << "void " << funcName << "(uint8_t* rdram, R5900Context* ctx, PS2Runtime* runtime);\n"; + ss << "void " << funcName << "(uint8_t* rdram, Ps2CpuContext* ctx, PS2Runtime* runtime);\n"; } // ss << "\n} // namespace stubs\n"; @@ -447,7 +447,7 @@ namespace ps2recomp ss << "#define PS2_RECOMPILED_FUNCTIONS_H\n\n"; ss << "#include \n\n"; - ss << "struct R5900Context;\n"; + ss << "struct Ps2CpuContext;\n"; ss << "class PS2Runtime;\n\n"; for (const auto &function : m_functions) @@ -460,13 +460,13 @@ namespace ps2recomp std::string finalName = sanitizeFunctionName(function.name); finalName = m_codeGenerator->getGeneratedFunctionName(function); - ss << "void " << finalName << "(uint8_t* rdram, R5900Context* ctx, PS2Runtime *runtime);\n"; + ss << "void " << finalName << "(uint8_t* rdram, Ps2CpuContext* ctx, PS2Runtime *runtime);\n"; } if (m_bootstrapInfo.valid) { ss << "void entry_" << std::hex << m_bootstrapInfo.entry << std::dec - << "(uint8_t* rdram, R5900Context* ctx, PS2Runtime *runtime);\n"; + << "(uint8_t* rdram, Ps2CpuContext* ctx, PS2Runtime *runtime);\n"; } ss << "\n#endif // PS2_RECOMPILED_FUNCTIONS_H\n"; @@ -496,7 +496,7 @@ namespace ps2recomp { if (inst.opcode == OPCODE_J || inst.opcode == OPCODE_JAL) { - return (inst.address & 0xF0000000) | (inst.target << 2); + return inst.target; } if (inst.opcode == OPCODE_SPECIAL && @@ -641,7 +641,7 @@ namespace ps2recomp std::cout << "Applied patch at 0x" << std::hex << address << std::dec << std::endl; } - Instruction inst = m_decoder->decodeInstruction(address, rawInstruction); + Instruction inst = decodeInstruction(address, rawInstruction); instructions.push_back(inst); } diff --git a/ps2xRecomp/src/r5900_decoder.cpp b/ps2xRecomp/src/r5900_decoder.cpp deleted file mode 100644 index bb45ce4..0000000 --- a/ps2xRecomp/src/r5900_decoder.cpp +++ /dev/null @@ -1,1105 +0,0 @@ -#include "ps2recomp/r5900_decoder.h" -#include - -namespace ps2recomp -{ - - R5900Decoder::R5900Decoder() - { - } - - R5900Decoder::~R5900Decoder() - { - } - - Instruction R5900Decoder::decodeInstruction(uint32_t address, uint32_t rawInstruction) - { - Instruction inst; - - inst.address = address; - inst.raw = rawInstruction; - inst.opcode = OPCODE(rawInstruction); - inst.rs = RS(rawInstruction); - inst.rt = RT(rawInstruction); - inst.rd = RD(rawInstruction); - inst.sa = SA(rawInstruction); - inst.function = FUNCTION(rawInstruction); - inst.immediate = IMMEDIATE(rawInstruction); - inst.simmediate = SIMMEDIATE(rawInstruction); - inst.target = TARGET(rawInstruction); - - inst.isMMI = false; - inst.isVU = false; - inst.isBranch = false; - inst.isJump = false; - inst.isCall = false; - inst.isReturn = false; - inst.hasDelaySlot = false; - inst.isMultimedia = false; - inst.isLoad = false; - inst.isStore = false; - - // Initialize the enhanced fields - inst.mmiType = 0; - inst.mmiFunction = 0; - inst.pmfhlVariation = 0; - inst.vuFunction = 0; - - inst.vectorInfo.isVector = false; - inst.vectorInfo.usesQReg = false; - inst.vectorInfo.usesPReg = false; - inst.vectorInfo.modifiesMAC = false; - inst.vectorInfo.vectorField = 0xF; // All fields (xyzw) - - inst.modificationInfo.modifiesGPR = false; - inst.modificationInfo.modifiesFPR = false; - inst.modificationInfo.modifiesVFR = false; - inst.modificationInfo.modifiesVIR = false; - inst.modificationInfo.modifiesVIC = false; - inst.modificationInfo.modifiesMemory = false; - inst.modificationInfo.modifiesControl = false; - - switch (inst.opcode) - { - case OPCODE_SPECIAL: - decodeSpecial(inst); - break; - - case OPCODE_REGIMM: - decodeRegimm(inst); - break; - - case OPCODE_J: - decodeJType(inst); - break; - - case OPCODE_JAL: - decodeJType(inst); - break; - - case OPCODE_BEQ: - case OPCODE_BNE: - case OPCODE_BLEZ: - case OPCODE_BGTZ: - case OPCODE_BEQL: - case OPCODE_BNEL: - case OPCODE_BLEZL: - case OPCODE_BGTZL: - decodeIType(inst); - inst.isBranch = true; - inst.hasDelaySlot = true; - inst.modificationInfo.modifiesControl = true; // PC potentially - break; - - case OPCODE_DADDI: - case OPCODE_DADDIU: - decodeIType(inst); - if (inst.rt != 0) - inst.modificationInfo.modifiesGPR = true; - break; - - case OPCODE_MMI: - decodeMMI(inst); - break; - - case OPCODE_LQ: - decodeIType(inst); - inst.isLoad = true; - inst.isMultimedia = true; // 128-bit load - break; - - case OPCODE_SQ: - decodeIType(inst); - inst.isStore = true; - inst.isMultimedia = true; // 128-bit store - inst.modificationInfo.modifiesMemory = true; - break; - - case OPCODE_LB: - case OPCODE_LH: - case OPCODE_LW: - case OPCODE_LBU: - case OPCODE_LHU: - case OPCODE_LWU: - case OPCODE_LD: - inst.isLoad = true; - if (inst.rt != 0) - inst.modificationInfo.modifiesGPR = true; - break; - - case OPCODE_LWL: - case OPCODE_LWR: - case OPCODE_LDL: - case OPCODE_LDR: - inst.isLoad = true; - if (inst.rt != 0) - inst.modificationInfo.modifiesGPR = true; - inst.modificationInfo.modifiesMemory = true; - break; - - case OPCODE_LL: - case OPCODE_LLD: - decodeIType(inst); - inst.isLoad = true; - if (inst.rt != 0) - { - inst.modificationInfo.modifiesGPR = true; - } - // LL/LLD manipulate the load-linked bit in COP0 status - inst.modificationInfo.modifiesControl = true; - break; - - case OPCODE_LWC1: - inst.isLoad = true; - inst.modificationInfo.modifiesFPR = true; - break; - - case OPCODE_LDC1: // Not present/used on EE FPU - case OPCODE_LWC2: // Maybe unused - case OPCODE_LDC2: // VU Load - inst.isLoad = true; - inst.isVU = true; - inst.modificationInfo.modifiesVFR = true; - break; - - case OPCODE_SB: - case OPCODE_SH: - case OPCODE_SW: - case OPCODE_SD: - inst.isStore = true; - inst.modificationInfo.modifiesMemory = true; - break; - - case OPCODE_SWL: - case OPCODE_SWR: - case OPCODE_SDL: - case OPCODE_SDR: - inst.isStore = true; - inst.modificationInfo.modifiesMemory = true; - break; - - case OPCODE_SWC1: - inst.isStore = true; - inst.modificationInfo.modifiesMemory = true; - break; - - case OPCODE_SDC1: // Not present/used on EE FPU - case OPCODE_SWC2: // Potentially unused - case OPCODE_SDC2: - inst.isStore = true; - inst.isVU = true; - inst.modificationInfo.modifiesMemory = true; - break; - - case OPCODE_SC: - case OPCODE_SCD: - inst.isStore = true; - inst.modificationInfo.modifiesMemory = true; - if (inst.rt != 0) - inst.modificationInfo.modifiesGPR = true; // Writes success/fail to rt - inst.modificationInfo.modifiesControl = true; // Reads/Clears LLBit - break; - - case OPCODE_ADDI: - case OPCODE_ADDIU: - case OPCODE_SLTI: - case OPCODE_SLTIU: - case OPCODE_ANDI: - case OPCODE_ORI: - case OPCODE_XORI: - case OPCODE_LUI: - decodeIType(inst); - if (inst.rt != 0) - inst.modificationInfo.modifiesGPR = true; - break; - - case OPCODE_CACHE: - decodeIType(inst); - inst.modificationInfo.modifiesControl = true; // Cache state - break; - - case OPCODE_PREF: - decodeIType(inst); - break; - - case OPCODE_COP0: - decodeCOP0(inst); - break; - - case OPCODE_COP1: - decodeCOP1(inst); - break; - - case OPCODE_COP2: - decodeCOP2(inst); - break; - - default: - // Default to I-type for most other instructions - decodeIType(inst); - break; - } - - // Generic multimedia flag if MMI or VU - if (inst.isMMI || inst.isVU) - { - inst.isMultimedia = true; - inst.vectorInfo.isVector = inst.isVU; // Only VU ops are truly vector - } - - return inst; - } - - void R5900Decoder::decodeRType(Instruction &inst) const - { - // R-type instructions already have all fields set correctly - if (inst.rd != 0) - inst.modificationInfo.modifiesGPR = true; - } - - void R5900Decoder::decodeIType(Instruction &inst) const - { - // I-type instructions already have all fields set correctly - if (!inst.isStore && !inst.isBranch && inst.rt != 0) - { - inst.modificationInfo.modifiesGPR = true; - } - } - - void R5900Decoder::decodeJType(Instruction &inst) const - { - // J-type instructions already have all fields set correctly - inst.isJump = true; - inst.hasDelaySlot = true; - inst.modificationInfo.modifiesControl = true; // PC - if (inst.opcode == OPCODE_JAL) - { - inst.isCall = true; - inst.modificationInfo.modifiesGPR = true; // $ra (r[31]) - } - } - - void R5900Decoder::decodeSpecial(Instruction &inst) const - { - if (inst.rd != 0) - inst.modificationInfo.modifiesGPR = true; - - switch (inst.function) - { - case SPECIAL_JR: - inst.isJump = true; - inst.hasDelaySlot = true; - inst.modificationInfo.modifiesGPR = false; // Doesn't modify GPR itself - inst.modificationInfo.modifiesControl = true; // PC - if (inst.rs == 31) - { - // jr $ra is typically a return - inst.isReturn = true; - } - break; - - case SPECIAL_JALR: - inst.isJump = true; - inst.isCall = true; - inst.hasDelaySlot = true; - if (inst.rd == 0) - inst.modificationInfo.modifiesGPR = false; // JALR $zero, $rs is like JR $rs - else - inst.modificationInfo.modifiesGPR = true; - inst.modificationInfo.modifiesControl = true; // PC - break; - - case SPECIAL_SYSCALL: - case SPECIAL_BREAK: - // Special handling for syscall/break - inst.modificationInfo.modifiesGPR = false; // No GPR change - inst.modificationInfo.modifiesControl = true; // Changes control flow, potentially registers via handler - break; - - case SPECIAL_MFHI: - case SPECIAL_MFLO: - if (inst.rd == 0) - inst.modificationInfo.modifiesGPR = false; - break; - case SPECIAL_MTHI: - case SPECIAL_MTLO: - // HI/LO register operations - inst.modificationInfo.modifiesGPR = false; // Doesn't modify rd - inst.modificationInfo.modifiesControl = true; // HI/LO - break; - - case SPECIAL_MULT: - case SPECIAL_MULTU: - case SPECIAL_DIV: - case SPECIAL_DIVU: - // Multiplication and division operations - inst.modificationInfo.modifiesGPR = false; // Doesn't modify rd - inst.modificationInfo.modifiesControl = true; // HI/LO - break; - - case SPECIAL_ADD: - case SPECIAL_ADDU: - case SPECIAL_SUB: - case SPECIAL_SUBU: - case SPECIAL_AND: - case SPECIAL_OR: - case SPECIAL_XOR: - case SPECIAL_NOR: - // ALU operations - if (inst.rd == 0) - inst.modificationInfo.modifiesGPR = false; - break; - - case SPECIAL_SLL: - case SPECIAL_SRL: - case SPECIAL_SRA: - case SPECIAL_SLLV: - case SPECIAL_SRLV: - case SPECIAL_SRAV: - // Shift operations - if (inst.rd == 0) - inst.modificationInfo.modifiesGPR = false; - break; - - // 64-bit specific operations - case SPECIAL_DADD: - case SPECIAL_DADDU: - case SPECIAL_DSUB: - case SPECIAL_DSUBU: - case SPECIAL_DSLL: - case SPECIAL_DSRL: - case SPECIAL_DSRA: - case SPECIAL_DSLL32: - case SPECIAL_DSRL32: - case SPECIAL_DSRA32: - case SPECIAL_DSLLV: - case SPECIAL_DSRLV: - case SPECIAL_DSRAV: - // 64-bit operations - if (inst.rd == 0) - inst.modificationInfo.modifiesGPR = false; - break; - - case SPECIAL_MOVZ: - case SPECIAL_MOVN: - if (inst.rd == 0) - inst.modificationInfo.modifiesGPR = false; - break; - - // Set on Less Than - case SPECIAL_SLT: - case SPECIAL_SLTU: - if (inst.rd == 0) - inst.modificationInfo.modifiesGPR = false; - break; - - case SPECIAL_TGE: - case SPECIAL_TGEU: - case SPECIAL_TLT: - case SPECIAL_TLTU: - case SPECIAL_TEQ: - case SPECIAL_TNE: - inst.modificationInfo.modifiesGPR = false; - inst.modificationInfo.modifiesControl = true; // Control flow change via trap - break; - - // PS2 Specific (MFSA/MTSA) - case SPECIAL_MFSA: // Modifies rd GPR - if (inst.rd == 0) - inst.modificationInfo.modifiesGPR = false; - break; - case SPECIAL_MTSA: // Modifies SA control register - inst.modificationInfo.modifiesGPR = false; - inst.modificationInfo.modifiesControl = true; // SA reg - break; - - case SPECIAL_SYNC: - inst.modificationInfo.modifiesGPR = false; - inst.modificationInfo.modifiesControl = true; - break; - } - } - - void R5900Decoder::decodeRegimm(Instruction &inst) const - { - uint32_t rt = inst.rt; - - switch (rt) - { - case REGIMM_BLTZ: - case REGIMM_BGEZ: - case REGIMM_BLTZL: - case REGIMM_BGEZL: - // Branches - inst.isBranch = true; - inst.hasDelaySlot = true; - inst.modificationInfo.modifiesControl = true; // PC potentially - break; - - case REGIMM_BLTZAL: - case REGIMM_BGEZAL: - case REGIMM_BLTZALL: - case REGIMM_BGEZALL: - // Branch and Link - inst.isBranch = true; - inst.isCall = true; - inst.hasDelaySlot = true; - inst.modificationInfo.modifiesGPR = true; // $ra (r[31]) - inst.modificationInfo.modifiesControl = true; // PC - break; - - case REGIMM_TGEI: - case REGIMM_TGEIU: - case REGIMM_TLTI: - case REGIMM_TLTIU: - case REGIMM_TEQI: - case REGIMM_TNEI: - // Trap Instructions - inst.modificationInfo.modifiesControl = true; - break; - - case REGIMM_MTSAB: - case REGIMM_MTSAH: - // PS2 specific MTSAB/MTSAH instructions (for QMFC2/QMTC2) - inst.isMultimedia = true; - inst.modificationInfo.modifiesControl = true; // SA register - break; - - default: - // Unknown REGIMM instructions - std::cerr << "Unknown REGIMM instruction: " << std::hex << inst.raw << std::endl; - break; - } - } - - void R5900Decoder::decodeMMI(Instruction &inst) const - { - inst.isMMI = true; - inst.isMultimedia = true; - inst.modificationInfo.modifiesGPR = true; // Most MMI ops write to rd GPR - if (inst.rd == 0) - inst.modificationInfo.modifiesGPR = false; // Except if rd is $zero - - // The function field is actually determined by the lowest 6 bits (as in R-type) - uint32_t mmiFunction = inst.function; - - uint32_t rs = inst.rs; - - if (mmiFunction == MMI_MMI0) - { - decodeMMI0(inst); - return; - } - if (mmiFunction == MMI_MMI1) - { - decodeMMI1(inst); - return; - } - if (mmiFunction == MMI_MMI2) - { - decodeMMI2(inst); - return; - } - if (mmiFunction == MMI_MMI3) - { - decodeMMI3(inst); - return; - } - - switch (mmiFunction) - { - case MMI_PLZCW: - // Parallel leading zero/one count word - break; - case MMI_MFHI1: - case MMI_MFLO1: - // Move from HI1/LO1 -> rd - if (inst.rd == 0) - { - inst.modificationInfo.modifiesGPR = false; - } - inst.modificationInfo.modifiesControl = false; - break; - case MMI_MTHI1: - case MMI_MTLO1: - // Move to HI1/LO1 - inst.modificationInfo.modifiesGPR = false; - inst.modificationInfo.modifiesControl = true; - break; - case MMI_PSLLH: - case MMI_PSRLH: - case MMI_PSRAH: - case MMI_PSLLW: - case MMI_PSRLW: - case MMI_PSRAW: - // Packed shift instructions; defaults already mark GPR modify (unless rd==0) - break; - - // HI/LO or HI1/LO1 producers/consumers - case MMI_MADD: - case MMI_MADDU: - case MMI_MSUB: - case MMI_MSUBU: - case MMI_MADD1: - case MMI_MADDU1: - case MMI_MULT1: - case MMI_MULTU1: - case MMI_DIV1: - case MMI_DIVU1: - inst.modificationInfo.modifiesGPR = false; // Writes to HI/LO or HI1/LO1 - inst.modificationInfo.modifiesControl = true; - break; - case MMI_PMTHL: - case MMI3_PMTHI: - case MMI3_PMTLO: - inst.modificationInfo.modifiesGPR = false; // Writes to HI/LO or HI1/LO1 - inst.modificationInfo.modifiesControl = true; - break; - case MMI_PMFHL: - decodePMFHL(inst); - break; - default: - // Unknown or unsupported MMI function - std::cerr << "Unknown MMI function: " << std::hex << mmiFunction << std::endl; - break; - } - } - - void R5900Decoder::decodeMMI0(Instruction &inst) const - { - inst.mmiType = 0; - inst.mmiFunction = inst.sa; - - uint32_t sa = inst.sa; - - switch (sa) - { - case MMI0_PADDW: - case MMI0_PSUBW: - case MMI0_PCGTW: - case MMI0_PMAXW: - case MMI0_PADDH: - case MMI0_PSUBH: - case MMI0_PCGTH: - case MMI0_PMAXH: - case MMI0_PADDB: - case MMI0_PSUBB: - case MMI0_PCGTB: - // Arithmetic and comparison operations - break; - - case MMI0_PADDSW: - case MMI0_PSUBSW: - case MMI0_PADDSH: - case MMI0_PSUBSH: - case MMI0_PADDSB: - case MMI0_PSUBSB: - // Saturated arithmetic operations - break; - - case MMI0_PEXTLW: - case MMI0_PPACW: - case MMI0_PEXTLH: - case MMI0_PPACH: - case MMI0_PEXTLB: - case MMI0_PPACB: - case MMI0_PEXT5: - case MMI0_PPAC5: - // Data packing/unpacking operations - break; - - default: - // Unknown MMI0 operation - break; - } - } - - void R5900Decoder::decodeMMI1(Instruction &inst) const - { - inst.mmiType = 1; - inst.mmiFunction = inst.sa; - - uint32_t subFunction = inst.function & 0x3F; - - uint32_t sa = inst.sa; - - switch (sa) - { - case MMI1_PABSW: - case MMI1_PABSH: - // Absolute value operations - break; - - case MMI1_PCEQW: - case MMI1_PCEQH: - case MMI1_PCEQB: - // Equality comparison operations - break; - - case MMI1_PMINW: - case MMI1_PMINH: - // Minimum value operations - break; - - case MMI1_PADDUW: - case MMI1_PSUBUW: - case MMI1_PEXTUW: - case MMI1_PADDUH: - case MMI1_PSUBUH: - case MMI1_PEXTUH: - case MMI1_PADDUB: - case MMI1_PSUBUB: - case MMI1_PEXTUB: - // Unsigned arithmetic and extension operations - break; - - case MMI1_QFSRV: - // Quadword funnel shift right variable - inst.isMultimedia = true; - break; - - default: - // Unknown MMI1 operation - break; - } - } - - void R5900Decoder::decodeMMI2(Instruction &inst) const - { - inst.mmiType = 2; - inst.mmiFunction = inst.sa; - - if (inst.sa == MMI2_PMADDW || inst.sa == MMI2_PMSUBW || - inst.sa == MMI2_PMULTW || inst.sa == MMI2_PDIVW || inst.sa == MMI2_PDIVBW || - inst.sa == MMI2_PMADDH || inst.sa == MMI2_PHMADH || - inst.sa == MMI2_PMSUBH || inst.sa == MMI2_PHMSBH || inst.sa == MMI2_PMULTH) - { - inst.modificationInfo.modifiesControl = true; // HI/LO - } - - uint32_t sa = inst.sa; - - switch (sa) - { - case MMI2_PMADDW: - case MMI2_PMSUBW: - case MMI2_PMADDH: - case MMI2_PHMADH: - case MMI2_PMSUBH: - case MMI2_PHMSBH: - case MMI2_PMULTH: - // Multiply/multiply-add operations - inst.isMultimedia = true; - break; - - case MMI2_PSLLVW: - case MMI2_PSRLVW: - // Variable shift operations - break; - - case MMI2_PMFHI: - case MMI2_PMFLO: - // Move from HI/LO registers - break; - - case MMI2_PINTH: - // Interleave half words - break; - - case MMI2_PMULTW: - case MMI2_PDIVW: - case MMI2_PDIVBW: - // Multiply/divide operations - inst.isMultimedia = true; - break; - - case MMI2_PCPYLD: - // Copy lower doubleword - break; - - case MMI2_PAND: - case MMI2_PXOR: - // Logical operations - break; - - case MMI2_PEXEH: - case MMI2_PREVH: - case MMI2_PEXEW: - case MMI2_PROT3W: - // Data permutation operations - break; - - default: - // Unknown MMI2 operation - break; - } - } - - void R5900Decoder::decodeMMI3(Instruction &inst) const - { - inst.mmiType = 3; - inst.mmiFunction = inst.sa; - - uint32_t sa = inst.sa; - - switch (sa) - { - case MMI3_PMADDUW: - // Unsigned multiply-add - inst.isMultimedia = true; - inst.modificationInfo.modifiesControl = true; // HI/LO - break; - - case MMI3_PSRAVW: - // Packed shift right arithmetic variable word - break; - - case MMI3_PMTHI: - inst.mmiFunction = MMI3_PMTHI; - inst.modificationInfo.modifiesGPR = false; - inst.modificationInfo.modifiesControl = true; // HI register is modified - break; - - case MMI3_PMTLO: - inst.mmiFunction = MMI3_PMTLO; - inst.modificationInfo.modifiesGPR = false; - inst.modificationInfo.modifiesControl = true; // LO register is modified - break; - - case MMI3_PINTEH: - // Interleave even halfwords - break; - - case MMI3_PMULTUW: - case MMI3_PDIVUW: - // Unsigned multiply/divide operations - inst.isMultimedia = true; - inst.modificationInfo.modifiesControl = true; // HI/LO - break; - - case MMI3_PCPYUD: - // Copy upper doubleword - break; - - case MMI3_POR: - case MMI3_PNOR: - // Logical operations - break; - - case MMI3_PEXCH: - case MMI3_PCPYH: - case MMI3_PEXCW: - // Data permutation operations - break; - - default: - // Unknown MMI3 operation - break; - } - } - - void R5900Decoder::decodeCOP0(Instruction &inst) const - { - // COP0 (System Control) instructions - uint8_t format = inst.rs; - inst.modificationInfo.modifiesControl = true; // Assume COP0 always modifies some control state - if (format == COP0_MF && inst.rt != 0) - { - inst.modificationInfo.modifiesGPR = true; - } - else if (format == COP0_CO && inst.function == COP0_CO_ERET) - { - inst.isReturn = true; - inst.hasDelaySlot = false; - } // ERET is special - else if (format == COP0_BC) - { - inst.isBranch = true; - inst.hasDelaySlot = true; - } - } - - void R5900Decoder::decodeCOP1(Instruction &inst) const - { - uint8_t format = inst.rs; - if (format == COP1_MF || format == COP1_CF) - { - if (inst.rt != 0) - inst.modificationInfo.modifiesGPR = true; - } - else if (format == COP1_BC) - { - inst.isBranch = true; - inst.hasDelaySlot = true; - inst.modificationInfo.modifiesControl = true; - } - else if (format == COP1_S || format == COP1_W || format == COP1_L) - { - inst.modificationInfo.modifiesFPR = true; - } - if (format == COP1_CT || (format == COP1_S && inst.function >= COP1_S_C_F)) - { - inst.modificationInfo.modifiesControl = true; - } // FCR31 - } - - void R5900Decoder::decodeCOP2(Instruction &inst) const - { - uint8_t format = inst.rs; - inst.isVU = true; - inst.isMultimedia = true; - - switch (format) - { - case COP2_QMFC2: - case COP2_CFC2: - if (inst.rt != 0) - inst.modificationInfo.modifiesGPR = true; - break; - case COP2_QMTC2: - inst.modificationInfo.modifiesVFR = true; - break; // Modifies VU state - case COP2_CTC2: - inst.modificationInfo.modifiesControl = true; - break; // Modifies VU control state - case COP2_BC: - inst.isBranch = true; - inst.hasDelaySlot = true; - inst.modificationInfo.modifiesControl = true; - break; - case COP2_CO: // VU Macro instructions (format >= 0x10) - case COP2_CO + 1: - case COP2_CO + 2: - case COP2_CO + 3: - case COP2_CO + 4: - case COP2_CO + 5: - case COP2_CO + 6: - case COP2_CO + 7: - case COP2_CO + 8: - case COP2_CO + 9: - case COP2_CO + 10: - case COP2_CO + 11: - case COP2_CO + 12: - case COP2_CO + 13: - case COP2_CO + 14: - case COP2_CO + 15: - { // Refine based on specific VU function - uint8_t vu_func = inst.function; - - if (vu_func == VU0_S2_VDIV || vu_func == VU0_S2_VSQRT || vu_func == VU0_S2_VRSQRT) - { - inst.vectorInfo.fsf = (inst.raw >> 10) & 0x3; // Extract bits 10-11 - inst.vectorInfo.ftf = (inst.raw >> 8) & 0x3; // Extract bits 8-9 - } - - inst.vectorInfo.vectorField = (inst.raw >> 21) & 0xF; - - inst.modificationInfo.modifiesVFR = true; // Default: Modifies Vector Float Reg - inst.modificationInfo.modifiesControl = true; // Default: Modifies Flags/Special Regs (Q, P, I, MAC, Clip...) - - if (vu_func >= 0x3C) // Special2 Table - { - switch (vu_func) - { - case VU0_S2_VDIV: - case VU0_S2_VSQRT: - case VU0_S2_VRSQRT: - inst.vectorInfo.usesQReg = true; - break; - case VU0_S2_VMTIR: - inst.modificationInfo.modifiesVFR = false; - inst.modificationInfo.modifiesVIC = true; - break; - case VU0_S2_VMFIR: - inst.modificationInfo.modifiesVIR = false; - break; // Reads VI, writes VF - case VU0_S2_VILWR: - inst.modificationInfo.modifiesVFR = false; - inst.modificationInfo.modifiesVIR = true; - inst.isLoad = true; - break; - case VU0_S2_VISWR: - inst.modificationInfo.modifiesVFR = false; - inst.modificationInfo.modifiesVIR = false; - inst.isStore = true; - inst.modificationInfo.modifiesMemory = true; - break; - - case VU0_S2_VRINIT: - case VU0_S2_VRXOR: - inst.modificationInfo.modifiesVFR = false; /* Modifies R */ - break; // Modifies R - case VU0_S2_VRGET: - inst.modificationInfo.modifiesControl = false; /* Reads R, writes VF */ - break; - case VU0_S2_VRNEXT: - inst.modificationInfo.modifiesControl = true; /* Modifies R */ - inst.modificationInfo.modifiesVFR = false; - break; // Writes R - case VU0_S2_VABS: - case VU0_S2_VMOVE: - case VU0_S2_VMR32: - inst.modificationInfo.modifiesControl = false; - break; // Only VF - case VU0_S2_VNOP: - inst.modificationInfo.modifiesVFR = false; - inst.modificationInfo.modifiesControl = false; - break; - case VU0_S2_VCLIPw: - inst.modificationInfo.modifiesVFR = false; /* Modifies Clip flags */ - break; - } - } - else // Special1 Table - { - if (vu_func >= VU0_S1_VIADD && vu_func <= VU0_S1_VIOR) - { - inst.modificationInfo.modifiesVFR = false; - inst.modificationInfo.modifiesVIR = true; - } // Integer ops - if (vu_func == VU0_S1_VIADDI) - { - inst.modificationInfo.modifiesVFR = false; - inst.modificationInfo.modifiesVIR = true; - } - if (vu_func == VU0_S2_VMFIR) - { - inst.modificationInfo.modifiesVIR = false; - } // Only reads VIR - if (vu_func == VU0_S2_VMTIR) - { - inst.modificationInfo.modifiesVFR = false; - inst.modificationInfo.modifiesVIC = true; - } // Modifies I reg - if (vu_func == VU0_S2_VILWR) - { - inst.modificationInfo.modifiesVFR = false; - inst.modificationInfo.modifiesVIR = true; - inst.isLoad = true; - } - if (vu_func == VU0_S2_VISWR) - { - inst.modificationInfo.modifiesVFR = false; - inst.modificationInfo.modifiesVIR = false; - inst.isStore = true; - inst.modificationInfo.modifiesMemory = true; - } - if (vu_func == VU0_S2_VDIV || vu_func == VU0_S2_VSQRT || vu_func == VU0_S2_VRSQRT) - { - inst.vectorInfo.usesQReg = true; - } - } - break; - } - } - } - - void R5900Decoder::decodePMFHL(Instruction &inst) const - { - uint32_t saField = inst.sa; - - switch (saField) - { - case PMFHL_LW: - inst.pmfhlVariation = PMFHL_LW; - break; - case PMFHL_UW: - inst.pmfhlVariation = PMFHL_UW; - break; - case PMFHL_SLW: - inst.pmfhlVariation = PMFHL_SLW; - break; - case PMFHL_LH: - inst.pmfhlVariation = PMFHL_LH; - break; - case PMFHL_SH: - inst.pmfhlVariation = PMFHL_SH; - break; - default: - inst.pmfhlVariation = 0xFF; - break; - } - } - - bool R5900Decoder::isBranchInstruction(const Instruction &inst) const - { - return inst.isBranch; - } - - bool R5900Decoder::isJumpInstruction(const Instruction &inst) const - { - return inst.isJump; - } - - bool R5900Decoder::isCallInstruction(const Instruction &inst) const - { - return inst.isCall; - } - - bool R5900Decoder::isReturnInstruction(const Instruction &inst) const - { - return inst.isReturn; - } - - bool R5900Decoder::isMMIInstruction(const Instruction &inst) const - { - return inst.isMMI; - } - - bool R5900Decoder::isVUInstruction(const Instruction &inst) const - { - return inst.isVU; - } - - bool R5900Decoder::isStore(const Instruction &inst) const - { - return inst.isStore; - } - - bool R5900Decoder::isLoad(const Instruction &inst) const - { - return inst.isLoad; - } - - bool R5900Decoder::hasDelaySlot(const Instruction &inst) const - { - return inst.hasDelaySlot; - } - - uint32_t R5900Decoder::getBranchTarget(const Instruction &inst) const - { - if (!inst.isBranch) - { - return 0; - } - - int32_t offset = inst.simmediate << 2; - return inst.address + 4 + offset; - } - - uint32_t R5900Decoder::getJumpTarget(const Instruction &inst) const - { - if (!inst.isJump) - { - return 0; - } - - if (inst.opcode == OPCODE_SPECIAL && - (inst.function == SPECIAL_JR || inst.function == SPECIAL_JALR)) - { - // JR/JALR: target is in the rs register (can't be determined statically) - return 0; - } - - if (inst.opcode == OPCODE_J || inst.opcode == OPCODE_JAL) - { - // J/JAL: target is in the lower 26 bits, shifted left by 2 - // and combined with the upper 4 bits of PC + 4 - uint32_t pc_upper = (inst.address + 4) & 0xF0000000; - return pc_upper | (inst.target << 2); - } - - return 0; - } - -} // namespace ps2recomp diff --git a/ps2xRuntime/Readme.md b/ps2xRuntime/Readme.md index 8016fca..782df59 100644 --- a/ps2xRuntime/Readme.md +++ b/ps2xRuntime/Readme.md @@ -15,7 +15,7 @@ You can add custom implementations for PS2 system calls or game functions by: 1. Creating function implementations that match the signature: ```cpp -void function_name(uint8_t* rdram, R5900Context* ctx, PS2Runtime *runtime); +void function_name(uint8_t* rdram, Ps2CpuContext* ctx, PS2Runtime *runtime); ``` 2. Registering them with the runtime: diff --git a/ps2xRuntime/include/ps2_runtime.h b/ps2xRuntime/include/ps2_runtime.h index cd16608..cb5fcc0 100644 --- a/ps2xRuntime/include/ps2_runtime.h +++ b/ps2xRuntime/include/ps2_runtime.h @@ -35,7 +35,7 @@ constexpr uint32_t PS2_VU1_DATA_BASE = 0x1100C000; constexpr uint32_t PS2_GS_BASE = 0x12000000; constexpr uint32_t PS2_GS_PRIV_REG_BASE = 0x12000000; // GS Privileged Registers constexpr uint32_t PS2_GS_PRIV_REG_SIZE = 0x2000; -constexpr size_t PS2_GS_VRAM_SIZE = 4 * 1024 * 1024; // 4MB GS VRAM +constexpr size_t PS2_GS_VRAM_SIZE = 4 * 1024 * 1024; // 4MB GS VRAM #define PS2_FIO_O_RDONLY 0x0001 #define PS2_FIO_O_WRONLY 0x0002 @@ -57,8 +57,8 @@ enum PS2Exception EXCEPTION_INTEGER_OVERFLOW = 0x0C, // From MIPS spec }; -// PS2 CPU context (R5900) -struct alignas(16) R5900Context +// PS2 CPU context (Emotion Engine R5900) +struct alignas(16) Ps2CpuContext { // General Purpose Registers (128-bit) __m128i r[32]; // Main registers @@ -99,7 +99,7 @@ struct alignas(16) R5900Context uint32_t vu0_itop; uint32_t vu0_info; uint32_t vu0_xitop; // VU0 XITOP - input ITOP for VIF/VU sync - uint32_t vu0_pc; + uint32_t vu0_pc; float vu0_cf[4]; // VU0 FMAC control floating-point registers @@ -134,7 +134,7 @@ struct alignas(16) R5900Context float f[32]; uint32_t fcr31; // Control/status register - R5900Context() + Ps2CpuContext() { for (int i = 0; i < 32; i++) { @@ -184,7 +184,6 @@ struct alignas(16) R5900Context vu0_itop = 0; vu0_info = 0; - // Reset COP0 registers cop0_index = 0; cop0_random = 47; // Start at maximum value @@ -235,10 +234,10 @@ struct alignas(16) R5900Context std::cout.flags(flags); // Restore format flags } - ~R5900Context() = default; + ~Ps2CpuContext() = default; }; -inline uint32_t getRegU32(const R5900Context *ctx, int reg) +inline uint32_t getRegU32(const Ps2CpuContext *ctx, int reg) { // Check if reg is valid (0-31) if (reg < 0 || reg > 31) @@ -246,17 +245,17 @@ inline uint32_t getRegU32(const R5900Context *ctx, int reg) return ctx->r[reg].m128i_u32[0]; } -inline void setReturnU32(R5900Context *ctx, uint32_t value) +inline void setReturnU32(Ps2CpuContext *ctx, uint32_t value) { ctx->r[2] = _mm_set_epi32(0, 0, 0, value); // $v0 } -inline void setReturnS32(R5900Context *ctx, int32_t value) +inline void setReturnS32(Ps2CpuContext *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) +inline void setReturnU64(Ps2CpuContext *ctx, uint64_t value) { // 64-bit returns use $v0/$v1 (r2/r3) ctx->r[2] = _mm_set_epi32(0, 0, 0, static_cast(value)); @@ -447,31 +446,31 @@ class PS2Runtime bool loadELF(const std::string &elfPath); void run(); - using RecompiledFunction = void (*)(uint8_t *, R5900Context *, PS2Runtime *); + using RecompiledFunction = void (*)(uint8_t *, Ps2CpuContext *, PS2Runtime *); void registerFunction(uint32_t address, RecompiledFunction func); RecompiledFunction lookupFunction(uint32_t address); bool hasFunction(uint32_t address) const; - void SignalException(R5900Context *ctx, PS2Exception exception); + void SignalException(Ps2CpuContext *ctx, PS2Exception exception); - void executeVU0Microprogram(uint8_t *rdram, R5900Context *ctx, uint32_t address); - void vu0StartMicroProgram(uint8_t *rdram, R5900Context *ctx, uint32_t address); + void executeVU0Microprogram(uint8_t *rdram, Ps2CpuContext *ctx, uint32_t address); + void vu0StartMicroProgram(uint8_t *rdram, Ps2CpuContext *ctx, uint32_t address); public: - void handleSyscall(uint8_t *rdram, R5900Context *ctx); - void handleBreak(uint8_t *rdram, R5900Context *ctx); + void handleSyscall(uint8_t *rdram, Ps2CpuContext *ctx); + void handleBreak(uint8_t *rdram, Ps2CpuContext *ctx); - void handleTrap(uint8_t *rdram, R5900Context *ctx); - void handleTLBR(uint8_t *rdram, R5900Context *ctx); - void handleTLBWI(uint8_t *rdram, R5900Context *ctx); - void handleTLBWR(uint8_t *rdram, R5900Context *ctx); - void handleTLBP(uint8_t *rdram, R5900Context *ctx); - void clearLLBit(R5900Context *ctx); + void handleTrap(uint8_t *rdram, Ps2CpuContext *ctx); + void handleTLBR(uint8_t *rdram, Ps2CpuContext *ctx); + void handleTLBWI(uint8_t *rdram, Ps2CpuContext *ctx); + void handleTLBWR(uint8_t *rdram, Ps2CpuContext *ctx); + void handleTLBP(uint8_t *rdram, Ps2CpuContext *ctx); + void clearLLBit(Ps2CpuContext *ctx); public: - inline R5900Context &cpu() { return m_cpuContext; } - inline const R5900Context &cpu() const { return m_cpuContext; } + inline Ps2CpuContext &cpu() { return m_cpuContext; } + inline const Ps2CpuContext &cpu() const { return m_cpuContext; } inline PS2Memory &memory() { return m_memory; } inline const PS2Memory &memory() const { return m_memory; } @@ -480,11 +479,11 @@ class PS2Runtime bool check_overflow = false; private: - void HandleIntegerOverflow(R5900Context *ctx); + void HandleIntegerOverflow(Ps2CpuContext *ctx); private: PS2Memory m_memory; - R5900Context m_cpuContext; + Ps2CpuContext m_cpuContext; std::unordered_map m_functionTable; diff --git a/ps2xRuntime/include/ps2_stubs.h b/ps2xRuntime/include/ps2_stubs.h index 213c048..c52ba25 100644 --- a/ps2xRuntime/include/ps2_stubs.h +++ b/ps2xRuntime/include/ps2_stubs.h @@ -7,12 +7,12 @@ namespace ps2_stubs { - #define PS2_DECLARE_STUB(name) void name(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime); + #define PS2_DECLARE_STUB(name) void name(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime); PS2_STUB_LIST(PS2_DECLARE_STUB) #undef PS2_DECLARE_STUB - void TODO(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime); - void TODO_NAMED(const char *name, uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime); + void TODO(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime); + void TODO_NAMED(const char *name, uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime); } #endif // PS2_STUBS_H diff --git a/ps2xRuntime/include/ps2_syscalls.h b/ps2xRuntime/include/ps2_syscalls.h index 97a4457..0e09249 100644 --- a/ps2xRuntime/include/ps2_syscalls.h +++ b/ps2xRuntime/include/ps2_syscalls.h @@ -27,11 +27,11 @@ static std::mutex g_sys_fd_mutex; namespace ps2_syscalls { - #define PS2_DECLARE_SYSCALL(name) void name(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime); + #define PS2_DECLARE_SYSCALL(name) void name(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime); PS2_SYSCALL_LIST(PS2_DECLARE_SYSCALL) #undef PS2_DECLARE_SYSCALL - void TODO(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime); + void TODO(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime); } #endif // PS2_SYSCALLS_H diff --git a/ps2xRuntime/main_example.cpp b/ps2xRuntime/main_example.cpp index 7b1ce7e..3a552fd 100644 --- a/ps2xRuntime/main_example.cpp +++ b/ps2xRuntime/main_example.cpp @@ -5,7 +5,7 @@ // Example of how to use the PS2 runtime with recompiled code // Stub implementation for PS2 syscalls -void syscall(uint8_t *rdram, R5900Context *ctx) +void syscall(uint8_t *rdram, Ps2CpuContext *ctx) { uint32_t syscallNum = ctx->r[4].m128i_u32[0]; std::cout << "Syscall " << syscallNum << " called" << std::endl; @@ -43,14 +43,14 @@ void syscall(uint8_t *rdram, R5900Context *ctx) } // Example implementation of FlushCache -void FlushCache(uint8_t *rdram, R5900Context *ctx) +void FlushCache(uint8_t *rdram, Ps2CpuContext *ctx) { uint32_t cacheType = ctx->r[4].m128i_u32[0]; std::cout << "FlushCache called with type: " << cacheType << std::endl; } // Example implementation of a recompiled function -void recompiled_main(uint8_t *rdram, R5900Context *ctx) +void recompiled_main(uint8_t *rdram, Ps2CpuContext *ctx) { std::cout << "Running recompiled main function" << std::endl; diff --git a/ps2xRuntime/output/ps2_runtime_macros.h b/ps2xRuntime/output/ps2_runtime_macros.h index bf02183..abc803b 100644 --- a/ps2xRuntime/output/ps2_runtime_macros.h +++ b/ps2xRuntime/output/ps2_runtime_macros.h @@ -6,10 +6,12 @@ #include -inline uint32_t ps2_clz32(uint32_t val) { +inline uint32_t ps2_clz32(uint32_t val) +{ #if defined(_MSC_VER) unsigned long idx; - if (_BitScanReverse(&idx, val)) { + if (_BitScanReverse(&idx, val)) + { return 31u - idx; } return 32u; @@ -20,9 +22,25 @@ inline uint32_t ps2_clz32(uint32_t val) { // Basic MIPS arithmetic operations #define ADD32(a, b) ((uint32_t)((a) + (b))) -#define ADD32_OV(rs, rt, result32, overflow) do { int32_t _a = (int32_t)(rs); int32_t _b = (int32_t)(rt); int32_t _r = _a + _b; overflow = (((_a ^ _b) >= 0) && ((_a ^ _r) < 0)); result32 = (uint32_t)_r; } while (0); +#define ADD32_OV(rs, rt, result32, overflow) \ + do \ + { \ + int32_t _a = (int32_t)(rs); \ + int32_t _b = (int32_t)(rt); \ + int32_t _r = _a + _b; \ + overflow = (((_a ^ _b) >= 0) && ((_a ^ _r) < 0)); \ + result32 = (uint32_t)_r; \ + } while (0); #define SUB32(a, b) ((uint32_t)((a) - (b))) -#define SUB32_OV(rs, rt, result32, overflow) do { int32_t _a = (int32_t)(rs); int32_t _b = (int32_t)(rt); int32_t _r = _a - _b; overflow = (((_a ^ _b) < 0) && ((_a ^ _r) < 0)); result32 = (uint32_t)_r; } while (0); +#define SUB32_OV(rs, rt, result32, overflow) \ + do \ + { \ + int32_t _a = (int32_t)(rs); \ + int32_t _b = (int32_t)(rt); \ + int32_t _r = _a - _b; \ + overflow = (((_a ^ _b) < 0) && ((_a ^ _r) < 0)); \ + result32 = (uint32_t)_r; \ + } while (0); #define MUL32(a, b) ((uint32_t)((a) * (b))) #define DIV32(a, b) ((uint32_t)((a) / (b))) #define AND32(a, b) ((uint32_t)((a) & (b))) @@ -65,16 +83,16 @@ inline uint32_t ps2_clz32(uint32_t val) { #define PS2_VMULQ(a, q) _mm_mul_ps((__m128)(a), _mm_set1_ps(q)) // Memory access helpers -#define READ8(addr) (*(uint8_t*)((rdram) + ((addr) & PS2_RAM_MASK))) -#define READ16(addr) (*(uint16_t*)((rdram) + ((addr) & PS2_RAM_MASK))) -#define READ32(addr) (*(uint32_t*)((rdram) + ((addr) & PS2_RAM_MASK))) -#define READ64(addr) (*(uint64_t*)((rdram) + ((addr) & PS2_RAM_MASK))) -#define READ128(addr) (*((__m128i*)((rdram) + ((addr) & PS2_RAM_MASK)))) -#define WRITE8(addr, val) (*(uint8_t*)((rdram) + ((addr) & PS2_RAM_MASK)) = (val)) -#define WRITE16(addr, val) (*(uint16_t*)((rdram) + ((addr) & PS2_RAM_MASK)) = (val)) -#define WRITE32(addr, val) (*(uint32_t*)((rdram) + ((addr) & PS2_RAM_MASK)) = (val)) -#define WRITE64(addr, val) (*(uint64_t*)((rdram) + ((addr) & PS2_RAM_MASK)) = (val)) -#define WRITE128(addr, val) (*((__m128i*)((rdram) + ((addr) & PS2_RAM_MASK))) = (val)) +#define READ8(addr) (*(uint8_t *)((rdram) + ((addr) & PS2_RAM_MASK))) +#define READ16(addr) (*(uint16_t *)((rdram) + ((addr) & PS2_RAM_MASK))) +#define READ32(addr) (*(uint32_t *)((rdram) + ((addr) & PS2_RAM_MASK))) +#define READ64(addr) (*(uint64_t *)((rdram) + ((addr) & PS2_RAM_MASK))) +#define READ128(addr) (*((__m128i *)((rdram) + ((addr) & PS2_RAM_MASK)))) +#define WRITE8(addr, val) (*(uint8_t *)((rdram) + ((addr) & PS2_RAM_MASK)) = (val)) +#define WRITE16(addr, val) (*(uint16_t *)((rdram) + ((addr) & PS2_RAM_MASK)) = (val)) +#define WRITE32(addr, val) (*(uint32_t *)((rdram) + ((addr) & PS2_RAM_MASK)) = (val)) +#define WRITE64(addr, val) (*(uint64_t *)((rdram) + ((addr) & PS2_RAM_MASK)) = (val)) +#define WRITE128(addr, val) (*((__m128i *)((rdram) + ((addr) & PS2_RAM_MASK))) = (val)) #define PS2_PCGTW(a, b) _mm_cmpgt_epi32((__m128i)(a), (__m128i)(b)) #define PS2_PCGTH(a, b) _mm_cmpgt_epi16((__m128i)(a), (__m128i)(b)) @@ -88,47 +106,53 @@ inline uint32_t ps2_clz32(uint32_t val) { #define PS2_PPACW(a, b) _mm_packs_epi32((__m128i)(b), (__m128i)(a)) #define PS2_PPACH(a, b) _mm_packs_epi16((__m128i)(b), (__m128i)(a)) #define PS2_PPACB(a, b) _mm_packus_epi16(_mm_packs_epi32((__m128i)(b), (__m128i)(a)), _mm_setzero_si128()) -#define PS2_PINTH(a, b) _mm_unpacklo_epi16(_mm_shuffle_epi32((__m128i)(b), _MM_SHUFFLE(3,2,1,0)), _mm_shuffle_epi32((__m128i)(a), _MM_SHUFFLE(3,2,1,0))) -#define PS2_PINTEH(a, b) _mm_unpackhi_epi16(_mm_shuffle_epi32((__m128i)(b), _MM_SHUFFLE(3,2,1,0)), _mm_shuffle_epi32((__m128i)(a), _MM_SHUFFLE(3,2,1,0))) -#define PS2_PMADDW(a, b) _mm_add_epi32(_mm_mullo_epi32(_mm_shuffle_epi32((__m128i)(a), _MM_SHUFFLE(1,0,3,2)), _mm_shuffle_epi32((__m128i)(b), _MM_SHUFFLE(1,0,3,2))), _mm_mullo_epi32(_mm_shuffle_epi32((__m128i)(a), _MM_SHUFFLE(3,2,1,0)), _mm_shuffle_epi32((__m128i)(b), _MM_SHUFFLE(3,2,1,0)))) +#define PS2_PINTH(a, b) _mm_unpacklo_epi16(_mm_shuffle_epi32((__m128i)(b), _MM_SHUFFLE(3, 2, 1, 0)), _mm_shuffle_epi32((__m128i)(a), _MM_SHUFFLE(3, 2, 1, 0))) +#define PS2_PINTEH(a, b) _mm_unpackhi_epi16(_mm_shuffle_epi32((__m128i)(b), _MM_SHUFFLE(3, 2, 1, 0)), _mm_shuffle_epi32((__m128i)(a), _MM_SHUFFLE(3, 2, 1, 0))) +#define PS2_PMADDW(a, b) _mm_add_epi32(_mm_mullo_epi32(_mm_shuffle_epi32((__m128i)(a), _MM_SHUFFLE(1, 0, 3, 2)), _mm_shuffle_epi32((__m128i)(b), _MM_SHUFFLE(1, 0, 3, 2))), _mm_mullo_epi32(_mm_shuffle_epi32((__m128i)(a), _MM_SHUFFLE(3, 2, 1, 0)), _mm_shuffle_epi32((__m128i)(b), _MM_SHUFFLE(3, 2, 1, 0)))) #define PS2_PSLLVW(a, b) _mm_custom_sllv_epi32((__m128i)(a), (__m128i)(b)) #define PS2_PSRLVW(a, b) _mm_custom_srlv_epi32((__m128i)(a), (__m128i)(b)) #define PS2_PSRAVW(a, b) _mm_custom_srav_epi32((__m128i)(a), (__m128i)(b)) -inline __m128i _mm_custom_sllv_epi32(__m128i a, __m128i count) { +inline __m128i _mm_custom_sllv_epi32(__m128i a, __m128i count) +{ int32_t a_arr[4], count_arr[4], result[4]; - _mm_storeu_si128((__m128i*)a_arr, a); - _mm_storeu_si128((__m128i*)count_arr, count); - for (int i = 0; i < 4; i++) { + _mm_storeu_si128((__m128i *)a_arr, a); + _mm_storeu_si128((__m128i *)count_arr, count); + for (int i = 0; i < 4; i++) + { result[i] = a_arr[i] << (count_arr[i] & 0x1F); } - return _mm_loadu_si128((__m128i*)result); + return _mm_loadu_si128((__m128i *)result); } -inline __m128i _mm_custom_srlv_epi32(__m128i a, __m128i count) { +inline __m128i _mm_custom_srlv_epi32(__m128i a, __m128i count) +{ int32_t a_arr[4], count_arr[4], result[4]; - _mm_storeu_si128((__m128i*)a_arr, a); - _mm_storeu_si128((__m128i*)count_arr, count); - for (int i = 0; i < 4; i++) { + _mm_storeu_si128((__m128i *)a_arr, a); + _mm_storeu_si128((__m128i *)count_arr, count); + for (int i = 0; i < 4; i++) + { result[i] = (uint32_t)a_arr[i] >> (count_arr[i] & 0x1F); } - return _mm_loadu_si128((__m128i*)result); + return _mm_loadu_si128((__m128i *)result); } -inline __m128i _mm_custom_srav_epi32(__m128i a, __m128i count) { +inline __m128i _mm_custom_srav_epi32(__m128i a, __m128i count) +{ int32_t a_arr[4], count_arr[4], result[4]; - _mm_storeu_si128((__m128i*)a_arr, a); - _mm_storeu_si128((__m128i*)count_arr, count); - for (int i = 0; i < 4; i++) { + _mm_storeu_si128((__m128i *)a_arr, a); + _mm_storeu_si128((__m128i *)count_arr, count); + for (int i = 0; i < 4; i++) + { result[i] = a_arr[i] >> (count_arr[i] & 0x1F); } - return _mm_loadu_si128((__m128i*)result); + return _mm_loadu_si128((__m128i *)result); } #define PS2_PMFHL_LW(hi, lo) _mm_unpacklo_epi64(lo, hi) #define PS2_PMFHL_UW(hi, lo) _mm_unpackhi_epi64(lo, hi) #define PS2_PMFHL_SLW(hi, lo) _mm_packs_epi32(lo, hi) -#define PS2_PMFHL_LH(hi, lo) _mm_shuffle_epi32(_mm_packs_epi32(lo, hi), _MM_SHUFFLE(3,1,2,0)) -#define PS2_PMFHL_SH(hi, lo) _mm_shufflehi_epi16(_mm_shufflelo_epi16(_mm_packs_epi32(lo, hi), _MM_SHUFFLE(3,1,2,0)), _MM_SHUFFLE(3,1,2,0)) +#define PS2_PMFHL_LH(hi, lo) _mm_shuffle_epi32(_mm_packs_epi32(lo, hi), _MM_SHUFFLE(3, 1, 2, 0)) +#define PS2_PMFHL_SH(hi, lo) _mm_shufflehi_epi16(_mm_shufflelo_epi16(_mm_packs_epi32(lo, hi), _MM_SHUFFLE(3, 1, 2, 0)), _MM_SHUFFLE(3, 1, 2, 0)) // FPU (COP1) operations #define FPU_ADD_S(a, b) ((float)(a) + (float)(b)) #define FPU_SUB_S(a, b) ((float)(a) - (float)(b)) @@ -182,34 +206,34 @@ inline __m128i _mm_custom_srav_epi32(__m128i a, __m128i count) { #define GPR_U64(ctx_ptr, reg_idx) ((reg_idx == 0) ? 0ULL : ctx_ptr->r[reg_idx].m128i_u64[0]) #define GPR_S64(ctx_ptr, reg_idx) ((reg_idx == 0) ? 0LL : ctx_ptr->r[reg_idx].m128i_i64[0]) #define GPR_VEC(ctx_ptr, reg_idx) ((reg_idx == 0) ? _mm_setzero_si128() : ctx_ptr->r[reg_idx]) -#define SET_GPR_U32(ctx_ptr, reg_idx, val) \ - do \ - { \ - if (reg_idx != 0) \ +#define SET_GPR_U32(ctx_ptr, reg_idx, val) \ + do \ + { \ + if (reg_idx != 0) \ ctx_ptr->r[reg_idx] = _mm_set_epi32(0, 0, 0, (val)); \ } while (0) -#define SET_GPR_S32(ctx_ptr, reg_idx, val) \ - do \ - { \ - if (reg_idx != 0) \ +#define SET_GPR_S32(ctx_ptr, reg_idx, val) \ + do \ + { \ + if (reg_idx != 0) \ ctx_ptr->r[reg_idx] = _mm_set_epi32(0, 0, 0, (val)); \ } while (0) -#define SET_GPR_U64(ctx_ptr, reg_idx, val) \ - do \ - { \ - if (reg_idx != 0) \ +#define SET_GPR_U64(ctx_ptr, reg_idx, val) \ + do \ + { \ + if (reg_idx != 0) \ ctx_ptr->r[reg_idx] = _mm_set_epi64x(0, (val)); \ } while (0) -#define SET_GPR_S64(ctx_ptr, reg_idx, val) \ - do \ - { \ - if (reg_idx != 0) \ +#define SET_GPR_S64(ctx_ptr, reg_idx, val) \ + do \ + { \ + if (reg_idx != 0) \ ctx_ptr->r[reg_idx] = _mm_set_epi64x(0, (val)); \ } while (0) #define SET_GPR_VEC(ctx_ptr, reg_idx, val) \ do \ { \ if (reg_idx != 0) \ - ctx_ptr->r[reg_idx] = (val); \ + ctx_ptr->r[reg_idx] = (val); \ } while (0) #endif // PS2_RUNTIME_MACROS_H diff --git a/ps2xRuntime/src/lib/ps2_runtime.cpp b/ps2xRuntime/src/lib/ps2_runtime.cpp index cd82a87..d397ec7 100644 --- a/ps2xRuntime/src/lib/ps2_runtime.cpp +++ b/ps2xRuntime/src/lib/ps2_runtime.cpp @@ -165,7 +165,6 @@ static void UploadFrame(Texture2D &tex, PS2Runtime *rt) UpdateTexture(tex, scratch.data()); } - PS2Runtime::PS2Runtime() { std::memset(&m_cpuContext, 0, sizeof(m_cpuContext)); @@ -305,7 +304,7 @@ PS2Runtime::RecompiledFunction PS2Runtime::lookupFunction(uint32_t address) std::cerr << "Warning: Function at address 0x" << std::hex << address << std::dec << " not found" << std::endl; - static RecompiledFunction defaultFunction = [](uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + static RecompiledFunction defaultFunction = [](uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { std::cerr << "Error: Called unimplemented function at address 0x" << std::hex << ctx->pc << std::dec << std::endl; }; @@ -313,7 +312,7 @@ PS2Runtime::RecompiledFunction PS2Runtime::lookupFunction(uint32_t address) return defaultFunction; } -void PS2Runtime::SignalException(R5900Context *ctx, PS2Exception exception) +void PS2Runtime::SignalException(Ps2CpuContext *ctx, PS2Exception exception) { if (exception == EXCEPTION_INTEGER_OVERFLOW) { @@ -322,8 +321,7 @@ void PS2Runtime::SignalException(R5900Context *ctx, PS2Exception exception) } } - -void PS2Runtime::executeVU0Microprogram(uint8_t *rdram, R5900Context *ctx, uint32_t address) +void PS2Runtime::executeVU0Microprogram(uint8_t *rdram, Ps2CpuContext *ctx, uint32_t address) { static std::unordered_map seen; int &count = seen[address]; @@ -346,54 +344,54 @@ void PS2Runtime::executeVU0Microprogram(uint8_t *rdram, R5900Context *ctx, uint3 // TODO: Implement a real interpreter. For now, no register mutations beyond defaults. } -void PS2Runtime::vu0StartMicroProgram(uint8_t *rdram, R5900Context *ctx, uint32_t address) +void PS2Runtime::vu0StartMicroProgram(uint8_t *rdram, Ps2CpuContext *ctx, uint32_t address) { // VCALLMS/VCALLMSR paths both end up here; reuse the same minimal stub. executeVU0Microprogram(rdram, ctx, address); } -void PS2Runtime::handleSyscall(uint8_t *rdram, R5900Context *ctx) +void PS2Runtime::handleSyscall(uint8_t *rdram, Ps2CpuContext *ctx) { std::cout << "Syscall encountered at PC: 0x" << std::hex << ctx->pc << std::dec << std::endl; } -void PS2Runtime::handleBreak(uint8_t *rdram, R5900Context *ctx) +void PS2Runtime::handleBreak(uint8_t *rdram, Ps2CpuContext *ctx) { std::cout << "Break encountered at PC: 0x" << std::hex << ctx->pc << std::dec << std::endl; } -void PS2Runtime::handleTrap(uint8_t *rdram, R5900Context *ctx) +void PS2Runtime::handleTrap(uint8_t *rdram, Ps2CpuContext *ctx) { std::cout << "Trap encountered at PC: 0x" << std::hex << ctx->pc << std::dec << std::endl; } -void PS2Runtime::handleTLBR(uint8_t *rdram, R5900Context *ctx) +void PS2Runtime::handleTLBR(uint8_t *rdram, Ps2CpuContext *ctx) { std::cout << "TLBR (TLB Read) at PC: 0x" << std::hex << ctx->pc << std::dec << std::endl; } -void PS2Runtime::handleTLBWI(uint8_t *rdram, R5900Context *ctx) +void PS2Runtime::handleTLBWI(uint8_t *rdram, Ps2CpuContext *ctx) { std::cout << "TLBWI (TLB Write Indexed) at PC: 0x" << std::hex << ctx->pc << std::dec << std::endl; } -void PS2Runtime::handleTLBWR(uint8_t *rdram, R5900Context *ctx) +void PS2Runtime::handleTLBWR(uint8_t *rdram, Ps2CpuContext *ctx) { std::cout << "TLBWR (TLB Write Random) at PC: 0x" << std::hex << ctx->pc << std::dec << std::endl; } -void PS2Runtime::handleTLBP(uint8_t *rdram, R5900Context *ctx) +void PS2Runtime::handleTLBP(uint8_t *rdram, Ps2CpuContext *ctx) { std::cout << "TLBP (TLB Probe) at PC: 0x" << std::hex << ctx->pc << std::dec << std::endl; } -void PS2Runtime::clearLLBit(R5900Context *ctx) +void PS2Runtime::clearLLBit(Ps2CpuContext *ctx) { ctx->cop0_status &= ~0x00000002; // LL bit is bit 1 in the status register std::cout << "LL bit cleared at PC: 0x" << std::hex << ctx->pc << std::dec << std::endl; } -void PS2Runtime::HandleIntegerOverflow(R5900Context *ctx) +void PS2Runtime::HandleIntegerOverflow(Ps2CpuContext *ctx) { std::cerr << "Integer overflow exception at PC: 0x" << std::hex << ctx->pc << std::dec << std::endl; diff --git a/ps2xRuntime/src/lib/ps2_stubs.cpp b/ps2xRuntime/src/lib/ps2_stubs.cpp index f7d4b96..ef9bfc3 100644 --- a/ps2xRuntime/src/lib/ps2_stubs.cpp +++ b/ps2xRuntime/src/lib/ps2_stubs.cpp @@ -87,7 +87,7 @@ namespace namespace ps2_stubs { - void malloc(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void malloc(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { size_t size = getRegU32(ctx, 4); // $a0 uint32_t handle = 0; @@ -112,7 +112,7 @@ namespace ps2_stubs setReturnU32(ctx, handle); } - void free(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void free(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t handle = getRegU32(ctx, 4); // $a0 @@ -138,7 +138,7 @@ namespace ps2_stubs // free dont have return } - void calloc(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void calloc(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { size_t num = getRegU32(ctx, 4); // $a0 size_t size = getRegU32(ctx, 5); // $a1 @@ -165,7 +165,7 @@ namespace ps2_stubs setReturnU32(ctx, handle); } - void realloc(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void realloc(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t old_handle = getRegU32(ctx, 4); // $a0 size_t new_size = getRegU32(ctx, 5); // $a1 @@ -247,7 +247,7 @@ namespace ps2_stubs setReturnU32(ctx, new_handle); } - void memcpy(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void memcpy(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t destAddr = getRegU32(ctx, 4); // $a0 uint32_t srcAddr = getRegU32(ctx, 5); // $a1 @@ -272,7 +272,7 @@ namespace ps2_stubs ctx->r[2] = ctx->r[4]; } - void memset(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void memset(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t destAddr = getRegU32(ctx, 4); // $a0 int value = (int)(getRegU32(ctx, 5) & 0xFF); // $a1 (char value) @@ -293,7 +293,7 @@ namespace ps2_stubs ctx->r[2] = ctx->r[4]; } - void memmove(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void memmove(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t destAddr = getRegU32(ctx, 4); // $a0 uint32_t srcAddr = getRegU32(ctx, 5); // $a1 @@ -318,7 +318,7 @@ namespace ps2_stubs ctx->r[2] = ctx->r[4]; } - void memcmp(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void memcmp(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t ptr1Addr = getRegU32(ctx, 4); // $a0 uint32_t ptr2Addr = getRegU32(ctx, 5); // $a1 @@ -346,7 +346,7 @@ namespace ps2_stubs setReturnS32(ctx, result); } - void strcpy(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void strcpy(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t destAddr = getRegU32(ctx, 4); // $a0 uint32_t srcAddr = getRegU32(ctx, 5); // $a1 @@ -370,7 +370,7 @@ namespace ps2_stubs ctx->r[2] = ctx->r[4]; } - void strncpy(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void strncpy(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t destAddr = getRegU32(ctx, 4); // $a0 uint32_t srcAddr = getRegU32(ctx, 5); // $a1 @@ -394,7 +394,7 @@ namespace ps2_stubs ctx->r[2] = ctx->r[4]; } - void strlen(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void strlen(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t strAddr = getRegU32(ctx, 4); // $a0 const char *hostStr = reinterpret_cast(getConstMemPtr(rdram, strAddr)); @@ -411,7 +411,7 @@ namespace ps2_stubs setReturnU32(ctx, (uint32_t)len); } - void strcmp(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void strcmp(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t str1Addr = getRegU32(ctx, 4); // $a0 uint32_t str2Addr = getRegU32(ctx, 5); // $a1 @@ -438,7 +438,7 @@ namespace ps2_stubs setReturnS32(ctx, result); } - void strncmp(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void strncmp(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t str1Addr = getRegU32(ctx, 4); // $a0 uint32_t str2Addr = getRegU32(ctx, 5); // $a1 @@ -465,7 +465,7 @@ namespace ps2_stubs setReturnS32(ctx, result); } - void strcat(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void strcat(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t destAddr = getRegU32(ctx, 4); // $a0 uint32_t srcAddr = getRegU32(ctx, 5); // $a1 @@ -489,7 +489,7 @@ namespace ps2_stubs ctx->r[2] = ctx->r[4]; } - void strncat(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void strncat(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t destAddr = getRegU32(ctx, 4); // $a0 uint32_t srcAddr = getRegU32(ctx, 5); // $a1 @@ -514,7 +514,7 @@ namespace ps2_stubs ctx->r[2] = ctx->r[4]; } - void strchr(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void strchr(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t strAddr = getRegU32(ctx, 4); // $a0 int char_code = (int)(getRegU32(ctx, 5) & 0xFF); // $a1 (char value) @@ -540,7 +540,7 @@ namespace ps2_stubs setReturnU32(ctx, resultAddr); } - void strrchr(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void strrchr(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t strAddr = getRegU32(ctx, 4); // $a0 int char_code = (int)(getRegU32(ctx, 5) & 0xFF); // $a1 (char value) @@ -566,7 +566,7 @@ namespace ps2_stubs setReturnU32(ctx, resultAddr); } - void strstr(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void strstr(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t haystackAddr = getRegU32(ctx, 4); // $a0 uint32_t needleAddr = getRegU32(ctx, 5); // $a1 @@ -596,7 +596,7 @@ namespace ps2_stubs setReturnU32(ctx, resultAddr); } - void printf(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void printf(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t format_addr = getRegU32(ctx, 4); // $a0 const char *format = reinterpret_cast(getConstMemPtr(rdram, format_addr)); @@ -618,7 +618,7 @@ namespace ps2_stubs setReturnS32(ctx, ret); } - void sprintf(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void sprintf(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t str_addr = getRegU32(ctx, 4); // $a0 uint32_t format_addr = getRegU32(ctx, 5); // $a1 @@ -645,7 +645,7 @@ namespace ps2_stubs setReturnS32(ctx, ret); } - void snprintf(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void snprintf(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t str_addr = getRegU32(ctx, 4); // $a0 size_t size = getRegU32(ctx, 5); // $a1 @@ -679,7 +679,7 @@ namespace ps2_stubs setReturnS32(ctx, ret); } - void puts(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void puts(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t strAddr = getRegU32(ctx, 4); // $a0 const char *hostStr = reinterpret_cast(getConstMemPtr(rdram, strAddr)); @@ -699,7 +699,7 @@ namespace ps2_stubs setReturnS32(ctx, result >= 0 ? 0 : -1); // PS2 might expect 0/-1 rather than EOF } - void fopen(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fopen(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t pathAddr = getRegU32(ctx, 4); // $a0 uint32_t modeAddr = getRegU32(ctx, 5); // $a1 @@ -737,7 +737,7 @@ namespace ps2_stubs setReturnU32(ctx, file_handle); } - void fclose(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fclose(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t file_handle = getRegU32(ctx, 4); // $a0 int ret = EOF; // Default to error @@ -767,7 +767,7 @@ namespace ps2_stubs setReturnS32(ctx, ret); } - void fread(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fread(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t ptrAddr = getRegU32(ctx, 4); // $a0 (buffer) uint32_t size = getRegU32(ctx, 5); // $a1 (element size) @@ -793,7 +793,7 @@ namespace ps2_stubs setReturnU32(ctx, (uint32_t)items_read); } - void fwrite(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fwrite(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t ptrAddr = getRegU32(ctx, 4); // $a0 (buffer) uint32_t size = getRegU32(ctx, 5); // $a1 (element size) @@ -819,7 +819,7 @@ namespace ps2_stubs setReturnU32(ctx, (uint32_t)items_written); } - void fprintf(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fprintf(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t file_handle = getRegU32(ctx, 4); // $a0 uint32_t format_addr = getRegU32(ctx, 5); // $a1 @@ -844,7 +844,7 @@ namespace ps2_stubs setReturnS32(ctx, ret); } - void fseek(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fseek(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t file_handle = getRegU32(ctx, 4); // $a0 long offset = (long)getRegU32(ctx, 5); // $a1 (Note: might need 64-bit for large files?) @@ -874,7 +874,7 @@ namespace ps2_stubs setReturnS32(ctx, ret); } - void ftell(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void ftell(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t file_handle = getRegU32(ctx, 4); // $a0 long ret = -1L; @@ -901,7 +901,7 @@ namespace ps2_stubs } } - void fflush(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fflush(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t file_handle = getRegU32(ctx, 4); // $a0 int ret = EOF; // Default error @@ -927,81 +927,81 @@ namespace ps2_stubs setReturnS32(ctx, ret); } - void sqrt(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void sqrt(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { float arg = ctx->f[12]; ctx->f[0] = ::sqrtf(arg); } - void sin(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void sin(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { float arg = ctx->f[12]; ctx->f[0] = ::sinf(arg); } - void cos(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void cos(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { float arg = ctx->f[12]; ctx->f[0] = ::cosf(arg); } - void tan(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void tan(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { float arg = ctx->f[12]; ctx->f[0] = ::tanf(arg); } - void atan2(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void atan2(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { float y = ctx->f[12]; float x = ctx->f[14]; ctx->f[0] = ::atan2f(y, x); } - void pow(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void pow(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { float base = ctx->f[12]; float exp = ctx->f[14]; ctx->f[0] = ::powf(base, exp); } - void exp(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void exp(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { float arg = ctx->f[12]; ctx->f[0] = ::expf(arg); } - void log(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void log(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { float arg = ctx->f[12]; ctx->f[0] = ::logf(arg); } - void log10(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void log10(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { float arg = ctx->f[12]; ctx->f[0] = ::log10f(arg); } - void ceil(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void ceil(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { float arg = ctx->f[12]; ctx->f[0] = ::ceilf(arg); } - void floor(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void floor(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { float arg = ctx->f[12]; ctx->f[0] = ::floorf(arg); } - void fabs(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fabs(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { float arg = ctx->f[12]; ctx->f[0] = ::fabsf(arg); } - void sceCdRead(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void sceCdRead(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t lbn = getRegU32(ctx, 4); // $a0 - logical block number uint32_t sectors = getRegU32(ctx, 5); // $a1 - sector count @@ -1029,7 +1029,7 @@ namespace ps2_stubs setReturnS32(ctx, 1); // Success } - void sceCdSync(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void sceCdSync(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1041,7 +1041,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); // 0 = completed/not busy } - void sceCdGetError(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void sceCdGetError(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1053,7 +1053,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); // no error } - void njSetBorderColor(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void njSetBorderColor(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1064,7 +1064,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void njSetTextureMemorySize(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void njSetTextureMemorySize(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1075,7 +1075,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void njInitVertexBuffer(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void njInitVertexBuffer(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1086,7 +1086,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void njTextureShadingMode(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void njTextureShadingMode(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1097,7 +1097,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void njInitView(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void njInitView(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1108,7 +1108,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void njSetAspect(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void njSetAspect(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1119,7 +1119,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void njInitSystem(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void njInitSystem(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1130,7 +1130,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void njInitPrint(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void njInitPrint(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1141,7 +1141,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void njPolygonCullingMode(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void njPolygonCullingMode(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1152,7 +1152,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void njSetView(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void njSetView(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1163,7 +1163,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void njGetMatrix(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void njGetMatrix(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1174,7 +1174,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void njInitTexture(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void njInitTexture(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1185,7 +1185,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void njInitTextureBuffer(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void njInitTextureBuffer(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1196,7 +1196,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void njSetPaletteMode(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void njSetPaletteMode(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1207,7 +1207,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void njClipZ(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void njClipZ(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1218,7 +1218,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void syRtcInit(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void syRtcInit(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1229,7 +1229,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void _builtin_set_imask(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void _builtin_set_imask(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1240,7 +1240,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void syFree(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void syFree(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1251,7 +1251,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void InitSdcParameter(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void InitSdcParameter(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1262,7 +1262,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void Ps2_pad_actuater(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void Ps2_pad_actuater(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1273,7 +1273,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void syMallocInit(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void syMallocInit(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1284,7 +1284,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void syHwInit(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void syHwInit(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1295,7 +1295,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void syHwInit2(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void syHwInit2(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1306,7 +1306,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void InitGdSystemEx(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void InitGdSystemEx(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1317,7 +1317,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void pdInitPeripheral(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void pdInitPeripheral(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1328,7 +1328,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void njSetVertexBuffer(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void njSetVertexBuffer(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1339,7 +1339,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void njPrintSize(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void njPrintSize(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1350,7 +1350,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void pdGetPeripheral(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void pdGetPeripheral(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1361,7 +1361,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void Ps2SwapDBuff(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void Ps2SwapDBuff(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1372,7 +1372,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void InitReadKeyEx(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void InitReadKeyEx(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1383,7 +1383,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void SetRepeatKeyTimer(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SetRepeatKeyTimer(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1394,7 +1394,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void StopFxProgram(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void StopFxProgram(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1405,7 +1405,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void sndr_trans_func(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void sndr_trans_func(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1428,7 +1428,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void sdDrvInit(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void sdDrvInit(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1439,7 +1439,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void ADXF_LoadPartitionNw(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void ADXF_LoadPartitionNw(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1451,7 +1451,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void sdSndStopAll(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void sdSndStopAll(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1462,7 +1462,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void sdSysFinish(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void sdSysFinish(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1473,7 +1473,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void ADXT_Init(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void ADXT_Init(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1484,7 +1484,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void ADXT_SetNumRetry(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void ADXT_SetNumRetry(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1495,7 +1495,7 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void cvFsSetDefDev(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void cvFsSetDefDev(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 8) @@ -1506,12 +1506,12 @@ namespace ps2_stubs setReturnS32(ctx, 0); } - void TODO(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void TODO(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { TODO_NAMED("unknown", rdram, ctx, runtime); } - void TODO_NAMED(const char *name, uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void TODO_NAMED(const char *name, uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t stub_num = getRegU32(ctx, 2); // $v0 uint32_t caller_ra = getRegU32(ctx, 31); // $ra diff --git a/ps2xRuntime/src/lib/ps2_syscalls.cpp b/ps2xRuntime/src/lib/ps2_syscalls.cpp index 129323a..9a546a8 100644 --- a/ps2xRuntime/src/lib/ps2_syscalls.cpp +++ b/ps2xRuntime/src/lib/ps2_syscalls.cpp @@ -130,27 +130,27 @@ std::string translatePs2Path(const char *ps2Path) namespace ps2_syscalls { - void FlushCache(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void FlushCache(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { std::cout << "Syscall: FlushCache (No-op)" << std::endl; // No-op for now setReturnS32(ctx, 0); } - void ResetEE(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void ResetEE(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { 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, PS2Runtime *runtime) + void SetMemoryMode(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { // Affects memory mapping / TLB behavior. // std::cout << "Syscall: SetMemoryMode (No-op)" << std::endl; setReturnS32(ctx, 0); // Success } - void CreateThread(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void CreateThread(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t paramAddr = getRegU32(ctx, 4); // $a0 points to ThreadParam const uint32_t *param = reinterpret_cast(getConstMemPtr(rdram, paramAddr)); @@ -184,14 +184,14 @@ namespace ps2_syscalls setReturnS32(ctx, id); } - void DeleteThread(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void DeleteThread(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { int tid = static_cast(getRegU32(ctx, 4)); // $a0 g_threads.erase(tid); setReturnS32(ctx, 0); } - void StartThread(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void StartThread(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { int tid = static_cast(getRegU32(ctx, 4)); // $a0 = thread id uint32_t arg = getRegU32(ctx, 5); // $a1 = user arg @@ -235,8 +235,8 @@ namespace ps2_syscalls g_activeThreads.fetch_add(1, std::memory_order_relaxed); std::thread([=]() mutable { - R5900Context threadCtxCopy = *ctx; // Copy current CPU state to simulate a new thread context - R5900Context *threadCtx = &threadCtxCopy; + Ps2CpuContext threadCtxCopy = *ctx; // Copy current CPU state to simulate a new thread context + Ps2CpuContext *threadCtx = &threadCtxCopy; if (info.stack && info.stackSize) { @@ -278,27 +278,27 @@ namespace ps2_syscalls setReturnS32(ctx, 0); } - void ExitThread(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void ExitThread(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { std::cout << "PS2 ExitThread: Thread is exiting (PC=0x" << std::hex << ctx->pc << std::dec << ")" << std::endl; setReturnS32(ctx, 0); } - void ExitDeleteThread(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void ExitDeleteThread(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { int tid = static_cast(getRegU32(ctx, 4)); g_threads.erase(tid); setReturnS32(ctx, 0); } - void TerminateThread(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void TerminateThread(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { int tid = static_cast(getRegU32(ctx, 4)); g_threads.erase(tid); setReturnS32(ctx, 0); } - void SuspendThread(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SuspendThread(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; int tid = static_cast(getRegU32(ctx, 4)); @@ -310,22 +310,22 @@ namespace ps2_syscalls setReturnS32(ctx, 0); } - void ResumeThread(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void ResumeThread(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } - void GetThreadId(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void GetThreadId(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, g_currentThreadId); } - void ReferThreadStatus(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void ReferThreadStatus(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } - void SleepThread(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SleepThread(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 16) @@ -336,7 +336,7 @@ namespace ps2_syscalls setReturnS32(ctx, 0); } - void WakeupThread(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void WakeupThread(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; int tid = static_cast(getRegU32(ctx, 4)); @@ -348,7 +348,7 @@ namespace ps2_syscalls setReturnS32(ctx, 0); } - void iWakeupThread(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void iWakeupThread(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; int tid = static_cast(getRegU32(ctx, 4)); @@ -360,7 +360,7 @@ namespace ps2_syscalls setReturnS32(ctx, 0); } - void ChangeThreadPriority(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void ChangeThreadPriority(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { int tid = static_cast(getRegU32(ctx, 4)); int newPrio = static_cast(getRegU32(ctx, 5)); @@ -372,7 +372,7 @@ namespace ps2_syscalls setReturnS32(ctx, 0); } - void RotateThreadReadyQueue(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void RotateThreadReadyQueue(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; int prio = static_cast(getRegU32(ctx, 4)); @@ -389,17 +389,17 @@ namespace ps2_syscalls setReturnS32(ctx, 0); } - void ReleaseWaitThread(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void ReleaseWaitThread(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } - void iReleaseWaitThread(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void iReleaseWaitThread(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } - void CreateSema(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void CreateSema(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t paramAddr = getRegU32(ctx, 4); // $a0 const uint32_t *param = reinterpret_cast(getConstMemPtr(rdram, paramAddr)); @@ -429,14 +429,14 @@ namespace ps2_syscalls setReturnS32(ctx, id); } - void DeleteSema(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void DeleteSema(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { int sid = static_cast(getRegU32(ctx, 4)); g_semas.erase(sid); setReturnS32(ctx, 0); } - void SignalSema(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SignalSema(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { int sid = static_cast(getRegU32(ctx, 4)); auto it = g_semas.find(sid); @@ -453,12 +453,12 @@ namespace ps2_syscalls setReturnS32(ctx, 0); } - void iSignalSema(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void iSignalSema(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { SignalSema(rdram, ctx, runtime); } - void WaitSema(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void WaitSema(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { int sid = static_cast(getRegU32(ctx, 4)); auto it = g_semas.find(sid); @@ -491,7 +491,7 @@ namespace ps2_syscalls setReturnS32(ctx, 0); } - void PollSema(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void PollSema(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { int sid = static_cast(getRegU32(ctx, 4)); auto it = g_semas.find(sid); @@ -509,78 +509,78 @@ namespace ps2_syscalls setReturnS32(ctx, 0); } - void iPollSema(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void iPollSema(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { PollSema(rdram, ctx, runtime); } - void ReferSemaStatus(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void ReferSemaStatus(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } - void iReferSemaStatus(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void iReferSemaStatus(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { ReferSemaStatus(rdram, ctx, runtime); } - void CreateEventFlag(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void CreateEventFlag(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { // TODO } - void DeleteEventFlag(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void DeleteEventFlag(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { // TODO } - void SetEventFlag(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SetEventFlag(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { // TODO } - void iSetEventFlag(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void iSetEventFlag(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { // TODO } - void ClearEventFlag(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void ClearEventFlag(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { // TODO } - void iClearEventFlag(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void iClearEventFlag(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { // TODO } - void WaitEventFlag(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void WaitEventFlag(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { // TODO } - void PollEventFlag(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void PollEventFlag(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { // TODO } - void iPollEventFlag(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void iPollEventFlag(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { // TODO } - void ReferEventFlagStatus(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void ReferEventFlagStatus(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { // TODO } - void iReferEventFlagStatus(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void iReferEventFlagStatus(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { // TODO } // According to GPT the real PS2 uses a timer interrupt to invoke a callback. For now, fire the callback immediately - void SetAlarm(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SetAlarm(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t usec = getRegU32(ctx, 4); uint32_t handler = getRegU32(ctx, 5); @@ -598,8 +598,8 @@ namespace ps2_syscalls // If the handler looks like a semaphore id, just kick it now. if (arg) { - R5900Context localCtx = *ctx; - R5900Context *ctxPtr = &localCtx; + Ps2CpuContext localCtx = *ctx; + Ps2CpuContext *ctxPtr = &localCtx; SET_GPR_U32(ctxPtr, 4, arg); SignalSema(rdram, ctxPtr, runtime); } @@ -607,47 +607,47 @@ namespace ps2_syscalls setReturnS32(ctx, 0); } - void iSetAlarm(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void iSetAlarm(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { SetAlarm(rdram, ctx, runtime); } - void CancelAlarm(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void CancelAlarm(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } - void iCancelAlarm(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void iCancelAlarm(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { CancelAlarm(rdram, ctx, runtime); } - void EnableIntc(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void EnableIntc(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } - void DisableIntc(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void DisableIntc(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } - void EnableDmac(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void EnableDmac(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } - void DisableDmac(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void DisableDmac(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } - void SifStopModule(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SifStopModule(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } - void SifLoadModule(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SifLoadModule(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t pathAddr = getRegU32(ctx, 4); const char *path = reinterpret_cast(getConstMemPtr(rdram, pathAddr)); @@ -661,12 +661,12 @@ namespace ps2_syscalls setReturnS32(ctx, 1); } - void SifInitRpc(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SifInitRpc(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } - void SifBindRpc(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SifBindRpc(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t clientPtr = getRegU32(ctx, 4); uint32_t rpcId = getRegU32(ctx, 5); @@ -697,7 +697,7 @@ namespace ps2_syscalls setReturnS32(ctx, 0); } - void SifCallRpc(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SifCallRpc(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t clientPtr = getRegU32(ctx, 4); uint32_t rpcId = getRegU32(ctx, 5); @@ -724,37 +724,37 @@ namespace ps2_syscalls setReturnS32(ctx, 0); } - void SifRegisterRpc(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SifRegisterRpc(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } - void SifCheckStatRpc(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SifCheckStatRpc(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 1); } - void SifSetRpcQueue(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SifSetRpcQueue(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } - void SifRemoveRpcQueue(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SifRemoveRpcQueue(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } - void SifRemoveRpc(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SifRemoveRpc(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } - void sceSifCallRpc(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void sceSifCallRpc(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { SifCallRpc(rdram, ctx, runtime); } - void sceSifSendCmd(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void sceSifSendCmd(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { static int logCount = 0; if (logCount < 5) @@ -768,13 +768,13 @@ namespace ps2_syscalls setReturnS32(ctx, 0); } - void _sceRpcGetPacket(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void _sceRpcGetPacket(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t queuePtr = getRegU32(ctx, 4); setReturnS32(ctx, static_cast(queuePtr)); } - void fioOpen(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fioOpen(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t pathAddr = getRegU32(ctx, 4); // $a0 int flags = (int)getRegU32(ctx, 5); // $a1 (PS2 FIO flags) @@ -819,7 +819,7 @@ namespace ps2_syscalls setReturnS32(ctx, ps2Fd); } - void fioClose(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fioClose(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { int ps2Fd = (int)getRegU32(ctx, 4); // $a0 std::cout << "fioClose: fd=" << ps2Fd << std::endl; @@ -839,7 +839,7 @@ namespace ps2_syscalls setReturnS32(ctx, ret == 0 ? 0 : -1); } - void fioRead(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fioRead(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { int ps2Fd = (int)getRegU32(ctx, 4); // $a0 uint32_t bufAddr = getRegU32(ctx, 5); // $a1 @@ -884,7 +884,7 @@ namespace ps2_syscalls setReturnS32(ctx, (int32_t)bytesRead); } - void fioWrite(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fioWrite(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { int ps2Fd = (int)getRegU32(ctx, 4); // $a0 uint32_t bufAddr = getRegU32(ctx, 5); // $a1 @@ -933,7 +933,7 @@ namespace ps2_syscalls setReturnS32(ctx, (int32_t)bytesWritten); } - void fioLseek(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fioLseek(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { int ps2Fd = (int)getRegU32(ctx, 4); // $a0 int32_t offset = getRegU32(ctx, 5); // $a1 (PS2 seems to use 32-bit offset here commonly) @@ -993,7 +993,7 @@ namespace ps2_syscalls } } - void fioMkdir(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fioMkdir(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { // TODO maybe we dont need this. uint32_t pathAddr = getRegU32(ctx, 4); // $a0 @@ -1031,7 +1031,7 @@ namespace ps2_syscalls } } - void fioChdir(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fioChdir(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { // TODO maybe we dont need this as well. uint32_t pathAddr = getRegU32(ctx, 4); // $a0 @@ -1070,7 +1070,7 @@ namespace ps2_syscalls } } - void fioRmdir(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fioRmdir(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t pathAddr = getRegU32(ctx, 4); // $a0 const char *ps2Path = reinterpret_cast(getConstMemPtr(rdram, pathAddr)); @@ -1105,7 +1105,7 @@ namespace ps2_syscalls } } - void fioGetstat(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fioGetstat(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { // we wont implement this for now. uint32_t pathAddr = getRegU32(ctx, 4); // $a0 @@ -1138,7 +1138,7 @@ namespace ps2_syscalls setReturnS32(ctx, -1); } - void fioRemove(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void fioRemove(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t pathAddr = getRegU32(ctx, 4); // $a0 const char *ps2Path = reinterpret_cast(getConstMemPtr(rdram, pathAddr)); @@ -1174,7 +1174,7 @@ namespace ps2_syscalls } } - void GsSetCrt(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void GsSetCrt(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { 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 @@ -1185,7 +1185,7 @@ namespace ps2_syscalls << ", frameMode=" << frameMode << std::endl; } - void GsGetIMR(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void GsGetIMR(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { // 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. @@ -1196,14 +1196,14 @@ namespace ps2_syscalls setReturnU64(ctx, imr); // Return in $v0/$v1 } - void GsPutIMR(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void GsPutIMR(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { 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, PS2Runtime *runtime) + void GsSetVideoMode(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { int mode = getRegU32(ctx, 4); // $a0 - video mode (various flags) @@ -1212,7 +1212,7 @@ namespace ps2_syscalls // Do nothing for now. } - void GetOsdConfigParam(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void GetOsdConfigParam(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t paramAddr = getRegU32(ctx, 4); // $a0 - pointer to parameter structure @@ -1234,7 +1234,7 @@ namespace ps2_syscalls setReturnS32(ctx, 0); } - void SetOsdConfigParam(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SetOsdConfigParam(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t paramAddr = getRegU32(ctx, 4); // $a0 - pointer to parameter structure @@ -1252,7 +1252,7 @@ namespace ps2_syscalls setReturnS32(ctx, 0); } - void GetRomName(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void GetRomName(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t bufAddr = getRegU32(ctx, 4); // $a0 size_t bufSize = getRegU32(ctx, 5); // $a1 @@ -1278,7 +1278,7 @@ namespace ps2_syscalls setReturnS32(ctx, (int32_t)strlen(hostBuf)); } - void SifLoadElfPart(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SifLoadElfPart(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t pathAddr = getRegU32(ctx, 4); // $a0 - pointer to ELF path @@ -1288,7 +1288,7 @@ namespace ps2_syscalls setReturnS32(ctx, 1); // dummy return value for success } - void sceSifLoadModule(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void sceSifLoadModule(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t moduePath = getRegU32(ctx, 4); // $a0 - pointer to module path @@ -1300,19 +1300,19 @@ namespace ps2_syscalls setReturnS32(ctx, 1); } - void TODO(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void TODO(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t syscall_num = getRegU32(ctx, 3); // Syscall number usually in $v1 ($r3) for SYSCALL instr uint32_t caller_ra = getRegU32(ctx, 31); // $ra 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 @@ -1331,7 +1331,7 @@ namespace ps2_syscalls // 0x3C SetupThread: returns stack pointer (stack + stack_size) // args: $a0 = stack base, $a1 = stack size, $a2 = gp, $a3 = entry point - void SetupThread(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void SetupThread(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { uint32_t stackBase = getRegU32(ctx, 4); uint32_t stackSize = getRegU32(ctx, 5); @@ -1340,19 +1340,19 @@ namespace ps2_syscalls } // 0x5A QueryBootMode (stub): return 0 for now - void QueryBootMode(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void QueryBootMode(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } // 0x5B GetThreadTLS (stub): return 0 - void GetThreadTLS(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void GetThreadTLS(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } // 0x74 RegisterExitHandler (stub): return 0 - void RegisterExitHandler(uint8_t *rdram, R5900Context *ctx, PS2Runtime *runtime) + void RegisterExitHandler(uint8_t *rdram, Ps2CpuContext *ctx, PS2Runtime *runtime) { setReturnS32(ctx, 0); } diff --git a/ps2xTest/CMakeLists.txt b/ps2xTest/CMakeLists.txt index cf35bde..9f92afb 100644 --- a/ps2xTest/CMakeLists.txt +++ b/ps2xTest/CMakeLists.txt @@ -8,7 +8,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) add_executable(ps2x_tests src/main.cpp src/code_generator_tests.cpp - src/r5900_decoder_tests.cpp + src/decoder_tests.cpp ) target_include_directories(ps2x_tests PRIVATE diff --git a/ps2xTest/src/code_generator_tests.cpp b/ps2xTest/src/code_generator_tests.cpp index b0c9f72..fc1d93a 100644 --- a/ps2xTest/src/code_generator_tests.cpp +++ b/ps2xTest/src/code_generator_tests.cpp @@ -122,7 +122,7 @@ void register_code_generator_tests() Instruction j{}; j.address = 0x4000; j.opcode = OPCODE_J; - j.target = (targetSym.address >> 2) & 0x3FFFFFF; + j.target = targetSym.address; // absolute target address j.hasDelaySlot = true; j.raw = 0x08000000 | (j.target & 0x3FFFFFF); @@ -203,7 +203,7 @@ void register_code_generator_tests() Instruction j{}; j.address = 0x8000; j.opcode = OPCODE_J; - j.target = (targetSym.address >> 2) & 0x3FFFFFF; + j.target = targetSym.address; // absolute target address j.hasDelaySlot = true; j.raw = (OPCODE_J << 26) | (j.target & 0x3FFFFFF); Instruction delay = makeNop(0x8004); diff --git a/ps2xTest/src/r5900_decoder_tests.cpp b/ps2xTest/src/decoder_tests.cpp similarity index 74% rename from ps2xTest/src/r5900_decoder_tests.cpp rename to ps2xTest/src/decoder_tests.cpp index 2affebe..8ef09c8 100644 --- a/ps2xTest/src/r5900_decoder_tests.cpp +++ b/ps2xTest/src/decoder_tests.cpp @@ -1,11 +1,11 @@ #include "MiniTest.h" -#include "ps2recomp/r5900_decoder.h" +#include "ps2recomp/decoder.h" using namespace ps2recomp; -void register_r5900_decoder_tests() +void register_decoder_tests() { - MiniTest::Case("R5900Decoder", [](TestCase &tc) + MiniTest::Case("Decoder", [](TestCase &tc) { tc.Run("decodes JAL with jump target and call flag", [](TestCase &t) { // jal 0x00400000 at address 0x1000 => opcode 0x0C100000 (target = 0x00400000 >> 2) @@ -13,13 +13,12 @@ void register_r5900_decoder_tests() uint32_t target = 0x00400000; uint32_t raw = (OPCODE_JAL << 26) | ((target >> 2) & 0x03FFFFFF); - R5900Decoder decoder; - Instruction inst = decoder.decodeInstruction(address, raw); + Instruction inst = decodeInstruction(address, raw); t.IsTrue(inst.isJump, "jal should be marked as jump"); t.IsTrue(inst.isCall, "jal should be marked as call"); t.IsTrue(inst.hasDelaySlot, "jal has a delay slot"); - t.Equals(decoder.getJumpTarget(inst), target, "jal jump target should match encoded target"); + t.Equals(getJumpTarget(inst), target, "jal jump target should match encoded target"); }); tc.Run("J computes target with upper PC bits", [](TestCase &t) { @@ -28,12 +27,11 @@ void register_r5900_decoder_tests() uint32_t encodedTarget = 0x0123456; // 0x048D1598 >> 2, but we want lower bits of 0x1234560 uint32_t raw = (OPCODE_J << 26) | (encodedTarget & 0x03FFFFFF); - R5900Decoder decoder; - Instruction inst = decoder.decodeInstruction(address, raw); + Instruction inst = decodeInstruction(address, raw); uint32_t expectedPcUpper = (address + 4) & 0xF0000000; uint32_t expected = expectedPcUpper | (encodedTarget << 2); - t.Equals(decoder.getJumpTarget(inst), expected, "J target should combine PC upper bits with encoded target"); + t.Equals(getJumpTarget(inst), expected, "J target should combine PC upper bits with encoded target"); }); tc.Run("JR/JALR jump target is zero (dynamic)", [](TestCase &t) { @@ -41,12 +39,11 @@ void register_r5900_decoder_tests() uint32_t jrRaw = (OPCODE_SPECIAL << 26) | (2 << 21) | SPECIAL_JR; uint32_t jalrRaw = (OPCODE_SPECIAL << 26) | (3 << 21) | (31 << 11) | SPECIAL_JALR; - R5900Decoder decoder; - Instruction jr = decoder.decodeInstruction(address, jrRaw); - Instruction jalr = decoder.decodeInstruction(address + 4, jalrRaw); + Instruction jr = decodeInstruction(address, jrRaw); + Instruction jalr = decodeInstruction(address + 4, jalrRaw); - t.Equals(decoder.getJumpTarget(jr), 0u, "JR jump target should be unknown (0)"); - t.Equals(decoder.getJumpTarget(jalr), 0u, "JALR jump target should be unknown (0)"); + t.Equals(getJumpTarget(jr), 0u, "JR jump target should be unknown (0)"); + t.Equals(getJumpTarget(jalr), 0u, "JALR jump target should be unknown (0)"); }); tc.Run("decodes BEQ sets branch flags and target", [](TestCase &t) { @@ -55,13 +52,12 @@ void register_r5900_decoder_tests() uint16_t offset = 0x0004; uint32_t raw = (OPCODE_BEQ << 26) | (1 << 21) | (2 << 16) | offset; - R5900Decoder decoder; - Instruction inst = decoder.decodeInstruction(address, raw); + Instruction inst = decodeInstruction(address, raw); t.IsTrue(inst.isBranch, "beq should be marked as branch"); t.IsTrue(inst.hasDelaySlot, "beq has a delay slot"); uint32_t expectedTarget = address + 4 + (static_cast(offset) << 2); - t.Equals(decoder.getBranchTarget(inst), expectedTarget, "beq target should be computed from simmediate"); + t.Equals(getBranchTarget(inst), expectedTarget, "beq target should be computed from simmediate"); }); tc.Run("branch target sign-extends negative offset", [](TestCase &t) { @@ -69,11 +65,10 @@ void register_r5900_decoder_tests() int16_t negOffset = -4; // jump back 16 bytes uint32_t raw = (OPCODE_BNE << 26) | (1 << 21) | (2 << 16) | (negOffset & 0xFFFF); - R5900Decoder decoder; - Instruction inst = decoder.decodeInstruction(address, raw); + Instruction inst = decodeInstruction(address, raw); uint32_t expectedTarget = address + 4 + (static_cast(negOffset) << 2); - t.Equals(decoder.getBranchTarget(inst), expectedTarget, "negative branch offsets should sign-extend"); + t.Equals(getBranchTarget(inst), expectedTarget, "negative branch offsets should sign-extend"); }); tc.Run("decodes load/store flags", [](TestCase &t) { @@ -81,9 +76,8 @@ void register_r5900_decoder_tests() uint32_t lwRaw = (OPCODE_LW << 26) | (1 << 21) | (2 << 16) | 0x10; uint32_t swRaw = (OPCODE_SW << 26) | (3 << 21) | (4 << 16) | 0x20; - R5900Decoder decoder; - Instruction lw = decoder.decodeInstruction(address, lwRaw); - Instruction sw = decoder.decodeInstruction(address + 4, swRaw); + Instruction lw = decodeInstruction(address, lwRaw); + Instruction sw = decodeInstruction(address + 4, swRaw); t.IsTrue(lw.isLoad, "lw should be marked as load"); t.IsFalse(lw.isStore, "lw should not be marked as store"); @@ -95,8 +89,7 @@ void register_r5900_decoder_tests() uint32_t address = 0x4000; uint32_t raw = (OPCODE_SPECIAL << 26) | (31 << 21) | SPECIAL_JR; // jr $ra - R5900Decoder decoder; - Instruction inst = decoder.decodeInstruction(address, raw); + Instruction inst = decodeInstruction(address, raw); t.IsTrue(inst.isJump, "jr should be jump"); t.IsTrue(inst.isReturn, "jr $ra should be marked as return"); @@ -108,8 +101,7 @@ void register_r5900_decoder_tests() uint32_t rd = 5; uint32_t raw = (OPCODE_SPECIAL << 26) | (2 << 21) | (rd << 11) | SPECIAL_JALR; // jalr $v0, $a0 - R5900Decoder decoder; - Instruction inst = decoder.decodeInstruction(address, raw); + Instruction inst = decodeInstruction(address, raw); t.IsTrue(inst.isJump, "jalr should be jump"); t.IsTrue(inst.isCall, "jalr should be call"); @@ -122,8 +114,7 @@ void register_r5900_decoder_tests() // Use opcode 0x1C (MMI), rs=1, rt=2, rd=3, sa=MMI0_PADDW (0) uint32_t raw = (OPCODE_MMI << 26) | (1 << 21) | (2 << 16) | (3 << 11) | MMI0_PADDW; - R5900Decoder decoder; - Instruction inst = decoder.decodeInstruction(address, raw); + Instruction inst = decodeInstruction(address, raw); t.IsTrue(inst.isMMI, "MMI opcode should set isMMI"); t.IsTrue(inst.isMultimedia, "MMI opcode should set multimedia flag"); @@ -136,8 +127,7 @@ void register_r5900_decoder_tests() // COP2, rs = COP2_CO (macro), function = VU0_S2_VDIV (0x31) uint32_t raw = (OPCODE_COP2 << 26) | (COP2_CO << 21) | VU0_S2_VDIV; - R5900Decoder decoder; - Instruction inst = decoder.decodeInstruction(address, raw); + Instruction inst = decodeInstruction(address, raw); t.IsTrue(inst.isVU, "VU macro should set isVU"); t.IsTrue(inst.isMultimedia, "VU macro should set multimedia"); @@ -152,15 +142,14 @@ void register_r5900_decoder_tests() uint16_t offset = 0x2; uint32_t raw = (OPCODE_REGIMM << 26) | (1 << 21) | (REGIMM_BGEZAL << 16) | offset; - R5900Decoder decoder; - Instruction inst = decoder.decodeInstruction(address, raw); + Instruction inst = decodeInstruction(address, raw); t.IsTrue(inst.isBranch, "bgezal should be branch"); t.IsTrue(inst.isCall, "bgezal should be call (link)"); t.IsTrue(inst.hasDelaySlot, "bgezal has delay slot"); t.IsTrue(inst.modificationInfo.modifiesGPR, "bgezal should mark GPR modification for $ra"); uint32_t expectedTarget = address + 4 + (static_cast(offset) << 2); - t.Equals(decoder.getBranchTarget(inst), expectedTarget, "bgezal target should be computed"); + t.Equals(getBranchTarget(inst), expectedTarget, "bgezal target should be computed"); }); tc.Run("LL/SC modify control and set load/store flags", [](TestCase &t) { @@ -168,9 +157,8 @@ void register_r5900_decoder_tests() uint32_t llRaw = (OPCODE_LL << 26) | (2 << 21) | (3 << 16) | 0x10; uint32_t scRaw = (OPCODE_SC << 26) | (4 << 21) | (5 << 16) | 0x20; - R5900Decoder decoder; - Instruction ll = decoder.decodeInstruction(address, llRaw); - Instruction sc = decoder.decodeInstruction(address + 4, scRaw); + Instruction ll = decodeInstruction(address, llRaw); + Instruction sc = decodeInstruction(address + 4, scRaw); t.IsTrue(ll.isLoad, "ll should be load"); t.IsTrue(ll.modificationInfo.modifiesControl, "ll should modify control (LL bit)"); @@ -183,8 +171,7 @@ void register_r5900_decoder_tests() uint32_t address = 0xA000; uint32_t raw = (OPCODE_COP0 << 26) | (COP0_CO << 21) | COP0_CO_ERET; - R5900Decoder decoder; - Instruction inst = decoder.decodeInstruction(address, raw); + Instruction inst = decodeInstruction(address, raw); t.IsTrue(inst.isReturn, "eret should be marked as return"); t.IsFalse(inst.hasDelaySlot, "eret should not have a delay slot"); diff --git a/ps2xTest/src/main.cpp b/ps2xTest/src/main.cpp index 729b92e..77ce1a8 100644 --- a/ps2xTest/src/main.cpp +++ b/ps2xTest/src/main.cpp @@ -1,11 +1,11 @@ #include "MiniTest.h" void register_code_generator_tests(); -void register_r5900_decoder_tests(); +void register_decoder_tests(); int main() { register_code_generator_tests(); - register_r5900_decoder_tests(); + register_decoder_tests(); return MiniTest::Run(); }