Clean up memory access handlers, reduce template specializations

This commit is contained in:
Connor McLaughlin 2019-09-25 00:36:24 +10:00
parent 4aca52cdf4
commit 9359d0778e
7 changed files with 260 additions and 165 deletions

View file

@ -47,53 +47,65 @@ bool Bus::Initialize(CPU::Core* cpu, DMA* dma, InterruptController* interrupt_co
void Bus::Reset() void Bus::Reset()
{ {
m_ram.fill(static_cast<u8>(0)); m_ram.fill(static_cast<u8>(0));
m_MEMCTRL.exp1_base = 0x1F000000;
m_MEMCTRL.exp2_base = 0x1F802000;
m_MEMCTRL.exp1_delay_size = 0x0013243F;
m_MEMCTRL.exp3_delay_size = 0x00003022;
m_MEMCTRL.bios_delay_size = 0x0013243F;
m_MEMCTRL.spu_delay_size = 0x200931E1;
m_MEMCTRL.cdrom_delay_size = 0x00020843;
m_MEMCTRL.exp2_delay_size = 0x00070777;
m_MEMCTRL.common_delay_size = 0x00031125;
m_ram_size_reg = UINT32_C(0x00000B88);
} }
bool Bus::DoState(StateWrapper& sw) bool Bus::DoState(StateWrapper& sw)
{ {
sw.DoBytes(m_ram.data(), m_ram.size()); sw.DoBytes(m_ram.data(), m_ram.size());
sw.DoBytes(m_bios.data(), m_bios.size()); sw.DoBytes(m_bios.data(), m_bios.size());
sw.DoArray(m_MEMCTRL.regs, countof(m_MEMCTRL.regs));
sw.Do(&m_ram_size_reg);
sw.Do(&m_tty_line_buffer); sw.Do(&m_tty_line_buffer);
return !sw.HasError(); return !sw.HasError();
} }
bool Bus::ReadByte(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u8* value) bool Bus::ReadByte(PhysicalMemoryAddress address, u8* value)
{ {
u32 temp = 0; u32 temp = 0;
const bool result = DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Byte>(cpu_address, bus_address, temp); const bool result = DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Byte>(address, temp);
*value = Truncate8(temp); *value = Truncate8(temp);
return result; return result;
} }
bool Bus::ReadHalfWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u16* value) bool Bus::ReadHalfWord(PhysicalMemoryAddress address, u16* value)
{ {
u32 temp = 0; u32 temp = 0;
const bool result = const bool result =
DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(cpu_address, bus_address, temp); DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(address, temp);
*value = Truncate16(temp); *value = Truncate16(temp);
return result; return result;
} }
bool Bus::ReadWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32* value) bool Bus::ReadWord(PhysicalMemoryAddress address, u32* value)
{ {
return DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(cpu_address, bus_address, *value); return DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(address, *value);
} }
bool Bus::WriteByte(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u8 value) bool Bus::WriteByte(PhysicalMemoryAddress address, u8 value)
{ {
u32 temp = ZeroExtend32(value); u32 temp = ZeroExtend32(value);
return DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Byte>(cpu_address, bus_address, temp); return DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Byte>(address, temp);
} }
bool Bus::WriteHalfWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u16 value) bool Bus::WriteHalfWord(PhysicalMemoryAddress address, u16 value)
{ {
u32 temp = ZeroExtend32(value); u32 temp = ZeroExtend32(value);
return DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(cpu_address, bus_address, temp); return DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(address, temp);
} }
bool Bus::WriteWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32 value) bool Bus::WriteWord(PhysicalMemoryAddress address, u32 value)
{ {
return DispatchAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(cpu_address, bus_address, value); return DispatchAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(address, value);
} }
void Bus::PatchBIOS(u32 address, u32 value, u32 mask /*= UINT32_C(0xFFFFFFFF)*/) void Bus::PatchBIOS(u32 address, u32 value, u32 mask /*= UINT32_C(0xFFFFFFFF)*/)
@ -154,8 +166,7 @@ bool Bus::LoadBIOS()
return true; return true;
} }
bool Bus::DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress cpu_address, bool Bus::DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address, u32& value)
PhysicalMemoryAddress bus_address, u32& value)
{ {
SmallString str; SmallString str;
str.AppendString("Invalid bus "); str.AppendString("Invalid bus ");
@ -171,7 +182,7 @@ bool Bus::DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, Physical
else else
str.AppendString("write"); str.AppendString("write");
str.AppendFormattedString(" at address 0x%08X (virtual address 0x%08X)", bus_address, cpu_address); str.AppendFormattedString(" at address 0x%08X", address);
if (type == MemoryAccessType::Write) if (type == MemoryAccessType::Write)
str.AppendFormattedString(" (value 0x%08X)", value); str.AppendFormattedString(" (value 0x%08X)", value);
@ -185,7 +196,7 @@ bool Bus::DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, Physical
bool Bus::DoReadEXP1(MemoryAccessSize size, u32 offset, u32& value) bool Bus::DoReadEXP1(MemoryAccessSize size, u32 offset, u32& value)
{ {
if (m_exp1_rom.empty()) if (m_exp1_rom.empty())
return DoInvalidAccess(MemoryAccessType::Read, size, EXP1_BASE | offset, EXP1_BASE | offset, value); return DoInvalidAccess(MemoryAccessType::Read, size, EXP1_BASE | offset, value);
if (offset == 0x20018) if (offset == 0x20018)
{ {
@ -221,7 +232,7 @@ bool Bus::DoReadEXP1(MemoryAccessSize size, u32 offset, u32& value)
bool Bus::DoWriteEXP1(MemoryAccessSize size, u32 offset, u32 value) bool Bus::DoWriteEXP1(MemoryAccessSize size, u32 offset, u32 value)
{ {
return DoInvalidAccess(MemoryAccessType::Write, size, EXP1_BASE | offset, EXP1_BASE | offset, value); return DoInvalidAccess(MemoryAccessType::Write, size, EXP1_BASE | offset, value);
} }
bool Bus::DoReadEXP2(MemoryAccessSize size, u32 offset, u32& value) bool Bus::DoReadEXP2(MemoryAccessSize size, u32 offset, u32& value)
@ -235,7 +246,7 @@ bool Bus::DoReadEXP2(MemoryAccessSize size, u32 offset, u32& value)
return true; return true;
} }
return DoInvalidAccess(MemoryAccessType::Read, size, EXP2_BASE | offset, EXP2_BASE | offset, value); return DoInvalidAccess(MemoryAccessType::Read, size, EXP2_BASE | offset, value);
} }
bool Bus::DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value) bool Bus::DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value)
@ -267,7 +278,43 @@ bool Bus::DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value)
return true; return true;
} }
return DoInvalidAccess(MemoryAccessType::Write, size, EXP2_BASE | offset, EXP2_BASE | offset, value); return DoInvalidAccess(MemoryAccessType::Write, size, EXP2_BASE | offset, value);
}
bool Bus::DoReadMemoryControl(MemoryAccessSize size, u32 offset, u32& value)
{
FixupUnalignedWordAccessW32(offset, value);
value = m_MEMCTRL.regs[offset / 4];
return true;
}
bool Bus::DoWriteMemoryControl(MemoryAccessSize size, u32 offset, u32 value)
{
FixupUnalignedWordAccessW32(offset, value);
m_MEMCTRL.regs[offset / 4] = value;
return true;
}
bool Bus::DoReadMemoryControl2(MemoryAccessSize size, u32 offset, u32& value)
{
if (offset == 0x00)
{
value = m_ram_size_reg;
return true;
}
return DoInvalidAccess(MemoryAccessType::Read, size, MEMCTRL2_BASE | offset, value);
}
bool Bus::DoWriteMemoryControl2(MemoryAccessSize size, u32 offset, u32 value)
{
if (offset == 0x00)
{
m_ram_size_reg = value;
return true;
}
return DoInvalidAccess(MemoryAccessType::Write, size, MEMCTRL2_BASE | offset, value);
} }
bool Bus::DoReadPad(MemoryAccessSize size, u32 offset, u32& value) bool Bus::DoReadPad(MemoryAccessSize size, u32 offset, u32& value)

