MMIO: Port the EXI MMIOs to the new interface.
This commit is contained in:
parent
353c145e64
commit
bdedaa24a9
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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<u32>([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<u32>([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<u32>(&m_DMAMemoryAddress),
|
||||
MMIO::DirectWrite<u32>(&m_DMAMemoryAddress)
|
||||
);
|
||||
mmio->Register(base + EXI_DMALENGTH,
|
||||
MMIO::DirectRead<u32>(&m_DMALength),
|
||||
MMIO::DirectWrite<u32>(&m_DMALength)
|
||||
);
|
||||
mmio->Register(base + EXI_DMACONTROL,
|
||||
MMIO::DirectRead<u32>(&m_Control.Hex),
|
||||
MMIO::ComplexWrite<u32>([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<u32>(&m_ImmData),
|
||||
MMIO::DirectWrite<u32>(&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);
|
||||
|
|
|
@ -9,30 +9,20 @@
|
|||
#include "EXI_Device.h"
|
||||
#include <memory>
|
||||
|
||||
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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue