diff --git a/Source/Project64-rsp-core/Project64-rsp-core.vcxproj b/Source/Project64-rsp-core/Project64-rsp-core.vcxproj index efe3d22af..3a083943d 100644 --- a/Source/Project64-rsp-core/Project64-rsp-core.vcxproj +++ b/Source/Project64-rsp-core/Project64-rsp-core.vcxproj @@ -66,6 +66,7 @@ + @@ -101,6 +102,7 @@ + diff --git a/Source/Project64-rsp-core/Project64-rsp-core.vcxproj.filters b/Source/Project64-rsp-core/Project64-rsp-core.vcxproj.filters index 58f3884d1..15ed5bbec 100644 --- a/Source/Project64-rsp-core/Project64-rsp-core.vcxproj.filters +++ b/Source/Project64-rsp-core/Project64-rsp-core.vcxproj.filters @@ -147,6 +147,9 @@ Source Files\Recompiler + + Source Files\Recompiler + @@ -242,5 +245,8 @@ Header Files\Recompiler + + Header Files\Recompiler + \ No newline at end of file diff --git a/Source/Project64-rsp-core/Recompiler/RspCodeBlock.cpp b/Source/Project64-rsp-core/Recompiler/RspCodeBlock.cpp new file mode 100644 index 000000000..a46a128ad --- /dev/null +++ b/Source/Project64-rsp-core/Recompiler/RspCodeBlock.cpp @@ -0,0 +1,86 @@ +#include "RspCodeBlock.h" +#include +#include + +RspCodeBlock::RspCodeBlock(CRSPSystem & System, uint32_t StartAddress, RspCodeType type) : + m_System(System), + m_StartAddress(StartAddress), + m_CodeType(type), + m_Valid(true) +{ + Analyze(); +} + +bool RspCodeBlock::Valid() const +{ + return m_Valid; +} + +void RspCodeBlock::Analyze(void) +{ + uint32_t Address = m_StartAddress; + uint8_t * IMEM = m_System.m_IMEM; + + enum EndHleTaskOp + { + J_0x1118 = 0x09000446 + }; + + bool FoundEnd = false; + for (;;) + { + RSPInstruction Instruction(Address, *(uint32_t *)(IMEM + (Address & 0xFFF))); + if (Instruction.IsConditionalBranch()) + { + uint32_t target = Instruction.ConditionalBranchTarget(); + if (std::find(m_BranchTargets.begin(), m_BranchTargets.end(), target) == m_BranchTargets.end()) + { + m_BranchTargets.insert(target); + } + } + else if (Instruction.IsStaticCall()) + { + uint32_t target = Instruction.StaticCallTarget(); + if (std::find(m_FunctionCalls.begin(), m_FunctionCalls.end(), target) == m_FunctionCalls.end()) + { + m_FunctionCalls.insert(target); + } + } + + m_Instructions.push_back(Instruction); + if (FoundEnd) + { + break; + } + if ((m_CodeType == RspCodeType_SUBROUTINE && Instruction.IsJumpReturn()) || + (m_CodeType == RspCodeType_TASK && Instruction.Value() == J_0x1118)) + { + bool JumpBeyond = false; + for (Addresses::iterator itr = m_BranchTargets.begin(); itr != m_BranchTargets.end(); itr++) + { + if (*itr > Address) + { + JumpBeyond = true; + break; + } + } + FoundEnd = !JumpBeyond; + } + Address += 4; + if (Address == 0x2000) + { + m_Valid = false; + return; + } + } + for (Addresses::iterator itr = m_FunctionCalls.begin(); itr != m_FunctionCalls.end(); itr++) + { + RspCodeBlockPtr FunctionCall = std::make_unique(m_System, *itr, RspCodeType_SUBROUTINE); + if (!FunctionCall->Valid()) + { + m_Valid = false; + return; + } + m_FunctionBlocks.push_back(std::move(FunctionCall)); + } +} diff --git a/Source/Project64-rsp-core/Recompiler/RspCodeBlock.h b/Source/Project64-rsp-core/Recompiler/RspCodeBlock.h new file mode 100644 index 000000000..b073a86bc --- /dev/null +++ b/Source/Project64-rsp-core/Recompiler/RspCodeBlock.h @@ -0,0 +1,42 @@ +#pragma once +#include +#include +#include +#include +#include + +class CRSPSystem; + +enum RspCodeType { + RspCodeType_TASK, + RspCodeType_SUBROUTINE, +}; + +class RspCodeBlock +{ + typedef std::vector RSPInstructions; + typedef std::set Addresses; + typedef std::unique_ptr RspCodeBlockPtr; + typedef std::vector RspCodeBlocks; + +public: + RspCodeBlock(CRSPSystem & System, uint32_t StartAddress, RspCodeType type); + + bool Valid() const; + +private: + RspCodeBlock(); + RspCodeBlock(const RspCodeBlock &); + RspCodeBlock & operator=(const RspCodeBlock &); + + void Analyze(); + + RSPInstructions m_Instructions; + uint32_t m_StartAddress; + RspCodeType m_CodeType; + CRSPSystem & m_System; + Addresses m_BranchTargets; + Addresses m_FunctionCalls; + RspCodeBlocks m_FunctionBlocks; + bool m_Valid; +}; \ No newline at end of file diff --git a/Source/Project64-rsp-core/cpu/RSPInstruction.h b/Source/Project64-rsp-core/cpu/RSPInstruction.h index 224959e86..1c0f34dfb 100644 --- a/Source/Project64-rsp-core/cpu/RSPInstruction.h +++ b/Source/Project64-rsp-core/cpu/RSPInstruction.h @@ -8,9 +8,16 @@ class RSPInstruction public: RSPInstruction(uint32_t Address, uint32_t Instruction); RSPInstruction & operator=(const RSPInstruction &); + RSPInstruction(const RSPInstruction & e); uint32_t Address() const; + uint32_t ConditionalBranchTarget() const; + uint32_t StaticCallTarget() const; bool IsBranch() const; + bool IsJumpReturn() const; + bool IsRegisterJump() const; + bool IsStaticCall() const; + bool IsConditionalBranch() const; bool IsNop() const; const char * Name() const; const char * Param() const; @@ -19,7 +26,6 @@ public: private: RSPInstruction(void); - RSPInstruction(const RSPInstruction &); void DecodeName(void) const; void DecodeSpecialName(void) const; diff --git a/Source/Project64-rsp-core/cpu/RSPiInstruction.cpp b/Source/Project64-rsp-core/cpu/RSPiInstruction.cpp index 29866ec99..9a0f3db81 100644 --- a/Source/Project64-rsp-core/cpu/RSPiInstruction.cpp +++ b/Source/Project64-rsp-core/cpu/RSPiInstruction.cpp @@ -20,11 +20,52 @@ RSPInstruction & RSPInstruction::operator=(const RSPInstruction & e) return *this; } +RSPInstruction::RSPInstruction(const RSPInstruction & e) : + m_Address(e.m_Address) +{ + m_Name[0] = '\0'; + m_Param[0] = '\0'; + m_Instruction.Value = e.m_Instruction.Value; +} + uint32_t RSPInstruction::Address() const { return m_Address; } +uint32_t RSPInstruction::ConditionalBranchTarget() const +{ + if (!IsConditionalBranch()) + { + return 0; + } + return (m_Address + 4 + ((short)m_Instruction.offset << 2)) & 0x1FFC; +} + +uint32_t RSPInstruction::StaticCallTarget() const +{ + if (!IsStaticCall()) + { + return 0; + } + return 0x1000 | (m_Instruction.target << 2) & 0xFFC; +} + +bool RSPInstruction::IsJumpReturn() const +{ + return IsRegisterJump() && m_Instruction.rs == 31; +} + +bool RSPInstruction::IsRegisterJump() const +{ + return m_Instruction.op == RSP_SPECIAL && (m_Instruction.funct == RSP_SPECIAL_JR || m_Instruction.funct == RSP_SPECIAL_JALR); +} + +bool RSPInstruction::IsStaticCall() const +{ + return m_Instruction.op == RSP_JAL; +} + bool RSPInstruction::IsBranch() const { switch (m_Instruction.op) @@ -106,6 +147,83 @@ bool RSPInstruction::IsBranch() const return false; } +bool RSPInstruction::IsConditionalBranch() const +{ + switch (m_Instruction.op) + { + case RSP_REGIMM: + switch (m_Instruction.rt) + { + case RSP_REGIMM_BLTZ: + case RSP_REGIMM_BGEZ: + case RSP_REGIMM_BLTZAL: + case RSP_REGIMM_BGEZAL: + return true; + default: + break; + } + break; + case RSP_SPECIAL: + switch (m_Instruction.funct) + { + case RSP_SPECIAL_SLL: + case RSP_SPECIAL_SRL: + case RSP_SPECIAL_SRA: + case RSP_SPECIAL_SLLV: + case RSP_SPECIAL_SRLV: + case RSP_SPECIAL_SRAV: + case RSP_SPECIAL_ADD: + case RSP_SPECIAL_ADDU: + case RSP_SPECIAL_SUB: + case RSP_SPECIAL_SUBU: + case RSP_SPECIAL_AND: + case RSP_SPECIAL_OR: + case RSP_SPECIAL_XOR: + case RSP_SPECIAL_NOR: + case RSP_SPECIAL_SLT: + case RSP_SPECIAL_SLTU: + case RSP_SPECIAL_BREAK: + case RSP_SPECIAL_JALR: + case RSP_SPECIAL_JR: + default: + break; + } + break; + case RSP_J: + case RSP_JAL: + break; + case RSP_BEQ: + case RSP_BNE: + case RSP_BLEZ: + case RSP_BGTZ: + return true; + case RSP_ADDI: + case RSP_ADDIU: + case RSP_SLTI: + case RSP_SLTIU: + case RSP_ANDI: + case RSP_ORI: + case RSP_XORI: + case RSP_LUI: + case RSP_CP0: + case RSP_CP2: + case RSP_LB: + case RSP_LH: + case RSP_LW: + case RSP_LBU: + case RSP_LHU: + case RSP_SB: + case RSP_SH: + case RSP_SW: + case RSP_LC2: + case RSP_SC2: + break; + default: + break; + } + return false; +} + bool RSPInstruction::IsNop() const { return m_Instruction.op == RSP_SPECIAL && m_Instruction.funct == RSP_SPECIAL_SLL && m_Instruction.rd == 0; diff --git a/Source/Project64-rsp-core/cpu/RspSystem.h b/Source/Project64-rsp-core/cpu/RspSystem.h index 7c104e733..4f6514758 100644 --- a/Source/Project64-rsp-core/cpu/RspSystem.h +++ b/Source/Project64-rsp-core/cpu/RspSystem.h @@ -17,6 +17,7 @@ class CRSPSystem : friend class RSPOp; friend class CRSPRecompilerOps; friend class CRSPRecompiler; + friend class RspCodeBlock; friend class CHleTask; friend class RSPDebuggerUI; friend class CRDPLog;