View file

@ -30,52 +30,84 @@ public:
void Reset(); void Reset();
bool DoState(StateWrapper& sw); bool DoState(StateWrapper& sw);
bool ReadByte(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u8* value); bool ReadByte(PhysicalMemoryAddress address, u8* value);
bool ReadHalfWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u16* value); bool ReadHalfWord(PhysicalMemoryAddress address, u16* value);
bool ReadWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32* value); bool ReadWord(PhysicalMemoryAddress address, u32* value);
bool WriteByte(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u8 value); bool WriteByte(PhysicalMemoryAddress address, u8 value);
bool WriteHalfWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u16 value); bool WriteHalfWord(PhysicalMemoryAddress address, u16 value);
bool WriteWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32 value); bool WriteWord(PhysicalMemoryAddress address, u32 value);
template<MemoryAccessType type, MemoryAccessSize size> template<MemoryAccessType type, MemoryAccessSize size>
bool DispatchAccess(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32& value); bool DispatchAccess(PhysicalMemoryAddress address, u32& value);
void PatchBIOS(u32 address, u32 value, u32 mask = UINT32_C(0xFFFFFFFF)); void PatchBIOS(u32 address, u32 value, u32 mask = UINT32_C(0xFFFFFFFF));
void SetExpansionROM(std::vector<u8> data); void SetExpansionROM(std::vector<u8> data);
private: private:
static constexpr u32 EXP1_BASE = 0x1F000000; enum : u32
static constexpr u32 EXP1_SIZE = 0x800000; {
static constexpr u32 EXP1_MASK = EXP1_SIZE - 1; EXP1_BASE = 0x1F000000,
static constexpr u32 PAD_BASE = 0x1F801040; EXP1_SIZE = 0x800000,
static constexpr u32 PAD_SIZE = 0x10; EXP1_MASK = EXP1_SIZE - 1,
static constexpr u32 PAD_MASK = PAD_SIZE - 1; MEMCTRL_BASE = 0x1F801000,
static constexpr u32 SIO_BASE = 0x1F801050; MEMCTRL_SIZE = 0x40,
static constexpr u32 SIO_SIZE = 0x10; MEMCTRL_MASK = MEMCTRL_SIZE - 1,
static constexpr u32 SIO_MASK = SIO_SIZE - 1; PAD_BASE = 0x1F801040,
static constexpr u32 INTERRUPT_CONTROLLER_BASE = 0x1F801070; PAD_SIZE = 0x10,
static constexpr u32 INTERRUPT_CONTROLLER_SIZE = 0x08; PAD_MASK = PAD_SIZE - 1,
static constexpr u32 INTERRUPT_CONTROLLER_MASK = INTERRUPT_CONTROLLER_SIZE - 1; SIO_BASE = 0x1F801050,
static constexpr u32 DMA_BASE = 0x1F801080; SIO_SIZE = 0x10,
static constexpr u32 DMA_SIZE = 0x80; SIO_MASK = SIO_SIZE - 1,
static constexpr u32 DMA_MASK = DMA_SIZE - 1; MEMCTRL2_BASE = 0x1F801060,
static constexpr u32 TIMERS_BASE = 0x1F801100; MEMCTRL2_SIZE = 0x10,
static constexpr u32 TIMERS_SIZE = 0x40; MEMCTRL2_MASK = MEMCTRL_SIZE - 1,
static constexpr u32 TIMERS_MASK = TIMERS_SIZE - 1; INTERRUPT_CONTROLLER_BASE = 0x1F801070,
static constexpr u32 CDROM_BASE = 0x1F801800; INTERRUPT_CONTROLLER_SIZE = 0x10,
static constexpr u32 CDROM_SIZE = 0x04; INTERRUPT_CONTROLLER_MASK = INTERRUPT_CONTROLLER_SIZE - 1,
static constexpr u32 CDROM_MASK = CDROM_SIZE - 1; DMA_BASE = 0x1F801080,
static constexpr u32 GPU_BASE = 0x1F801810; DMA_SIZE = 0x80,
static constexpr u32 GPU_SIZE = 0x10; DMA_MASK = DMA_SIZE - 1,
static constexpr u32 GPU_MASK = GPU_SIZE - 1; TIMERS_BASE = 0x1F801100,
static constexpr u32 SPU_BASE = 0x1F801C00; TIMERS_SIZE = 0x40,
static constexpr u32 SPU_SIZE = 0x300; TIMERS_MASK = TIMERS_SIZE - 1,
static constexpr u32 SPU_MASK = 0x3FF; CDROM_BASE = 0x1F801800,
static constexpr u32 EXP2_BASE = 0x1F802000; CDROM_SIZE = 0x04,
static constexpr u32 EXP2_SIZE = 0x2000; CDROM_MASK = CDROM_SIZE - 1,
static constexpr u32 EXP2_MASK = EXP2_SIZE - 1; GPU_BASE = 0x1F801810,
static constexpr u32 BIOS_BASE = 0x1FC00000; GPU_SIZE = 0x10,
static constexpr u32 BIOS_SIZE = 0x80000; GPU_MASK = GPU_SIZE - 1,
SPU_BASE = 0x1F801C00,
SPU_SIZE = 0x300,
SPU_MASK = 0x3FF,
EXP2_BASE = 0x1F802000,
EXP2_SIZE = 0x2000,
EXP2_MASK = EXP2_SIZE - 1,
BIOS_BASE = 0x1FC00000,
BIOS_SIZE = 0x80000
};
enum : u32
{
MEMCTRL_REG_COUNT = 9
};
union MEMCTRL
{
u32 regs[MEMCTRL_REG_COUNT];
struct
{
u32 exp1_base;
u32 exp2_base;
u32 exp1_delay_size;
u32 exp3_delay_size;
u32 bios_delay_size;
u32 spu_delay_size;
u32 cdrom_delay_size;
u32 exp2_delay_size;
u32 common_delay_size;
};
};
bool LoadBIOS(); bool LoadBIOS();
@ -85,8 +117,7 @@ private:
template<MemoryAccessType type, MemoryAccessSize size> template<MemoryAccessType type, MemoryAccessSize size>
bool DoBIOSAccess(u32 offset, u32& value); bool DoBIOSAccess(u32 offset, u32& value);
bool DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress cpu_address, bool DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address, u32& value);
PhysicalMemoryAddress bus_address, u32& value);
bool DoReadEXP1(MemoryAccessSize size, u32 offset, u32& value); bool DoReadEXP1(MemoryAccessSize size, u32 offset, u32& value);
bool DoWriteEXP1(MemoryAccessSize size, u32 offset, u32 value); bool DoWriteEXP1(MemoryAccessSize size, u32 offset, u32 value);
@ -94,6 +125,12 @@ private:
bool DoReadEXP2(MemoryAccessSize size, u32 offset, u32& value); bool DoReadEXP2(MemoryAccessSize size, u32 offset, u32& value);
bool DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value); bool DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value);
bool DoReadMemoryControl(MemoryAccessSize size, u32 offset, u32& value);
bool DoWriteMemoryControl(MemoryAccessSize size, u32 offset, u32 value);
bool DoReadMemoryControl2(MemoryAccessSize size, u32 offset, u32& value);
bool DoWriteMemoryControl2(MemoryAccessSize size, u32 offset, u32 value);
bool DoReadPad(MemoryAccessSize size, u32 offset, u32& value); bool DoReadPad(MemoryAccessSize size, u32 offset, u32& value);
bool DoWritePad(MemoryAccessSize size, u32 offset, u32 value); bool DoWritePad(MemoryAccessSize size, u32 offset, u32 value);
@ -131,6 +168,9 @@ private:
std::array<u8, 524288> m_bios{}; // 512K BIOS ROM std::array<u8, 524288> m_bios{}; // 512K BIOS ROM
std::vector<u8> m_exp1_rom; std::vector<u8> m_exp1_rom;
MEMCTRL m_MEMCTRL = {};
u32 m_ram_size_reg = 0;
String m_tty_line_buffer; String m_tty_line_buffer;
}; };

