mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-29 17:15:40 +00:00
CPU/NewRec: Handle inside-block SMC
i.e. Spyro 2/3 PAL.
This commit is contained in:
parent
20de40a597
commit
e10ff550d5
|
@ -1602,11 +1602,13 @@ void CPU::NewRec::Compiler::CompileLoadStoreTemplate(void (Compiler::*func)(Comp
|
|||
|
||||
// constant address?
|
||||
std::optional<VirtualMemoryAddress> addr;
|
||||
std::optional<VirtualMemoryAddress> spec_addr;
|
||||
bool use_fastmem = CodeCache::IsUsingFastmem() && !g_settings.cpu_recompiler_memory_exceptions &&
|
||||
!SpecIsCacheIsolated() && !CodeCache::HasPreviouslyFaultedOnPC(m_current_instruction_pc);
|
||||
if (HasConstantReg(rs))
|
||||
{
|
||||
addr = GetConstantRegU32(rs) + inst->i.imm_sext32();
|
||||
spec_addr = addr;
|
||||
cf.const_s = true;
|
||||
|
||||
if (!Bus::CanUseFastmemForAddress(addr.value()))
|
||||
|
@ -1617,7 +1619,7 @@ void CPU::NewRec::Compiler::CompileLoadStoreTemplate(void (Compiler::*func)(Comp
|
|||
}
|
||||
else
|
||||
{
|
||||
const std::optional<VirtualMemoryAddress> spec_addr = SpecExec_LoadStoreAddr();
|
||||
spec_addr = SpecExec_LoadStoreAddr();
|
||||
if (use_fastmem && spec_addr.has_value() && !Bus::CanUseFastmemForAddress(spec_addr.value()))
|
||||
{
|
||||
Log_DebugFmt("Not using fastmem for speculative {:08X}", spec_addr.value());
|
||||
|
@ -1671,6 +1673,22 @@ void CPU::NewRec::Compiler::CompileLoadStoreTemplate(void (Compiler::*func)(Comp
|
|||
}
|
||||
|
||||
(this->*func)(cf, size, sign, use_fastmem, addr);
|
||||
|
||||
if (store && !m_block_ended && !m_current_instruction_branch_delay_slot && spec_addr.has_value() &&
|
||||
GetSegmentForAddress(spec_addr.value()) != Segment::KSEG2)
|
||||
{
|
||||
// Get rid of physical aliases.
|
||||
const u32 phys_spec_addr = VirtualAddressToPhysical(spec_addr.value());
|
||||
if (phys_spec_addr >= VirtualAddressToPhysical(m_block->pc) &&
|
||||
phys_spec_addr < VirtualAddressToPhysical(m_block->pc + (m_block->size * sizeof(Instruction))))
|
||||
{
|
||||
Log_WarningFmt("Instruction {:08X} speculatively writes to {:08X} inside block {:08X}-{:08X}. Truncating block.",
|
||||
m_current_instruction_pc, phys_spec_addr, m_block->pc,
|
||||
m_block->pc + (m_block->size * sizeof(Instruction)));
|
||||
m_block->size = ((m_current_instruction_pc - m_block->pc) / sizeof(Instruction)) + 1;
|
||||
iinfo->is_last_instruction = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::NewRec::Compiler::FlushForLoadStore(const std::optional<VirtualMemoryAddress>& address, bool store,
|
||||
|
|
|
@ -402,7 +402,7 @@ protected:
|
|||
TickCount m_gte_done_cycle = 0;
|
||||
|
||||
const Instruction* inst = nullptr;
|
||||
const CodeCache::InstructionInfo* iinfo = nullptr;
|
||||
CodeCache::InstructionInfo* iinfo = nullptr;
|
||||
u32 m_current_instruction_pc = 0;
|
||||
bool m_current_instruction_branch_delay_slot = false;
|
||||
bool m_branch_delay_slot_swapped = false;
|
||||
|
|
|
@ -1983,6 +1983,10 @@ void CPU::NewRec::AArch32Compiler::TestInterrupts(const vixl::aarch32::Register&
|
|||
|
||||
SwitchToFarCode(true, ne);
|
||||
BackupHostState();
|
||||
|
||||
// Update load delay, this normally happens at the end of an instruction, but we're finishing it early.
|
||||
UpdateLoadDelay();
|
||||
|
||||
Flush(FLUSH_END_BLOCK | FLUSH_FOR_EXCEPTION | FLUSH_FOR_C_CALL);
|
||||
|
||||
// Can't use EndBlockWithException() here, because it'll use the wrong PC.
|
||||
|
|
|
@ -1957,6 +1957,10 @@ void CPU::NewRec::AArch64Compiler::TestInterrupts(const vixl::aarch64::WRegister
|
|||
|
||||
SwitchToFarCode(true, ne);
|
||||
BackupHostState();
|
||||
|
||||
// Update load delay, this normally happens at the end of an instruction, but we're finishing it early.
|
||||
UpdateLoadDelay();
|
||||
|
||||
Flush(FLUSH_END_BLOCK | FLUSH_FOR_EXCEPTION | FLUSH_FOR_C_CALL);
|
||||
|
||||
// Can't use EndBlockWithException() here, because it'll use the wrong PC.
|
||||
|
|
|
@ -2212,7 +2212,12 @@ void CPU::NewRec::RISCV64Compiler::TestInterrupts(const biscuit::GPR& sr)
|
|||
rvAsm->SRLIW(sr, sr, 8);
|
||||
rvAsm->ANDI(sr, sr, 0xFF);
|
||||
SwitchToFarCode(true, &Assembler::BEQ, sr, zero);
|
||||
|
||||
BackupHostState();
|
||||
|
||||
// Update load delay, this normally happens at the end of an instruction, but we're finishing it early.
|
||||
UpdateLoadDelay();
|
||||
|
||||
Flush(FLUSH_END_BLOCK | FLUSH_FOR_EXCEPTION | FLUSH_FOR_C_CALL);
|
||||
|
||||
// Can't use EndBlockWithException() here, because it'll use the wrong PC.
|
||||
|
|
|
@ -1935,6 +1935,10 @@ void CPU::NewRec::X64Compiler::TestInterrupts(const Xbyak::Reg32& sr)
|
|||
|
||||
SwitchToFarCode(true, &CodeGenerator::jnz);
|
||||
BackupHostState();
|
||||
|
||||
// Update load delay, this normally happens at the end of an instruction, but we're finishing it early.
|
||||
UpdateLoadDelay();
|
||||
|
||||
Flush(FLUSH_END_BLOCK | FLUSH_FOR_EXCEPTION | FLUSH_FOR_C_CALL);
|
||||
|
||||
// Can't use EndBlockWithException() here, because it'll use the wrong PC.
|
||||
|
|
Loading…
Reference in a new issue