MMIO: Port the EXI MMIOs to the new interface.

This commit is contained in:
Pierre Bourdon 2014-01-25 23:02:29 +01:00
parent 353c145e64
commit bdedaa24a9
6 changed files with 145 additions and 191 deletions

View File

@ -9,6 +9,7 @@
#include "ProcessorInterface.h" #include "ProcessorInterface.h"
#include "../PowerPC/PowerPC.h" #include "../PowerPC/PowerPC.h"
#include "MMIO.h"
#include "EXI.h" #include "EXI.h"
#include "Sram.h" #include "Sram.h"
@ -62,6 +63,19 @@ void PauseAndLock(bool doLock, bool unpauseOnUnlock)
channel->PauseAndLock(doLock, 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) void ChangeDeviceCallback(u64 userdata, int cyclesLate)
{ {
@ -101,34 +115,14 @@ void Update()
void Read32(u32& _uReturnValue, const u32 _iAddress) void Read32(u32& _uReturnValue, const u32 _iAddress)
{ {
// TODO 0xfff00000 is mapped to EXI -> mapped to first MB of maskrom // HACK: Remove this function when the new MMIO interface is used.
u32 iAddr = _iAddress & 0x3FF; Memory::mmio_mapping->Read(_iAddress, _uReturnValue);
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;
}
} }
void Write32(const u32 _iValue, const u32 _iAddress) void Write32(const u32 _iValue, const u32 _iAddress)
{ {
// TODO 0xfff00000 is mapped to EXI -> mapped to first MB of maskrom // HACK: Remove this function when the new MMIO interface is used.
u32 iAddr = _iAddress & 0x3FF; Memory::mmio_mapping->Write(_iAddress, _iValue);
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);
} }
void UpdateInterrupts() void UpdateInterrupts()

View File

@ -8,6 +8,7 @@
#include "EXI_Channel.h" #include "EXI_Channel.h"
#include "Thread.h" #include "Thread.h"
class PointerWrap; class PointerWrap;
namespace MMIO { class Mapping; }
enum enum
{ {
@ -22,6 +23,8 @@ void Shutdown();
void DoState(PointerWrap &p); void DoState(PointerWrap &p);
void PauseAndLock(bool doLock, bool unpauseOnUnlock); void PauseAndLock(bool doLock, bool unpauseOnUnlock);
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
void Update(); void Update();
void UpdateInterrupts(); void UpdateInterrupts();

View File

@ -7,6 +7,7 @@
#include "EXI.h" #include "EXI.h"
#include "../ConfigManager.h" #include "../ConfigManager.h"
#include "../Movie.h" #include "../Movie.h"
#include "MMIO.h"
#define EXI_READ 0 #define EXI_READ 0
#define EXI_WRITE 1 #define EXI_WRITE 1
@ -41,6 +42,117 @@ CEXIChannel::~CEXIChannel()
RemoveDevices(); 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() void CEXIChannel::RemoveDevices()
{ {
for (auto& device : m_pDevices) for (auto& device : m_pDevices)
@ -115,152 +227,6 @@ void CEXIChannel::Update()
device->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) void CEXIChannel::DoState(PointerWrap &p)
{ {
p.DoPOD(m_Status); p.DoPOD(m_Status);

View File

@ -9,30 +9,20 @@
#include "EXI_Device.h" #include "EXI_Device.h"
#include <memory> #include <memory>
namespace MMIO { class Mapping; }
class CEXIChannel class CEXIChannel
{ {
private: private:
enum enum
{ {
EXI_STATUS = 0, EXI_STATUS = 0x00,
EXI_DMAADDR = 1, EXI_DMAADDR = 0x04,
EXI_DMALENGTH = 2, EXI_DMALENGTH = 0x08,
EXI_DMACONTROL = 3, EXI_DMACONTROL = 0x0C,
EXI_IMMDATA = 4 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" // EXI Status Register - "Channel Parameter Register"
union UEXI_STATUS union UEXI_STATUS
@ -104,15 +94,14 @@ public:
CEXIChannel(u32 ChannelId); CEXIChannel(u32 ChannelId);
~CEXIChannel(); ~CEXIChannel();
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
void AddDevice(const TEXIDevices device_type, const int device_num); void AddDevice(const TEXIDevices device_type, const int device_num);
void AddDevice(IEXIDevice* pDevice, const int device_num, bool notifyPresenceChanged=true); void AddDevice(IEXIDevice* pDevice, const int device_num, bool notifyPresenceChanged=true);
// Remove all devices // Remove all devices
void RemoveDevices(); void RemoveDevices();
void Read32(u32& _uReturnValue, const u32 _iRegister);
void Write32(const u32 _iValue, const u32 _iRegister);
void Update(); void Update();
bool IsCausingInterrupt(); bool IsCausingInterrupt();
void DoState(PointerWrap &p); void DoState(PointerWrap &p);

View File

@ -38,11 +38,11 @@ namespace HW
VideoInterface::Init(); VideoInterface::Init();
SerialInterface::Init(); SerialInterface::Init();
ProcessorInterface::Init(); ProcessorInterface::Init();
ExpansionInterface::Init(); // Needs to be initialized before Memory
Memory::Init(); Memory::Init();
DSP::Init(SConfig::GetInstance().m_LocalCoreStartupParameter.bDSPHLE); DSP::Init(SConfig::GetInstance().m_LocalCoreStartupParameter.bDSPHLE);
DVDInterface::Init(); DVDInterface::Init();
GPFifo::Init(); GPFifo::Init();
ExpansionInterface::Init();
CCPU::Init(SConfig::GetInstance().m_LocalCoreStartupParameter.iCPUCore); CCPU::Init(SConfig::GetInstance().m_LocalCoreStartupParameter.iCPUCore);
SystemTimers::Init(); SystemTimers::Init();

View File

@ -316,6 +316,7 @@ void InitMMIO(MMIO::Mapping* mmio)
DSP::RegisterMMIO(mmio, 0xCC005000); DSP::RegisterMMIO(mmio, 0xCC005000);
DVDInterface::RegisterMMIO(mmio, 0xCC006000); DVDInterface::RegisterMMIO(mmio, 0xCC006000);
SerialInterface::RegisterMMIO(mmio, 0xCC006400); SerialInterface::RegisterMMIO(mmio, 0xCC006400);
ExpansionInterface::RegisterMMIO(mmio, 0xCC006800);
AudioInterface::RegisterMMIO(mmio, 0xCC006C00); AudioInterface::RegisterMMIO(mmio, 0xCC006C00);
} }
@ -326,6 +327,7 @@ void InitMMIOWii(MMIO::Mapping* mmio)
WII_IPCInterface::RegisterMMIO(mmio, 0xCD000000); WII_IPCInterface::RegisterMMIO(mmio, 0xCD000000);
DVDInterface::RegisterMMIO(mmio, 0xCD006000); DVDInterface::RegisterMMIO(mmio, 0xCD006000);
SerialInterface::RegisterMMIO(mmio, 0xCD006400); SerialInterface::RegisterMMIO(mmio, 0xCD006400);
ExpansionInterface::RegisterMMIO(mmio, 0xCD006800);
AudioInterface::RegisterMMIO(mmio, 0xCD006C00); AudioInterface::RegisterMMIO(mmio, 0xCD006C00);
} }