View file

@ -74,117 +74,107 @@ bool Bus::DoBIOSAccess(u32 offset, u32& value)
} }
template<MemoryAccessType type, MemoryAccessSize size> template<MemoryAccessType type, MemoryAccessSize size>
bool Bus::DispatchAccess(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32& value) bool Bus::DispatchAccess(PhysicalMemoryAddress address, u32& value)
{ {
if (bus_address < 0x800000) if (address < 0x800000)
{ {
return DoRAMAccess<type, size>(bus_address, value); return DoRAMAccess<type, size>(address, value);
} }
else if (bus_address < EXP1_BASE) else if (address < EXP1_BASE)
{ {
return DoInvalidAccess(type, size, cpu_address, bus_address, value); return DoInvalidAccess(type, size, address, value);
} }
else if (bus_address < (EXP1_BASE + EXP1_SIZE)) else if (address < (EXP1_BASE + EXP1_SIZE))
{ {
return (type == MemoryAccessType::Read) ? DoReadEXP1(size, bus_address & EXP1_MASK, value) : return (type == MemoryAccessType::Read) ? DoReadEXP1(size, address & EXP1_MASK, value) :
DoWriteEXP1(size, bus_address & EXP1_MASK, value); DoWriteEXP1(size, address & EXP1_MASK, value);
} }
else if (bus_address < PAD_BASE) else if (address < MEMCTRL_BASE)
{ {
return DoInvalidAccess(type, size, cpu_address, bus_address, value); return DoInvalidAccess(type, size, address, value);
} }
else if (bus_address < (PAD_BASE + PAD_SIZE)) else if (address < (MEMCTRL_BASE + MEMCTRL_SIZE))
{ {
return (type == MemoryAccessType::Read) ? DoReadPad(size, bus_address & PAD_MASK, value) : return (type == MemoryAccessType::Read) ? DoReadMemoryControl(size, address & PAD_MASK, value) :
DoWritePad(size, bus_address & PAD_MASK, value); DoWriteMemoryControl(size, address & PAD_MASK, value);
} }
else if (bus_address < (SIO_BASE + SIO_SIZE)) else if (address < (PAD_BASE + PAD_SIZE))
{ {
return (type == MemoryAccessType::Read) ? DoReadSIO(size, bus_address & SIO_MASK, value) : return (type == MemoryAccessType::Read) ? DoReadPad(size, address & PAD_MASK, value) :
DoWriteSIO(size, bus_address & SIO_MASK, value); DoWritePad(size, address & PAD_MASK, value);
} }
else if (bus_address < INTERRUPT_CONTROLLER_BASE) else if (address < (SIO_BASE + SIO_SIZE))
{ {
return DoInvalidAccess(type, size, cpu_address, bus_address, value); return (type == MemoryAccessType::Read) ? DoReadSIO(size, address & SIO_MASK, value) :
DoWriteSIO(size, address & SIO_MASK, value);
} }
else if (bus_address < (INTERRUPT_CONTROLLER_BASE + INTERRUPT_CONTROLLER_SIZE)) else if (address < (MEMCTRL2_BASE + MEMCTRL2_SIZE))
{
return (type == MemoryAccessType::Read) ? DoReadMemoryControl2(size, address & PAD_MASK, value) :
DoWriteMemoryControl2(size, address & PAD_MASK, value);
}
else if (address < (INTERRUPT_CONTROLLER_BASE + INTERRUPT_CONTROLLER_SIZE))
{ {
return (type == MemoryAccessType::Read) ? return (type == MemoryAccessType::Read) ?
DoReadInterruptController(size, bus_address & INTERRUPT_CONTROLLER_MASK, value) : DoReadInterruptController(size, address & INTERRUPT_CONTROLLER_MASK, value) :
DoWriteInterruptController(size, bus_address & INTERRUPT_CONTROLLER_MASK, value); DoWriteInterruptController(size, address & INTERRUPT_CONTROLLER_MASK, value);
} }
else if (bus_address < DMA_BASE) else if (address < (DMA_BASE + DMA_SIZE))
{ {
return DoInvalidAccess(type, size, cpu_address, bus_address, value); return (type == MemoryAccessType::Read) ? DoReadDMA(size, address & DMA_MASK, value) :
DoWriteDMA(size, address & DMA_MASK, value);
} }
else if (bus_address < (DMA_BASE + DMA_SIZE)) else if (address < (TIMERS_BASE + TIMERS_SIZE))
{ {
return (type == MemoryAccessType::Read) ? DoReadDMA(size, bus_address & DMA_MASK, value) : return (type == MemoryAccessType::Read) ? DoReadTimers(size, address & TIMERS_MASK, value) :
DoWriteDMA(size, bus_address & DMA_MASK, value); DoWriteTimers(size, address & TIMERS_MASK, value);
} }
else if (bus_address < TIMERS_BASE) else if (address < CDROM_BASE)
{ {
return DoInvalidAccess(type, size, cpu_address, bus_address, value); return DoInvalidAccess(type, size, address, value);
} }
else if (bus_address < (TIMERS_BASE + TIMERS_SIZE)) else if (address < (CDROM_BASE + GPU_SIZE))
{ {
return (type == MemoryAccessType::Read) ? DoReadTimers(size, bus_address & TIMERS_MASK, value) : return (type == MemoryAccessType::Read) ? DoReadCDROM(size, address & CDROM_MASK, value) :
DoWriteTimers(size, bus_address & TIMERS_MASK, value); DoWriteCDROM(size, address & CDROM_MASK, value);
} }
else if (bus_address < CDROM_BASE) else if (address < GPU_BASE)
{ {
return DoInvalidAccess(type, size, cpu_address, bus_address, value); return DoInvalidAccess(type, size, address, value);
} }
else if (bus_address < (CDROM_BASE + GPU_SIZE)) else if (address < (GPU_BASE + GPU_SIZE))
{ {
return (type == MemoryAccessType::Read) ? DoReadCDROM(size, bus_address & CDROM_MASK, value) : return (type == MemoryAccessType::Read) ? DoReadGPU(size, address & GPU_MASK, value) :
DoWriteCDROM(size, bus_address & CDROM_MASK, value); DoWriteGPU(size, address & GPU_MASK, value);
} }
else if (bus_address < GPU_BASE) else if (address < SPU_BASE)
{ {
return DoInvalidAccess(type, size, cpu_address, bus_address, value); return DoInvalidAccess(type, size, address, value);
} }
else if (bus_address < (GPU_BASE + GPU_SIZE)) else if (address < (SPU_BASE + SPU_SIZE))
{ {
return (type == MemoryAccessType::Read) ? DoReadGPU(size, bus_address & GPU_MASK, value) : return (type == MemoryAccessType::Read) ? DoReadSPU(size, address & SPU_MASK, value) :
DoWriteGPU(size, bus_address & GPU_MASK, value); DoWriteSPU(size, address & SPU_MASK, value);
} }
else if (bus_address < SPU_BASE) else if (address < EXP2_BASE)
{ {
return DoInvalidAccess(type, size, cpu_address, bus_address, value); return DoInvalidAccess(type, size, address, value);
} }
else if (bus_address < (SPU_BASE + SPU_SIZE)) else if (address < (EXP2_BASE + EXP2_SIZE))
{ {
return (type == MemoryAccessType::Read) ? DoReadSPU(size, bus_address & SPU_MASK, value) : return (type == MemoryAccessType::Read) ? DoReadEXP2(size, address & EXP2_MASK, value) :
DoWriteSPU(size, bus_address & SPU_MASK, value); DoWriteEXP2(size, address & EXP2_MASK, value);
} }
else if (bus_address < EXP2_BASE) else if (address < BIOS_BASE)
{ {
return DoInvalidAccess(type, size, cpu_address, bus_address, value); return DoInvalidAccess(type, size, address, value);
} }
else if (bus_address < (EXP2_BASE + EXP2_SIZE)) else if (address < (BIOS_BASE + BIOS_SIZE))
{ {
return (type == MemoryAccessType::Read) ? DoReadEXP2(size, bus_address & EXP2_MASK, value) : return DoBIOSAccess<type, size>(static_cast<u32>(address - BIOS_BASE), value);
DoWriteEXP2(size, bus_address & EXP2_MASK, value);
}
else if (bus_address < BIOS_BASE)
{
return DoInvalidAccess(type, size, cpu_address, bus_address, value);
}
else if (bus_address < (BIOS_BASE + BIOS_SIZE))
{
return DoBIOSAccess<type, size>(static_cast<u32>(bus_address - BIOS_BASE), value);
}
else if (bus_address < 0x1FFE0000)
{
return DoInvalidAccess(type, size, cpu_address, bus_address, value);
}
else if (bus_address < 0x1FFE0200) // I/O Ports (Cache Control)
{
return DoInvalidAccess(type, size, cpu_address, bus_address, value);
} }
else else
{ {
return DoInvalidAccess(type, size, cpu_address, bus_address, value); return DoInvalidAccess(type, size, address, value);
} }
} }

