diff --git a/Source/Core/Core/HW/EXI.cpp b/Source/Core/Core/HW/EXI.cpp index 4e9c9057ef..850d4812e6 100644 --- a/Source/Core/Core/HW/EXI.cpp +++ b/Source/Core/Core/HW/EXI.cpp @@ -9,6 +9,7 @@ #include "ProcessorInterface.h" #include "../PowerPC/PowerPC.h" +#include "MMIO.h" #include "EXI.h" #include "Sram.h" @@ -62,6 +63,19 @@ void PauseAndLock(bool doLock, bool unpauseOnUnlock) channel->PauseAndLock(doLock, unpauseOnUnlock); } +void RegisterMMIO(MMIO::Mapping* mmio, u32 base) +{ + for (int i = 0; i < MAX_EXI_CHANNELS; ++i) + { + _dbg_assert_(EXPANSIONINTERFACE, g_Channels[i] != nullptr); + // Each channel has 5 32 bit registers assigned to it. We offset the + // base that we give to each channel for registration. + // + // Be careful: this means the base is no longer aligned on a page + // boundary and using "base | FOO" is not valid! + g_Channels[i]->RegisterMMIO(mmio, base + 5 * 4 * i); + } +} void ChangeDeviceCallback(u64 userdata, int cyclesLate) { @@ -101,34 +115,14 @@ void Update() void Read32(u32& _uReturnValue, const u32 _iAddress) { - // TODO 0xfff00000 is mapped to EXI -> mapped to first MB of maskrom - u32 iAddr = _iAddress & 0x3FF; - u32 iRegister = (iAddr >> 2) % 5; - u32 iChannel = (iAddr >> 2) / 5; - - _dbg_assert_(EXPANSIONINTERFACE, iChannel < MAX_EXI_CHANNELS); - - if (iChannel < MAX_EXI_CHANNELS) - { - g_Channels[iChannel]->Read32(_uReturnValue, iRegister); - } - else - { - _uReturnValue = 0; - } + // HACK: Remove this function when the new MMIO interface is used. + Memory::mmio_mapping->Read(_iAddress, _uReturnValue); } void Write32(const u32 _iValue, const u32 _iAddress) { - // TODO 0xfff00000 is mapped to EXI -> mapped to first MB of maskrom - u32 iAddr = _iAddress & 0x3FF; - u32 iRegister = (iAddr >> 2) % 5; - u32 iChannel = (iAddr >> 2) / 5; - - _dbg_assert_(EXPANSIONINTERFACE, iChannel < MAX_EXI_CHANNELS); - - if (iChannel < MAX_EXI_CHANNELS) - g_Channels[iChannel]->Write32(_iValue, iRegister); + // HACK: Remove this function when the new MMIO interface is used. + Memory::mmio_mapping->Write(_iAddress, _iValue); } void UpdateInterrupts() diff --git a/Source/Core/Core/HW/EXI.h b/Source/Core/Core/HW/EXI.h index b60dbda105..21c33ad16a 100644 --- a/Source/Core/Core/HW/EXI.h +++ b/Source/Core/Core/HW/EXI.h @@ -8,6 +8,7 @@ #include "EXI_Channel.h" #include "Thread.h" class PointerWrap; +namespace MMIO { class Mapping; } enum { @@ -22,6 +23,8 @@ void Shutdown(); void DoState(PointerWrap &p); void PauseAndLock(bool doLock, bool unpauseOnUnlock); +void RegisterMMIO(MMIO::Mapping* mmio, u32 base); + void Update(); void UpdateInterrupts(); diff --git a/Source/Core/Core/HW/EXI_Channel.cpp b/Source/Core/Core/HW/EXI_Channel.cpp index a57b06914c..52fd79fa3c 100644 --- a/Source/Core/Core/HW/EXI_Channel.cpp +++ b/Source/Core/Core/HW/EXI_Channel.cpp @@ -7,6 +7,7 @@ #include "EXI.h" #include "../ConfigManager.h" #include "../Movie.h" +#include "MMIO.h" #define EXI_READ 0 #define EXI_WRITE 1 @@ -41,6 +42,117 @@ CEXIChannel::~CEXIChannel() RemoveDevices(); } +void CEXIChannel::RegisterMMIO(MMIO::Mapping* mmio, u32 base) +{ + // Warning: the base is not aligned on a page boundary here. We can't use | + // to select a register address, instead we need to use +. + + mmio->Register(base + EXI_STATUS, + MMIO::ComplexRead([this](u32) { + // check if external device is present + // pretty sure it is memcard only, not entirely sure + if (m_ChannelId == 2) + { + m_Status.EXT = 0; + } + else + { + m_Status.EXT = GetDevice(1)->IsPresent() ? 1 : 0; + } + + return m_Status.Hex; + }), + MMIO::ComplexWrite([this](u32, u32 val) { + UEXI_STATUS newStatus(val); + + m_Status.EXIINTMASK = newStatus.EXIINTMASK; + if (newStatus.EXIINT) + m_Status.EXIINT = 0; + + m_Status.TCINTMASK = newStatus.TCINTMASK; + if (newStatus.TCINT) + m_Status.TCINT = 0; + + m_Status.CLK = newStatus.CLK; + + if (m_ChannelId == 0 || m_ChannelId == 1) + { + m_Status.EXTINTMASK = newStatus.EXTINTMASK; + + if (newStatus.EXTINT) + m_Status.EXTINT = 0; + } + + if (m_ChannelId == 0) + m_Status.ROMDIS = newStatus.ROMDIS; + + IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT ^ newStatus.CHIP_SELECT); + m_Status.CHIP_SELECT = newStatus.CHIP_SELECT; + if (pDevice != NULL) + pDevice->SetCS(m_Status.CHIP_SELECT); + + CoreTiming::ScheduleEvent_Threadsafe_Immediate(updateInterrupts, 0); + }) + ); + + mmio->Register(base + EXI_DMAADDR, + MMIO::DirectRead(&m_DMAMemoryAddress), + MMIO::DirectWrite(&m_DMAMemoryAddress) + ); + mmio->Register(base + EXI_DMALENGTH, + MMIO::DirectRead(&m_DMALength), + MMIO::DirectWrite(&m_DMALength) + ); + mmio->Register(base + EXI_DMACONTROL, + MMIO::DirectRead(&m_Control.Hex), + MMIO::ComplexWrite([this](u32, u32 val) { + m_Control.Hex = val; + + if (m_Control.TSTART) + { + IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT); + if (pDevice == NULL) + return; + + if (m_Control.DMA == 0) + { + // immediate data + switch (m_Control.RW) + { + case EXI_READ: m_ImmData = pDevice->ImmRead(m_Control.TLEN + 1); break; + case EXI_WRITE: pDevice->ImmWrite(m_ImmData, m_Control.TLEN + 1); break; + case EXI_READWRITE: pDevice->ImmReadWrite(m_ImmData, m_Control.TLEN + 1); break; + default: _dbg_assert_msg_(EXPANSIONINTERFACE,0,"EXI Imm: Unknown transfer type %i", m_Control.RW); + } + m_Control.TSTART = 0; + } + else + { + // DMA + switch (m_Control.RW) + { + case EXI_READ: pDevice->DMARead (m_DMAMemoryAddress, m_DMALength); break; + case EXI_WRITE: pDevice->DMAWrite(m_DMAMemoryAddress, m_DMALength); break; + default: _dbg_assert_msg_(EXPANSIONINTERFACE,0,"EXI DMA: Unknown transfer type %i", m_Control.RW); + } + m_Control.TSTART = 0; + } + + if(!m_Control.TSTART) // completed ! + { + m_Status.TCINT = 1; + CoreTiming::ScheduleEvent_Threadsafe_Immediate(updateInterrupts, 0); + } + } + }) + ); + + mmio->Register(base + EXI_IMMDATA, + MMIO::DirectRead(&m_ImmData), + MMIO::DirectWrite(&m_ImmData) + ); +} + void CEXIChannel::RemoveDevices() { for (auto& device : m_pDevices) @@ -115,152 +227,6 @@ void CEXIChannel::Update() device->Update(); } -void CEXIChannel::Read32(u32& _uReturnValue, const u32 _iRegister) -{ - switch (_iRegister) - { - case EXI_STATUS: - { - // check if external device is present - // pretty sure it is memcard only, not entirely sure - if (m_ChannelId == 2) - { - m_Status.EXT = 0; - } - else - { - m_Status.EXT = GetDevice(1)->IsPresent() ? 1 : 0; - } - - _uReturnValue = m_Status.Hex; - break; - } - - case EXI_DMAADDR: - _uReturnValue = m_DMAMemoryAddress; - break; - - case EXI_DMALENGTH: - _uReturnValue = m_DMALength; - break; - - case EXI_DMACONTROL: - _uReturnValue = m_Control.Hex; - break; - - case EXI_IMMDATA: - _uReturnValue = m_ImmData; - break; - - default: - _dbg_assert_(EXPANSIONINTERFACE, 0); - _uReturnValue = 0xDEADBEEF; - } - - DEBUG_LOG(EXPANSIONINTERFACE, "(r32) 0x%08x channel: %i register: %s", - _uReturnValue, m_ChannelId, Debug_GetRegisterName(_iRegister)); -} - -void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister) -{ - DEBUG_LOG(EXPANSIONINTERFACE, "(w32) 0x%08x channel: %i register: %s", - _iValue, m_ChannelId, Debug_GetRegisterName(_iRegister)); - - switch (_iRegister) - { - case EXI_STATUS: - { - UEXI_STATUS newStatus(_iValue); - - m_Status.EXIINTMASK = newStatus.EXIINTMASK; - if (newStatus.EXIINT) - m_Status.EXIINT = 0; - - m_Status.TCINTMASK = newStatus.TCINTMASK; - if (newStatus.TCINT) - m_Status.TCINT = 0; - - m_Status.CLK = newStatus.CLK; - - if (m_ChannelId == 0 || m_ChannelId == 1) - { - m_Status.EXTINTMASK = newStatus.EXTINTMASK; - - if (newStatus.EXTINT) - m_Status.EXTINT = 0; - } - - if (m_ChannelId == 0) - m_Status.ROMDIS = newStatus.ROMDIS; - - IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT ^ newStatus.CHIP_SELECT); - m_Status.CHIP_SELECT = newStatus.CHIP_SELECT; - if (pDevice != NULL) - pDevice->SetCS(m_Status.CHIP_SELECT); - - CoreTiming::ScheduleEvent_Threadsafe_Immediate(updateInterrupts, 0); - } - break; - - case EXI_DMAADDR: - INFO_LOG(EXPANSIONINTERFACE, "Wrote DMAAddr, channel %i", m_ChannelId); - m_DMAMemoryAddress = _iValue; - break; - - case EXI_DMALENGTH: - INFO_LOG(EXPANSIONINTERFACE, "Wrote DMALength, channel %i", m_ChannelId); - m_DMALength = _iValue; - break; - - case EXI_DMACONTROL: - INFO_LOG(EXPANSIONINTERFACE, "Wrote DMAControl, channel %i", m_ChannelId); - m_Control.Hex = _iValue; - - if (m_Control.TSTART) - { - IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT); - if (pDevice == NULL) - return; - - if (m_Control.DMA == 0) - { - // immediate data - switch (m_Control.RW) - { - case EXI_READ: m_ImmData = pDevice->ImmRead(m_Control.TLEN + 1); break; - case EXI_WRITE: pDevice->ImmWrite(m_ImmData, m_Control.TLEN + 1); break; - case EXI_READWRITE: pDevice->ImmReadWrite(m_ImmData, m_Control.TLEN + 1); break; - default: _dbg_assert_msg_(EXPANSIONINTERFACE,0,"EXI Imm: Unknown transfer type %i", m_Control.RW); - } - m_Control.TSTART = 0; - } - else - { - // DMA - switch (m_Control.RW) - { - case EXI_READ: pDevice->DMARead (m_DMAMemoryAddress, m_DMALength); break; - case EXI_WRITE: pDevice->DMAWrite(m_DMAMemoryAddress, m_DMALength); break; - default: _dbg_assert_msg_(EXPANSIONINTERFACE,0,"EXI DMA: Unknown transfer type %i", m_Control.RW); - } - m_Control.TSTART = 0; - } - - if(!m_Control.TSTART) // completed ! - { - m_Status.TCINT = 1; - CoreTiming::ScheduleEvent_Threadsafe_Immediate(updateInterrupts, 0); - } - } - break; - - case EXI_IMMDATA: - INFO_LOG(EXPANSIONINTERFACE, "Wrote IMMData, channel %i", m_ChannelId); - m_ImmData = _iValue; - break; - } -} - void CEXIChannel::DoState(PointerWrap &p) { p.DoPOD(m_Status); diff --git a/Source/Core/Core/HW/EXI_Channel.h b/Source/Core/Core/HW/EXI_Channel.h index 582ea48513..aedc09c3ea 100644 --- a/Source/Core/Core/HW/EXI_Channel.h +++ b/Source/Core/Core/HW/EXI_Channel.h @@ -9,30 +9,20 @@ #include "EXI_Device.h" #include +namespace MMIO { class Mapping; } + class CEXIChannel { private: enum { - EXI_STATUS = 0, - EXI_DMAADDR = 1, - EXI_DMALENGTH = 2, - EXI_DMACONTROL = 3, - EXI_IMMDATA = 4 + EXI_STATUS = 0x00, + EXI_DMAADDR = 0x04, + EXI_DMALENGTH = 0x08, + EXI_DMACONTROL = 0x0C, + EXI_IMMDATA = 0x10 }; - const char* Debug_GetRegisterName(u32 _register) - { - switch (_register) - { - case EXI_STATUS: return "STATUS"; - case EXI_DMAADDR: return "DMAADDR"; - case EXI_DMALENGTH: return "DMALENGTH"; - case EXI_DMACONTROL: return "DMACONTROL"; - case EXI_IMMDATA: return "IMMDATA"; - default: return "!!! Unknown EXI Register !!!"; - } - } // EXI Status Register - "Channel Parameter Register" union UEXI_STATUS @@ -104,15 +94,14 @@ public: CEXIChannel(u32 ChannelId); ~CEXIChannel(); + void RegisterMMIO(MMIO::Mapping* mmio, u32 base); + void AddDevice(const TEXIDevices device_type, const int device_num); void AddDevice(IEXIDevice* pDevice, const int device_num, bool notifyPresenceChanged=true); // Remove all devices void RemoveDevices(); - void Read32(u32& _uReturnValue, const u32 _iRegister); - void Write32(const u32 _iValue, const u32 _iRegister); - void Update(); bool IsCausingInterrupt(); void DoState(PointerWrap &p); diff --git a/Source/Core/Core/HW/HW.cpp b/Source/Core/Core/HW/HW.cpp index 586344ecc6..63f934588a 100644 --- a/Source/Core/Core/HW/HW.cpp +++ b/Source/Core/Core/HW/HW.cpp @@ -38,11 +38,11 @@ namespace HW VideoInterface::Init(); SerialInterface::Init(); ProcessorInterface::Init(); + ExpansionInterface::Init(); // Needs to be initialized before Memory Memory::Init(); DSP::Init(SConfig::GetInstance().m_LocalCoreStartupParameter.bDSPHLE); DVDInterface::Init(); GPFifo::Init(); - ExpansionInterface::Init(); CCPU::Init(SConfig::GetInstance().m_LocalCoreStartupParameter.iCPUCore); SystemTimers::Init(); diff --git a/Source/Core/Core/HW/Memmap.cpp b/Source/Core/Core/HW/Memmap.cpp index 7c37adeb67..e912f6fa5f 100644 --- a/Source/Core/Core/HW/Memmap.cpp +++ b/Source/Core/Core/HW/Memmap.cpp @@ -316,6 +316,7 @@ void InitMMIO(MMIO::Mapping* mmio) DSP::RegisterMMIO(mmio, 0xCC005000); DVDInterface::RegisterMMIO(mmio, 0xCC006000); SerialInterface::RegisterMMIO(mmio, 0xCC006400); + ExpansionInterface::RegisterMMIO(mmio, 0xCC006800); AudioInterface::RegisterMMIO(mmio, 0xCC006C00); } @@ -326,6 +327,7 @@ void InitMMIOWii(MMIO::Mapping* mmio) WII_IPCInterface::RegisterMMIO(mmio, 0xCD000000); DVDInterface::RegisterMMIO(mmio, 0xCD006000); SerialInterface::RegisterMMIO(mmio, 0xCD006400); + ExpansionInterface::RegisterMMIO(mmio, 0xCD006800); AudioInterface::RegisterMMIO(mmio, 0xCD006C00); }