Duckstation/src/pse/cpu_core.inl

143 lines
3.4 KiB
Plaintext
Raw Normal View History

2019-09-09 07:01:26 +00:00
#pragma once
#include "YBaseLib/Assert.h"
#include "bus.h"
#include "cpu_core.h"
namespace CPU {
template<MemoryAccessType type, MemoryAccessSize size, bool is_instruction_fetch, bool raise_exceptions>
bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
2019-09-09 07:01:26 +00:00
{
switch (address >> 29)
{
case 0x00: // KUSEG 0M-512M
{
if constexpr (type == MemoryAccessType::Write)
{
if (m_cop0_regs.sr.Isc)
return true;
2019-09-09 07:01:26 +00:00
}
2019-09-14 03:52:57 +00:00
const PhysicalMemoryAddress phys_addr = address & UINT32_C(0x1FFFFFFF);
if ((phys_addr & DCACHE_LOCATION_MASK) == DCACHE_LOCATION)
{
DoScratchpadAccess<type, size>(phys_addr, value);
return true;
}
if (!m_bus->DispatchAccess<type, size>(address, phys_addr, value))
{
2019-09-09 07:01:26 +00:00
Panic("Bus error");
return false;
}
return true;
2019-09-09 07:01:26 +00:00
}
case 0x01: // KUSEG 512M-1024M
case 0x02: // KUSEG 1024M-1536M
case 0x03: // KUSEG 1536M-2048M
{
// Above 512mb raises an exception.
Panic("Bad user access");
return false;
2019-09-09 07:01:26 +00:00
}
case 0x04: // KSEG0 - physical memory cached
{
if constexpr (type == MemoryAccessType::Write)
{
if (m_cop0_regs.sr.Isc)
return true;
2019-09-09 07:01:26 +00:00
}
2019-09-14 03:52:57 +00:00
const PhysicalMemoryAddress phys_addr = address & UINT32_C(0x1FFFFFFF);
if ((phys_addr & DCACHE_LOCATION_MASK) == DCACHE_LOCATION)
{
DoScratchpadAccess<type, size>(phys_addr, value);
return true;
}
2019-09-09 07:01:26 +00:00
if (!m_bus->DispatchAccess<type, size>(address, address & UINT32_C(0x1FFFFFFF), value))
{
2019-09-09 07:01:26 +00:00
Panic("Bus error");
return false;
}
return true;
2019-09-09 07:01:26 +00:00
}
break;
case 0x05: // KSEG1 - physical memory uncached
{
2019-09-14 03:52:57 +00:00
const PhysicalMemoryAddress phys_addr = address & UINT32_C(0x1FFFFFFF);
if (!m_bus->DispatchAccess<type, size>(address, phys_addr, value))
{
2019-09-09 07:01:26 +00:00
Panic("Bus error");
return false;
}
return true;
2019-09-09 07:01:26 +00:00
}
break;
case 0x06: // KSEG2
case 0x07: // KSEG2
{
if (address == 0xFFFE0130)
{
if constexpr (type == MemoryAccessType::Read)
value = m_cache_control;
else
WriteCacheControl(value);
return true;
2019-09-09 07:01:26 +00:00
}
else
{
Panic("KSEG2 access");
return false;
2019-09-09 07:01:26 +00:00
}
}
default:
UnreachableCode();
return false;
2019-09-09 07:01:26 +00:00
}
}
2019-09-14 03:52:57 +00:00
template<MemoryAccessType type, MemoryAccessSize size>
void CPU::Core::DoScratchpadAccess(PhysicalMemoryAddress address, u32& value)
{
const PhysicalMemoryAddress cache_offset = address & DCACHE_OFFSET_MASK;
if constexpr (size == MemoryAccessSize::Byte)
{
if constexpr (type == MemoryAccessType::Read)
value = ZeroExtend32(m_dcache[cache_offset]);
else
m_dcache[cache_offset] = Truncate8(value);
}
else if constexpr (size == MemoryAccessSize::HalfWord)
{
if constexpr (type == MemoryAccessType::Read)
{
u16 temp;
std::memcpy(&temp, &m_dcache[cache_offset], sizeof(temp));
value = ZeroExtend32(temp);
}
else
{
u16 temp = Truncate16(value);
std::memcpy(&m_dcache[cache_offset], &temp, sizeof(temp));
}
}
else if constexpr (size == MemoryAccessSize::Word)
{
if constexpr (type == MemoryAccessType::Read)
std::memcpy(&value, &m_dcache[cache_offset], sizeof(value));
else
std::memcpy(&m_dcache[cache_offset], &value, sizeof(value));
}
}
2019-09-09 07:01:26 +00:00
} // namespace CPU