View file

@ -92,8 +92,11 @@ void Core::SetPC(u32 new_pc)
bool Core::ReadMemoryByte(VirtualMemoryAddress addr, u8* value) bool Core::ReadMemoryByte(VirtualMemoryAddress addr, u8* value)
{ {
u32 temp = 0; u32 temp = 0;
const bool result = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Byte, false, true>(addr, temp); const bool result = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Byte>(addr, temp);
*value = Truncate8(temp); *value = Truncate8(temp);
if (!result)
RaiseException(Exception::DBE);
return result; return result;
} }
@ -103,8 +106,11 @@ bool Core::ReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value)
return false; return false;
u32 temp = 0; u32 temp = 0;
const bool result = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::HalfWord, false, true>(addr, temp); const bool result = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(addr, temp);
*value = Truncate16(temp); *value = Truncate16(temp);
if (!result)
RaiseException(Exception::DBE);
return result; return result;
} }
@ -113,13 +119,21 @@ bool Core::ReadMemoryWord(VirtualMemoryAddress addr, u32* value)
if (!DoAlignmentCheck<MemoryAccessType::Read, MemoryAccessSize::Word>(addr)) if (!DoAlignmentCheck<MemoryAccessType::Read, MemoryAccessSize::Word>(addr))
return false; return false;
return DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word, false, true>(addr, *value); const bool result = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(addr, *value);
if (!result)
RaiseException(Exception::DBE);
return result;
} }
bool Core::WriteMemoryByte(VirtualMemoryAddress addr, u8 value) bool Core::WriteMemoryByte(VirtualMemoryAddress addr, u8 value)
{ {
u32 temp = ZeroExtend32(value); u32 temp = ZeroExtend32(value);
return DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Byte, false, true>(addr, temp); const bool result = DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Byte>(addr, temp);
if (!result)
RaiseException(Exception::DBE);
return result;
} }
bool Core::WriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value) bool Core::WriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value)
@ -128,7 +142,11 @@ bool Core::WriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value)
return false; return false;
u32 temp = ZeroExtend32(value); u32 temp = ZeroExtend32(value);
return DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::HalfWord, false, true>(addr, temp); const bool result = DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::HalfWord>(addr, temp);
if (!result)
RaiseException(Exception::DBE);
return result;
} }
bool Core::WriteMemoryWord(VirtualMemoryAddress addr, u32 value) bool Core::WriteMemoryWord(VirtualMemoryAddress addr, u32 value)
@ -136,13 +154,17 @@ bool Core::WriteMemoryWord(VirtualMemoryAddress addr, u32 value)
if (!DoAlignmentCheck<MemoryAccessType::Write, MemoryAccessSize::Word>(addr)) if (!DoAlignmentCheck<MemoryAccessType::Write, MemoryAccessSize::Word>(addr))
return false; return false;
return DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Word, false, true>(addr, value); const bool result = DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(addr, value);
if (!result)
RaiseException(Exception::DBE);
return result;
} }
bool Core::SafeReadMemoryByte(VirtualMemoryAddress addr, u8* value) bool Core::SafeReadMemoryByte(VirtualMemoryAddress addr, u8* value)
{ {
u32 temp = 0; u32 temp = 0;
const bool result = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Byte, false, false>(addr, temp); const bool result = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Byte>(addr, temp);
*value = Truncate8(temp); *value = Truncate8(temp);
return result; return result;
} }
@ -150,31 +172,31 @@ bool Core::SafeReadMemoryByte(VirtualMemoryAddress addr, u8* value)
bool Core::SafeReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value) bool Core::SafeReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value)
{ {
u32 temp = 0; u32 temp = 0;
const bool result = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::HalfWord, false, false>(addr, temp); const bool result = DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(addr, temp);
*value = Truncate16(temp); *value = Truncate16(temp);
return result; return result;
} }
bool Core::SafeReadMemoryWord(VirtualMemoryAddress addr, u32* value) bool Core::SafeReadMemoryWord(VirtualMemoryAddress addr, u32* value)
{ {
return DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word, false, false>(addr, *value); return DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(addr, *value);
} }
bool Core::SafeWriteMemoryByte(VirtualMemoryAddress addr, u8 value) bool Core::SafeWriteMemoryByte(VirtualMemoryAddress addr, u8 value)
{ {
u32 temp = ZeroExtend32(value); u32 temp = ZeroExtend32(value);
return DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Byte, false, false>(addr, temp); return DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Byte>(addr, temp);
} }
bool Core::SafeWriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value) bool Core::SafeWriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value)
{ {
u32 temp = ZeroExtend32(value); u32 temp = ZeroExtend32(value);
return DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::HalfWord, false, false>(addr, temp); return DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::HalfWord>(addr, temp);
} }
bool Core::SafeWriteMemoryWord(VirtualMemoryAddress addr, u32 value) bool Core::SafeWriteMemoryWord(VirtualMemoryAddress addr, u32 value)
{ {
return DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Word, false, false>(addr, value); return DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(addr, value);
} }
void Core::Branch(u32 target) void Core::Branch(u32 target)
@ -420,8 +442,8 @@ static constexpr bool SubOverflow(u32 old_value, u32 sub_value, u32 new_value)
void Core::DisassembleAndPrint(u32 addr) void Core::DisassembleAndPrint(u32 addr)
{ {
u32 bits; u32 bits = 0;
DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word, true, false>(addr, bits); DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(addr, bits);
PrintInstruction(bits, addr); PrintInstruction(bits, addr);
} }
@ -459,14 +481,17 @@ bool Core::FetchInstruction()
{ {
m_regs.pc = m_regs.npc; m_regs.pc = m_regs.npc;
if (!DoAlignmentCheck<MemoryAccessType::Read, MemoryAccessSize::Word>( if (!DoAlignmentCheck<MemoryAccessType::Read, MemoryAccessSize::Word>(static_cast<VirtualMemoryAddress>(m_regs.npc)))
static_cast<VirtualMemoryAddress>(m_regs.npc)) ||
!DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word, true, true>(
static_cast<VirtualMemoryAddress>(m_regs.npc), m_next_instruction.bits))
{ {
// this will call FetchInstruction() again when the pipeline is flushed. // this will call FetchInstruction() again when the pipeline is flushed.
return false; return false;
} }
if (!DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(static_cast<VirtualMemoryAddress>(m_regs.npc),
m_next_instruction.bits))
{
RaiseException(Exception::IBE);
return false;
}
m_regs.npc += sizeof(m_next_instruction.bits); m_regs.npc += sizeof(m_next_instruction.bits);
return true; return true;

View file

@ -41,6 +41,7 @@ public:
// Sets the PC and flushes the pipeline. // Sets the PC and flushes the pipeline.
void SetPC(u32 new_pc); void SetPC(u32 new_pc);
// Memory reads variants which do not raise exceptions.
bool SafeReadMemoryByte(VirtualMemoryAddress addr, u8* value); bool SafeReadMemoryByte(VirtualMemoryAddress addr, u8* value);
bool SafeReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value); bool SafeReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value);
bool SafeReadMemoryWord(VirtualMemoryAddress addr, u32* value); bool SafeReadMemoryWord(VirtualMemoryAddress addr, u32* value);
@ -53,7 +54,7 @@ public:
void ClearExternalInterrupt(u8 bit); void ClearExternalInterrupt(u8 bit);
private: private:
template<MemoryAccessType type, MemoryAccessSize size, bool is_instruction_fetch, bool raise_exceptions> template<MemoryAccessType type, MemoryAccessSize size>
bool DoMemoryAccess(VirtualMemoryAddress address, u32& value); bool DoMemoryAccess(VirtualMemoryAddress address, u32& value);
template<MemoryAccessType type, MemoryAccessSize size> template<MemoryAccessType type, MemoryAccessSize size>

