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;