diff --git a/Source/Android/PluginRSP/PluginRSP.vcxproj b/Source/Android/PluginRSP/PluginRSP.vcxproj
index 923621d77..48c0489aa 100644
--- a/Source/Android/PluginRSP/PluginRSP.vcxproj
+++ b/Source/Android/PluginRSP/PluginRSP.vcxproj
@@ -45,6 +45,9 @@
+
+ {a72c9f08-ebb4-443d-9982-da21ae8b367d}
+
{731bd205-2826-4631-b7af-117658e88dbc}
diff --git a/Source/Project64-rsp-core/Hle/HleTask.cpp b/Source/Project64-rsp-core/Hle/HleTask.cpp
index 297fb1895..6307486e2 100644
--- a/Source/Project64-rsp-core/Hle/HleTask.cpp
+++ b/Source/Project64-rsp-core/Hle/HleTask.cpp
@@ -41,7 +41,59 @@ bool CHleTask::IsHleTask(void)
return false;
}
-void CHleTask::ExecuteTask_1a13a51a(TASK_INFO & TaskInfo)
+#if defined(__amd64__) || defined(_M_X64)
+void CHleTask::SetupCommandList(const TASK_INFO & TaskInfo)
+{
+ uint32_t JumpTableLength = 0x7E, JumpTablePos = 0x10;
+ if ((HLETaskType)(TaskInfo.Type) == HLETaskType::Audio)
+ {
+ if (*((uint32_t *)&m_DMEM[0]) == 0x00000001 && *((uint32_t *)&m_DMEM[0x30]) == 0xf0000f00)
+ {
+ JumpTableLength = 0x10;
+ JumpTablePos = 0x10;
+ }
+ }
+
+ uint32_t JumpTableCRC = crc32(0L, m_IMEM + JumpTablePos, JumpTableLength << 1);
+ TaskFunctionMap::iterator itr = m_FunctionMap.find(JumpTableCRC);
+ if (itr != m_FunctionMap.end())
+ {
+ m_TaskFunctions = &itr->second;
+ return;
+ }
+
+ if (m_FunctionMap.size() > 0)
+ {
+ g_Notify->BreakPoint(__FILE__, __LINE__);
+ }
+ m_TaskFunctions = nullptr;
+
+ TaskFunctions JumpFunctions;
+ for (uint32_t i = 0, n = JumpTableLength; i < n; i++)
+ {
+ uint16_t FuncAddress = *((uint16_t *)(m_DMEM + (((i << 1) + JumpTablePos) ^ 2)));
+ if (FuncAddress != 0x1118)
+ {
+ m_Recompiler.CompileHLETask(FuncAddress);
+ void * FuncPtr = *(JumpTable + ((FuncAddress & 0xFFF) >> 2));
+ JumpFunctions.emplace_back(TaskFunctionAddress(FuncAddress, FuncPtr));
+ }
+ else
+ {
+ JumpFunctions.emplace_back(TaskFunctionAddress(FuncAddress, nullptr));
+ }
+ }
+ m_FunctionMap[JumpTableCRC] = JumpFunctions;
+ itr = m_FunctionMap.find(JumpTableCRC);
+ if (itr == m_FunctionMap.end())
+ {
+ g_Notify->BreakPoint(__FILE__, __LINE__);
+ return;
+ }
+ m_TaskFunctions = &itr->second;
+}
+
+void CHleTask::ExecuteTask_1a13a51a(const TASK_INFO & TaskInfo)
{
*((uint32_t *)(m_DMEM + 0x320)) = 0;
GPR_T8 = 0x360;
@@ -92,16 +144,13 @@ void CHleTask::ExecuteTask_1a13a51a(TASK_INFO & TaskInfo)
{
RSPSystem.SyncSystem()->ExecuteOps(0x10000, 0x118);
}
-#if defined(_M_IX86) && defined(_MSC_VER)
- void * Block = FunctionAddress.second;
- _asm {
- pushad
- call Block
- popad
+ typedef void (*FuncPtr)();
+ FuncPtr func = (FuncPtr)(*(JumpTable + ((*m_SP_PC_REG & 0xFFF) >> 2)));
+ if (func == nullptr)
+ {
+ g_Notify->BreakPoint(__FILE__, __LINE__);
}
-#else
- g_Notify->BreakPoint(__FILE__, __LINE__);
-#endif
+ func();
if (SyncCPU)
{
RSPSystem.BasicSyncCheck();
@@ -147,6 +196,41 @@ void CHleTask::ExecuteTask_1a13a51a(TASK_INFO & TaskInfo)
}
}
+void CHleTask::SetupTask(const TASK_INFO & TaskInfo)
+{
+ if (TaskInfo.Flags != 0)
+ {
+ g_Notify->BreakPoint(__FILE__, __LINE__);
+ }
+ if (*m_SP_DMA_FULL_REG != 0)
+ {
+ g_Notify->BreakPoint(__FILE__, __LINE__);
+ }
+ m_RSPRegisterHandler->WriteReg(RSPRegister_MEM_ADDR, 0);
+ m_RSPRegisterHandler->WriteReg(RSPRegister_DRAM_ADDR, TaskInfo.UcodeData);
+ m_RSPRegisterHandler->WriteReg(RSPRegister_RD_LEN, TaskInfo.UcodeDataSize);
+ if (*m_SP_DMA_BUSY_REG != 0 || (*m_SP_STATUS_REG & 0x80) != 0)
+ {
+ g_Notify->BreakPoint(__FILE__, __LINE__);
+ }
+ m_RSPRegisterHandler->WriteReg(RSPRegister_MEM_ADDR, 0x1080);
+ m_RSPRegisterHandler->WriteReg(RSPRegister_DRAM_ADDR, TaskInfo.Ucode);
+ m_RSPRegisterHandler->WriteReg(RSPRegister_RD_LEN, 0x0F7F);
+ if (*m_SP_DMA_BUSY_REG != 0 || (*m_SP_STATUS_REG & 0x80) != 0)
+ {
+ g_Notify->BreakPoint(__FILE__, __LINE__);
+ }
+ *m_SP_SEMAPHORE_REG = 0;
+ if (SyncCPU)
+ {
+ *m_SP_PC_REG = 0x80;
+ RSPSystem.SyncSystem()->ExecuteOps(200, 0x080);
+ RSPSystem.BasicSyncCheck();
+ }
+ SetupCommandList(TaskInfo);
+}
+#endif
+
bool CHleTask::ProcessHleTask(void)
{
TASK_INFO & TaskInfo = *((TASK_INFO *)(m_DMEM + 0xFC0));
@@ -185,3 +269,29 @@ bool CHleTask::ProcessHleTask(void)
}
return false;
}
+
+bool CHleTask::HleTaskRecompiler(void)
+{
+ const TASK_INFO & TaskInfo = *((TASK_INFO *)(m_DMEM + 0xFC0));
+
+ if (SyncCPU)
+ {
+ RSPSystem.SetupSyncCPU();
+ }
+ SetupTask(TaskInfo);
+ uint32_t UcodeSize = TaskInfo.UcodeSize;
+ if (UcodeSize < 0x4 || TaskInfo.UcodeSize > 0x0F80)
+ {
+ UcodeSize = 0x0F80;
+ }
+ m_UcodeCRC = crc32(0L, m_IMEM + 0x80, UcodeSize);
+ if (m_UcodeCRC == 0x1a13a51a)
+ {
+ ExecuteTask_1a13a51a(TaskInfo);
+ }
+ else
+ {
+ g_Notify->BreakPoint(__FILE__, __LINE__);
+ }
+ return true;
+}
diff --git a/Source/Project64-rsp-core/Hle/HleTask.h b/Source/Project64-rsp-core/Hle/HleTask.h
index 8db495ffd..83136ddb8 100644
--- a/Source/Project64-rsp-core/Hle/HleTask.h
+++ b/Source/Project64-rsp-core/Hle/HleTask.h
@@ -49,13 +49,16 @@ public:
bool IsHleTask(void);
bool ProcessHleTask(void);
+ bool HleTaskRecompiler(void);
private:
CHleTask(void);
CHleTask(const CHleTask & copy);
CHleTask & operator=(const CHleTask & rhs);
- void ExecuteTask_1a13a51a(TASK_INFO & TaskInfo);
+ void SetupCommandList(const TASK_INFO & TaskInfo);
+ void ExecuteTask_1a13a51a(const TASK_INFO & TaskInfo);
+ void SetupTask(const TASK_INFO & TaskInfo);
void (*&CheckInterrupts)(void);
void (*&ProcessDList)(void);
diff --git a/Source/Project64-rsp-core/Project64-rsp-core.vcxproj b/Source/Project64-rsp-core/Project64-rsp-core.vcxproj
index 4f9af9da3..efe3d22af 100644
--- a/Source/Project64-rsp-core/Project64-rsp-core.vcxproj
+++ b/Source/Project64-rsp-core/Project64-rsp-core.vcxproj
@@ -37,6 +37,7 @@
NotUsing
+ $(SolutionDir)Source\3rdParty\asmjit\src;%(AdditionalIncludeDirectories)
@@ -64,8 +65,10 @@
+
+
@@ -96,7 +99,10 @@
+
+
+
diff --git a/Source/Project64-rsp-core/Project64-rsp-core.vcxproj.filters b/Source/Project64-rsp-core/Project64-rsp-core.vcxproj.filters
index 74489c752..58f3884d1 100644
--- a/Source/Project64-rsp-core/Project64-rsp-core.vcxproj.filters
+++ b/Source/Project64-rsp-core/Project64-rsp-core.vcxproj.filters
@@ -66,9 +66,6 @@
Source Files\Recompiler
-
- Source Files\Recompiler
-
Source Files\Recompiler
@@ -141,6 +138,15 @@
Source Files\Recompiler
+
+ Source Files\Recompiler
+
+
+ Source Files\Recompiler
+
+
+ Source Files\Recompiler
+
@@ -173,9 +179,6 @@
Header Files\Settings
-
- Header Files\Recompiler
-
Header Files\cpu
@@ -227,5 +230,17 @@
Header Files\Recompiler
+
+ Header Files
+
+
+ Header Files\Recompiler
+
+
+ Header Files\Recompiler
+
+
+ Header Files\Recompiler
+
\ No newline at end of file
diff --git a/Source/Project64-rsp-core/Recompiler/RspAssembler.cpp b/Source/Project64-rsp-core/Recompiler/RspAssembler.cpp
new file mode 100644
index 000000000..9543f6193
--- /dev/null
+++ b/Source/Project64-rsp-core/Recompiler/RspAssembler.cpp
@@ -0,0 +1,37 @@
+#if defined(__amd64__) || defined(_M_X64)
+
+#include "RspAssembler.h"
+#include
+#include
+#include
+
+RspAssembler::RspAssembler(asmjit::CodeHolder * CodeHolder, std::string & CodeLog) :
+ asmjit::x86::Assembler(CodeHolder),
+ m_CodeLog(CodeLog)
+{
+ setLogger(nullptr);
+ setErrorHandler(this);
+ addFlags(asmjit::FormatFlags::kHexOffsets);
+ addFlags(asmjit::FormatFlags::kHexImms);
+ addFlags(asmjit::FormatFlags::kExplainImms);
+}
+
+void RspAssembler::handleError(asmjit::Error /*err*/, const char * /*message*/, asmjit::BaseEmitter * /*origin*/)
+{
+ g_Notify->BreakPoint(__FILE__, __LINE__);
+}
+
+asmjit::Error RspAssembler::_log(const char * data, size_t size) noexcept
+{
+ stdstr AsmjitLog(std::string(data, size));
+ AsmjitLog.Trim("\n");
+ m_CodeLog.append(stdstr_f(" %s\n", AsmjitLog.c_str()));
+ return asmjit::kErrorOk;
+}
+
+void RspAssembler::Reset(void)
+{
+ setLogger(LogAsmCode ? this : nullptr);
+}
+
+#endif
\ No newline at end of file
diff --git a/Source/Project64-rsp-core/Recompiler/RspAssembler.h b/Source/Project64-rsp-core/Recompiler/RspAssembler.h
new file mode 100644
index 000000000..c14b14efb
--- /dev/null
+++ b/Source/Project64-rsp-core/Recompiler/RspAssembler.h
@@ -0,0 +1,26 @@
+#pragma once
+#if defined(__amd64__) || defined(_M_X64)
+
+#include
+
+class RspAssembler :
+ public asmjit::x86::Assembler,
+ public asmjit::ErrorHandler,
+ public asmjit::Logger
+{
+public:
+ RspAssembler(asmjit::CodeHolder * CodeHolder, std::string & CodeLog);
+
+ void Reset(void);
+
+private:
+ RspAssembler();
+ RspAssembler(const RspAssembler &);
+ RspAssembler & operator=(const RspAssembler &);
+
+ void handleError(asmjit::Error err, const char * message, asmjit::BaseEmitter * origin);
+ asmjit::Error _log(const char * data, size_t size) noexcept;
+ std::string & m_CodeLog;
+};
+
+#endif
\ No newline at end of file
diff --git a/Source/Project64-rsp-core/Recompiler/RspRecompilerCPU-x64.cpp b/Source/Project64-rsp-core/Recompiler/RspRecompilerCPU-x64.cpp
new file mode 100644
index 000000000..903b7644f
--- /dev/null
+++ b/Source/Project64-rsp-core/Recompiler/RspRecompilerCPU-x64.cpp
@@ -0,0 +1,119 @@
+#if defined(__amd64__) || defined(_M_X64)
+
+#include "RspRecompilerCPU-x64.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define AddressOf(Addr) CRSPRecompiler::GetAddressOf(5, (Addr))
+
+extern CLog * CPULog;
+
+CRSPRecompiler::CRSPRecompiler(CRSPSystem & System) :
+ m_System(System),
+ m_BlockID(0),
+ m_Assembler(nullptr)
+{
+ m_Environment = asmjit::Environment::host();
+ m_CodeHolder.init(m_Environment);
+ m_CodeHolder.setErrorHandler(this);
+ m_CodeHolder.setLogger(nullptr);
+
+ m_Assembler = new RspAssembler(&m_CodeHolder, m_CodeLog);
+}
+
+CRSPRecompiler::~CRSPRecompiler()
+{
+ if (m_Assembler != nullptr)
+ {
+ delete m_Assembler;
+ m_Assembler = nullptr;
+ }
+}
+
+void CRSPRecompiler::Reset()
+{
+ m_Assembler->Reset();
+}
+
+void CRSPRecompiler::CompileHLETask(uint32_t Address)
+{
+ Log("====== Block %d ======", m_BlockID++);
+ Log("asm code at: %016llX", (uint64_t)RecompPos);
+ Log("Jump table: %X", Table);
+ Log("Start of block: %X", Address);
+ Log("====== Recompiled code ======");
+
+ *(JumpTable + ((Address & 0xFFF) >> 2)) = RecompPos;
+
+ m_Assembler->push(asmjit::x86::rbp);
+ m_Assembler->mov(asmjit::x86::rbp, asmjit::x86::rsp);
+ m_Assembler->sub(asmjit::x86::rsp, 0x30);
+ m_Assembler->mov(asmjit::x86::rcx, asmjit::imm((uintptr_t)&m_System));
+ m_Assembler->mov(asmjit::x86::edx, asmjit::imm(0x10000));
+ m_Assembler->mov(asmjit::x86::r8d, asmjit::imm(0x118));
+ m_Assembler->mov(asmjit::x86::rax, asmjit::imm(AddressOf(&CRSPSystem::ExecuteOps)));
+ m_Assembler->call(asmjit::x86::rax);
+ m_Assembler->add(asmjit::x86::rsp, 0x30);
+ m_Assembler->pop(asmjit::x86::rbp);
+ m_Assembler->ret();
+ m_Assembler->finalize();
+
+ m_CodeHolder.relocateToBase((uint64_t)RecompPos);
+ size_t codeSize = m_CodeHolder.codeSize();
+ m_CodeHolder.copyFlattenedData(RecompPos, codeSize);
+ RecompPos += codeSize;
+
+ if (LogAsmCode && !m_CodeLog.empty() && CPULog != nullptr)
+ {
+ CPULog->Log(m_CodeLog.c_str());
+ CPULog->Log("\r\n");
+ CPULog->Flush();
+ m_CodeLog.clear();
+ }
+#endif
+}
+
+void CRSPRecompiler::Log(_Printf_format_string_ const char * Text, ...)
+{
+ if (!LogAsmCode)
+ {
+ return;
+ }
+
+ va_list args;
+ va_start(args, Text);
+#pragma warning(push)
+#pragma warning(disable : 4996)
+ size_t nlen = _vscprintf(Text, args) + 1;
+ char * buffer = (char *)alloca(nlen * sizeof(char));
+ buffer[nlen - 1] = 0;
+ if (buffer != nullptr)
+ {
+ vsprintf(buffer, Text, args);
+ m_CodeLog += buffer;
+ m_CodeLog += "\n";
+ }
+#pragma warning(pop)
+ va_end(args);
+}
+
+void CRSPRecompiler::handleError(asmjit::Error /*err*/, const char * /*message*/, asmjit::BaseEmitter * /*origin*/)
+{
+ g_Notify->BreakPoint(__FILE__, __LINE__);
+}
+
+uintptr_t CRSPRecompiler::GetAddressOf(int value, ...)
+{
+ void * Address;
+
+ va_list ap;
+ va_start(ap, value);
+ Address = va_arg(ap, void *);
+ va_end(ap);
+
+ return (uintptr_t)Address;
+}
diff --git a/Source/Project64-rsp-core/Recompiler/RspRecompilerCPU-x64.h b/Source/Project64-rsp-core/Recompiler/RspRecompilerCPU-x64.h
new file mode 100644
index 000000000..ad0369572
--- /dev/null
+++ b/Source/Project64-rsp-core/Recompiler/RspRecompilerCPU-x64.h
@@ -0,0 +1,37 @@
+#if defined(__amd64__) || defined(_M_X64)
+
+#pragma once
+#include "asmjit.h"
+
+class CRSPSystem;
+class RspAssembler;
+
+class CRSPRecompiler :
+ public asmjit::ErrorHandler
+{
+public:
+ CRSPRecompiler(CRSPSystem & System);
+ ~CRSPRecompiler();
+
+ void Reset();
+ void CompileHLETask(uint32_t Address);
+ void Log(_Printf_format_string_ const char * Text, ...);
+
+private:
+ CRSPRecompiler();
+ CRSPRecompiler(const CRSPRecompiler &);
+ CRSPRecompiler & operator=(const CRSPRecompiler &);
+
+ void handleError(asmjit::Error err, const char * message, asmjit::BaseEmitter * origin);
+
+ static uintptr_t GetAddressOf(int32_t value, ...);
+
+ CRSPSystem & m_System;
+ std::string m_CodeLog;
+ uint32_t m_BlockID;
+ asmjit::Environment m_Environment;
+ asmjit::CodeHolder m_CodeHolder;
+ RspAssembler * m_Assembler;
+};
+
+#endif
\ No newline at end of file
diff --git a/Source/Project64-rsp-core/Recompiler/asmjit.h b/Source/Project64-rsp-core/Recompiler/asmjit.h
new file mode 100644
index 000000000..489436083
--- /dev/null
+++ b/Source/Project64-rsp-core/Recompiler/asmjit.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#define ASMJIT_STATIC
+
+#ifdef new
+#pragma push_macro("new")
+#undef new
+#include
+#pragma pop_macro("new")
+#else
+#include
+#endif
+#include
+#include
+#include
diff --git a/Source/Project64-rsp-core/cpu/RSPCpu.cpp b/Source/Project64-rsp-core/cpu/RSPCpu.cpp
index 9af19e5a9..d4cb6cc60 100644
--- a/Source/Project64-rsp-core/cpu/RSPCpu.cpp
+++ b/Source/Project64-rsp-core/cpu/RSPCpu.cpp
@@ -95,6 +95,25 @@ be greater than the number of cycles that the RSP should have performed.
uint32_t DoRspCycles(uint32_t Cycles)
{
+#if defined(__amd64__) || defined(_M_X64)
+ if (CRSPSettings::CPUMethod() == RSPCpuMethod::RecompilerTasks)
+ {
+ if (!RSPSystem.IsHleTask() || !RSPSystem.HleTaskRecompiler())
+ {
+ if (g_RSPDebugger != nullptr)
+ {
+ g_RSPDebugger->RspCyclesStart();
+ RSPSystem.ExecuteOps((uint32_t)-1, (uint32_t)-1);
+ g_RSPDebugger->RspCyclesStop();
+ }
+ else
+ {
+ RSPSystem.ExecuteOps((uint32_t)-1, (uint32_t)-1);
+ }
+ }
+ return Cycles;
+ }
+#endif
if (CRSPSettings::CPUMethod() == RSPCpuMethod::HighLevelEmulation && RSPSystem.ProcessHleTask())
{
return Cycles;
@@ -110,17 +129,13 @@ uint32_t DoRspCycles(uint32_t Cycles)
{
RSPSystem.RunRecompiler();
}
-#endif
-#if defined(__amd64__) || defined(_M_X64)
- if (CRSPSettings::CPUMethod() == RSPCpuMethod::RecompilerTasks)
- {
- RSPSystem.ExecuteOps((uint32_t)-1, (uint32_t)-1);
- }
-#endif
else
{
+#endif
RSPSystem.ExecuteOps((uint32_t)-1, (uint32_t)-1);
+#if defined(__i386__) || defined(_M_IX86)
}
+#endif
if (g_RSPDebugger != nullptr)
{
g_RSPDebugger->RspCyclesStop();
diff --git a/Source/Project64-rsp-core/cpu/RspSystem.cpp b/Source/Project64-rsp-core/cpu/RspSystem.cpp
index 8a7a0ddb0..6a4763356 100644
--- a/Source/Project64-rsp-core/cpu/RspSystem.cpp
+++ b/Source/Project64-rsp-core/cpu/RspSystem.cpp
@@ -13,9 +13,7 @@ CRSPSystem::CRSPSystem() :
CHleTask(*this),
m_SyncSystem(nullptr),
m_BaseSystem(nullptr),
-#if defined(__i386__) || defined(_M_IX86)
m_Recompiler(*this),
-#endif
m_RSPRegisterHandler(nullptr),
m_Op(*this),
m_NextInstruction(RSPPIPELINE_NORMAL),
@@ -133,6 +131,7 @@ void CRSPSystem::Reset(RSP_INFO & Info)
{
m_SyncSystem->Reset(Info);
}
+ m_Recompiler.Reset();
}
void CRSPSystem::RomClosed(void)
diff --git a/Source/Project64-rsp-core/cpu/RspSystem.h b/Source/Project64-rsp-core/cpu/RspSystem.h
index 19712bb71..7c104e733 100644
--- a/Source/Project64-rsp-core/cpu/RspSystem.h
+++ b/Source/Project64-rsp-core/cpu/RspSystem.h
@@ -1,6 +1,7 @@
#pragma once
#include
#include
+#include
#include
#include
#include
@@ -53,9 +54,7 @@ private:
CRSPSystem * m_SyncSystem;
CRSPSystem * m_BaseSystem;
-#if defined(__i386__) || defined(_M_IX86)
CRSPRecompiler m_Recompiler;
-#endif
RSPRegisterHandlerPlugin * m_RSPRegisterHandler;
CRSPRegisters m_Reg;
RSPOp m_Op;
diff --git a/Source/Project64-rsp/Project64-rsp.vcxproj b/Source/Project64-rsp/Project64-rsp.vcxproj
index a1b71578a..6e410fef5 100644
--- a/Source/Project64-rsp/Project64-rsp.vcxproj
+++ b/Source/Project64-rsp/Project64-rsp.vcxproj
@@ -39,6 +39,7 @@
NotUsing
+ $(SolutionDir)Source\3rdParty\asmjit\src;%(AdditionalIncludeDirectories)
@@ -57,6 +58,9 @@
+
+ {a72c9f08-ebb4-443d-9982-da21ae8b367d}
+
{731bd205-2826-4631-b7af-117658e88dbc}