This commit is contained in:
Stenzek 2025-03-02 20:20:11 +10:00
parent fc90d84788
commit b18c61f4b2
No known key found for this signature in database
4 changed files with 927 additions and 343 deletions

View File

@ -714,22 +714,11 @@ PageFaultHandler::HandlerResult PageFaultHandler::HandlePageFault(void* exceptio
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace CPU::CodeCache::CachedInterpreterFunctions { namespace CPU::CodeCache::CachedInterpreterFunctions {
static void CompileOrRevalidateBlock(const CachedInterpreterInstruction* cinst); static DEFINE_CACHED_INTERPRETER_HANDLER(CompileOrRevalidateBlock);
static void LookupAndExecuteBlock(const CachedInterpreterInstruction* cinst); static DEFINE_CACHED_INTERPRETER_HANDLER(LookupAndExecuteBlock);
static void LogCurrentState(const CachedInterpreterInstruction* cinst);
static void CheckAndUpdateICacheTags(const CachedInterpreterInstruction* cinst);
static void AddDynamicFetchTicks(const CachedInterpreterInstruction* cinst);
static void AddUncachedFetchTicks(const CachedInterpreterInstruction* cinst);
static void EndBlock(const CachedInterpreterInstruction* cinst);
} // namespace CPU::CodeCache::CachedInterpreterFunctions } // namespace CPU::CodeCache::CachedInterpreterFunctions
void CPU::CodeCache::CachedInterpreterFunctions::CompileOrRevalidateBlock(const CachedInterpreterInstruction* cinst) DEFINE_CACHED_INTERPRETER_HANDLER(CPU::CodeCache::CachedInterpreterFunctions::LookupAndExecuteBlock)
{
CompileCachedInterpreterBlock(g_state.pc);
END_CACHED_INTERPRETER_INSTRUCTION(cinst);
}
void CPU::CodeCache::CachedInterpreterFunctions::LookupAndExecuteBlock(const CachedInterpreterInstruction*)
{ {
const u32 pc = g_state.pc; const u32 pc = g_state.pc;
const u32 table = pc >> LUT_TABLE_SHIFT; const u32 table = pc >> LUT_TABLE_SHIFT;
@ -742,56 +731,13 @@ void CPU::CodeCache::CachedInterpreterFunctions::LookupAndExecuteBlock(const Cac
#else #else
do do
{ {
cinst->handler(cinst); cinst = cinst->handler(cinst);
cinst++; } while (cinst);
} while (cinst->handler); return nullptr;
#endif #endif
} }
void CPU::CodeCache::CachedInterpreterFunctions::LogCurrentState(const CachedInterpreterInstruction* cinst) DEFINE_CACHED_INTERPRETER_HANDLER(CPU::CodeCache::CachedInterpreterFunctions::CompileOrRevalidateBlock)
{
CPU::CodeCache::LogCurrentState();
END_CACHED_INTERPRETER_INSTRUCTION(cinst);
}
void CPU::CodeCache::CachedInterpreterFunctions::CheckAndUpdateICacheTags(const CachedInterpreterInstruction* cinst)
{
CPU::CheckAndUpdateICacheTags(cinst->arg);
END_CACHED_INTERPRETER_INSTRUCTION(cinst);
}
void CPU::CodeCache::CachedInterpreterFunctions::AddDynamicFetchTicks(const CachedInterpreterInstruction* cinst)
{
AddPendingTicks(static_cast<TickCount>(
cinst->arg *
static_cast<u32>(*Bus::GetMemoryAccessTimePtr(g_state.pc & PHYSICAL_MEMORY_ADDRESS_MASK, MemoryAccessSize::Word))));
END_CACHED_INTERPRETER_INSTRUCTION(cinst);
}
void CPU::CodeCache::CachedInterpreterFunctions::AddUncachedFetchTicks(const CachedInterpreterInstruction* cinst)
{
CPU::AddPendingTicks(static_cast<TickCount>(cinst->arg));
END_CACHED_INTERPRETER_INSTRUCTION(cinst);
}
void CPU::CodeCache::CachedInterpreterFunctions::EndBlock(const CachedInterpreterInstruction* cinst)
{
// TODO: jump to top of block if looping, block linking, etc.
return;
}
void CPU::CodeCache::SetCachedInterpreterHandlers()
{
static constexpr const CachedInterpreterInstruction compile_or_revalidate_block[] = {
{&CachedInterpreterFunctions::CompileOrRevalidateBlock, 0u},
{&CachedInterpreterFunctions::LookupAndExecuteBlock, 0u},
{nullptr, 0u},
};
g_compile_or_revalidate_block = compile_or_revalidate_block;
}
void CPU::CodeCache::CompileCachedInterpreterBlock(const u32)
{ {
const u32 start_pc = g_state.pc; const u32 start_pc = g_state.pc;
MemMap::BeginCodeWrite(); MemMap::BeginCodeWrite();
@ -806,13 +752,13 @@ void CPU::CodeCache::CompileCachedInterpreterBlock(const u32)
{ {
DebugAssert(block->host_code); DebugAssert(block->host_code);
SetCodeLUT(start_pc, block->host_code); SetCodeLUT(start_pc, block->host_code);
// BacklinkBlocks(start_pc, block->host_code); BacklinkBlocks(start_pc, block->host_code);
MemMap::EndCodeWrite(); MemMap::EndCodeWrite();
return; CACHED_INTERPRETER_HANDLER_RETURN(static_cast<const CachedInterpreterInstruction*>(block->host_code));
} }
// remove outward links from this block, since we're recompiling it // remove outward links from this block, since we're recompiling it
// UnlinkBlockExits(block); UnlinkBlockExits(block);
} }
BlockMetadata metadata = {}; BlockMetadata metadata = {};
@ -822,6 +768,7 @@ void CPU::CodeCache::CompileCachedInterpreterBlock(const u32)
Panic("Fixme"); Panic("Fixme");
} }
// TODO: size calc is wrong, should use max insn size
const u32 required_space = sizeof(CachedInterpreterInstruction) * (static_cast<u32>(s_block_instructions.size()) + 3); const u32 required_space = sizeof(CachedInterpreterInstruction) * (static_cast<u32>(s_block_instructions.size()) + 3);
if (GetFreeCodeSpace() < required_space) if (GetFreeCodeSpace() < required_space)
{ {
@ -833,67 +780,34 @@ void CPU::CodeCache::CompileCachedInterpreterBlock(const u32)
if (!block) if (!block)
{ {
Panic("Fixme"); Panic("Fixme");
return;
} }
const CPU::Instruction* mips_insns = block->Instructions(); CachedInterpreterCompiler compiler(block, reinterpret_cast<CachedInterpreterInstruction*>(GetFreeCodePointer()));
CachedInterpreterInstruction* cstart = reinterpret_cast<CachedInterpreterInstruction*>(GetFreeCodePointer()); if (!compiler.CompileBlock())
CachedInterpreterInstruction* cinst = cstart; Panic("Fixme");
if (false) block->host_code = compiler.GetCodeStart();
{ block->host_code_size = compiler.GetCodeSize();
cinst->handler = &CachedInterpreterFunctions::LogCurrentState; CommitCode(block->host_code_size);
cinst->arg = 0;
cinst++;
}
if (block->HasFlag(BlockFlags::IsUsingICache)) SetCodeLUT(start_pc, block->host_code);
{ BacklinkBlocks(start_pc, block->host_code);
cinst->handler = &CachedInterpreterFunctions::CheckAndUpdateICacheTags;
cinst->arg = block->icache_line_count;
cinst++;
}
else if (block->HasFlag(BlockFlags::NeedsDynamicFetchTicks))
{
cinst->handler = &CachedInterpreterFunctions::AddDynamicFetchTicks;
cinst->arg = block->size;
cinst++;
}
else if (block->uncached_fetch_ticks > 0)
{
cinst->handler = &CachedInterpreterFunctions::AddUncachedFetchTicks;
cinst->arg = static_cast<u32>(block->uncached_fetch_ticks);
cinst++;
}
for (u32 i = 0; i < block->size; i++)
{
const Instruction insn = *(mips_insns++);
cinst->handler = GetCachedInterpreterHandler(insn);
cinst->arg = insn.bits;
if (!cinst->handler)
Panic("Fixme");
cinst++;
}
// end
#ifdef HAS_MUSTTAIL
cinst->handler = &CachedInterpreterFunctions::EndBlock;
#else
cinst->handler = nullptr;
#endif
cinst->arg = 0;
cinst++;
block->host_code = cstart;
block->host_code_size = static_cast<u32>(cinst - cstart) * sizeof(CachedInterpreterInstruction);
SetCodeLUT(start_pc, cstart);
CommitCode(required_space);
MemMap::EndCodeWrite(); MemMap::EndCodeWrite();
// TODO: Block linking! // TODO: Block linking!
CACHED_INTERPRETER_HANDLER_RETURN(static_cast<const CachedInterpreterInstruction*>(block->host_code));
}
void CPU::CodeCache::SetCachedInterpreterHandlers()
{
static constexpr const CachedInterpreterInstruction compile_or_revalidate_block_seq = {
&CachedInterpreterFunctions::CompileOrRevalidateBlock};
static constexpr const CachedInterpreterInstruction lookup_and_execute_block_seq = {
&CachedInterpreterFunctions::LookupAndExecuteBlock};
g_compile_or_revalidate_block = &compile_or_revalidate_block_seq;
g_dispatcher = &lookup_and_execute_block_seq;
} }
[[noreturn]] void CPU::CodeCache::ExecuteCachedInterpreter() [[noreturn]] void CPU::CodeCache::ExecuteCachedInterpreter()
@ -933,9 +847,8 @@ void CPU::CodeCache::CompileCachedInterpreterBlock(const u32)
#else #else
do do
{ {
cinst->handler(cinst); cinst = cinst->handler(cinst);
cinst++; } while (cinst);
} while (cinst->handler);
#endif #endif
CHECK_DOWNCOUNT(); CHECK_DOWNCOUNT();
@ -952,7 +865,7 @@ void CPU::CodeCache::CompileCachedInterpreterBlock(const u32)
void CPU::CodeCache::LogCurrentState() void CPU::CodeCache::LogCurrentState()
{ {
#if 0 #if 0
if (System::GetGlobalTickCounter() == 2546728915) if (System::GetGlobalTickCounter() == 9953322268)
__debugbreak(); __debugbreak();
#endif #endif
#if 0 #if 0
@ -1542,11 +1455,25 @@ void CPU::CodeCache::BacklinkBlocks(u32 pc, const void* dst)
return; return;
const auto link_range = s_block_links.equal_range(pc); const auto link_range = s_block_links.equal_range(pc);
for (auto it = link_range.first; it != link_range.second; ++it) if (IsUsingRecompiler())
{ {
DEBUG_LOG("Backlinking {} with dst pc {:08X} to {}{}", it->second, pc, dst, for (auto it = link_range.first; it != link_range.second; ++it)
(dst == g_compile_or_revalidate_block) ? "[compiler]" : ""); {
EmitJump(it->second, dst, true); DEBUG_LOG("Backlinking {} with dst pc {:08X} to {}{}", it->second, pc, dst,
(dst == g_compile_or_revalidate_block) ? "[compiler]" : "");
EmitJump(it->second, dst, true);
}
}
else
{
// TODO: maybe move this up to the compiler function
for (auto it = link_range.first; it != link_range.second; ++it)
{
DEBUG_LOG("Backlinking {} with dst pc {:08X} to {}{}", it->second, pc, dst,
(dst == g_compile_or_revalidate_block) ? "[compiler]" : "");
std::memcpy(it->second, &dst, sizeof(void*));
}
} }
} }

View File

@ -212,21 +212,108 @@ static_assert(sizeof(PageProtectionInfo) == (sizeof(Block*) * 2 + 8));
struct CachedInterpreterInstruction; struct CachedInterpreterInstruction;
using CachedInterpreterHandler = void (*)(const CachedInterpreterInstruction*);
CachedInterpreterHandler GetCachedInterpreterHandler(const Instruction inst);
#ifdef HAS_MUSTTAIL #ifdef HAS_MUSTTAIL
#define END_CACHED_INTERPRETER_INSTRUCTION(arg) RETURN_MUSTTAIL((arg + 1)->handler(arg + 1)); using CachedInterpreterHandler = void (*)(const CachedInterpreterInstruction*);
#define DEFINE_CACHED_INTERPRETER_HANDLER(name) void name(const CPU::CodeCache::CachedInterpreterInstruction* cbaseinst)
#define CACHED_INTERPRETER_INSTRUCTION_TYPE(type) const type* cinst = static_cast<const type*>(cbaseinst)
#define CACHED_INTERPRETER_HANDLER_RETURN(value) RETURN_MUSTTAIL(value->handler(value))
#define END_CACHED_INTERPRETER_INSTRUCTION() CACHED_INTERPRETER_HANDLER_RETURN((cinst + 1))
#else #else
#define END_CACHED_INTERPRETER_INSTRUCTION(arg) using CachedInterpreterHandler = const CachedInterpreterInstruction* (*)(const CachedInterpreterInstruction*);
#define DEFINE_CACHED_INTERPRETER_HANDLER(name) \
const CPU::CodeCache::CachedInterpreterInstruction* name( \
const CPU::CodeCache::CachedInterpreterInstruction* cbaseinst)
#define CACHED_INTERPRETER_INSTRUCTION_TYPE(type) const type* cinst = static_cast<const type*>(cbaseinst)
#define CACHED_INTERPRETER_HANDLER_RETURN(value) return value
#define END_CACHED_INTERPRETER_INSTRUCTION() CACHED_INTERPRETER_HANDLER_RETURN((cinst + 1))
#endif #endif
struct CachedInterpreterInstruction struct CachedInterpreterInstruction
{ {
CachedInterpreterHandler handler; CachedInterpreterHandler handler;
};
static_assert(sizeof(CachedInterpreterInstruction) == sizeof(CachedInterpreterHandler));
struct CachedInterpreterIntArgInstruction : CachedInterpreterInstruction
{
u32 arg; u32 arg;
}; };
struct CachedInterpreterMIPSInstruction : CachedInterpreterInstruction
{
Instruction inst;
u32 pc;
};
struct CachedInterpreterBlockLinkInstruction : CachedInterpreterInstruction
{
const CachedInterpreterInstruction* target;
u32 target_pc;
};
struct CachedInterpreterConditionalBranchInstruction : CachedInterpreterMIPSInstruction
{
const CachedInterpreterInstruction* not_taken_target;
};
class CachedInterpreterCompiler
{
public:
CachedInterpreterCompiler(Block* block, CachedInterpreterInstruction* cinst);
CachedInterpreterInstruction* GetCodeStart() const { return m_code_start; }
u32 GetCodeSize() const
{
return static_cast<u32>(reinterpret_cast<u8*>(m_code_ptr) - reinterpret_cast<u8*>(m_code_start));
}
bool CompileBlock();
private:
bool CompileInstruction();
bool CompileBranchDelaySlot();
bool CompileUnconditionalBranch();
bool CompileConditionalBranch();
bool CompileIndirectBranch();
void BackupState();
void RestoreState();
void AddBlockLinkInstruction(u32 target_pc);
template<typename T>
T* AddInstruction()
{
T* ret = static_cast<T*>(m_code_ptr);
m_code_ptr = (ret + 1);
return ret;
}
Block* m_block = nullptr;
CachedInterpreterInstruction* m_code_start = nullptr;
CachedInterpreterInstruction* m_code_ptr = nullptr;
const Instruction* inst = nullptr;
const InstructionInfo* iinfo = nullptr;
u32 m_compiler_pc = 0;
u32 m_current_instruction_pc = 0;
bool m_block_ended = false;
bool m_has_load_delay = false;
struct StateBackup
{
const Instruction* inst;
const InstructionInfo* iinfo;
u32 compiler_pc;
u32 current_instruction_pc;
bool block_ended;
bool has_load_delay;
};
StateBackup m_state_backup = {};
};
template<PGXPMode pgxp_mode> template<PGXPMode pgxp_mode>
void InterpretUncachedBlock(); void InterpretUncachedBlock();

File diff suppressed because it is too large Load Diff

View File

@ -168,77 +168,79 @@ void UncheckedWriteMemoryWord(u32 address, u32 value);
#endif #endif
#define CPU_FOR_EACH_INSTRUCTION(X) \ // clang-format off
X(b) \ #define CPU_FOR_EACH_INSTRUCTION(X, eX) \
X(j) \ X(b) \
X(jal) \ X(j) \
X(beq) \ X(jal) \
X(bne) \ X(beq) \
X(blez) \ X(bne) \
X(bgtz) \ X(blez) \
X(addi) \ X(bgtz) \
X(addiu) \ eX(addi) \
X(slti) \ X(addiu) \
X(sltiu) \ X(slti) \
X(andi) \ X(sltiu) \
X(ori) \ X(andi) \
X(xori) \ X(ori) \
X(lui) \ X(xori) \
X(lb) \ X(lui) \
X(lh) \ eX(lb) \
X(lwl) \ eX(lh) \
X(lw) \ eX(lwl) \
X(lbu) \ eX(lw) \
X(lhu) \ eX(lbu) \
X(lwr) \ eX(lhu) \
X(sb) \ eX(lwr) \
X(sh) \ eX(sb) \
X(swl) \ eX(sh) \
X(sw) \ eX(swl) \
X(swr) \ eX(sw) \
X(mfc0) \ eX(swr) \
X(mtc0) \ eX(mfc0) \
X(rfe) \ eX(mtc0) \
X(mfc2) \ X(rfe) \
X(mtc2) \ X(mfc2) \
X(cfc2) \ X(mtc2) \
X(ctc2) \ X(cfc2) \
X(cop2) \ X(ctc2) \
X(lwc0) \ X(cop2) \
X(lwc1) \ eX(lwc0) \
X(lwc2) \ eX(lwc1) \
X(lwc3) \ eX(lwc2) \
X(swc0) \ eX(lwc3) \
X(swc1) \ eX(swc0) \
X(swc2) \ eX(swc1) \
X(swc3) \ eX(swc2) \
X(sll) \ eX(swc3) \
X(srl) \ X(sll) \
X(sra) \ X(srl) \
X(sllv) \ X(sra) \
X(srlv) \ X(sllv) \
X(srav) \ X(srlv) \
X(jr) \ X(srav) \
X(jalr) \ X(jr) \
X(syscall) \ X(jalr) \
X(break) \ X(syscall) \
X(mfhi) \ X(break)\
X(mthi) \ X(mfhi) \
X(mflo) \ X(mthi) \
X(mtlo) \ X(mflo) \
X(mult) \ X(mtlo) \
X(multu) \ X(mult) \
X(div) \ X(multu) \
X(divu) \ X(div) \
X(add) \ X(divu) \
X(addu) \ eX(add) \
X(sub) \ X(addu) \
X(subu) \ eX(sub) \
X(and) \ X(subu) \
X(or) \ X(and) \
X(xor) \ X(or) \
X(nor) \ X(xor) \
X(slt) \ X(nor) \
X(slt) \
X(sltu) X(sltu)
// clang-format on
} // namespace CPU } // namespace CPU