mirror of
https://github.com/stenzek/duckstation.git
synced 2025-06-07 12:05:52 +00:00
testing
This commit is contained in:
parent
859f5090c8
commit
872a48d616
@ -73,10 +73,10 @@ static void SetRegAccess(InstructionInfo* inst, Reg reg, bool write);
|
|||||||
static void AddBlockToPageList(Block* block);
|
static void AddBlockToPageList(Block* block);
|
||||||
static void RemoveBlockFromPageList(Block* block);
|
static void RemoveBlockFromPageList(Block* block);
|
||||||
|
|
||||||
static Block* CreateCachedInterpreterBlock(u32 pc);
|
static void SetCachedInterpreterHandlers();
|
||||||
|
static void CompileCachedInterpreterBlock(const u32);
|
||||||
|
static void ExecuteCachedInterpreterBlock(const CachedInterpreterInstruction* cinst);
|
||||||
[[noreturn]] static void ExecuteCachedInterpreter();
|
[[noreturn]] static void ExecuteCachedInterpreter();
|
||||||
template<PGXPMode pgxp_mode>
|
|
||||||
[[noreturn]] static void ExecuteCachedInterpreterImpl();
|
|
||||||
|
|
||||||
// Fast map provides lookup from PC to function
|
// Fast map provides lookup from PC to function
|
||||||
// Function pointers are offset so that you don't need to subtract
|
// Function pointers are offset so that you don't need to subtract
|
||||||
@ -216,6 +216,12 @@ void CPU::CodeCache::Reset()
|
|||||||
CompileASMFunctions();
|
CompileASMFunctions();
|
||||||
ResetCodeLUT();
|
ResetCodeLUT();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetCachedInterpreterHandlers();
|
||||||
|
ResetCodeBuffer();
|
||||||
|
ResetCodeLUT();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::CodeCache::Shutdown()
|
void CPU::CodeCache::Shutdown()
|
||||||
@ -708,15 +714,136 @@ PageFaultHandler::HandlerResult PageFaultHandler::HandlePageFault(void* exceptio
|
|||||||
// MARK: - Cached Interpreter
|
// MARK: - Cached Interpreter
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
CPU::CodeCache::Block* CPU::CodeCache::CreateCachedInterpreterBlock(u32 pc)
|
void CPU::CodeCache::SetCachedInterpreterHandlers()
|
||||||
{
|
{
|
||||||
BlockMetadata metadata = {};
|
static constexpr const CachedInterpreterInstruction compile_or_revalidate_block[] = {
|
||||||
ReadBlockInstructions(pc, &s_block_instructions, &metadata);
|
{&CompileCachedInterpreterBlock, 0u},
|
||||||
return CreateBlock(pc, s_block_instructions, metadata);
|
{nullptr, 0u},
|
||||||
|
};
|
||||||
|
|
||||||
|
g_compile_or_revalidate_block = compile_or_revalidate_block;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<PGXPMode pgxp_mode>
|
void CPU::CodeCache::CompileCachedInterpreterBlock(const u32)
|
||||||
[[noreturn]] void CPU::CodeCache::ExecuteCachedInterpreterImpl()
|
{
|
||||||
|
const u32 start_pc = g_state.pc;
|
||||||
|
MemMap::BeginCodeWrite();
|
||||||
|
|
||||||
|
// Revalidation
|
||||||
|
Block* block = LookupBlock(start_pc);
|
||||||
|
if (block)
|
||||||
|
{
|
||||||
|
// we should only be here if the block got invalidated
|
||||||
|
DebugAssert(block->state != BlockState::Valid);
|
||||||
|
if (RevalidateBlock(block))
|
||||||
|
{
|
||||||
|
DebugAssert(block->host_code);
|
||||||
|
SetCodeLUT(start_pc, block->host_code);
|
||||||
|
// BacklinkBlocks(start_pc, block->host_code);
|
||||||
|
MemMap::EndCodeWrite();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove outward links from this block, since we're recompiling it
|
||||||
|
// UnlinkBlockExits(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockMetadata metadata = {};
|
||||||
|
if (!ReadBlockInstructions(start_pc, &s_block_instructions, &metadata))
|
||||||
|
{
|
||||||
|
ERROR_LOG("Failed to read block at 0x{:08X}, falling back to uncached interpreter", start_pc);
|
||||||
|
Panic("Fixme");
|
||||||
|
}
|
||||||
|
|
||||||
|
const u32 required_space = sizeof(CachedInterpreterInstruction) * (static_cast<u32>(s_block_instructions.size()) + 3);
|
||||||
|
if (GetFreeCodeSpace() < required_space)
|
||||||
|
{
|
||||||
|
ERROR_LOG("Out of code space while compiling {:08X}. Resetting code cache.", start_pc);
|
||||||
|
CodeCache::Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
block = CreateBlock(start_pc, s_block_instructions, metadata);
|
||||||
|
if (!block)
|
||||||
|
{
|
||||||
|
Panic("Fixme");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CPU::Instruction* mips_insns = block->Instructions();
|
||||||
|
CachedInterpreterInstruction* cstart = reinterpret_cast<CachedInterpreterInstruction*>(GetFreeCodePointer());
|
||||||
|
CachedInterpreterInstruction* cinst = cstart;
|
||||||
|
|
||||||
|
if (false)
|
||||||
|
{
|
||||||
|
cinst->handler = [](u32) { LogCurrentState(); };
|
||||||
|
cinst->arg = 0;
|
||||||
|
cinst++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block->HasFlag(BlockFlags::IsUsingICache))
|
||||||
|
{
|
||||||
|
cinst->handler = &CheckAndUpdateICacheTags;
|
||||||
|
cinst->arg = block->icache_line_count;
|
||||||
|
cinst++;
|
||||||
|
}
|
||||||
|
else if (block->HasFlag(BlockFlags::NeedsDynamicFetchTicks))
|
||||||
|
{
|
||||||
|
static const auto dynamic_fetch_handler = [](u32 size) {
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
else if (block->uncached_fetch_ticks > 0)
|
||||||
|
{
|
||||||
|
cinst->handler = reinterpret_cast<CachedInterpreterHandler>(&CPU::AddPendingTicks);
|
||||||
|
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
|
||||||
|
cinst->handler = nullptr;
|
||||||
|
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();
|
||||||
|
|
||||||
|
// execute it
|
||||||
|
ExecuteCachedInterpreterBlock(cstart);
|
||||||
|
|
||||||
|
// 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()
|
||||||
{
|
{
|
||||||
#define CHECK_DOWNCOUNT() \
|
#define CHECK_DOWNCOUNT() \
|
||||||
if (g_state.pending_ticks >= g_state.downcount) \
|
if (g_state.pending_ticks >= g_state.downcount) \
|
||||||
@ -733,94 +860,32 @@ template<PGXPMode pgxp_mode>
|
|||||||
LogCurrentState();
|
LogCurrentState();
|
||||||
#endif
|
#endif
|
||||||
#if 0
|
#if 0
|
||||||
if ((g_state.pending_ticks + TimingEvents::GetGlobalTickCounter()) == 3301006214)
|
if ((g_state.pending_ticks + TimingEvents::GetGlobalTickCounter()) == 108345628)
|
||||||
__debugbreak();
|
__debugbreak();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Manually done because we don't want to compile blocks without a LUT.
|
// Manually done because we don't want to compile blocks without a LUT.
|
||||||
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;
|
||||||
Block* block;
|
const u32 idx = (pc & 0xFFFF) >> 2;
|
||||||
if (s_block_lut[table])
|
const CachedInterpreterInstruction* cinst =
|
||||||
{
|
reinterpret_cast<const CachedInterpreterInstruction*>(g_code_lut[table][idx]);
|
||||||
const u32 idx = (pc & 0xFFFF) >> 2;
|
|
||||||
block = s_block_lut[table][idx];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Likely invalid code...
|
|
||||||
goto interpret_block;
|
|
||||||
}
|
|
||||||
|
|
||||||
reexecute_block:
|
reexecute_block:
|
||||||
if (!block)
|
// Execute block.
|
||||||
{
|
|
||||||
if ((block = CreateCachedInterpreterBlock(pc))->size == 0) [[unlikely]]
|
|
||||||
goto interpret_block;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (block->state == BlockState::FallbackToInterpreter) [[unlikely]]
|
|
||||||
goto interpret_block;
|
|
||||||
|
|
||||||
if ((block->state != BlockState::Valid && !RevalidateBlock(block)) ||
|
|
||||||
(block->protection == PageProtectionMode::ManualCheck && !IsBlockCodeCurrent(block)))
|
|
||||||
{
|
|
||||||
if ((block = CreateCachedInterpreterBlock(pc))->size == 0) [[unlikely]]
|
|
||||||
goto interpret_block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DebugAssert(!(HasPendingInterrupt()));
|
DebugAssert(!(HasPendingInterrupt()));
|
||||||
if (block->HasFlag(BlockFlags::IsUsingICache))
|
ExecuteCachedInterpreterBlock(cinst);
|
||||||
{
|
|
||||||
CheckAndUpdateICacheTags(block->icache_line_count);
|
|
||||||
}
|
|
||||||
else if (block->HasFlag(BlockFlags::NeedsDynamicFetchTicks))
|
|
||||||
{
|
|
||||||
AddPendingTicks(
|
|
||||||
static_cast<TickCount>(block->size * static_cast<u32>(*Bus::GetMemoryAccessTimePtr(
|
|
||||||
block->pc & PHYSICAL_MEMORY_ADDRESS_MASK, MemoryAccessSize::Word))));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddPendingTicks(block->uncached_fetch_ticks);
|
|
||||||
}
|
|
||||||
|
|
||||||
InterpretCachedBlock<pgxp_mode>(block);
|
|
||||||
|
|
||||||
CHECK_DOWNCOUNT();
|
CHECK_DOWNCOUNT();
|
||||||
|
|
||||||
// Handle self-looping blocks
|
// Handle self-looping blocks
|
||||||
if (g_state.pc == block->pc)
|
// if (g_state.pc == pc)
|
||||||
goto reexecute_block;
|
// goto reexecute_block;
|
||||||
else
|
|
||||||
continue;
|
|
||||||
|
|
||||||
interpret_block:
|
|
||||||
InterpretUncachedBlock<pgxp_mode>();
|
|
||||||
CHECK_DOWNCOUNT();
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TimingEvents::RunEvents();
|
TimingEvents::RunEvents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] void CPU::CodeCache::ExecuteCachedInterpreter()
|
|
||||||
{
|
|
||||||
if (g_settings.gpu_pgxp_enable)
|
|
||||||
{
|
|
||||||
if (g_settings.gpu_pgxp_cpu)
|
|
||||||
ExecuteCachedInterpreterImpl<PGXPMode::CPU>();
|
|
||||||
else
|
|
||||||
ExecuteCachedInterpreterImpl<PGXPMode::Memory>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ExecuteCachedInterpreterImpl<PGXPMode::Disabled>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPU::CodeCache::LogCurrentState()
|
void CPU::CodeCache::LogCurrentState()
|
||||||
{
|
{
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -205,8 +205,14 @@ struct PageProtectionInfo
|
|||||||
};
|
};
|
||||||
static_assert(sizeof(PageProtectionInfo) == (sizeof(Block*) * 2 + 8));
|
static_assert(sizeof(PageProtectionInfo) == (sizeof(Block*) * 2 + 8));
|
||||||
|
|
||||||
template<PGXPMode pgxp_mode>
|
using CachedInterpreterHandler = void(*)(u32 arg);
|
||||||
void InterpretCachedBlock(const Block* block);
|
CachedInterpreterHandler GetCachedInterpreterHandler(const Instruction inst);
|
||||||
|
|
||||||
|
struct CachedInterpreterInstruction
|
||||||
|
{
|
||||||
|
CachedInterpreterHandler handler;
|
||||||
|
u32 arg;
|
||||||
|
};
|
||||||
|
|
||||||
template<PGXPMode pgxp_mode>
|
template<PGXPMode pgxp_mode>
|
||||||
void InterpretUncachedBlock();
|
void InterpretUncachedBlock();
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -168,4 +168,77 @@ void UncheckedWriteMemoryWord(u32 address, u32 value);
|
|||||||
|
|
||||||
#endif
|
#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) \
|
||||||
|
X(sltu)
|
||||||
|
|
||||||
} // namespace CPU
|
} // namespace CPU
|
Loading…
x
Reference in New Issue
Block a user