Clean up memory access handlers, reduce template specializations
This commit is contained in:
parent
4aca52cdf4
commit
9359d0778e
|
@ -47,53 +47,65 @@ bool Bus::Initialize(CPU::Core* cpu, DMA* dma, InterruptController* interrupt_co
|
|||
void Bus::Reset()
|
||||
{
|
||||
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)
|
||||
{
|
||||
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));
|
||||
sw.Do(&m_ram_size_reg);
|
||||
sw.Do(&m_tty_line_buffer);
|
||||
return !sw.HasError();
|
||||
}
|
||||
|
||||
bool Bus::ReadByte(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u8* value)
|
||||
bool Bus::ReadByte(PhysicalMemoryAddress address, u8* value)
|
||||
{
|
||||
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);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Bus::ReadHalfWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u16* value)
|
||||
bool Bus::ReadHalfWord(PhysicalMemoryAddress address, u16* value)
|
||||
{
|
||||
u32 temp = 0;
|
||||
const bool result =
|
||||
DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(cpu_address, bus_address, temp);
|
||||
DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::HalfWord>(address, temp);
|
||||
*value = Truncate16(temp);
|
||||
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);
|
||||
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);
|
||||
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)*/)
|
||||
|
@ -154,8 +166,7 @@ bool Bus::LoadBIOS()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Bus::DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress cpu_address,
|
||||
PhysicalMemoryAddress bus_address, u32& value)
|
||||
bool Bus::DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address, u32& value)
|
||||
{
|
||||
SmallString str;
|
||||
str.AppendString("Invalid bus ");
|
||||
|
@ -171,7 +182,7 @@ bool Bus::DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, Physical
|
|||
else
|
||||
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)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -221,7 +232,7 @@ bool Bus::DoReadEXP1(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)
|
||||
|
@ -235,7 +246,7 @@ bool Bus::DoReadEXP2(MemoryAccessSize size, u32 offset, u32& value)
|
|||
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)
|
||||
|
@ -267,7 +278,43 @@ bool Bus::DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value)
|
|||
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)
|
||||
|
|
122
src/pse/bus.h
122
src/pse/bus.h
|
@ -30,52 +30,84 @@ public:
|
|||
void Reset();
|
||||
bool DoState(StateWrapper& sw);
|
||||
|
||||
bool ReadByte(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u8* value);
|
||||
bool ReadHalfWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u16* value);
|
||||
bool ReadWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32* value);
|
||||
bool WriteByte(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u8 value);
|
||||
bool WriteHalfWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u16 value);
|
||||
bool WriteWord(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32 value);
|
||||
bool ReadByte(PhysicalMemoryAddress address, u8* value);
|
||||
bool ReadHalfWord(PhysicalMemoryAddress address, u16* value);
|
||||
bool ReadWord(PhysicalMemoryAddress address, u32* value);
|
||||
bool WriteByte(PhysicalMemoryAddress address, u8 value);
|
||||
bool WriteHalfWord(PhysicalMemoryAddress address, u16 value);
|
||||
bool WriteWord(PhysicalMemoryAddress address, u32 value);
|
||||
|
||||
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 SetExpansionROM(std::vector<u8> data);
|
||||
|
||||
private:
|
||||
static constexpr u32 EXP1_BASE = 0x1F000000;
|
||||
static constexpr u32 EXP1_SIZE = 0x800000;
|
||||
static constexpr u32 EXP1_MASK = EXP1_SIZE - 1;
|
||||
static constexpr u32 PAD_BASE = 0x1F801040;
|
||||
static constexpr u32 PAD_SIZE = 0x10;
|
||||
static constexpr u32 PAD_MASK = PAD_SIZE - 1;
|
||||
static constexpr u32 SIO_BASE = 0x1F801050;
|
||||
static constexpr u32 SIO_SIZE = 0x10;
|
||||
static constexpr u32 SIO_MASK = SIO_SIZE - 1;
|
||||
static constexpr u32 INTERRUPT_CONTROLLER_BASE = 0x1F801070;
|
||||
static constexpr u32 INTERRUPT_CONTROLLER_SIZE = 0x08;
|
||||
static constexpr u32 INTERRUPT_CONTROLLER_MASK = INTERRUPT_CONTROLLER_SIZE - 1;
|
||||
static constexpr u32 DMA_BASE = 0x1F801080;
|
||||
static constexpr u32 DMA_SIZE = 0x80;
|
||||
static constexpr u32 DMA_MASK = DMA_SIZE - 1;
|
||||
static constexpr u32 TIMERS_BASE = 0x1F801100;
|
||||
static constexpr u32 TIMERS_SIZE = 0x40;
|
||||
static constexpr u32 TIMERS_MASK = TIMERS_SIZE - 1;
|
||||
static constexpr u32 CDROM_BASE = 0x1F801800;
|
||||
static constexpr u32 CDROM_SIZE = 0x04;
|
||||
static constexpr u32 CDROM_MASK = CDROM_SIZE - 1;
|
||||
static constexpr u32 GPU_BASE = 0x1F801810;
|
||||
static constexpr u32 GPU_SIZE = 0x10;
|
||||
static constexpr u32 GPU_MASK = GPU_SIZE - 1;
|
||||
static constexpr u32 SPU_BASE = 0x1F801C00;
|
||||
static constexpr u32 SPU_SIZE = 0x300;
|
||||
static constexpr u32 SPU_MASK = 0x3FF;
|
||||
static constexpr u32 EXP2_BASE = 0x1F802000;
|
||||
static constexpr u32 EXP2_SIZE = 0x2000;
|
||||
static constexpr u32 EXP2_MASK = EXP2_SIZE - 1;
|
||||
static constexpr u32 BIOS_BASE = 0x1FC00000;
|
||||
static constexpr u32 BIOS_SIZE = 0x80000;
|
||||
enum : u32
|
||||
{
|
||||
EXP1_BASE = 0x1F000000,
|
||||
EXP1_SIZE = 0x800000,
|
||||
EXP1_MASK = EXP1_SIZE - 1,
|
||||
MEMCTRL_BASE = 0x1F801000,
|
||||
MEMCTRL_SIZE = 0x40,
|
||||
MEMCTRL_MASK = MEMCTRL_SIZE - 1,
|
||||
PAD_BASE = 0x1F801040,
|
||||
PAD_SIZE = 0x10,
|
||||
PAD_MASK = PAD_SIZE - 1,
|
||||
SIO_BASE = 0x1F801050,
|
||||
SIO_SIZE = 0x10,
|
||||
SIO_MASK = SIO_SIZE - 1,
|
||||
MEMCTRL2_BASE = 0x1F801060,
|
||||
MEMCTRL2_SIZE = 0x10,
|
||||
MEMCTRL2_MASK = MEMCTRL_SIZE - 1,
|
||||
INTERRUPT_CONTROLLER_BASE = 0x1F801070,
|
||||
INTERRUPT_CONTROLLER_SIZE = 0x10,
|
||||
INTERRUPT_CONTROLLER_MASK = INTERRUPT_CONTROLLER_SIZE - 1,
|
||||
DMA_BASE = 0x1F801080,
|
||||
DMA_SIZE = 0x80,
|
||||
DMA_MASK = DMA_SIZE - 1,
|
||||
TIMERS_BASE = 0x1F801100,
|
||||
TIMERS_SIZE = 0x40,
|
||||
TIMERS_MASK = TIMERS_SIZE - 1,
|
||||
CDROM_BASE = 0x1F801800,
|
||||
CDROM_SIZE = 0x04,
|
||||
CDROM_MASK = CDROM_SIZE - 1,
|
||||
GPU_BASE = 0x1F801810,
|
||||
GPU_SIZE = 0x10,
|
||||
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();
|
||||
|
||||
|
@ -85,8 +117,7 @@ private:
|
|||
template<MemoryAccessType type, MemoryAccessSize size>
|
||||
bool DoBIOSAccess(u32 offset, u32& value);
|
||||
|
||||
bool DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress cpu_address,
|
||||
PhysicalMemoryAddress bus_address, u32& value);
|
||||
bool 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);
|
||||
|
@ -94,6 +125,12 @@ private:
|
|||
bool DoReadEXP2(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 DoWritePad(MemoryAccessSize size, u32 offset, u32 value);
|
||||
|
||||
|
@ -131,6 +168,9 @@ private:
|
|||
std::array<u8, 524288> m_bios{}; // 512K BIOS ROM
|
||||
std::vector<u8> m_exp1_rom;
|
||||
|
||||
MEMCTRL m_MEMCTRL = {};
|
||||
u32 m_ram_size_reg = 0;
|
||||
|
||||
String m_tty_line_buffer;
|
||||
};
|
||||
|
||||
|
|
126
src/pse/bus.inl
126
src/pse/bus.inl
|
@ -74,117 +74,107 @@ bool Bus::DoBIOSAccess(u32 offset, u32& value)
|
|||
}
|
||||
|
||||
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) :
|
||||
DoWriteEXP1(size, bus_address & EXP1_MASK, value);
|
||||
return (type == MemoryAccessType::Read) ? DoReadEXP1(size, 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) :
|
||||
DoWritePad(size, bus_address & PAD_MASK, value);
|
||||
return (type == MemoryAccessType::Read) ? DoReadMemoryControl(size, 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) :
|
||||
DoWriteSIO(size, bus_address & SIO_MASK, value);
|
||||
return (type == MemoryAccessType::Read) ? DoReadPad(size, address & PAD_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) ?
|
||||
DoReadInterruptController(size, bus_address & INTERRUPT_CONTROLLER_MASK, value) :
|
||||
DoWriteInterruptController(size, bus_address & INTERRUPT_CONTROLLER_MASK, value);
|
||||
DoReadInterruptController(size, 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) :
|
||||
DoWriteDMA(size, bus_address & DMA_MASK, value);
|
||||
return (type == MemoryAccessType::Read) ? DoReadTimers(size, address & TIMERS_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) :
|
||||
DoWriteTimers(size, bus_address & TIMERS_MASK, value);
|
||||
return (type == MemoryAccessType::Read) ? DoReadCDROM(size, address & CDROM_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) :
|
||||
DoWriteCDROM(size, bus_address & CDROM_MASK, value);
|
||||
return (type == MemoryAccessType::Read) ? DoReadGPU(size, address & GPU_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) :
|
||||
DoWriteGPU(size, bus_address & GPU_MASK, value);
|
||||
return (type == MemoryAccessType::Read) ? DoReadSPU(size, address & SPU_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) :
|
||||
DoWriteSPU(size, bus_address & SPU_MASK, value);
|
||||
return (type == MemoryAccessType::Read) ? DoReadEXP2(size, address & EXP2_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) :
|
||||
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);
|
||||
return DoBIOSAccess<type, size>(static_cast<u32>(address - BIOS_BASE), value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return DoInvalidAccess(type, size, cpu_address, bus_address, value);
|
||||
return DoInvalidAccess(type, size, address, value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,8 +92,11 @@ void Core::SetPC(u32 new_pc)
|
|||
bool Core::ReadMemoryByte(VirtualMemoryAddress addr, u8* value)
|
||||
{
|
||||
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);
|
||||
if (!result)
|
||||
RaiseException(Exception::DBE);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -103,8 +106,11 @@ bool Core::ReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value)
|
|||
return false;
|
||||
|
||||
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);
|
||||
if (!result)
|
||||
RaiseException(Exception::DBE);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -113,13 +119,21 @@ bool Core::ReadMemoryWord(VirtualMemoryAddress addr, u32* value)
|
|||
if (!DoAlignmentCheck<MemoryAccessType::Read, MemoryAccessSize::Word>(addr))
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
@ -128,7 +142,11 @@ bool Core::WriteMemoryHalfWord(VirtualMemoryAddress addr, u16 value)
|
|||
return false;
|
||||
|
||||
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)
|
||||
|
@ -136,13 +154,17 @@ bool Core::WriteMemoryWord(VirtualMemoryAddress addr, u32 value)
|
|||
if (!DoAlignmentCheck<MemoryAccessType::Write, MemoryAccessSize::Word>(addr))
|
||||
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)
|
||||
{
|
||||
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);
|
||||
return result;
|
||||
}
|
||||
|
@ -150,31 +172,31 @@ bool Core::SafeReadMemoryByte(VirtualMemoryAddress addr, u8* value)
|
|||
bool Core::SafeReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value)
|
||||
{
|
||||
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);
|
||||
return result;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Word, false, false>(addr, value);
|
||||
return DoMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(addr, value);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
u32 bits;
|
||||
DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word, true, false>(addr, bits);
|
||||
u32 bits = 0;
|
||||
DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(addr, bits);
|
||||
PrintInstruction(bits, addr);
|
||||
}
|
||||
|
||||
|
@ -459,14 +481,17 @@ bool Core::FetchInstruction()
|
|||
{
|
||||
m_regs.pc = m_regs.npc;
|
||||
|
||||
if (!DoAlignmentCheck<MemoryAccessType::Read, MemoryAccessSize::Word>(
|
||||
static_cast<VirtualMemoryAddress>(m_regs.npc)) ||
|
||||
!DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word, true, true>(
|
||||
static_cast<VirtualMemoryAddress>(m_regs.npc), m_next_instruction.bits))
|
||||
if (!DoAlignmentCheck<MemoryAccessType::Read, MemoryAccessSize::Word>(static_cast<VirtualMemoryAddress>(m_regs.npc)))
|
||||
{
|
||||
// this will call FetchInstruction() again when the pipeline is flushed.
|
||||
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);
|
||||
return true;
|
||||
|
|
|
@ -41,6 +41,7 @@ public:
|
|||
// Sets the PC and flushes the pipeline.
|
||||
void SetPC(u32 new_pc);
|
||||
|
||||
// Memory reads variants which do not raise exceptions.
|
||||
bool SafeReadMemoryByte(VirtualMemoryAddress addr, u8* value);
|
||||
bool SafeReadMemoryHalfWord(VirtualMemoryAddress addr, u16* value);
|
||||
bool SafeReadMemoryWord(VirtualMemoryAddress addr, u32* value);
|
||||
|
@ -53,7 +54,7 @@ public:
|
|||
void ClearExternalInterrupt(u8 bit);
|
||||
|
||||
private:
|
||||
template<MemoryAccessType type, MemoryAccessSize size, bool is_instruction_fetch, bool raise_exceptions>
|
||||
template<MemoryAccessType type, MemoryAccessSize size>
|
||||
bool DoMemoryAccess(VirtualMemoryAddress address, u32& value);
|
||||
|
||||
template<MemoryAccessType type, MemoryAccessSize size>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
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)
|
||||
{
|
||||
switch (address >> 29)
|
||||
|
@ -25,7 +25,7 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!m_bus->DispatchAccess<type, size>(address, phys_addr, value))
|
||||
if (!m_bus->DispatchAccess<type, size>(phys_addr, value))
|
||||
{
|
||||
Panic("Bus error");
|
||||
return false;
|
||||
|
@ -39,7 +39,6 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
|
|||
case 0x03: // KUSEG 1536M-2048M
|
||||
{
|
||||
// Above 512mb raises an exception.
|
||||
RaiseException(is_instruction_fetch ? Exception::IBE : Exception::DBE);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -58,7 +57,7 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
|
|||
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");
|
||||
return false;
|
||||
|
@ -71,7 +70,7 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
|
|||
case 0x05: // KSEG1 - physical memory uncached
|
||||
{
|
||||
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");
|
||||
return false;
|
||||
|
@ -95,7 +94,6 @@ bool Core::DoMemoryAccess(VirtualMemoryAddress address, u32& value)
|
|||
}
|
||||
else
|
||||
{
|
||||
RaiseException(is_instruction_fetch ? Exception::IBE : Exception::DBE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -234,8 +234,7 @@ void DMA::RunDMA(Channel channel)
|
|||
words_remaining--;
|
||||
|
||||
u32 value = 0;
|
||||
m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(current_address, current_address,
|
||||
value);
|
||||
m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(current_address, value);
|
||||
DMAWrite(channel, value, current_address, words_remaining);
|
||||
|
||||
current_address = (current_address + increment) & ADDRESS_MASK;
|
||||
|
@ -249,8 +248,7 @@ void DMA::RunDMA(Channel channel)
|
|||
words_remaining--;
|
||||
|
||||
u32 value = DMARead(channel, current_address, words_remaining);
|
||||
m_bus->DispatchAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(current_address, current_address,
|
||||
value);
|
||||
m_bus->DispatchAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(current_address, value);
|
||||
|
||||
current_address = (current_address + increment) & ADDRESS_MASK;
|
||||
} while (words_remaining > 0);
|
||||
|
@ -269,8 +267,7 @@ void DMA::RunDMA(Channel channel)
|
|||
for (;;)
|
||||
{
|
||||
u32 header;
|
||||
m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(current_address, current_address,
|
||||
header);
|
||||
m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(current_address, header);
|
||||
|
||||
const u32 word_count = header >> 24;
|
||||
const u32 next_address = header & UINT32_C(0xFFFFFF);
|
||||
|
@ -286,8 +283,7 @@ void DMA::RunDMA(Channel channel)
|
|||
words_remaining--;
|
||||
|
||||
u32 memory_value = 0;
|
||||
m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(current_address, current_address,
|
||||
memory_value);
|
||||
m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(current_address, memory_value);
|
||||
DMAWrite(channel, memory_value, current_address, words_remaining);
|
||||
current_address = (current_address + UINT32_C(4)) & ADDRESS_MASK;
|
||||
} while (words_remaining > 0);
|
||||
|
@ -316,8 +312,7 @@ void DMA::RunDMA(Channel channel)
|
|||
words_remaining--;
|
||||
|
||||
u32 value = 0;
|
||||
m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(current_address, current_address,
|
||||
value);
|
||||
m_bus->DispatchAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(current_address, value);
|
||||
DMAWrite(channel, value, current_address, words_remaining);
|
||||
|
||||
current_address = (current_address + increment) & ADDRESS_MASK;
|
||||
|
@ -331,8 +326,7 @@ void DMA::RunDMA(Channel channel)
|
|||
words_remaining--;
|
||||
|
||||
u32 value = DMARead(channel, current_address, words_remaining);
|
||||
m_bus->DispatchAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(current_address, current_address,
|
||||
value);
|
||||
m_bus->DispatchAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(current_address, value);
|
||||
|
||||
current_address = (current_address + increment) & ADDRESS_MASK;
|
||||
} while (words_remaining > 0);
|
||||
|
|
Loading…
Reference in New Issue