From d3717e66c3906731da743d8ee1d9283bc225ea8d Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Thu, 18 Feb 2021 17:46:20 +1000 Subject: [PATCH] CPU/Recompiler: Handle self-modifying code within same block Fixes Spyro 2 and 3 PAL with recompiler. --- src/core/cpu_recompiler_code_generator.cpp | 26 ++++++++++++++++++++++ src/core/cpu_recompiler_code_generator.h | 1 + 2 files changed, 27 insertions(+) diff --git a/src/core/cpu_recompiler_code_generator.cpp b/src/core/cpu_recompiler_code_generator.cpp index b569cd52e..3ba83b682 100644 --- a/src/core/cpu_recompiler_code_generator.cpp +++ b/src/core/cpu_recompiler_code_generator.cpp @@ -1008,6 +1008,13 @@ void CodeGenerator::InstructionEpilogue(const CodeBlockInstruction& cbi) } } +void CodeGenerator::TruncateBlockAtCurrentInstruction() +{ + Log_DevPrintf("Truncating block %08X at %08X", m_block->GetPC(), m_current_instruction->pc); + m_block_end = m_current_instruction + 1; + WriteNewPC(CalculatePC(), true); +} + void CodeGenerator::AddPendingCycles(bool commit) { if (m_delayed_cycles_add == 0) @@ -1496,6 +1503,25 @@ bool CodeGenerator::Compile_Store(const CodeBlockInstruction& cbi) } InstructionEpilogue(cbi); + + if (address_spec) + { + const CPU::Segment seg = GetSegmentForAddress(*address_spec); + if (seg == Segment::KUSEG || seg == Segment::KSEG0 || seg == Segment::KSEG1) + { + const PhysicalMemoryAddress phys_addr = VirtualAddressToPhysical(*address_spec); + const PhysicalMemoryAddress block_start = VirtualAddressToPhysical(m_block->GetPC()); + const PhysicalMemoryAddress block_end = VirtualAddressToPhysical( + m_block->GetPC() + static_cast(m_block->instructions.size()) * sizeof(Instruction)); + if (phys_addr >= block_start && phys_addr < block_end) + { + Log_WarningPrintf("Instruction %08X speculatively writes to %08X inside block %08X-%08X. Truncating block.", + cbi.pc, phys_addr, block_start, block_end); + TruncateBlockAtCurrentInstruction(); + } + } + } + return true; } diff --git a/src/core/cpu_recompiler_code_generator.h b/src/core/cpu_recompiler_code_generator.h index fcd8a4d20..e6db0e7dd 100644 --- a/src/core/cpu_recompiler_code_generator.h +++ b/src/core/cpu_recompiler_code_generator.h @@ -196,6 +196,7 @@ private: void BlockEpilogue(); void InstructionPrologue(const CodeBlockInstruction& cbi, TickCount cycles, bool force_sync = false); void InstructionEpilogue(const CodeBlockInstruction& cbi); + void TruncateBlockAtCurrentInstruction(); void AddPendingCycles(bool commit); Value CalculatePC(u32 offset = 0);