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}