2019-09-09 07:01:26 +00:00
|
|
|
#pragma once
|
|
|
|
#include "bus.h"
|
|
|
|
|
|
|
|
template<MemoryAccessType type, MemoryAccessSize size>
|
2019-10-04 10:23:47 +00:00
|
|
|
TickCount Bus::DoRAMAccess(u32 offset, u32& value)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
|
|
|
// TODO: Configurable mirroring.
|
|
|
|
offset &= UINT32_C(0x1FFFFF);
|
|
|
|
if constexpr (type == MemoryAccessType::Read)
|
|
|
|
{
|
|
|
|
if constexpr (size == MemoryAccessSize::Byte)
|
|
|
|
{
|
|
|
|
value = ZeroExtend32(m_ram[offset]);
|
|
|
|
}
|
|
|
|
else if constexpr (size == MemoryAccessSize::HalfWord)
|
|
|
|
{
|
|
|
|
u16 temp;
|
|
|
|
std::memcpy(&temp, &m_ram[offset], sizeof(u16));
|
|
|
|
value = ZeroExtend32(temp);
|
|
|
|
}
|
|
|
|
else if constexpr (size == MemoryAccessSize::Word)
|
|
|
|
{
|
|
|
|
std::memcpy(&value, &m_ram[offset], sizeof(u32));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-11-19 10:30:04 +00:00
|
|
|
const u32 page_index = offset / CPU_CODE_CACHE_PAGE_SIZE;
|
|
|
|
if (m_ram_code_bits[page_index])
|
|
|
|
DoInvalidateCodeCache(page_index);
|
|
|
|
|
2019-09-09 07:01:26 +00:00
|
|
|
if constexpr (size == MemoryAccessSize::Byte)
|
|
|
|
{
|
|
|
|
m_ram[offset] = Truncate8(value);
|
|
|
|
}
|
|
|
|
else if constexpr (size == MemoryAccessSize::HalfWord)
|
|
|
|
{
|
|
|
|
const u16 temp = Truncate16(value);
|
|
|
|
std::memcpy(&m_ram[offset], &temp, sizeof(u16));
|
|
|
|
}
|
|
|
|
else if constexpr (size == MemoryAccessSize::Word)
|
|
|
|
{
|
|
|
|
std::memcpy(&m_ram[offset], &value, sizeof(u32));
|
|
|
|
}
|
2019-11-16 15:47:46 +00:00
|
|
|
}
|
2019-11-17 12:11:16 +00:00
|
|
|
|
|
|
|
// Nocash docs say RAM takes 6 cycles to access.
|
2019-11-26 14:01:47 +00:00
|
|
|
return (type == MemoryAccessType::Read) ? RAM_READ_ACCESS_DELAY : RAM_WRITE_ACCESS_DELAY;
|
2019-09-09 07:01:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<MemoryAccessType type, MemoryAccessSize size>
|
2019-10-04 10:23:47 +00:00
|
|
|
TickCount Bus::DoBIOSAccess(u32 offset, u32& value)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
|
|
|
// TODO: Configurable mirroring.
|
|
|
|
if constexpr (type == MemoryAccessType::Read)
|
|
|
|
{
|
|
|
|
offset &= UINT32_C(0x7FFFF);
|
|
|
|
if constexpr (size == MemoryAccessSize::Byte)
|
|
|
|
{
|
|
|
|
value = ZeroExtend32(m_bios[offset]);
|
|
|
|
}
|
|
|
|
else if constexpr (size == MemoryAccessSize::HalfWord)
|
|
|
|
{
|
|
|
|
u16 temp;
|
|
|
|
std::memcpy(&temp, &m_bios[offset], sizeof(u16));
|
|
|
|
value = ZeroExtend32(temp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::memcpy(&value, &m_bios[offset], sizeof(u32));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Writes are ignored.
|
|
|
|
}
|
|
|
|
|
2019-10-04 10:23:47 +00:00
|
|
|
return m_bios_access_time[static_cast<u32>(size)];
|
2019-09-09 07:01:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<MemoryAccessType type, MemoryAccessSize size>
|
2019-10-04 10:23:47 +00:00
|
|
|
TickCount Bus::DispatchAccess(PhysicalMemoryAddress address, u32& value)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
2019-09-24 14:36:24 +00:00
|
|
|
if (address < 0x800000)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
2019-09-24 14:36:24 +00:00
|
|
|
return DoRAMAccess<type, size>(address, value);
|
2019-09-09 07:01:26 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < EXP1_BASE)
|
2019-09-22 15:28:00 +00:00
|
|
|
{
|
2019-09-24 14:36:24 +00:00
|
|
|
return DoInvalidAccess(type, size, address, value);
|
2019-09-22 15:28:00 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < (EXP1_BASE + EXP1_SIZE))
|
2019-09-22 15:28:00 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
if constexpr (type == MemoryAccessType::Read)
|
2019-11-26 14:01:47 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
value = DoReadEXP1(size, address & EXP1_MASK);
|
2019-11-26 14:01:47 +00:00
|
|
|
return m_exp1_access_time[static_cast<u32>(size)];
|
|
|
|
}
|
2019-10-04 10:23:47 +00:00
|
|
|
else
|
2019-11-26 14:01:47 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
DoWriteEXP1(size, address & EXP1_MASK, value);
|
2019-11-26 14:01:47 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2019-09-22 15:28:00 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < MEMCTRL_BASE)
|
2019-09-20 06:47:41 +00:00
|
|
|
{
|
2019-09-24 14:36:24 +00:00
|
|
|
return DoInvalidAccess(type, size, address, value);
|
2019-09-20 06:47:41 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < (MEMCTRL_BASE + MEMCTRL_SIZE))
|
2019-09-20 06:47:41 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
if constexpr (type == MemoryAccessType::Read)
|
|
|
|
value = DoReadMemoryControl(size, address & PAD_MASK);
|
|
|
|
else
|
|
|
|
DoWriteMemoryControl(size, address & PAD_MASK, value);
|
|
|
|
|
2019-11-26 14:01:47 +00:00
|
|
|
return 0;
|
2019-09-20 06:47:41 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < (PAD_BASE + PAD_SIZE))
|
2019-09-22 15:28:00 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
if constexpr (type == MemoryAccessType::Read)
|
|
|
|
value = DoReadPad(size, address & PAD_MASK);
|
|
|
|
else
|
|
|
|
DoWritePad(size, address & PAD_MASK, value);
|
2019-11-17 12:11:16 +00:00
|
|
|
|
2019-11-26 14:01:47 +00:00
|
|
|
return 0;
|
2019-09-22 15:28:00 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < (SIO_BASE + SIO_SIZE))
|
2019-09-17 06:26:00 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
if constexpr (type == MemoryAccessType::Read)
|
|
|
|
value = DoReadSIO(size, address & SIO_MASK);
|
|
|
|
else
|
|
|
|
DoWriteSIO(size, address & SIO_MASK, value);
|
2019-11-17 12:11:16 +00:00
|
|
|
|
2019-11-26 14:01:47 +00:00
|
|
|
return 0;
|
2019-09-17 06:26:00 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < (MEMCTRL2_BASE + MEMCTRL2_SIZE))
|
2019-09-17 06:26:00 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
if constexpr (type == MemoryAccessType::Read)
|
|
|
|
value = DoReadMemoryControl2(size, address & PAD_MASK);
|
|
|
|
else
|
|
|
|
DoWriteMemoryControl2(size, address & PAD_MASK, value);
|
|
|
|
|
2019-11-26 14:01:47 +00:00
|
|
|
return 0;
|
2019-09-20 13:40:19 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < (INTERRUPT_CONTROLLER_BASE + INTERRUPT_CONTROLLER_SIZE))
|
2019-09-20 13:40:19 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
if constexpr (type == MemoryAccessType::Read)
|
|
|
|
value = DoReadInterruptController(size, address & INTERRUPT_CONTROLLER_MASK);
|
|
|
|
else
|
|
|
|
DoWriteInterruptController(size, address & INTERRUPT_CONTROLLER_MASK, value);
|
2019-11-17 12:11:16 +00:00
|
|
|
|
2019-11-26 14:01:47 +00:00
|
|
|
return 0;
|
2019-09-20 13:40:19 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < (DMA_BASE + DMA_SIZE))
|
2019-09-17 09:22:39 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
if constexpr (type == MemoryAccessType::Read)
|
|
|
|
value = DoReadDMA(size, address & DMA_MASK);
|
|
|
|
else
|
|
|
|
DoWriteDMA(size, address & DMA_MASK, value);
|
2019-11-17 12:11:16 +00:00
|
|
|
|
2019-11-26 14:01:47 +00:00
|
|
|
return 0;
|
2019-09-17 09:22:39 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < (TIMERS_BASE + TIMERS_SIZE))
|
2019-09-17 09:22:39 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
if constexpr (type == MemoryAccessType::Read)
|
|
|
|
value = DoReadTimers(size, address & TIMERS_MASK);
|
|
|
|
else
|
|
|
|
DoWriteTimers(size, address & TIMERS_MASK, value);
|
2019-11-17 12:11:16 +00:00
|
|
|
|
2019-11-26 14:01:47 +00:00
|
|
|
return 0;
|
2019-09-17 09:22:39 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < CDROM_BASE)
|
2019-09-11 04:01:19 +00:00
|
|
|
{
|
2019-09-24 14:36:24 +00:00
|
|
|
return DoInvalidAccess(type, size, address, value);
|
2019-09-11 04:01:19 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < (CDROM_BASE + GPU_SIZE))
|
2019-09-11 04:01:19 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
if constexpr (type == MemoryAccessType::Read)
|
2019-11-26 14:01:47 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
value = DoReadCDROM(size, address & CDROM_MASK);
|
2019-11-26 14:01:47 +00:00
|
|
|
return m_cdrom_access_time[static_cast<u32>(size)];
|
|
|
|
}
|
2019-10-04 10:23:47 +00:00
|
|
|
else
|
2019-11-26 14:01:47 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
DoWriteCDROM(size, address & CDROM_MASK, value);
|
2019-11-26 14:01:47 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2019-09-11 04:01:19 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < (GPU_BASE + GPU_SIZE))
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
if constexpr (type == MemoryAccessType::Read)
|
|
|
|
value = DoReadGPU(size, address & GPU_MASK);
|
|
|
|
else
|
|
|
|
DoWriteGPU(size, address & GPU_MASK, value);
|
2019-11-17 12:11:16 +00:00
|
|
|
|
2019-11-26 14:01:47 +00:00
|
|
|
return 0;
|
2019-09-09 07:01:26 +00:00
|
|
|
}
|
2019-09-29 02:51:34 +00:00
|
|
|
else if (address < (MDEC_BASE + MDEC_SIZE))
|
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
if constexpr (type == MemoryAccessType::Read)
|
|
|
|
value = DoReadMDEC(size, address & MDEC_MASK);
|
|
|
|
else
|
|
|
|
DoWriteMDEC(size, address & MDEC_MASK, value);
|
2019-11-17 12:11:16 +00:00
|
|
|
|
2019-11-26 14:01:47 +00:00
|
|
|
return 0;
|
2019-09-29 02:51:34 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < SPU_BASE)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
2019-09-24 14:36:24 +00:00
|
|
|
return DoInvalidAccess(type, size, address, value);
|
2019-09-09 07:01:26 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < (SPU_BASE + SPU_SIZE))
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
if constexpr (type == MemoryAccessType::Read)
|
2019-11-26 14:01:47 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
value = DoReadSPU(size, address & SPU_MASK);
|
2019-11-26 14:01:47 +00:00
|
|
|
return m_spu_access_time[static_cast<u32>(size)];
|
|
|
|
}
|
2019-10-04 10:23:47 +00:00
|
|
|
else
|
2019-11-26 14:01:47 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
DoWriteSPU(size, address & SPU_MASK, value);
|
2019-11-26 14:01:47 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2019-09-09 07:01:26 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < EXP2_BASE)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
2019-09-24 14:36:24 +00:00
|
|
|
return DoInvalidAccess(type, size, address, value);
|
2019-09-09 07:01:26 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < (EXP2_BASE + EXP2_SIZE))
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
if constexpr (type == MemoryAccessType::Read)
|
2019-11-26 14:01:47 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
value = DoReadEXP2(size, address & EXP2_MASK);
|
2019-11-26 14:01:47 +00:00
|
|
|
return m_exp2_access_time[static_cast<u32>(size)];
|
|
|
|
}
|
2019-10-04 10:23:47 +00:00
|
|
|
else
|
2019-11-26 14:01:47 +00:00
|
|
|
{
|
2019-10-04 10:23:47 +00:00
|
|
|
DoWriteEXP2(size, address & EXP2_MASK, value);
|
2019-11-26 14:01:47 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2019-09-09 07:01:26 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < BIOS_BASE)
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
2019-09-24 14:36:24 +00:00
|
|
|
return DoInvalidAccess(type, size, address, value);
|
2019-09-09 07:01:26 +00:00
|
|
|
}
|
2019-09-24 14:36:24 +00:00
|
|
|
else if (address < (BIOS_BASE + BIOS_SIZE))
|
2019-09-09 07:01:26 +00:00
|
|
|
{
|
2019-09-24 14:36:24 +00:00
|
|
|
return DoBIOSAccess<type, size>(static_cast<u32>(address - BIOS_BASE), value);
|
2019-09-09 07:01:26 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-09-24 14:36:24 +00:00
|
|
|
return DoInvalidAccess(type, size, address, value);
|
2019-09-09 07:01:26 +00:00
|
|
|
}
|
|
|
|
}
|