mirror of
https://github.com/jpd002/Play-.git
synced 2025-04-28 21:57:57 +03:00

Some checks are pending
Build Android / build_android (apk) (push) Waiting to run
Build Android / build_android (libretro) (push) Waiting to run
Build iOS / build_ios (push) Waiting to run
Build JavaScript / build_js (push) Waiting to run
Build Linux / build_linux (push) Waiting to run
Build Linux ARM32 / build_linux_arm32 (push) Waiting to run
Build Linux ARM64 / build_linux_arm64 (push) Waiting to run
Build macOS / build_macos (push) Waiting to run
Build Windows / build_windows (x86_32, Visual Studio 16 2019, installer32.nsi, win32_msvc2019, Win32) (push) Waiting to run
Build Windows / build_windows (x86_64, Visual Studio 16 2019, installer64.nsi, win64_msvc2019_64, x64) (push) Waiting to run
Build Windows Psf / build_windows_psf (off, x86_64, Visual Studio 16 2019, installer64.nsi, x64) (push) Waiting to run
Build Windows Psf / build_windows_psf (on, x86_64, Visual Studio 16 2019, installer64.nsi, x64) (push) Waiting to run
Check Format / run_clangformat (push) Waiting to run
124 lines
4.2 KiB
C++
124 lines
4.2 KiB
C++
#include "VuExecutor.h"
|
|
#include "VuBasicBlock.h"
|
|
#include "VUShared.h"
|
|
#include "xxhash.h"
|
|
|
|
// clang-format off
|
|
const CVuExecutor::BLOCK_COMPILE_HINTS CVuExecutor::g_blockCompileHints[] =
|
|
{
|
|
// Tri-Ace VU0 decompression code
|
|
{ std::make_pair(uint128{0x3aa43f7c, 0xe932516c, 0x6786472d, 0xf5333e12}, 0x58U), VUShared::COMPILEHINT_USE_ACCURATE_ADDI },
|
|
};
|
|
// clang-format on
|
|
|
|
CVuExecutor::CVuExecutor(CMIPS& context, uint32 maxAddress)
|
|
: CGenericMipsExecutor(context, maxAddress, BLOCK_CATEGORY_PS2_VU)
|
|
{
|
|
}
|
|
|
|
void CVuExecutor::Reset()
|
|
{
|
|
m_cachedBlocks.clear();
|
|
CGenericMipsExecutor::Reset();
|
|
}
|
|
|
|
BasicBlockPtr CVuExecutor::BlockFactory(CMIPS& context, uint32 begin, uint32 end)
|
|
{
|
|
uint32 blockSize = ((end - begin) + 4) / 4;
|
|
uint32 blockSizeByte = blockSize * 4;
|
|
|
|
auto map = m_context.m_pMemoryMap->GetInstructionMap(begin);
|
|
assert(m_context.m_pMemoryMap->GetInstructionMap(end) == map);
|
|
uint32 localBegin = begin - map->nStart;
|
|
auto blockMemory = reinterpret_cast<const uint32*>(reinterpret_cast<uint8*>(map->pPointer) + localBegin);
|
|
|
|
auto xxHash = XXH3_128bits(blockMemory, blockSizeByte);
|
|
uint128 hash;
|
|
memcpy(&hash, &xxHash, sizeof(xxHash));
|
|
static_assert(sizeof(hash) == sizeof(xxHash));
|
|
auto blockKey = std::make_pair(hash, blockSizeByte);
|
|
|
|
//Don't use the cached blocks of we have a breakpoint in our block range.
|
|
bool hasBreakpoint = m_context.HasBreakpointInRange(begin, end);
|
|
if(!hasBreakpoint)
|
|
{
|
|
auto beginBlockIterator = m_cachedBlocks.lower_bound(blockKey);
|
|
auto endBlockIterator = m_cachedBlocks.upper_bound(blockKey);
|
|
//Check if we have a block that has the same contents and the same range.
|
|
for(auto blockIterator = beginBlockIterator; blockIterator != endBlockIterator; blockIterator++)
|
|
{
|
|
const auto& basicBlock(blockIterator->second);
|
|
if(basicBlock->GetBeginAddress() == begin && basicBlock->GetEndAddress() == end)
|
|
{
|
|
return basicBlock;
|
|
}
|
|
}
|
|
//Check if we have a block that has the same contents but not the same range. Reuse the code of that block if that's the case.
|
|
if(beginBlockIterator != endBlockIterator)
|
|
{
|
|
auto result = std::make_shared<CVuBasicBlock>(context, begin, end, m_blockCategory);
|
|
result->CopyFunctionFrom(beginBlockIterator->second);
|
|
m_cachedBlocks.insert(std::make_pair(blockKey, result));
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//Totally new block, build it from scratch
|
|
auto result = std::make_shared<CVuBasicBlock>(context, begin, end, m_blockCategory);
|
|
|
|
auto blockCompileHintsIterator = std::find_if(std::begin(g_blockCompileHints), std::end(g_blockCompileHints),
|
|
[&](const auto& item) { return item.blockKey == blockKey; });
|
|
if(blockCompileHintsIterator != std::end(g_blockCompileHints))
|
|
{
|
|
result->AddBlockCompileHints(blockCompileHintsIterator->hints);
|
|
}
|
|
|
|
result->Compile();
|
|
if(!hasBreakpoint)
|
|
{
|
|
m_cachedBlocks.insert(std::make_pair(blockKey, result));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void CVuExecutor::PartitionFunction(uint32 startAddress)
|
|
{
|
|
uint32 endAddress = std::min<uint32>(startAddress + MAX_BLOCK_SIZE - 4, m_maxAddress - 4);
|
|
uint32 branchAddress = MIPS_INVALID_PC;
|
|
for(uint32 address = startAddress; address < endAddress; address += 8)
|
|
{
|
|
uint32 addrLo = address + 0;
|
|
uint32 addrHi = address + 4;
|
|
uint32 lowerOp = m_context.m_pMemoryMap->GetInstruction(addrLo);
|
|
uint32 upperOp = m_context.m_pMemoryMap->GetInstruction(addrHi);
|
|
auto branchType = m_context.m_pArch->IsInstructionBranch(&m_context, addrLo, lowerOp);
|
|
if(upperOp & VUShared::VU_UPPEROP_BIT_E)
|
|
{
|
|
endAddress = address + 0xC;
|
|
break;
|
|
}
|
|
else if(upperOp & (VUShared::VU_UPPEROP_BIT_D | VUShared::VU_UPPEROP_BIT_T))
|
|
{
|
|
endAddress = address + 0x04;
|
|
break;
|
|
}
|
|
else if(branchType == MIPS_BRANCH_NORMAL)
|
|
{
|
|
branchAddress = m_context.m_pArch->GetInstructionEffectiveAddress(&m_context, addrLo, lowerOp);
|
|
endAddress = address + 0xC;
|
|
break;
|
|
}
|
|
else if(branchType == MIPS_BRANCH_NODELAY)
|
|
{
|
|
//Should never happen
|
|
assert(false);
|
|
}
|
|
}
|
|
assert((endAddress - startAddress) <= MAX_BLOCK_SIZE);
|
|
CreateBlock(startAddress, endAddress);
|
|
auto block = static_cast<CVuBasicBlock*>(FindBlockStartingAt(startAddress));
|
|
if(block->IsLinkable())
|
|
{
|
|
SetupBlockLinks(startAddress, endAddress, branchAddress);
|
|
}
|
|
}
|