This commit is contained in:
Stenzek 2025-03-02 15:48:28 +10:00
parent 872a48d616
commit fc90d84788
No known key found for this signature in database
3 changed files with 111 additions and 32 deletions

View File

@ -75,7 +75,6 @@ static void RemoveBlockFromPageList(Block* block);
static void SetCachedInterpreterHandlers(); static void SetCachedInterpreterHandlers();
static void CompileCachedInterpreterBlock(const u32); static void CompileCachedInterpreterBlock(const u32);
static void ExecuteCachedInterpreterBlock(const CachedInterpreterInstruction* cinst);
[[noreturn]] static void ExecuteCachedInterpreter(); [[noreturn]] static void ExecuteCachedInterpreter();
// Fast map provides lookup from PC to function // Fast map provides lookup from PC to function
@ -714,10 +713,78 @@ PageFaultHandler::HandlerResult PageFaultHandler::HandlePageFault(void* exceptio
// MARK: - Cached Interpreter // MARK: - Cached Interpreter
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace CPU::CodeCache::CachedInterpreterFunctions {
static void CompileOrRevalidateBlock(const CachedInterpreterInstruction* cinst);
static void LookupAndExecuteBlock(const CachedInterpreterInstruction* cinst);
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
void CPU::CodeCache::CachedInterpreterFunctions::CompileOrRevalidateBlock(const CachedInterpreterInstruction* cinst)
{
CompileCachedInterpreterBlock(g_state.pc);
END_CACHED_INTERPRETER_INSTRUCTION(cinst);
}
void CPU::CodeCache::CachedInterpreterFunctions::LookupAndExecuteBlock(const CachedInterpreterInstruction*)
{
const u32 pc = g_state.pc;
const u32 table = pc >> LUT_TABLE_SHIFT;
const u32 idx = (pc & 0xFFFF) >> 2;
const CachedInterpreterInstruction* cinst =
reinterpret_cast<const CachedInterpreterInstruction*>(g_code_lut[table][idx]);
#ifdef HAS_MUSTTAIL
RETURN_MUSTTAIL(cinst->handler(cinst));
#else
do
{
cinst->handler(cinst);
cinst++;
} while (cinst->handler);
#endif
}
void CPU::CodeCache::CachedInterpreterFunctions::LogCurrentState(const CachedInterpreterInstruction* cinst)
{
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() void CPU::CodeCache::SetCachedInterpreterHandlers()
{ {
static constexpr const CachedInterpreterInstruction compile_or_revalidate_block[] = { static constexpr const CachedInterpreterInstruction compile_or_revalidate_block[] = {
{&CompileCachedInterpreterBlock, 0u}, {&CachedInterpreterFunctions::CompileOrRevalidateBlock, 0u},
{&CachedInterpreterFunctions::LookupAndExecuteBlock, 0u},
{nullptr, 0u}, {nullptr, 0u},
}; };
@ -775,32 +842,26 @@ void CPU::CodeCache::CompileCachedInterpreterBlock(const u32)
if (false) if (false)
{ {
cinst->handler = [](u32) { LogCurrentState(); }; cinst->handler = &CachedInterpreterFunctions::LogCurrentState;
cinst->arg = 0; cinst->arg = 0;
cinst++; cinst++;
} }
if (block->HasFlag(BlockFlags::IsUsingICache)) if (block->HasFlag(BlockFlags::IsUsingICache))
{ {
cinst->handler = &CheckAndUpdateICacheTags; cinst->handler = &CachedInterpreterFunctions::CheckAndUpdateICacheTags;
cinst->arg = block->icache_line_count; cinst->arg = block->icache_line_count;
cinst++; cinst++;
} }
else if (block->HasFlag(BlockFlags::NeedsDynamicFetchTicks)) else if (block->HasFlag(BlockFlags::NeedsDynamicFetchTicks))
{ {
static const auto dynamic_fetch_handler = [](u32 size) { cinst->handler = &CachedInterpreterFunctions::AddDynamicFetchTicks;
AddPendingTicks(
static_cast<TickCount>(size * static_cast<u32>(*Bus::GetMemoryAccessTimePtr(
g_state.pc & PHYSICAL_MEMORY_ADDRESS_MASK, MemoryAccessSize::Word))));
};
cinst->handler = dynamic_fetch_handler;
cinst->arg = block->size; cinst->arg = block->size;
cinst++; cinst++;
} }
else if (block->uncached_fetch_ticks > 0) else if (block->uncached_fetch_ticks > 0)
{ {
cinst->handler = reinterpret_cast<CachedInterpreterHandler>(&CPU::AddPendingTicks); cinst->handler = &CachedInterpreterFunctions::AddUncachedFetchTicks;
cinst->arg = static_cast<u32>(block->uncached_fetch_ticks); cinst->arg = static_cast<u32>(block->uncached_fetch_ticks);
cinst++; cinst++;
} }
@ -817,7 +878,11 @@ void CPU::CodeCache::CompileCachedInterpreterBlock(const u32)
} }
// end // end
#ifdef HAS_MUSTTAIL
cinst->handler = &CachedInterpreterFunctions::EndBlock;
#else
cinst->handler = nullptr; cinst->handler = nullptr;
#endif
cinst->arg = 0; cinst->arg = 0;
cinst++; cinst++;
@ -828,21 +893,9 @@ void CPU::CodeCache::CompileCachedInterpreterBlock(const u32)
CommitCode(required_space); CommitCode(required_space);
MemMap::EndCodeWrite(); MemMap::EndCodeWrite();
// execute it
ExecuteCachedInterpreterBlock(cstart);
// TODO: Block linking! // TODO: Block linking!
} }
ALWAYS_INLINE_RELEASE void CPU::CodeCache::ExecuteCachedInterpreterBlock(const CachedInterpreterInstruction* cinst)
{
do
{
cinst->handler(cinst->arg);
cinst++;
} while (cinst->handler);
}
[[noreturn]] void CPU::CodeCache::ExecuteCachedInterpreter() [[noreturn]] void CPU::CodeCache::ExecuteCachedInterpreter()
{ {
#define CHECK_DOWNCOUNT() \ #define CHECK_DOWNCOUNT() \
@ -874,7 +927,17 @@ ALWAYS_INLINE_RELEASE void CPU::CodeCache::ExecuteCachedInterpreterBlock(const C
reexecute_block: reexecute_block:
// Execute block. // Execute block.
DebugAssert(!(HasPendingInterrupt())); DebugAssert(!(HasPendingInterrupt()));
ExecuteCachedInterpreterBlock(cinst);
#ifdef HAS_MUSTTAIL
cinst->handler(cinst);
#else
do
{
cinst->handler(cinst);
cinst++;
} while (cinst->handler);
#endif
CHECK_DOWNCOUNT(); CHECK_DOWNCOUNT();
// Handle self-looping blocks // Handle self-looping blocks

View File

@ -13,6 +13,11 @@
#include <array> #include <array>
#include <unordered_map> #include <unordered_map>
#ifdef __clang__
#define HAS_MUSTTAIL 1
#define RETURN_MUSTTAIL(val) __attribute__((musttail)) return val
#endif
namespace CPU::CodeCache { namespace CPU::CodeCache {
enum : u32 enum : u32
@ -205,9 +210,17 @@ struct PageProtectionInfo
}; };
static_assert(sizeof(PageProtectionInfo) == (sizeof(Block*) * 2 + 8)); static_assert(sizeof(PageProtectionInfo) == (sizeof(Block*) * 2 + 8));
using CachedInterpreterHandler = void(*)(u32 arg); struct CachedInterpreterInstruction;
using CachedInterpreterHandler = void (*)(const CachedInterpreterInstruction*);
CachedInterpreterHandler GetCachedInterpreterHandler(const Instruction inst); CachedInterpreterHandler GetCachedInterpreterHandler(const Instruction inst);
#ifdef HAS_MUSTTAIL
#define END_CACHED_INTERPRETER_INSTRUCTION(arg) RETURN_MUSTTAIL((arg + 1)->handler(arg + 1));
#else
#define END_CACHED_INTERPRETER_INSTRUCTION(arg)
#endif
struct CachedInterpreterInstruction struct CachedInterpreterInstruction
{ {
CachedInterpreterHandler handler; CachedInterpreterHandler handler;

View File

@ -2775,29 +2775,31 @@ void CPU::SetSingleStepFlag()
namespace CPU { namespace CPU {
#define MAKE_CACHED_INSTRUCTION_HANDLER(insn) \ #define MAKE_CACHED_INSTRUCTION_HANDLER(insn) \
template<PGXPMode pgxp_mode> \ template<PGXPMode pgxp_mode> \
static void CachedInstructionHandler_##insn(u32 arg) \ static void CachedInstructionHandler_##insn(const CPU::CodeCache::CachedInterpreterInstruction* cinst) \
{ \ { \
const Instruction inst{cinst->arg}; \
g_state.pending_ticks++; \ g_state.pending_ticks++; \
g_state.current_instruction.bits = arg; \ g_state.current_instruction.bits = inst.bits; \
g_state.current_instruction_pc = g_state.pc; \ g_state.current_instruction_pc = g_state.pc; \
g_state.current_instruction_was_branch_taken = g_state.branch_was_taken; \ g_state.current_instruction_was_branch_taken = g_state.branch_was_taken; \
g_state.branch_was_taken = false; \ g_state.branch_was_taken = false; \
g_state.exception_raised = false; \ g_state.exception_raised = false; \
g_state.pc = g_state.npc; \ g_state.pc = g_state.npc; \
g_state.npc += 4; \ g_state.npc += 4; \
Execute_##insn<pgxp_mode, false>(Instruction{arg}); \ Execute_##insn<pgxp_mode, false>(inst); \
UpdateLoadDelay(); /* TODO: For non-load instructions, we don't need to update next_load_delay_reg */ \ UpdateLoadDelay(); /* TODO: For non-load instructions, we don't need to update next_load_delay_reg */ \
g_state.next_instruction_is_branch_delay_slot = false; /* FIXME */ \ g_state.next_instruction_is_branch_delay_slot = false; /* FIXME */ \
END_CACHED_INTERPRETER_INSTRUCTION(cinst); \
} }
CPU_FOR_EACH_INSTRUCTION(MAKE_CACHED_INSTRUCTION_HANDLER); CPU_FOR_EACH_INSTRUCTION(MAKE_CACHED_INSTRUCTION_HANDLER);
// TODO: inline gte ops // TODO: inline gte ops
static void CachedInstructionHandler_gte(u32 arg) static void CachedInstructionHandler_gte(const CPU::CodeCache::CachedInterpreterInstruction* cinst)
{ {
g_state.pending_ticks++; g_state.pending_ticks++;
g_state.current_instruction.bits = arg; g_state.current_instruction.bits = cinst->arg;
g_state.current_instruction_pc = g_state.pc; g_state.current_instruction_pc = g_state.pc;
g_state.current_instruction_was_branch_taken = g_state.branch_was_taken; g_state.current_instruction_was_branch_taken = g_state.branch_was_taken;
g_state.branch_was_taken = false; g_state.branch_was_taken = false;
@ -2805,9 +2807,10 @@ static void CachedInstructionHandler_gte(u32 arg)
g_state.pc = g_state.npc; g_state.pc = g_state.npc;
g_state.npc += 4; g_state.npc += 4;
StallUntilGTEComplete(); StallUntilGTEComplete();
GTE::ExecuteInstruction(arg); GTE::ExecuteInstruction(cinst->arg);
UpdateLoadDelay(); UpdateLoadDelay();
g_state.next_instruction_is_branch_delay_slot = false; /* FIXME */ g_state.next_instruction_is_branch_delay_slot = false; /* FIXME */
END_CACHED_INTERPRETER_INSTRUCTION(cinst);
} }
} // namespace CPU } // namespace CPU