View file

@ -5,7 +5,7 @@
namespace CPU { namespace CPU {
template<MemoryAccessType type, MemoryAccessSize size, bool is_instruction_fetch, bool raise_exceptions> template<MemoryAccessType type, MemoryAccessSize size>
bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value) bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
{ {
switch (address >> 29) switch (address >> 29)
@ -25,7 +25,7 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
return true; return true;
} }
if (!m_bus->DispatchAccess<type, size>(address, phys_addr, value)) if (!m_bus->DispatchAccess<type, size>(phys_addr, value))
{ {
Panic("Bus error"); Panic("Bus error");
return false; return false;
@ -39,7 +39,6 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
case 0x03: // KUSEG 1536M-2048M case 0x03: // KUSEG 1536M-2048M
{ {
// Above 512mb raises an exception. // Above 512mb raises an exception.
RaiseException(is_instruction_fetch ? Exception::IBE : Exception::DBE);
return false; return false;
} }
@ -58,7 +57,7 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
return true; return true;
} }
if (!m_bus->DispatchAccess<type, size>(address, address & UINT32_C(0x1FFFFFFF), value)) if (!m_bus->DispatchAccess<type, size>(phys_addr, value))
{ {
Panic("Bus error"); Panic("Bus error");
return false; return false;
@ -71,7 +70,7 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
case 0x05: // KSEG1 - physical memory uncached case 0x05: // KSEG1 - physical memory uncached
{ {
const PhysicalMemoryAddress phys_addr = address & UINT32_C(0x1FFFFFFF); const PhysicalMemoryAddress phys_addr = address & UINT32_C(0x1FFFFFFF);
if (!m_bus->DispatchAccess<type, size>(address, phys_addr, value)) if (!m_bus->DispatchAccess<type, size>(phys_addr, value))
{ {
Panic("Bus error"); Panic("Bus error");
return false; return false;
@ -95,7 +94,6 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
} }
else else
{ {
RaiseException(is_instruction_fetch ? Exception::IBE : Exception::DBE);
return false; return false;
} }
} }

View file

@ -234,8 +234,7 @@ void DMA::RunDMA(Channel channel)
words_remaining--; words_remaining--;
u32 value = 0; u32 value = 0;
m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(current_address, current_address, m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(current_address, value);
value);
DMAWrite(channel, value, current_address, words_remaining); DMAWrite(channel, value, current_address, words_remaining);
current_address = (current_address + increment) & ADDRESS_MASK; current_address = (current_address + increment) & ADDRESS_MASK;
@ -249,8 +248,7 @@ void DMA::RunDMA(Channel channel)
words_remaining--; words_remaining--;
u32 value = DMARead(channel, current_address, words_remaining); u32 value = DMARead(channel, current_address, words_remaining);
m_bus->DispatchAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(current_address, current_address, m_bus->DispatchAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(current_address, value);
value);
current_address = (current_address + increment) & ADDRESS_MASK; current_address = (current_address + increment) & ADDRESS_MASK;
} while (words_remaining > 0); } while (words_remaining > 0);
@ -269,8 +267,7 @@ void DMA::RunDMA(Channel channel)
for (;;) for (;;)
{ {
u32 header; u32 header;
m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(current_address, current_address, m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(current_address, header);
header);
const u32 word_count = header >> 24; const u32 word_count = header >> 24;
const u32 next_address = header & UINT32_C(0xFFFFFF); const u32 next_address = header & UINT32_C(0xFFFFFF);
@ -286,8 +283,7 @@ void DMA::RunDMA(Channel channel)
words_remaining--; words_remaining--;
u32 memory_value = 0; u32 memory_value = 0;
m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(current_address, current_address, m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(current_address, memory_value);
memory_value);
DMAWrite(channel, memory_value, current_address, words_remaining); DMAWrite(channel, memory_value, current_address, words_remaining);
current_address = (current_address + UINT32_C(4)) & ADDRESS_MASK; current_address = (current_address + UINT32_C(4)) & ADDRESS_MASK;
} while (words_remaining > 0); } while (words_remaining > 0);
@ -316,8 +312,7 @@ void DMA::RunDMA(Channel channel)
words_remaining--; words_remaining--;
u32 value = 0; u32 value = 0;
m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(current_address, current_address, m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(current_address, value);
value);
DMAWrite(channel, value, current_address, words_remaining); DMAWrite(channel, value, current_address, words_remaining);
current_address = (current_address + increment) & ADDRESS_MASK; current_address = (current_address + increment) & ADDRESS_MASK;
@ -331,8 +326,7 @@ void DMA::RunDMA(Channel channel)
words_remaining--; words_remaining--;
u32 value = DMARead(channel, current_address, words_remaining); u32 value = DMARead(channel, current_address, words_remaining);
m_bus->DispatchAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(current_address, current_address, m_bus->DispatchAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(current_address, value);
value);
current_address = (current_address + increment) & ADDRESS_MASK; current_address = (current_address + increment) & ADDRESS_MASK;
} while (words_remaining > 0); } while (words_remaining > 0);