CPU: Memory access timings
This commit is contained in:
parent
fd1c4f1457
commit
4422fb0545
164
src/core/bus.cpp
164
src/core/bus.cpp
|
@ -64,6 +64,11 @@ void Bus::Reset()
|
|||
|
||||
bool Bus::DoState(StateWrapper& sw)
|
||||
{
|
||||
sw.Do(&m_exp1_access_time);
|
||||
sw.Do(&m_exp2_access_time);
|
||||
sw.Do(&m_bios_access_time);
|
||||
sw.Do(&m_cdrom_access_time);
|
||||
sw.Do(&m_spu_access_time);
|
||||
sw.DoBytes(m_ram.data(), m_ram.size());
|
||||
sw.DoBytes(m_bios.data(), m_bios.size());
|
||||
sw.DoArray(m_MEMCTRL.regs, countof(m_MEMCTRL.regs));
|
||||
|
@ -223,7 +228,7 @@ void Bus::RecalculateMemoryTimings()
|
|||
m_spu_access_time[2]);
|
||||
}
|
||||
|
||||
bool Bus::DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address, u32& value)
|
||||
TickCount Bus::DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address, u32& value)
|
||||
{
|
||||
SmallString str;
|
||||
str.AppendString("Invalid bus ");
|
||||
|
@ -247,13 +252,16 @@ bool Bus::DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, Physical
|
|||
if (type == MemoryAccessType::Read)
|
||||
value = UINT32_C(0xFFFFFFFF);
|
||||
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool Bus::DoReadEXP1(MemoryAccessSize size, u32 offset, u32& value)
|
||||
u32 Bus::DoReadEXP1(MemoryAccessSize size, u32 offset)
|
||||
{
|
||||
if (m_exp1_rom.empty())
|
||||
return DoInvalidAccess(MemoryAccessType::Read, size, EXP1_BASE | offset, value);
|
||||
{
|
||||
// EXP1 not present.
|
||||
return UINT32_C(0xFFFFFFFF);
|
||||
}
|
||||
|
||||
if (offset == 0x20018)
|
||||
{
|
||||
|
@ -264,10 +272,10 @@ bool Bus::DoReadEXP1(MemoryAccessSize size, u32 offset, u32& value)
|
|||
const u32 transfer_size = u32(1) << static_cast<u32>(size);
|
||||
if ((offset + transfer_size) > m_exp1_rom.size())
|
||||
{
|
||||
value = UINT32_C(0);
|
||||
return true;
|
||||
return UINT32_C(0);
|
||||
}
|
||||
|
||||
u32 value;
|
||||
if (size == MemoryAccessSize::Byte)
|
||||
{
|
||||
value = ZeroExtend32(m_exp1_rom[offset]);
|
||||
|
@ -284,36 +292,32 @@ bool Bus::DoReadEXP1(MemoryAccessSize size, u32 offset, u32& value)
|
|||
}
|
||||
|
||||
// Log_DevPrintf("EXP1 read: 0x%08X -> 0x%08X", EXP1_BASE | offset, value);
|
||||
return true;
|
||||
return value;
|
||||
}
|
||||
|
||||
bool Bus::DoWriteEXP1(MemoryAccessSize size, u32 offset, u32 value)
|
||||
void Bus::DoWriteEXP1(MemoryAccessSize size, u32 offset, u32 value)
|
||||
{
|
||||
return DoInvalidAccess(MemoryAccessType::Write, size, EXP1_BASE | offset, value);
|
||||
Log_WarningPrintf("EXP1 write: 0x%08X <- 0x%08X", EXP1_BASE | offset, value);
|
||||
}
|
||||
|
||||
bool Bus::DoReadEXP2(MemoryAccessSize size, u32 offset, u32& value)
|
||||
u32 Bus::DoReadEXP2(MemoryAccessSize size, u32 offset)
|
||||
{
|
||||
offset &= EXP2_MASK;
|
||||
|
||||
// rx/tx buffer empty
|
||||
if (offset == 0x21)
|
||||
{
|
||||
value = 0x04 | 0x08;
|
||||
return true;
|
||||
return 0x04 | 0x08;
|
||||
}
|
||||
|
||||
return DoInvalidAccess(MemoryAccessType::Read, size, EXP2_BASE | offset, value);
|
||||
Log_WarningPrintf("EXP2 read: 0x%08X", EXP2_BASE | offset);
|
||||
return UINT32_C(0xFFFFFFFF);
|
||||
}
|
||||
|
||||
bool Bus::DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value)
|
||||
void Bus::DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value)
|
||||
{
|
||||
offset &= EXP2_MASK;
|
||||
|
||||
if (offset == 0x23)
|
||||
{
|
||||
if (value == '\r')
|
||||
return true;
|
||||
return;
|
||||
|
||||
if (value == '\n')
|
||||
{
|
||||
|
@ -326,26 +330,26 @@ bool Bus::DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value)
|
|||
m_tty_line_buffer.AppendCharacter(Truncate8(value));
|
||||
}
|
||||
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (offset == 0x41)
|
||||
{
|
||||
Log_WarningPrintf("BIOS POST status: %02X", value & UINT32_C(0x0F));
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
return DoInvalidAccess(MemoryAccessType::Write, size, EXP2_BASE | offset, value);
|
||||
Log_WarningPrintf("EXP2 write: 0x%08X <- 0x%08X", EXP2_BASE | offset, value);
|
||||
}
|
||||
|
||||
bool Bus::DoReadMemoryControl(MemoryAccessSize size, u32 offset, u32& value)
|
||||
u32 Bus::DoReadMemoryControl(MemoryAccessSize size, u32 offset)
|
||||
{
|
||||
u32 value = m_MEMCTRL.regs[offset / 4];
|
||||
FixupUnalignedWordAccessW32(offset, value);
|
||||
value = m_MEMCTRL.regs[offset / 4];
|
||||
return true;
|
||||
return value;
|
||||
}
|
||||
|
||||
bool Bus::DoWriteMemoryControl(MemoryAccessSize size, u32 offset, u32 value)
|
||||
void Bus::DoWriteMemoryControl(MemoryAccessSize size, u32 offset, u32 value)
|
||||
{
|
||||
FixupUnalignedWordAccessW32(offset, value);
|
||||
|
||||
|
@ -357,165 +361,151 @@ bool Bus::DoWriteMemoryControl(MemoryAccessSize size, u32 offset, u32 value)
|
|||
m_MEMCTRL.regs[index] = new_value;
|
||||
RecalculateMemoryTimings();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Bus::DoReadMemoryControl2(MemoryAccessSize size, u32 offset, u32& value)
|
||||
u32 Bus::DoReadMemoryControl2(MemoryAccessSize size, u32 offset)
|
||||
{
|
||||
if (offset == 0x00)
|
||||
{
|
||||
value = m_ram_size_reg;
|
||||
return true;
|
||||
}
|
||||
return m_ram_size_reg;
|
||||
|
||||
return DoInvalidAccess(MemoryAccessType::Read, size, MEMCTRL2_BASE | offset, value);
|
||||
u32 value = 0;
|
||||
DoInvalidAccess(MemoryAccessType::Read, size, MEMCTRL2_BASE | offset, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
bool Bus::DoWriteMemoryControl2(MemoryAccessSize size, u32 offset, u32 value)
|
||||
void Bus::DoWriteMemoryControl2(MemoryAccessSize size, u32 offset, u32 value)
|
||||
{
|
||||
if (offset == 0x00)
|
||||
{
|
||||
m_ram_size_reg = value;
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
return DoInvalidAccess(MemoryAccessType::Write, size, MEMCTRL2_BASE | offset, value);
|
||||
DoInvalidAccess(MemoryAccessType::Write, size, MEMCTRL2_BASE | offset, value);
|
||||
}
|
||||
|
||||
bool Bus::DoReadPad(MemoryAccessSize size, u32 offset, u32& value)
|
||||
u32 Bus::DoReadPad(MemoryAccessSize size, u32 offset)
|
||||
{
|
||||
value = m_pad->ReadRegister(offset);
|
||||
return true;
|
||||
return m_pad->ReadRegister(offset);
|
||||
}
|
||||
|
||||
bool Bus::DoWritePad(MemoryAccessSize size, u32 offset, u32 value)
|
||||
void Bus::DoWritePad(MemoryAccessSize size, u32 offset, u32 value)
|
||||
{
|
||||
m_pad->WriteRegister(offset, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Bus::DoReadSIO(MemoryAccessSize size, u32 offset, u32& value)
|
||||
u32 Bus::DoReadSIO(MemoryAccessSize size, u32 offset)
|
||||
{
|
||||
Log_ErrorPrintf("SIO Read 0x%08X", offset);
|
||||
value = 0;
|
||||
if (offset == 0x04)
|
||||
value = 0x5;
|
||||
|
||||
return true;
|
||||
return 0x5;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Bus::DoWriteSIO(MemoryAccessSize size, u32 offset, u32 value)
|
||||
void Bus::DoWriteSIO(MemoryAccessSize size, u32 offset, u32 value)
|
||||
{
|
||||
Log_ErrorPrintf("SIO Write 0x%08X <- 0x%08X", offset, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Bus::DoReadCDROM(MemoryAccessSize size, u32 offset, u32& value)
|
||||
u32 Bus::DoReadCDROM(MemoryAccessSize size, u32 offset)
|
||||
{
|
||||
// TODO: Splitting of half/word reads.
|
||||
Assert(size == MemoryAccessSize::Byte);
|
||||
value = ZeroExtend32(m_cdrom->ReadRegister(offset));
|
||||
return true;
|
||||
return ZeroExtend32(m_cdrom->ReadRegister(offset));
|
||||
}
|
||||
|
||||
bool Bus::DoWriteCDROM(MemoryAccessSize size, u32 offset, u32 value)
|
||||
void Bus::DoWriteCDROM(MemoryAccessSize size, u32 offset, u32 value)
|
||||
{
|
||||
// TODO: Splitting of half/word reads.
|
||||
Assert(size == MemoryAccessSize::Byte);
|
||||
m_cdrom->WriteRegister(offset, Truncate8(value));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Bus::DoReadGPU(MemoryAccessSize size, u32 offset, u32& value)
|
||||
u32 Bus::DoReadGPU(MemoryAccessSize size, u32 offset)
|
||||
{
|
||||
Assert(size == MemoryAccessSize::Word);
|
||||
value = m_gpu->ReadRegister(offset);
|
||||
return true;
|
||||
return m_gpu->ReadRegister(offset);
|
||||
}
|
||||
|
||||
bool Bus::DoWriteGPU(MemoryAccessSize size, u32 offset, u32 value)
|
||||
void Bus::DoWriteGPU(MemoryAccessSize size, u32 offset, u32 value)
|
||||
{
|
||||
Assert(size == MemoryAccessSize::Word);
|
||||
m_gpu->WriteRegister(offset, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Bus::DoReadMDEC(MemoryAccessSize size, u32 offset, u32& value)
|
||||
u32 Bus::DoReadMDEC(MemoryAccessSize size, u32 offset)
|
||||
{
|
||||
Assert(size == MemoryAccessSize::Word);
|
||||
value = m_mdec->ReadRegister(offset);
|
||||
return true;
|
||||
return m_mdec->ReadRegister(offset);
|
||||
}
|
||||
|
||||
bool Bus::DoWriteMDEC(MemoryAccessSize size, u32 offset, u32 value)
|
||||
void Bus::DoWriteMDEC(MemoryAccessSize size, u32 offset, u32 value)
|
||||
{
|
||||
Assert(size == MemoryAccessSize::Word);
|
||||
m_mdec->WriteRegister(offset, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Bus::DoReadInterruptController(MemoryAccessSize size, u32 offset, u32& value)
|
||||
u32 Bus::DoReadInterruptController(MemoryAccessSize size, u32 offset)
|
||||
{
|
||||
u32 value = m_interrupt_controller->ReadRegister(offset);
|
||||
FixupUnalignedWordAccessW32(offset, value);
|
||||
value = m_interrupt_controller->ReadRegister(offset);
|
||||
return true;
|
||||
return value;
|
||||
}
|
||||
|
||||
bool Bus::DoWriteInterruptController(MemoryAccessSize size, u32 offset, u32 value)
|
||||
void Bus::DoWriteInterruptController(MemoryAccessSize size, u32 offset, u32 value)
|
||||
{
|
||||
FixupUnalignedWordAccessW32(offset, value);
|
||||
m_interrupt_controller->WriteRegister(offset, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Bus::DoReadTimers(MemoryAccessSize size, u32 offset, u32& value)
|
||||
u32 Bus::DoReadTimers(MemoryAccessSize size, u32 offset)
|
||||
{
|
||||
u32 value = m_timers->ReadRegister(offset);
|
||||
FixupUnalignedWordAccessW32(offset, value);
|
||||
value = m_timers->ReadRegister(offset);
|
||||
return true;
|
||||
return value;
|
||||
}
|
||||
|
||||
bool Bus::DoWriteTimers(MemoryAccessSize size, u32 offset, u32 value)
|
||||
void Bus::DoWriteTimers(MemoryAccessSize size, u32 offset, u32 value)
|
||||
{
|
||||
FixupUnalignedWordAccessW32(offset, value);
|
||||
m_timers->WriteRegister(offset, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Bus::DoReadSPU(MemoryAccessSize size, u32 offset, u32& value)
|
||||
u32 Bus::DoReadSPU(MemoryAccessSize size, u32 offset)
|
||||
{
|
||||
// 32-bit reads are read as two 16-bit writes.
|
||||
// 32-bit reads are read as two 16-bit accesses.
|
||||
if (size == MemoryAccessSize::Word)
|
||||
{
|
||||
const u16 lsb = m_spu->ReadRegister(offset);
|
||||
const u16 msb = m_spu->ReadRegister(offset + 2);
|
||||
value = ZeroExtend32(lsb) | (ZeroExtend32(msb) << 16);
|
||||
return ZeroExtend32(lsb) | (ZeroExtend32(msb) << 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = ZeroExtend32(m_spu->ReadRegister(offset));
|
||||
return ZeroExtend32(m_spu->ReadRegister(offset));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Bus::DoWriteSPU(MemoryAccessSize size, u32 offset, u32 value)
|
||||
void Bus::DoWriteSPU(MemoryAccessSize size, u32 offset, u32 value)
|
||||
{
|
||||
// 32-bit writes are written as two 16-bit writes.
|
||||
// TODO: Ignore if address is not aligned.
|
||||
if (size == MemoryAccessSize::Word)
|
||||
{
|
||||
Assert(Common::IsAlignedPow2(offset, 2));
|
||||
m_spu->WriteRegister(offset, Truncate16(value));
|
||||
m_spu->WriteRegister(offset + 2, Truncate16(value >> 16));
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
Assert(Common::IsAlignedPow2(offset, 2));
|
||||
m_spu->WriteRegister(offset, Truncate16(value));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Bus::DoReadDMA(MemoryAccessSize size, u32 offset, u32& value)
|
||||
u32 Bus::DoReadDMA(MemoryAccessSize size, u32 offset)
|
||||
{
|
||||
u32 value = m_dma->ReadRegister(offset);
|
||||
switch (size)
|
||||
{
|
||||
case MemoryAccessSize::Byte:
|
||||
|
@ -529,11 +519,10 @@ bool Bus::DoReadDMA(MemoryAccessSize size, u32 offset, u32& value)
|
|||
break;
|
||||
}
|
||||
|
||||
value = m_dma->ReadRegister(offset);
|
||||
return true;
|
||||
return value;
|
||||
}
|
||||
|
||||
bool Bus::DoWriteDMA(MemoryAccessSize size, u32 offset, u32 value)
|
||||
void Bus::DoWriteDMA(MemoryAccessSize size, u32 offset, u32 value)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
|
@ -552,5 +541,4 @@ bool Bus::DoWriteDMA(MemoryAccessSize size, u32 offset, u32 value)
|
|||
}
|
||||
|
||||
m_dma->WriteRegister(offset, value);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
bool WriteWord(PhysicalMemoryAddress address, u32 value);
|
||||
|
||||
template<MemoryAccessType type, MemoryAccessSize size>
|
||||
bool DispatchAccess(PhysicalMemoryAddress address, u32& value);
|
||||
TickCount DispatchAccess(PhysicalMemoryAddress address, u32& value);
|
||||
|
||||
void PatchBIOS(u32 address, u32 value, u32 mask = UINT32_C(0xFFFFFFFF));
|
||||
void SetExpansionROM(std::vector<u8> data);
|
||||
|
@ -93,6 +93,7 @@ private:
|
|||
|
||||
enum : u32
|
||||
{
|
||||
RAM_ACCESS_DELAY = 6, // Nocash docs say RAM takes 6 cycles to access.
|
||||
MEMCTRL_REG_COUNT = 9
|
||||
};
|
||||
|
||||
|
@ -148,51 +149,51 @@ private:
|
|||
void RecalculateMemoryTimings();
|
||||
|
||||
template<MemoryAccessType type, MemoryAccessSize size>
|
||||
bool DoRAMAccess(u32 offset, u32& value);
|
||||
TickCount DoRAMAccess(u32 offset, u32& value);
|
||||
|
||||
template<MemoryAccessType type, MemoryAccessSize size>
|
||||
bool DoBIOSAccess(u32 offset, u32& value);
|
||||
TickCount DoBIOSAccess(u32 offset, u32& value);
|
||||
|
||||
bool DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address, u32& value);
|
||||
TickCount DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address, u32& value);
|
||||
|
||||
bool DoReadEXP1(MemoryAccessSize size, u32 offset, u32& value);
|
||||
bool DoWriteEXP1(MemoryAccessSize size, u32 offset, u32 value);
|
||||
u32 DoReadEXP1(MemoryAccessSize size, u32 offset);
|
||||
void DoWriteEXP1(MemoryAccessSize size, u32 offset, u32 value);
|
||||
|
||||
bool DoReadEXP2(MemoryAccessSize size, u32 offset, u32& value);
|
||||
bool DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value);
|
||||
u32 DoReadEXP2(MemoryAccessSize size, u32 offset);
|
||||
void DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value);
|
||||
|
||||
bool DoReadMemoryControl(MemoryAccessSize size, u32 offset, u32& value);
|
||||
bool DoWriteMemoryControl(MemoryAccessSize size, u32 offset, u32 value);
|
||||
u32 DoReadMemoryControl(MemoryAccessSize size, u32 offset);
|
||||
void DoWriteMemoryControl(MemoryAccessSize size, u32 offset, u32 value);
|
||||
|
||||
bool DoReadMemoryControl2(MemoryAccessSize size, u32 offset, u32& value);
|
||||
bool DoWriteMemoryControl2(MemoryAccessSize size, u32 offset, u32 value);
|
||||
u32 DoReadMemoryControl2(MemoryAccessSize size, u32 offset);
|
||||
void DoWriteMemoryControl2(MemoryAccessSize size, u32 offset, u32 value);
|
||||
|
||||
bool DoReadPad(MemoryAccessSize size, u32 offset, u32& value);
|
||||
bool DoWritePad(MemoryAccessSize size, u32 offset, u32 value);
|
||||
u32 DoReadPad(MemoryAccessSize size, u32 offset);
|
||||
void DoWritePad(MemoryAccessSize size, u32 offset, u32 value);
|
||||
|
||||
bool DoReadSIO(MemoryAccessSize size, u32 offset, u32& value);
|
||||
bool DoWriteSIO(MemoryAccessSize size, u32 offset, u32 value);
|
||||
u32 DoReadSIO(MemoryAccessSize size, u32 offset);
|
||||
void DoWriteSIO(MemoryAccessSize size, u32 offset, u32 value);
|
||||
|
||||
bool DoReadCDROM(MemoryAccessSize size, u32 offset, u32& value);
|
||||
bool DoWriteCDROM(MemoryAccessSize size, u32 offset, u32 value);
|
||||
u32 DoReadCDROM(MemoryAccessSize size, u32 offset);
|
||||
void DoWriteCDROM(MemoryAccessSize size, u32 offset, u32 value);
|
||||
|
||||
bool DoReadGPU(MemoryAccessSize size, u32 offset, u32& value);
|
||||
bool DoWriteGPU(MemoryAccessSize size, u32 offset, u32 value);
|
||||
u32 DoReadGPU(MemoryAccessSize size, u32 offset);
|
||||
void DoWriteGPU(MemoryAccessSize size, u32 offset, u32 value);
|
||||
|
||||
bool DoReadMDEC(MemoryAccessSize size, u32 offset, u32& value);
|
||||
bool DoWriteMDEC(MemoryAccessSize size, u32 offset, u32 value);
|
||||
u32 DoReadMDEC(MemoryAccessSize size, u32 offset);
|
||||
void DoWriteMDEC(MemoryAccessSize size, u32 offset, u32 value);
|
||||
|
||||
bool DoReadInterruptController(MemoryAccessSize size, u32 offset, u32& value);
|
||||
bool DoWriteInterruptController(MemoryAccessSize size, u32 offset, u32 value);
|
||||
u32 DoReadInterruptController(MemoryAccessSize size, u32 offset);
|
||||
void DoWriteInterruptController(MemoryAccessSize size, u32 offset, u32 value);
|
||||
|
||||
bool DoReadDMA(MemoryAccessSize size, u32 offset, u32& value);
|
||||
bool DoWriteDMA(MemoryAccessSize size, u32 offset, u32 value);
|
||||
u32 DoReadDMA(MemoryAccessSize size, u32 offset);
|
||||
void DoWriteDMA(MemoryAccessSize size, u32 offset, u32 value);
|
||||
|
||||
bool DoReadTimers(MemoryAccessSize size, u32 offset, u32& value);
|
||||
bool DoWriteTimers(MemoryAccessSize size, u32 offset, u32 value);
|
||||
u32 DoReadTimers(MemoryAccessSize size, u32 offset);
|
||||
void DoWriteTimers(MemoryAccessSize size, u32 offset, u32 value);
|
||||
|
||||
bool DoReadSPU(MemoryAccessSize size, u32 offset, u32& value);
|
||||
bool DoWriteSPU(MemoryAccessSize size, u32 offset, u32 value);
|
||||
u32 DoReadSPU(MemoryAccessSize size, u32 offset);
|
||||
void DoWriteSPU(MemoryAccessSize size, u32 offset, u32 value);
|
||||
|
||||
CPU::Core* m_cpu = nullptr;
|
||||
DMA* m_dma = nullptr;
|
||||
|
@ -204,6 +205,8 @@ private:
|
|||
SPU* m_spu = nullptr;
|
||||
MDEC* m_mdec = nullptr;
|
||||
|
||||
std::array<TickCount, 3> m_exp1_access_time = {};
|
||||
std::array<TickCount, 3> m_exp2_access_time = {};
|
||||
std::array<TickCount, 3> m_bios_access_time = {};
|
||||
std::array<TickCount, 3> m_cdrom_access_time = {};
|
||||
std::array<TickCount, 3> m_spu_access_time = {};
|
||||
|
|
116
src/core/bus.inl
116
src/core/bus.inl
|
@ -2,7 +2,7 @@
|
|||
#include "bus.h"
|
||||
|
||||
template<MemoryAccessType type, MemoryAccessSize size>
|
||||
bool Bus::DoRAMAccess(u32 offset, u32& value)
|
||||
TickCount Bus::DoRAMAccess(u32 offset, u32& value)
|
||||
{
|
||||
// TODO: Configurable mirroring.
|
||||
offset &= UINT32_C(0x1FFFFF);
|
||||
|
@ -40,11 +40,12 @@ bool Bus::DoRAMAccess(u32 offset, u32& value)
|
|||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
// Nocash docs say RAM takes 6 cycles to access.
|
||||
return RAM_ACCESS_DELAY;
|
||||
}
|
||||
|
||||
template<MemoryAccessType type, MemoryAccessSize size>
|
||||
bool Bus::DoBIOSAccess(u32 offset, u32& value)
|
||||
TickCount Bus::DoBIOSAccess(u32 offset, u32& value)
|
||||
{
|
||||
// TODO: Configurable mirroring.
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
|
@ -70,11 +71,11 @@ bool Bus::DoBIOSAccess(u32 offset, u32& value)
|
|||
// Writes are ignored.
|
||||
}
|
||||
|
||||
return true;
|
||||
return m_bios_access_time[static_cast<u32>(size)];
|
||||
}
|
||||
|
||||
template<MemoryAccessType type, MemoryAccessSize size>
|
||||
bool Bus::DispatchAccess(PhysicalMemoryAddress address, u32& value)
|
||||
TickCount Bus::DispatchAccess(PhysicalMemoryAddress address, u32& value)
|
||||
{
|
||||
if (address < 0x800000)
|
||||
{
|
||||
|
@ -86,8 +87,12 @@ bool Bus::DispatchAccess(PhysicalMemoryAddress address, u32& value)
|
|||
}
|
||||
else if (address < (EXP1_BASE + EXP1_SIZE))
|
||||
{
|
||||
return (type == MemoryAccessType::Read) ? DoReadEXP1(size, address & EXP1_MASK, value) :
|
||||
DoWriteEXP1(size, address & EXP1_MASK, value);
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
value = DoReadEXP1(size, address & EXP1_MASK);
|
||||
else
|
||||
DoWriteEXP1(size, address & EXP1_MASK, value);
|
||||
|
||||
return m_exp1_access_time[static_cast<u32>(size)];
|
||||
}
|
||||
else if (address < MEMCTRL_BASE)
|
||||
{
|
||||
|
@ -95,39 +100,66 @@ bool Bus::DispatchAccess(PhysicalMemoryAddress address, u32& value)
|
|||
}
|
||||
else if (address < (MEMCTRL_BASE + MEMCTRL_SIZE))
|
||||
{
|
||||
return (type == MemoryAccessType::Read) ? DoReadMemoryControl(size, address & PAD_MASK, value) :
|
||||
DoWriteMemoryControl(size, address & PAD_MASK, value);
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
value = DoReadMemoryControl(size, address & PAD_MASK);
|
||||
else
|
||||
DoWriteMemoryControl(size, address & PAD_MASK, value);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if (address < (PAD_BASE + PAD_SIZE))
|
||||
{
|
||||
return (type == MemoryAccessType::Read) ? DoReadPad(size, address & PAD_MASK, value) :
|
||||
DoWritePad(size, address & PAD_MASK, value);
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
value = DoReadPad(size, address & PAD_MASK);
|
||||
else
|
||||
DoWritePad(size, address & PAD_MASK, value);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if (address < (SIO_BASE + SIO_SIZE))
|
||||
{
|
||||
return (type == MemoryAccessType::Read) ? DoReadSIO(size, address & SIO_MASK, value) :
|
||||
DoWriteSIO(size, address & SIO_MASK, value);
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
value = DoReadSIO(size, address & SIO_MASK);
|
||||
else
|
||||
DoWriteSIO(size, address & SIO_MASK, value);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if (address < (MEMCTRL2_BASE + MEMCTRL2_SIZE))
|
||||
{
|
||||
return (type == MemoryAccessType::Read) ? DoReadMemoryControl2(size, address & PAD_MASK, value) :
|
||||
DoWriteMemoryControl2(size, address & PAD_MASK, value);
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
value = DoReadMemoryControl2(size, address & PAD_MASK);
|
||||
else
|
||||
DoWriteMemoryControl2(size, address & PAD_MASK, value);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if (address < (INTERRUPT_CONTROLLER_BASE + INTERRUPT_CONTROLLER_SIZE))
|
||||
{
|
||||
return (type == MemoryAccessType::Read) ?
|
||||
DoReadInterruptController(size, address & INTERRUPT_CONTROLLER_MASK, value) :
|
||||
DoWriteInterruptController(size, address & INTERRUPT_CONTROLLER_MASK, value);
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
value = DoReadInterruptController(size, address & INTERRUPT_CONTROLLER_MASK);
|
||||
else
|
||||
DoWriteInterruptController(size, address & INTERRUPT_CONTROLLER_MASK, value);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if (address < (DMA_BASE + DMA_SIZE))
|
||||
{
|
||||
return (type == MemoryAccessType::Read) ? DoReadDMA(size, address & DMA_MASK, value) :
|
||||
DoWriteDMA(size, address & DMA_MASK, value);
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
value = DoReadDMA(size, address & DMA_MASK);
|
||||
else
|
||||
DoWriteDMA(size, address & DMA_MASK, value);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if (address < (TIMERS_BASE + TIMERS_SIZE))
|
||||
{
|
||||
return (type == MemoryAccessType::Read) ? DoReadTimers(size, address & TIMERS_MASK, value) :
|
||||
DoWriteTimers(size, address & TIMERS_MASK, value);
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
value = DoReadTimers(size, address & TIMERS_MASK);
|
||||
else
|
||||
DoWriteTimers(size, address & TIMERS_MASK, value);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if (address < CDROM_BASE)
|
||||
{
|
||||
|
@ -135,18 +167,30 @@ bool Bus::DispatchAccess(PhysicalMemoryAddress address, u32& value)
|
|||
}
|
||||
else if (address < (CDROM_BASE + GPU_SIZE))
|
||||
{
|
||||
return (type == MemoryAccessType::Read) ? DoReadCDROM(size, address & CDROM_MASK, value) :
|
||||
DoWriteCDROM(size, address & CDROM_MASK, value);
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
value = DoReadCDROM(size, address & CDROM_MASK);
|
||||
else
|
||||
DoWriteCDROM(size, address & CDROM_MASK, value);
|
||||
|
||||
return m_cdrom_access_time[static_cast<u32>(size)];
|
||||
}
|
||||
else if (address < (GPU_BASE + GPU_SIZE))
|
||||
{
|
||||
return (type == MemoryAccessType::Read) ? DoReadGPU(size, address & GPU_MASK, value) :
|
||||
DoWriteGPU(size, address & GPU_MASK, value);
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
value = DoReadGPU(size, address & GPU_MASK);
|
||||
else
|
||||
DoWriteGPU(size, address & GPU_MASK, value);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if (address < (MDEC_BASE + MDEC_SIZE))
|
||||
{
|
||||
return (type == MemoryAccessType::Read) ? DoReadMDEC(size, address & MDEC_MASK, value) :
|
||||
DoWriteMDEC(size, address & MDEC_MASK, value);
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
value = DoReadMDEC(size, address & MDEC_MASK);
|
||||
else
|
||||
DoWriteMDEC(size, address & MDEC_MASK, value);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if (address < SPU_BASE)
|
||||
{
|
||||
|
@ -154,8 +198,12 @@ bool Bus::DispatchAccess(PhysicalMemoryAddress address, u32& value)
|
|||
}
|
||||
else if (address < (SPU_BASE + SPU_SIZE))
|
||||
{
|
||||
return (type == MemoryAccessType::Read) ? DoReadSPU(size, address & SPU_MASK, value) :
|
||||
DoWriteSPU(size, address & SPU_MASK, value);
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
value = DoReadSPU(size, address & SPU_MASK);
|
||||
else
|
||||
DoWriteSPU(size, address & SPU_MASK, value);
|
||||
|
||||
return m_spu_access_time[static_cast<u32>(size)];
|
||||
}
|
||||
else if (address < EXP2_BASE)
|
||||
{
|
||||
|
@ -163,8 +211,12 @@ bool Bus::DispatchAccess(PhysicalMemoryAddress address, u32& value)
|
|||
}
|
||||
else if (address < (EXP2_BASE + EXP2_SIZE))
|
||||
{
|
||||
return (type == MemoryAccessType::Read) ? DoReadEXP2(size, address & EXP2_MASK, value) :
|
||||
DoWriteEXP2(size, address & EXP2_MASK, value);
|
||||
if constexpr (type == MemoryAccessType::Read)
|
||||
value = DoReadEXP2(size, address & EXP2_MASK);
|
||||
else
|
||||
DoWriteEXP2(size, address & EXP2_MASK, value);
|
||||
|
||||
return m_exp2_access_time[static_cast<u32>(size)];
|
||||
}
|
||||
else if (address < BIOS_BASE)
|
||||
{
|
||||
|
|
|
@ -95,12 +95,16 @@ void Core::SetPC(u32 new_pc)
|
|||
bool Core::ReadMemoryByte(VirtualMemoryAddress addr, u8* value)
|
||||
{
|
||||
u32 temp = 0;
|
||||
const bool result = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Byte>(addr, temp);
|
||||
const TickCount cycles = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Byte>(addr, temp);
|
||||
*value = Truncate8(temp);
|
||||
if (!result)
|
||||
if (cycles < 0)
|
||||
{
|
||||
RaiseException(Exception::DBE);
|
||||
return false;
|
||||
}
|
||||
|
||||
return result;
|
||||
AddTicks(cycles - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Core::ReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value)
|
||||
|
@ -109,12 +113,16 @@ bool Core::ReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value)
|
|||
return false;
|
||||
|
||||
u32 temp = 0;
|
||||
const bool result = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(addr, temp);
|
||||
const TickCount cycles = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(addr, temp);
|
||||
*value = Truncate16(temp);
|
||||
if (!result)
|
||||
if (cycles < 0)
|
||||
{
|
||||
RaiseException(Exception::DBE);
|
||||
return false;
|
||||
}
|
||||
|
||||
return result;
|
||||
AddTicks(cycles - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Core::ReadMemoryWord(VirtualMemoryAddress addr, u32* value)
|
||||
|
@ -122,21 +130,29 @@ bool Core::ReadMemoryWord(VirtualMemoryAddress addr, u32* value)
|
|||
if (!DoAlignmentCheck<MemoryAccessType::Read, MemoryAccessSize::Word>(addr))
|
||||
return false;
|
||||
|
||||
const bool result = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(addr, *value);
|
||||
if (!result)
|
||||
const TickCount cycles = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(addr, *value);
|
||||
if (cycles < 0)
|
||||
{
|
||||
RaiseException(Exception::DBE);
|
||||
return false;
|
||||
}
|
||||
|
||||
return result;
|
||||
AddTicks(cycles - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Core::WriteMemoryByte(VirtualMemoryAddress addr, u8 value)
|
||||
{
|
||||
u32 temp = ZeroExtend32(value);
|
||||
const bool result = DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Byte>(addr, temp);
|
||||
if (!result)
|
||||
const TickCount cycles = DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Byte>(addr, temp);
|
||||
if (cycles < 0)
|
||||
{
|
||||
RaiseException(Exception::DBE);
|
||||
return false;
|
||||
}
|
||||
|
||||
return result;
|
||||
AddTicks(cycles - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Core::WriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value)
|
||||
|
@ -145,11 +161,15 @@ bool Core::WriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value)
|
|||
return false;
|
||||
|
||||
u32 temp = ZeroExtend32(value);
|
||||
const bool result = DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::HalfWord>(addr, temp);
|
||||
if (!result)
|
||||
const TickCount cycles = DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::HalfWord>(addr, temp);
|
||||
if (cycles < 0)
|
||||
{
|
||||
RaiseException(Exception::DBE);
|
||||
return false;
|
||||
}
|
||||
|
||||
return result;
|
||||
AddTicks(cycles - 1);
|
||||
return cycles;
|
||||
}
|
||||
|
||||
bool Core::WriteMemoryWord(VirtualMemoryAddress addr, u32 value)
|
||||
|
@ -157,49 +177,53 @@ bool Core::WriteMemoryWord(VirtualMemoryAddress addr, u32 value)
|
|||
if (!DoAlignmentCheck<MemoryAccessType::Write, MemoryAccessSize::Word>(addr))
|
||||
return false;
|
||||
|
||||
const bool result = DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(addr, value);
|
||||
if (!result)
|
||||
const TickCount cycles = DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(addr, value);
|
||||
if (cycles < 0)
|
||||
{
|
||||
RaiseException(Exception::DBE);
|
||||
return false;
|
||||
}
|
||||
|
||||
return result;
|
||||
AddTicks(cycles - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Core::SafeReadMemoryByte(VirtualMemoryAddress addr, u8* value)
|
||||
{
|
||||
u32 temp = 0;
|
||||
const bool result = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Byte>(addr, temp);
|
||||
const TickCount cycles = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Byte>(addr, temp);
|
||||
*value = Truncate8(temp);
|
||||
return result;
|
||||
return (cycles >= 0);
|
||||
}
|
||||
|
||||
bool Core::SafeReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value)
|
||||
{
|
||||
u32 temp = 0;
|
||||
const bool result = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(addr, temp);
|
||||
const TickCount cycles = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(addr, temp);
|
||||
*value = Truncate16(temp);
|
||||
return result;
|
||||
return (cycles >= 0);
|
||||
}
|
||||
|
||||
bool Core::SafeReadMemoryWord(VirtualMemoryAddress addr, u32* value)
|
||||
{
|
||||
return DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(addr, *value);
|
||||
return DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(addr, *value) >= 0;
|
||||
}
|
||||
|
||||
bool Core::SafeWriteMemoryByte(VirtualMemoryAddress addr, u8 value)
|
||||
{
|
||||
u32 temp = ZeroExtend32(value);
|
||||
return DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Byte>(addr, temp);
|
||||
return DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Byte>(addr, temp) >= 0;
|
||||
}
|
||||
|
||||
bool Core::SafeWriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value)
|
||||
{
|
||||
u32 temp = ZeroExtend32(value);
|
||||
return DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::HalfWord>(addr, temp);
|
||||
return DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::HalfWord>(addr, temp) >= 0;
|
||||
}
|
||||
|
||||
bool Core::SafeWriteMemoryWord(VirtualMemoryAddress addr, u32 value)
|
||||
{
|
||||
return DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(addr, value);
|
||||
return DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(addr, value) >= 0;
|
||||
}
|
||||
|
||||
void Core::Branch(u32 target)
|
||||
|
@ -235,10 +259,13 @@ void Core::RaiseException(Exception excode)
|
|||
|
||||
void Core::RaiseException(Exception excode, u32 EPC, bool BD, bool BT, u8 CE)
|
||||
{
|
||||
Log_DebugPrintf("Exception %u at 0x%08X (epc=0x%08X, BD=%s, CE=%u)", static_cast<u32>(excode),
|
||||
m_current_instruction_pc, EPC, BD ? "true" : "false", ZeroExtend32(CE));
|
||||
#ifdef Y_BUILD_CONFIG_DEBUG
|
||||
DisassembleAndPrint(m_current_instruction_pc, 4, 0);
|
||||
if (excode != Exception::INT && excode != Exception::Syscall && excode != Exception::BP)
|
||||
{
|
||||
Log_DebugPrintf("Exception %u at 0x%08X (epc=0x%08X, BD=%s, CE=%u)", static_cast<u32>(excode),
|
||||
m_current_instruction_pc, EPC, BD ? "true" : "false", ZeroExtend32(CE));
|
||||
DisassembleAndPrint(m_current_instruction_pc, 4, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_cop0_regs.EPC = EPC;
|
||||
|
@ -499,8 +526,8 @@ void Core::Execute()
|
|||
{
|
||||
while (m_downcount >= 0)
|
||||
{
|
||||
m_pending_ticks += 2;
|
||||
m_downcount -= 2;
|
||||
m_pending_ticks += 1;
|
||||
m_downcount -= 1;
|
||||
|
||||
// now executing the instruction we previously fetched
|
||||
m_current_instruction = m_next_instruction;
|
||||
|
@ -542,7 +569,7 @@ bool Core::FetchInstruction()
|
|||
RaiseException(Exception::AdEL, m_regs.npc, false, false, 0);
|
||||
return false;
|
||||
}
|
||||
else if (!DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(m_regs.npc, m_next_instruction.bits))
|
||||
else if (DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(m_regs.npc, m_next_instruction.bits) < 0)
|
||||
{
|
||||
// Bus errors don't set BadVaddr.
|
||||
RaiseException(Exception::IBE, m_regs.npc, false, false, 0);
|
||||
|
|
|
@ -56,7 +56,7 @@ public:
|
|||
|
||||
private:
|
||||
template<MemoryAccessType type, MemoryAccessSize size>
|
||||
bool DoMemoryAccess(VirtualMemoryAddress address, u32& value);
|
||||
TickCount DoMemoryAccess(VirtualMemoryAddress address, u32& value);
|
||||
|
||||
template<MemoryAccessType type, MemoryAccessSize size>
|
||||
bool DoAlignmentCheck(VirtualMemoryAddress address);
|
||||
|
@ -75,6 +75,13 @@ private:
|
|||
bool InUserMode() const { return m_cop0_regs.sr.KUc; }
|
||||
bool InKernelMode() const { return !m_cop0_regs.sr.KUc; }
|
||||
|
||||
// timing
|
||||
void AddTicks(TickCount ticks)
|
||||
{
|
||||
m_pending_ticks += ticks;
|
||||
m_downcount -= ticks;
|
||||
}
|
||||
|
||||
void DisassembleAndPrint(u32 addr);
|
||||
void DisassembleAndPrint(u32 addr, u32 instructions_before, u32 instructions_after);
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
namespace CPU {
|
||||
|
||||
template<MemoryAccessType type, MemoryAccessSize size>
|
||||
bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
|
||||
TickCount Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
|
||||
{
|
||||
switch (address >> 29)
|
||||
{
|
||||
|
@ -15,23 +15,17 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
|
|||
if constexpr (type == MemoryAccessType::Write)
|
||||
{
|
||||
if (m_cop0_regs.sr.Isc)
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const PhysicalMemoryAddress phys_addr = address & UINT32_C(0x1FFFFFFF);
|
||||
if ((phys_addr & DCACHE_LOCATION_MASK) == DCACHE_LOCATION)
|
||||
{
|
||||
DoScratchpadAccess<type, size>(phys_addr, value);
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!m_bus->DispatchAccess<type, size>(phys_addr, value))
|
||||
{
|
||||
Panic("Bus error");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return m_bus->DispatchAccess<type, size>(phys_addr, value);
|
||||
}
|
||||
|
||||
case 0x01: // KUSEG 512M-1024M
|
||||
|
@ -39,7 +33,7 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
|
|||
case 0x03: // KUSEG 1536M-2048M
|
||||
{
|
||||
// Above 512mb raises an exception.
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
case 0x04: // KSEG0 - physical memory cached
|
||||
|
@ -47,36 +41,24 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
|
|||
if constexpr (type == MemoryAccessType::Write)
|
||||
{
|
||||
if (m_cop0_regs.sr.Isc)
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const PhysicalMemoryAddress phys_addr = address & UINT32_C(0x1FFFFFFF);
|
||||
if ((phys_addr & DCACHE_LOCATION_MASK) == DCACHE_LOCATION)
|
||||
{
|
||||
DoScratchpadAccess<type, size>(phys_addr, value);
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!m_bus->DispatchAccess<type, size>(phys_addr, value))
|
||||
{
|
||||
Panic("Bus error");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return m_bus->DispatchAccess<type, size>(phys_addr, value);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x05: // KSEG1 - physical memory uncached
|
||||
{
|
||||
const PhysicalMemoryAddress phys_addr = address & UINT32_C(0x1FFFFFFF);
|
||||
if (!m_bus->DispatchAccess<type, size>(phys_addr, value))
|
||||
{
|
||||
Panic("Bus error");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return m_bus->DispatchAccess<type, size>(phys_addr, value);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -90,11 +72,11 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
|
|||
else
|
||||
WriteCacheControl(value);
|
||||
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue