From 9e3bb6221613582f5f5a7575c0564f5191bf24c9 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Wed, 20 Nov 2019 01:19:03 +1000 Subject: [PATCH] CPU/CodeCache: Fast path for self-linking blocks --- src/core/cpu_code_cache.cpp | 32 ++++++++++++++++++++++++-------- src/core/cpu_code_cache.h | 3 ++- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/core/cpu_code_cache.cpp b/src/core/cpu_code_cache.cpp index bfb0f4b1e..5d7e58b68 100644 --- a/src/core/cpu_code_cache.cpp +++ b/src/core/cpu_code_cache.cpp @@ -5,8 +5,6 @@ #include "cpu_recompiler_code_generator.h" #include "cpu_recompiler_thunks.h" #include "system.h" -#include -#include Log_SetChannel(CPU::CodeCache); namespace CPU { @@ -31,15 +29,18 @@ void CodeCache::Initialize(System* system, Core* core, Bus* bus) void CodeCache::Execute() { + CodeBlockKey next_block_key = GetNextBlockKey(); + while (m_core->m_downcount >= 0) { if (m_core->HasPendingInterrupt()) { // TODO: Fill in m_next_instruction... m_core->DispatchInterrupt(); + next_block_key = GetNextBlockKey(); } - m_current_block = GetNextBlock(); + m_current_block = LookupBlock(next_block_key); if (!m_current_block) { Log_WarningPrintf("Falling back to uncached interpreter at 0x%08X", m_core->GetRegs().pc); @@ -47,18 +48,29 @@ void CodeCache::Execute() continue; } + reexecute_block: if (USE_RECOMPILER) m_current_block->host_code(m_core); else InterpretCachedBlock(*m_current_block); + next_block_key = GetNextBlockKey(); if (m_current_block_flushed) { m_current_block_flushed = false; delete m_current_block; + m_current_block = nullptr; + continue; } - m_current_block = nullptr; + // Loop to same block? + next_block_key = GetNextBlockKey(); + if (next_block_key.bits == m_current_block->key.bits) + { + // we can jump straight to it if there's no pending interrupts + if (m_core->m_downcount >= 0 && !m_core->HasPendingInterrupt()) + goto reexecute_block; + } } } @@ -72,14 +84,18 @@ void CodeCache::Reset() m_code_buffer->Reset(); } -const CPU::CodeBlock* CodeCache::GetNextBlock() +CodeBlockKey CodeCache::GetNextBlockKey() const { const u32 address = m_bus->UnmirrorAddress(m_core->m_regs.pc & UINT32_C(0x1FFFFFFF)); CodeBlockKey key = {}; key.SetPC(address); key.user_mode = m_core->InUserMode(); + return key; +} +const CPU::CodeBlock* CodeCache::LookupBlock(CodeBlockKey key) +{ BlockMap::iterator iter = m_blocks.find(key.bits); if (iter != m_blocks.end()) return iter->second; @@ -89,7 +105,7 @@ const CPU::CodeBlock* CodeCache::GetNextBlock() if (CompileBlock(block)) { // insert into the page map - if (m_bus->IsRAMAddress(address)) + if (m_bus->IsRAMAddress(key.GetPC())) { const u32 start_page = block->GetStartPageIndex(); const u32 end_page = block->GetEndPageIndex(); @@ -102,7 +118,7 @@ const CPU::CodeBlock* CodeCache::GetNextBlock() } else { - Log_ErrorPrintf("Failed to compile block at PC=0x%08X", address); + Log_ErrorPrintf("Failed to compile block at PC=0x%08X", key.GetPC()); } iter = m_blocks.emplace(key.bits, block).first; @@ -314,4 +330,4 @@ void CodeCache::InterpretUncachedBlock() } } -} // namespace CPU \ No newline at end of file +} // namespace CPU diff --git a/src/core/cpu_code_cache.h b/src/core/cpu_code_cache.h index 5b9882032..7855b412d 100644 --- a/src/core/cpu_code_cache.h +++ b/src/core/cpu_code_cache.h @@ -34,7 +34,8 @@ public: private: using BlockMap = std::unordered_map; - const CodeBlock* GetNextBlock(); + CodeBlockKey GetNextBlockKey() const; + const CodeBlock* LookupBlock(CodeBlockKey key); bool CompileBlock(CodeBlock* block); void FlushBlock(CodeBlock* block); void InterpretCachedBlock(const CodeBlock& block);