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 {
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);
static DEFINE_CACHED_INTERPRETER_HANDLER(CompileOrRevalidateBlock);
static DEFINE_CACHED_INTERPRETER_HANDLER(LookupAndExecuteBlock);
} // 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*)
DEFINE_CACHED_INTERPRETER_HANDLER(CPU::CodeCache::CachedInterpreterFunctions::LookupAndExecuteBlock)
{
const u32 pc = g_state.pc;
const u32 table = pc >> LUT_TABLE_SHIFT;
@ -742,56 +731,13 @@ void CPU::CodeCache::CachedInterpreterFunctions::LookupAndExecuteBlock(const Cac
#else
do
{
cinst->handler(cinst);
cinst++;
} while (cinst->handler);
cinst = cinst->handler(cinst);
} while (cinst);
return nullptr;
#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()
{
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)
DEFINE_CACHED_INTERPRETER_HANDLER(CPU::CodeCache::CachedInterpreterFunctions::CompileOrRevalidateBlock)
{
const u32 start_pc = g_state.pc;
MemMap::BeginCodeWrite();
@ -806,13 +752,13 @@ void CPU::CodeCache::CompileCachedInterpreterBlock(const u32)
{
DebugAssert(block->host_code);
SetCodeLUT(start_pc, block->host_code);
// BacklinkBlocks(start_pc, block->host_code);
BacklinkBlocks(start_pc, block->host_code);
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
// UnlinkBlockExits(block);
UnlinkBlockExits(block);
}
BlockMetadata metadata = {};
@ -822,6 +768,7 @@ void CPU::CodeCache::CompileCachedInterpreterBlock(const u32)
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);
if (GetFreeCodeSpace() < required_space)
{
@ -833,67 +780,34 @@ void CPU::CodeCache::CompileCachedInterpreterBlock(const u32)
if (!block)
{
Panic("Fixme");
return;
}
const CPU::Instruction* mips_insns = block->Instructions();
CachedInterpreterInstruction* cstart = reinterpret_cast<CachedInterpreterInstruction*>(GetFreeCodePointer());
CachedInterpreterInstruction* cinst = cstart;
CachedInterpreterCompiler compiler(block, reinterpret_cast<CachedInterpreterInstruction*>(GetFreeCodePointer()));
if (!compiler.CompileBlock())
Panic("Fixme");
if (false)
{
cinst->handler = &CachedInterpreterFunctions::LogCurrentState;
cinst->arg = 0;
cinst++;
}
block->host_code = compiler.GetCodeStart();
block->host_code_size = compiler.GetCodeSize();
CommitCode(block->host_code_size);
if (block->HasFlag(BlockFlags::IsUsingICache))
{
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);
SetCodeLUT(start_pc, block->host_code);
BacklinkBlocks(start_pc, block->host_code);
MemMap::EndCodeWrite();
// 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()
@ -933,9 +847,8 @@ void CPU::CodeCache::CompileCachedInterpreterBlock(const u32)
#else
do
{
cinst->handler(cinst);
cinst++;
} while (cinst->handler);
cinst = cinst->handler(cinst);
} while (cinst);
#endif
CHECK_DOWNCOUNT();
@ -952,7 +865,7 @@ void CPU::CodeCache::CompileCachedInterpreterBlock(const u32)
void CPU::CodeCache::LogCurrentState()
{
#if 0
if (System::GetGlobalTickCounter() == 2546728915)
if (System::GetGlobalTickCounter() == 9953322268)
__debugbreak();
#endif
#if 0
@ -1542,11 +1455,25 @@ void CPU::CodeCache::BacklinkBlocks(u32 pc, const void* dst)
return;
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,
(dst == g_compile_or_revalidate_block) ? "[compiler]" : "");
EmitJump(it->second, dst, true);
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]" : "");
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;
using CachedInterpreterHandler = void (*)(const CachedInterpreterInstruction*);
CachedInterpreterHandler GetCachedInterpreterHandler(const Instruction inst);
#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
#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
struct CachedInterpreterInstruction
{
CachedInterpreterHandler handler;
};
static_assert(sizeof(CachedInterpreterInstruction) == sizeof(CachedInterpreterHandler));
struct CachedInterpreterIntArgInstruction : CachedInterpreterInstruction
{
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>
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
#define CPU_FOR_EACH_INSTRUCTION(X) \
X(b) \
X(j) \
X(jal) \
X(beq) \
X(bne) \
X(blez) \
X(bgtz) \
X(addi) \
X(addiu) \
X(slti) \
X(sltiu) \
X(andi) \
X(ori) \
X(xori) \
X(lui) \
X(lb) \
X(lh) \
X(lwl) \
X(lw) \
X(lbu) \
X(lhu) \
X(lwr) \
X(sb) \
X(sh) \
X(swl) \
X(sw) \
X(swr) \
X(mfc0) \
X(mtc0) \
X(rfe) \
X(mfc2) \
X(mtc2) \
X(cfc2) \
X(ctc2) \
X(cop2) \
X(lwc0) \
X(lwc1) \
X(lwc2) \
X(lwc3) \
X(swc0) \
X(swc1) \
X(swc2) \
X(swc3) \
X(sll) \
X(srl) \
X(sra) \
X(sllv) \
X(srlv) \
X(srav) \
X(jr) \
X(jalr) \
X(syscall) \
X(break) \
X(mfhi) \
X(mthi) \
X(mflo) \
X(mtlo) \
X(mult) \
X(multu) \
X(div) \
X(divu) \
X(add) \
X(addu) \
X(sub) \
X(subu) \
X(and) \
X(or) \
X(xor) \
X(nor) \
X(slt) \
// clang-format off
#define CPU_FOR_EACH_INSTRUCTION(X, eX) \
X(b) \
X(j) \
X(jal) \
X(beq) \
X(bne) \
X(blez) \
X(bgtz) \
eX(addi) \
X(addiu) \
X(slti) \
X(sltiu) \
X(andi) \
X(ori) \
X(xori) \
X(lui) \
eX(lb) \
eX(lh) \
eX(lwl) \
eX(lw) \
eX(lbu) \
eX(lhu) \
eX(lwr) \
eX(sb) \
eX(sh) \
eX(swl) \
eX(sw) \
eX(swr) \
eX(mfc0) \
eX(mtc0) \
X(rfe) \
X(mfc2) \
X(mtc2) \
X(cfc2) \
X(ctc2) \
X(cop2) \
eX(lwc0) \
eX(lwc1) \
eX(lwc2) \
eX(lwc3) \
eX(swc0) \
eX(swc1) \
eX(swc2) \
eX(swc3) \
X(sll) \
X(srl) \
X(sra) \
X(sllv) \
X(srlv) \
X(srav) \
X(jr) \
X(jalr) \
X(syscall) \
X(break)\
X(mfhi) \
X(mthi) \
X(mflo) \
X(mtlo) \
X(mult) \
X(multu) \
X(div) \
X(divu) \
eX(add) \
X(addu) \
eX(sub) \
X(subu) \
X(and) \
X(or) \
X(xor) \
X(nor) \
X(slt) \
X(sltu)
// clang-format on
} // namespace CPU