mirror of
https://github.com/stenzek/duckstation.git
synced 2025-06-08 12:35:48 +00:00
CPU: Correctly mask upper 1.5GB of KUSEG
Stops fastmem going into a loop when trying to backpatch accesses above 512MB.
This commit is contained in:
parent
0a1e8e27f0
commit
0479500357
@ -625,7 +625,7 @@ void Bus::MapFastmemViews()
|
|||||||
|
|
||||||
auto MapRAM = [](u32 base_address) {
|
auto MapRAM = [](u32 base_address) {
|
||||||
// Don't map RAM that isn't accessible.
|
// Don't map RAM that isn't accessible.
|
||||||
if ((base_address & CPU::PHYSICAL_MEMORY_ADDRESS_MASK) >= g_ram_mapped_size)
|
if (CPU::VirtualAddressToPhysical(base_address) >= g_ram_mapped_size)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
u8* ram_ptr = g_ram + (base_address & g_ram_mask);
|
u8* ram_ptr = g_ram + (base_address & g_ram_mask);
|
||||||
@ -676,7 +676,7 @@ void Bus::RemapFastmemViews()
|
|||||||
|
|
||||||
bool Bus::CanUseFastmemForAddress(VirtualMemoryAddress address)
|
bool Bus::CanUseFastmemForAddress(VirtualMemoryAddress address)
|
||||||
{
|
{
|
||||||
const PhysicalMemoryAddress paddr = address & CPU::PHYSICAL_MEMORY_ADDRESS_MASK;
|
const PhysicalMemoryAddress paddr = CPU::VirtualAddressToPhysical(address);
|
||||||
|
|
||||||
switch (g_settings.cpu_fastmem_mode)
|
switch (g_settings.cpu_fastmem_mode)
|
||||||
{
|
{
|
||||||
|
@ -777,9 +777,8 @@ template<PGXPMode pgxp_mode>
|
|||||||
}
|
}
|
||||||
else if (block->HasFlag(BlockFlags::NeedsDynamicFetchTicks))
|
else if (block->HasFlag(BlockFlags::NeedsDynamicFetchTicks))
|
||||||
{
|
{
|
||||||
AddPendingTicks(
|
AddPendingTicks(static_cast<TickCount>(
|
||||||
static_cast<TickCount>(block->size * static_cast<u32>(*Bus::GetMemoryAccessTimePtr(
|
block->size * static_cast<u32>(*Bus::GetMemoryAccessTimePtr(block->pc & KSEG_MASK, MemoryAccessSize::Word))));
|
||||||
block->pc & PHYSICAL_MEMORY_ADDRESS_MASK, MemoryAccessSize::Word))));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -857,8 +856,8 @@ bool CPU::CodeCache::ReadBlockInstructions(u32 start_pc, BlockInstructionList* i
|
|||||||
|
|
||||||
const PageProtectionMode protection = GetProtectionModeForPC(start_pc);
|
const PageProtectionMode protection = GetProtectionModeForPC(start_pc);
|
||||||
const bool use_icache = CPU::IsCachedAddress(start_pc);
|
const bool use_icache = CPU::IsCachedAddress(start_pc);
|
||||||
const bool dynamic_fetch_ticks = (!use_icache && Bus::GetMemoryAccessTimePtr(start_pc & PHYSICAL_MEMORY_ADDRESS_MASK,
|
const bool dynamic_fetch_ticks =
|
||||||
MemoryAccessSize::Word) != nullptr);
|
(!use_icache && Bus::GetMemoryAccessTimePtr(VirtualAddressToPhysical(start_pc), MemoryAccessSize::Word) != nullptr);
|
||||||
u32 pc = start_pc;
|
u32 pc = start_pc;
|
||||||
bool is_branch_delay_slot = false;
|
bool is_branch_delay_slot = false;
|
||||||
bool is_load_delay_slot = false;
|
bool is_load_delay_slot = false;
|
||||||
|
@ -2476,8 +2476,8 @@ template<PGXPMode pgxp_mode, bool debug>
|
|||||||
if (s_trace_to_log)
|
if (s_trace_to_log)
|
||||||
LogInstruction(g_state.current_instruction.bits, g_state.current_instruction_pc, true);
|
LogInstruction(g_state.current_instruction.bits, g_state.current_instruction_pc, true);
|
||||||
|
|
||||||
// handle all mirrors of the syscall trampoline
|
// handle all mirrors of the syscall trampoline. will catch 200000A0 etc, but those aren't fetchable anyway
|
||||||
const u32 masked_pc = (g_state.current_instruction_pc & PHYSICAL_MEMORY_ADDRESS_MASK);
|
const u32 masked_pc = (g_state.current_instruction_pc & KSEG_MASK);
|
||||||
if (masked_pc == 0xA0) [[unlikely]]
|
if (masked_pc == 0xA0) [[unlikely]]
|
||||||
HandleA0Syscall();
|
HandleA0Syscall();
|
||||||
else if (masked_pc == 0xB0) [[unlikely]]
|
else if (masked_pc == 0xB0) [[unlikely]]
|
||||||
@ -2721,7 +2721,10 @@ ALWAYS_INLINE_RELEASE bool CPU::DoInstructionRead(PhysicalMemoryAddress address,
|
|||||||
{
|
{
|
||||||
using namespace Bus;
|
using namespace Bus;
|
||||||
|
|
||||||
address &= PHYSICAL_MEMORY_ADDRESS_MASK;
|
// We can shortcut around VirtualAddressToPhysical() here because we're never going to be
|
||||||
|
// calling with an out-of-range address.
|
||||||
|
DebugAssert(VirtualAddressToPhysical(address) == (address & KSEG_MASK));
|
||||||
|
address &= KSEG_MASK;
|
||||||
|
|
||||||
if (address < RAM_MIRROR_END)
|
if (address < RAM_MIRROR_END)
|
||||||
{
|
{
|
||||||
@ -2764,7 +2767,8 @@ TickCount CPU::GetInstructionReadTicks(VirtualMemoryAddress address)
|
|||||||
{
|
{
|
||||||
using namespace Bus;
|
using namespace Bus;
|
||||||
|
|
||||||
address &= PHYSICAL_MEMORY_ADDRESS_MASK;
|
DebugAssert(VirtualAddressToPhysical(address) == (address & KSEG_MASK));
|
||||||
|
address &= KSEG_MASK;
|
||||||
|
|
||||||
if (address < RAM_MIRROR_END)
|
if (address < RAM_MIRROR_END)
|
||||||
{
|
{
|
||||||
@ -2784,7 +2788,8 @@ TickCount CPU::GetICacheFillTicks(VirtualMemoryAddress address)
|
|||||||
{
|
{
|
||||||
using namespace Bus;
|
using namespace Bus;
|
||||||
|
|
||||||
address &= PHYSICAL_MEMORY_ADDRESS_MASK;
|
DebugAssert(VirtualAddressToPhysical(address) == (address & KSEG_MASK));
|
||||||
|
address &= KSEG_MASK;
|
||||||
|
|
||||||
if (address < RAM_MIRROR_END)
|
if (address < RAM_MIRROR_END)
|
||||||
{
|
{
|
||||||
@ -3030,7 +3035,7 @@ ALWAYS_INLINE bool CPU::DoSafeMemoryAccess(VirtualMemoryAddress address, u32& va
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
address &= PHYSICAL_MEMORY_ADDRESS_MASK;
|
address &= KSEG_MASK;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -3046,7 +3051,7 @@ ALWAYS_INLINE bool CPU::DoSafeMemoryAccess(VirtualMemoryAddress address, u32& va
|
|||||||
|
|
||||||
case 0x05: // KSEG1 - physical memory uncached
|
case 0x05: // KSEG1 - physical memory uncached
|
||||||
{
|
{
|
||||||
address &= PHYSICAL_MEMORY_ADDRESS_MASK;
|
address &= KSEG_MASK;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3231,7 +3236,7 @@ bool CPU::SafeReadMemoryBytes(VirtualMemoryAddress addr, void* data, u32 length)
|
|||||||
using namespace Bus;
|
using namespace Bus;
|
||||||
|
|
||||||
const u32 seg = (addr >> 29);
|
const u32 seg = (addr >> 29);
|
||||||
if ((seg != 0 && seg != 4 && seg != 5) || (((addr + length) & PHYSICAL_MEMORY_ADDRESS_MASK) >= RAM_MIRROR_END) ||
|
if ((seg != 0 && seg != 4 && seg != 5) || (((addr + length) & KSEG_MASK) >= RAM_MIRROR_END) ||
|
||||||
(((addr & g_ram_mask) + length) > g_ram_size))
|
(((addr & g_ram_mask) + length) > g_ram_size))
|
||||||
{
|
{
|
||||||
u8* ptr = static_cast<u8*>(data);
|
u8* ptr = static_cast<u8*>(data);
|
||||||
@ -3255,7 +3260,7 @@ bool CPU::SafeWriteMemoryBytes(VirtualMemoryAddress addr, const void* data, u32
|
|||||||
using namespace Bus;
|
using namespace Bus;
|
||||||
|
|
||||||
const u32 seg = (addr >> 29);
|
const u32 seg = (addr >> 29);
|
||||||
if ((seg != 0 && seg != 4 && seg != 5) || (((addr + length) & PHYSICAL_MEMORY_ADDRESS_MASK) >= RAM_MIRROR_END) ||
|
if ((seg != 0 && seg != 4 && seg != 5) || (((addr + length) & KSEG_MASK) >= RAM_MIRROR_END) ||
|
||||||
(((addr & g_ram_mask) + length) > g_ram_size))
|
(((addr & g_ram_mask) + length) > g_ram_size))
|
||||||
{
|
{
|
||||||
const u8* ptr = static_cast<const u8*>(data);
|
const u8* ptr = static_cast<const u8*>(data);
|
||||||
@ -3284,7 +3289,7 @@ bool CPU::SafeZeroMemoryBytes(VirtualMemoryAddress addr, u32 length)
|
|||||||
using namespace Bus;
|
using namespace Bus;
|
||||||
|
|
||||||
const u32 seg = (addr >> 29);
|
const u32 seg = (addr >> 29);
|
||||||
if ((seg != 0 && seg != 4 && seg != 5) || (((addr + length) & PHYSICAL_MEMORY_ADDRESS_MASK) >= RAM_MIRROR_END) ||
|
if ((seg != 0 && seg != 4 && seg != 5) || (((addr + length) & KSEG_MASK) >= RAM_MIRROR_END) ||
|
||||||
(((addr & g_ram_mask) + length) > g_ram_size))
|
(((addr & g_ram_mask) + length) > g_ram_size))
|
||||||
{
|
{
|
||||||
while ((addr & 3u) != 0 && length > 0)
|
while ((addr & 3u) != 0 && length > 0)
|
||||||
@ -3328,7 +3333,7 @@ void* CPU::GetDirectReadMemoryPointer(VirtualMemoryAddress address, MemoryAccess
|
|||||||
if (seg != 0 && seg != 4 && seg != 5)
|
if (seg != 0 && seg != 4 && seg != 5)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
const PhysicalMemoryAddress paddr = address & PHYSICAL_MEMORY_ADDRESS_MASK;
|
const PhysicalMemoryAddress paddr = VirtualAddressToPhysical(address);
|
||||||
if (paddr < RAM_MIRROR_END)
|
if (paddr < RAM_MIRROR_END)
|
||||||
{
|
{
|
||||||
if (read_ticks)
|
if (read_ticks)
|
||||||
@ -3364,7 +3369,7 @@ void* CPU::GetDirectWriteMemoryPointer(VirtualMemoryAddress address, MemoryAcces
|
|||||||
if (seg != 0 && seg != 4 && seg != 5)
|
if (seg != 0 && seg != 4 && seg != 5)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
const PhysicalMemoryAddress paddr = address & PHYSICAL_MEMORY_ADDRESS_MASK;
|
const PhysicalMemoryAddress paddr = address & KSEG_MASK;
|
||||||
|
|
||||||
if (paddr < RAM_MIRROR_END)
|
if (paddr < RAM_MIRROR_END)
|
||||||
return &g_ram[paddr & g_ram_mask];
|
return &g_ram[paddr & g_ram_mask];
|
||||||
|
@ -10,6 +10,13 @@ struct fastjmp_buf;
|
|||||||
|
|
||||||
namespace CPU {
|
namespace CPU {
|
||||||
|
|
||||||
|
// Memory address mask used for fetching as well as loadstores (removes cached/uncached/user/kernel bits).
|
||||||
|
enum : PhysicalMemoryAddress
|
||||||
|
{
|
||||||
|
KSEG_MASK = 0x1FFFFFFF,
|
||||||
|
KUSEG_MASK = 0x7FFFFFFF,
|
||||||
|
};
|
||||||
|
|
||||||
void SetPC(u32 new_pc);
|
void SetPC(u32 new_pc);
|
||||||
|
|
||||||
// exceptions
|
// exceptions
|
||||||
@ -104,7 +111,8 @@ ALWAYS_INLINE static Segment GetSegmentForAddress(VirtualMemoryAddress address)
|
|||||||
|
|
||||||
ALWAYS_INLINE static constexpr PhysicalMemoryAddress VirtualAddressToPhysical(VirtualMemoryAddress address)
|
ALWAYS_INLINE static constexpr PhysicalMemoryAddress VirtualAddressToPhysical(VirtualMemoryAddress address)
|
||||||
{
|
{
|
||||||
return (address & PHYSICAL_MEMORY_ADDRESS_MASK);
|
// KUSEG goes to the first 2GB, others are only 512MB.
|
||||||
|
return (address & ((address & 0x80000000u) ? KSEG_MASK : KUSEG_MASK));
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE static VirtualMemoryAddress PhysicalAddressToVirtual(PhysicalMemoryAddress address, Segment segment)
|
ALWAYS_INLINE static VirtualMemoryAddress PhysicalAddressToVirtual(PhysicalMemoryAddress address, Segment segment)
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "cpu_pgxp.h"
|
#include "cpu_pgxp.h"
|
||||||
#include "bus.h"
|
#include "bus.h"
|
||||||
#include "cpu_core.h"
|
#include "cpu_core.h"
|
||||||
|
#include "cpu_core_private.h"
|
||||||
#include "cpu_disasm.h"
|
#include "cpu_disasm.h"
|
||||||
#include "gpu_types.h"
|
#include "gpu_types.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
@ -270,7 +271,8 @@ ALWAYS_INLINE_RELEASE CPU::PGXPValue* CPU::PGXP::GetPtr(u32 addr)
|
|||||||
if ((addr & SCRATCHPAD_ADDR_MASK) == SCRATCHPAD_ADDR)
|
if ((addr & SCRATCHPAD_ADDR_MASK) == SCRATCHPAD_ADDR)
|
||||||
return &s_mem[PGXP_MEM_SCRATCH_OFFSET + ((addr & SCRATCHPAD_OFFSET_MASK) >> 2)];
|
return &s_mem[PGXP_MEM_SCRATCH_OFFSET + ((addr & SCRATCHPAD_OFFSET_MASK) >> 2)];
|
||||||
|
|
||||||
const u32 paddr = (addr & PHYSICAL_MEMORY_ADDRESS_MASK);
|
// Don't worry about >512MB here for performance reasons.
|
||||||
|
const u32 paddr = (addr & KSEG_MASK);
|
||||||
if (paddr < Bus::RAM_MIRROR_END)
|
if (paddr < Bus::RAM_MIRROR_END)
|
||||||
return &s_mem[(paddr & Bus::g_ram_mask) >> 2];
|
return &s_mem[(paddr & Bus::g_ram_mask) >> 2];
|
||||||
else
|
else
|
||||||
|
@ -84,7 +84,7 @@ void CPU::Recompiler::Recompiler::BeginBlock()
|
|||||||
|
|
||||||
if (g_settings.bios_tty_logging)
|
if (g_settings.bios_tty_logging)
|
||||||
{
|
{
|
||||||
const u32 masked_pc = (m_block->pc & PHYSICAL_MEMORY_ADDRESS_MASK);
|
const u32 masked_pc = VirtualAddressToPhysical(m_block->pc);
|
||||||
if (masked_pc == 0xa0)
|
if (masked_pc == 0xa0)
|
||||||
GenerateCall(reinterpret_cast<const void*>(&CPU::HandleA0Syscall));
|
GenerateCall(reinterpret_cast<const void*>(&CPU::HandleA0Syscall));
|
||||||
else if (masked_pc == 0xb0)
|
else if (masked_pc == 0xb0)
|
||||||
@ -1735,8 +1735,7 @@ void CPU::Recompiler::Recompiler::TruncateBlock()
|
|||||||
|
|
||||||
const TickCount* CPU::Recompiler::Recompiler::GetFetchMemoryAccessTimePtr() const
|
const TickCount* CPU::Recompiler::Recompiler::GetFetchMemoryAccessTimePtr() const
|
||||||
{
|
{
|
||||||
const TickCount* ptr =
|
const TickCount* ptr = Bus::GetMemoryAccessTimePtr(VirtualAddressToPhysical(m_block->pc), MemoryAccessSize::Word);
|
||||||
Bus::GetMemoryAccessTimePtr(m_block->pc & PHYSICAL_MEMORY_ADDRESS_MASK, MemoryAccessSize::Word);
|
|
||||||
AssertMsg(ptr, "Address has dynamic fetch ticks");
|
AssertMsg(ptr, "Address has dynamic fetch ticks");
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
@ -2437,10 +2436,9 @@ CPU::Recompiler::Recompiler::SpecValue CPU::Recompiler::Recompiler::SpecReadMem(
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PhysicalMemoryAddress phys_addr = address & PHYSICAL_MEMORY_ADDRESS_MASK;
|
if (CPU::CodeCache::AddressInRAM(address))
|
||||||
if (Bus::IsRAMAddress(phys_addr))
|
|
||||||
{
|
{
|
||||||
u32 ram_offset = phys_addr & Bus::g_ram_mask;
|
u32 ram_offset = address & Bus::g_ram_mask;
|
||||||
std::memcpy(&value, &Bus::g_ram[ram_offset], sizeof(value));
|
std::memcpy(&value, &Bus::g_ram[ram_offset], sizeof(value));
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@ -2457,9 +2455,10 @@ void CPU::Recompiler::Recompiler::SpecWriteMem(u32 address, SpecValue value)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PhysicalMemoryAddress phys_addr = address & PHYSICAL_MEMORY_ADDRESS_MASK;
|
if ((address & SCRATCHPAD_ADDR_MASK) == SCRATCHPAD_ADDR)
|
||||||
if ((address & SCRATCHPAD_ADDR_MASK) == SCRATCHPAD_ADDR || Bus::IsRAMAddress(phys_addr))
|
|
||||||
m_speculative_constants.memory.emplace(address, value);
|
m_speculative_constants.memory.emplace(address, value);
|
||||||
|
else if (CPU::CodeCache::AddressInRAM(address))
|
||||||
|
m_speculative_constants.memory.emplace(address & Bus::g_ram_mask, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Recompiler::Recompiler::SpecInvalidateMem(VirtualMemoryAddress address)
|
void CPU::Recompiler::Recompiler::SpecInvalidateMem(VirtualMemoryAddress address)
|
||||||
|
@ -12,11 +12,6 @@
|
|||||||
|
|
||||||
namespace CPU {
|
namespace CPU {
|
||||||
|
|
||||||
// Memory address mask used for fetching as well as loadstores (removes cached/uncached/user/kernel bits).
|
|
||||||
enum : PhysicalMemoryAddress
|
|
||||||
{
|
|
||||||
PHYSICAL_MEMORY_ADDRESS_MASK = 0x1FFFFFFF
|
|
||||||
};
|
|
||||||
enum : u32
|
enum : u32
|
||||||
{
|
{
|
||||||
INSTRUCTION_SIZE = sizeof(u32)
|
INSTRUCTION_SIZE = sizeof(u32)
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "memory_scanner.h"
|
#include "memory_scanner.h"
|
||||||
#include "bus.h"
|
#include "bus.h"
|
||||||
#include "cpu_core.h"
|
#include "cpu_core.h"
|
||||||
|
#include "cpu_core_private.h"
|
||||||
|
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
|
|
||||||
@ -11,7 +12,7 @@
|
|||||||
|
|
||||||
LOG_CHANNEL(Cheats);
|
LOG_CHANNEL(Cheats);
|
||||||
|
|
||||||
static bool IsValidScanAddress(PhysicalMemoryAddress address)
|
static bool IsValidScanAddress(VirtualMemoryAddress address)
|
||||||
{
|
{
|
||||||
if ((address & CPU::SCRATCHPAD_ADDR_MASK) == CPU::SCRATCHPAD_ADDR &&
|
if ((address & CPU::SCRATCHPAD_ADDR_MASK) == CPU::SCRATCHPAD_ADDR &&
|
||||||
(address & CPU::SCRATCHPAD_OFFSET_MASK) < CPU::SCRATCHPAD_SIZE)
|
(address & CPU::SCRATCHPAD_OFFSET_MASK) < CPU::SCRATCHPAD_SIZE)
|
||||||
@ -19,12 +20,11 @@ static bool IsValidScanAddress(PhysicalMemoryAddress address)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
address &= CPU::PHYSICAL_MEMORY_ADDRESS_MASK;
|
const PhysicalMemoryAddress phys_address = CPU::VirtualAddressToPhysical(address);
|
||||||
|
if (phys_address < Bus::RAM_MIRROR_END)
|
||||||
if (address < Bus::RAM_MIRROR_END)
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (address >= Bus::BIOS_BASE && address < (Bus::BIOS_BASE + Bus::BIOS_SIZE))
|
if (phys_address >= Bus::BIOS_BASE && phys_address < (Bus::BIOS_BASE + Bus::BIOS_SIZE))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user