Merge pull request #4704 from lioncash/exi-channel

EXI_Channel: Minor cleanup
This commit is contained in:
Matthew Parlane 2017-01-22 16:53:09 +13:00 committed by GitHub
commit d9c873bc8b
2 changed files with 118 additions and 117 deletions

View File

@ -20,19 +20,15 @@ enum
EXI_READWRITE EXI_READWRITE
}; };
CEXIChannel::CEXIChannel(u32 ChannelId) CEXIChannel::CEXIChannel(u32 channel_id) : m_channel_id(channel_id)
: m_DMAMemoryAddress(0), m_DMALength(0), m_ImmData(0), m_ChannelId(ChannelId)
{ {
m_Control.Hex = 0; if (m_channel_id == 0 || m_channel_id == 1)
m_Status.Hex = 0; m_status.EXTINT = 1;
if (m_channel_id == 1)
if (m_ChannelId == 0 || m_ChannelId == 1) m_status.CHIP_SELECT = 1;
m_Status.EXTINT = 1;
if (m_ChannelId == 1)
m_Status.CHIP_SELECT = 1;
for (auto& device : m_devices) for (auto& device : m_devices)
device = EXIDevice_Create(EXIDEVICE_NONE, m_ChannelId); device = EXIDevice_Create(EXIDEVICE_NONE, m_channel_id);
} }
CEXIChannel::~CEXIChannel() CEXIChannel::~CEXIChannel()
@ -48,115 +44,115 @@ void CEXIChannel::RegisterMMIO(MMIO::Mapping* mmio, u32 base)
mmio->Register(base + EXI_STATUS, MMIO::ComplexRead<u32>([this](u32) { mmio->Register(base + EXI_STATUS, MMIO::ComplexRead<u32>([this](u32) {
// check if external device is present // check if external device is present
// pretty sure it is memcard only, not entirely sure // pretty sure it is memcard only, not entirely sure
if (m_ChannelId == 2) if (m_channel_id == 2)
{ {
m_Status.EXT = 0; m_status.EXT = 0;
} }
else else
{ {
m_Status.EXT = GetDevice(1)->IsPresent() ? 1 : 0; m_status.EXT = GetDevice(1)->IsPresent() ? 1 : 0;
} }
return m_Status.Hex; return m_status.Hex;
}), }),
MMIO::ComplexWrite<u32>([this](u32, u32 val) { MMIO::ComplexWrite<u32>([this](u32, u32 val) {
UEXI_STATUS newStatus(val); UEXI_STATUS new_status(val);
m_Status.EXIINTMASK = newStatus.EXIINTMASK; m_status.EXIINTMASK = new_status.EXIINTMASK;
if (newStatus.EXIINT) if (new_status.EXIINT)
m_Status.EXIINT = 0; m_status.EXIINT = 0;
m_Status.TCINTMASK = newStatus.TCINTMASK; m_status.TCINTMASK = new_status.TCINTMASK;
if (newStatus.TCINT) if (new_status.TCINT)
m_Status.TCINT = 0; m_status.TCINT = 0;
m_Status.CLK = newStatus.CLK; m_status.CLK = new_status.CLK;
if (m_ChannelId == 0 || m_ChannelId == 1) if (m_channel_id == 0 || m_channel_id == 1)
{ {
m_Status.EXTINTMASK = newStatus.EXTINTMASK; m_status.EXTINTMASK = new_status.EXTINTMASK;
if (newStatus.EXTINT) if (new_status.EXTINT)
m_Status.EXTINT = 0; m_status.EXTINT = 0;
} }
if (m_ChannelId == 0) if (m_channel_id == 0)
m_Status.ROMDIS = newStatus.ROMDIS; m_status.ROMDIS = new_status.ROMDIS;
IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT ^ newStatus.CHIP_SELECT); IEXIDevice* device = GetDevice(m_status.CHIP_SELECT ^ new_status.CHIP_SELECT);
m_Status.CHIP_SELECT = newStatus.CHIP_SELECT; m_status.CHIP_SELECT = new_status.CHIP_SELECT;
if (pDevice != nullptr) if (device != nullptr)
pDevice->SetCS(m_Status.CHIP_SELECT); device->SetCS(m_status.CHIP_SELECT);
ExpansionInterface::UpdateInterrupts(); ExpansionInterface::UpdateInterrupts();
})); }));
mmio->Register(base + EXI_DMAADDR, MMIO::DirectRead<u32>(&m_DMAMemoryAddress), mmio->Register(base + EXI_DMA_ADDRESS, MMIO::DirectRead<u32>(&m_dma_memory_address),
MMIO::DirectWrite<u32>(&m_DMAMemoryAddress)); MMIO::DirectWrite<u32>(&m_dma_memory_address));
mmio->Register(base + EXI_DMALENGTH, MMIO::DirectRead<u32>(&m_DMALength), mmio->Register(base + EXI_DMA_LENGTH, MMIO::DirectRead<u32>(&m_dma_length),
MMIO::DirectWrite<u32>(&m_DMALength)); MMIO::DirectWrite<u32>(&m_dma_length));
mmio->Register(base + EXI_DMACONTROL, MMIO::DirectRead<u32>(&m_Control.Hex), mmio->Register(base + EXI_DMA_CONTROL, MMIO::DirectRead<u32>(&m_control.Hex),
MMIO::ComplexWrite<u32>([this](u32, u32 val) { MMIO::ComplexWrite<u32>([this](u32, u32 val) {
m_Control.Hex = val; m_control.Hex = val;
if (m_Control.TSTART) if (m_control.TSTART)
{ {
IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT); IEXIDevice* device = GetDevice(m_status.CHIP_SELECT);
if (pDevice == nullptr) if (device == nullptr)
return; return;
if (m_Control.DMA == 0) if (m_control.DMA == 0)
{ {
// immediate data // immediate data
switch (m_Control.RW) switch (m_control.RW)
{ {
case EXI_READ: case EXI_READ:
m_ImmData = pDevice->ImmRead(m_Control.TLEN + 1); m_imm_data = device->ImmRead(m_control.TLEN + 1);
break; break;
case EXI_WRITE: case EXI_WRITE:
pDevice->ImmWrite(m_ImmData, m_Control.TLEN + 1); device->ImmWrite(m_imm_data, m_control.TLEN + 1);
break; break;
case EXI_READWRITE: case EXI_READWRITE:
pDevice->ImmReadWrite(m_ImmData, m_Control.TLEN + 1); device->ImmReadWrite(m_imm_data, m_control.TLEN + 1);
break; break;
default: default:
_dbg_assert_msg_(EXPANSIONINTERFACE, 0, _dbg_assert_msg_(EXPANSIONINTERFACE, 0,
"EXI Imm: Unknown transfer type %i", m_Control.RW); "EXI Imm: Unknown transfer type %i", m_control.RW);
} }
} }
else else
{ {
// DMA // DMA
switch (m_Control.RW) switch (m_control.RW)
{ {
case EXI_READ: case EXI_READ:
pDevice->DMARead(m_DMAMemoryAddress, m_DMALength); device->DMARead(m_dma_memory_address, m_dma_length);
break; break;
case EXI_WRITE: case EXI_WRITE:
pDevice->DMAWrite(m_DMAMemoryAddress, m_DMALength); device->DMAWrite(m_dma_memory_address, m_dma_length);
break; break;
default: default:
_dbg_assert_msg_(EXPANSIONINTERFACE, 0, _dbg_assert_msg_(EXPANSIONINTERFACE, 0,
"EXI DMA: Unknown transfer type %i", m_Control.RW); "EXI DMA: Unknown transfer type %i", m_control.RW);
} }
} }
m_Control.TSTART = 0; m_control.TSTART = 0;
// Check if device needs specific timing, otherwise just complete transfer // Check if device needs specific timing, otherwise just complete transfer
// immediately // immediately
if (!pDevice->UseDelayedTransferCompletion()) if (!device->UseDelayedTransferCompletion())
SendTransferComplete(); SendTransferComplete();
} }
})); }));
mmio->Register(base + EXI_IMMDATA, MMIO::DirectRead<u32>(&m_ImmData), mmio->Register(base + EXI_IMM_DATA, MMIO::DirectRead<u32>(&m_imm_data),
MMIO::DirectWrite<u32>(&m_ImmData)); MMIO::DirectWrite<u32>(&m_imm_data));
} }
void CEXIChannel::SendTransferComplete() void CEXIChannel::SendTransferComplete()
{ {
m_Status.TCINT = 1; m_status.TCINT = 1;
ExpansionInterface::UpdateInterrupts(); ExpansionInterface::UpdateInterrupts();
} }
@ -168,7 +164,7 @@ void CEXIChannel::RemoveDevices()
void CEXIChannel::AddDevice(const TEXIDevices device_type, const int device_num) void CEXIChannel::AddDevice(const TEXIDevices device_type, const int device_num)
{ {
AddDevice(EXIDevice_Create(device_type, m_ChannelId), device_num); AddDevice(EXIDevice_Create(device_type, m_channel_id), device_num);
} }
void CEXIChannel::AddDevice(std::unique_ptr<IEXIDevice> device, const int device_num, void CEXIChannel::AddDevice(std::unique_ptr<IEXIDevice> device, const int device_num,
@ -182,10 +178,10 @@ void CEXIChannel::AddDevice(std::unique_ptr<IEXIDevice> device, const int device
if (notify_presence_changed) if (notify_presence_changed)
{ {
// This means "device presence changed", software has to check // This means "device presence changed", software has to check
// m_Status.EXT to see if it is now present or not // m_status.EXT to see if it is now present or not
if (m_ChannelId != 2) if (m_channel_id != 2)
{ {
m_Status.EXTINT = 1; m_status.EXTINT = 1;
ExpansionInterface::UpdateInterrupts(); ExpansionInterface::UpdateInterrupts();
} }
} }
@ -193,14 +189,14 @@ void CEXIChannel::AddDevice(std::unique_ptr<IEXIDevice> device, const int device
bool CEXIChannel::IsCausingInterrupt() bool CEXIChannel::IsCausingInterrupt()
{ {
if (m_ChannelId != 2 && GetDevice(1)->IsInterruptSet()) if (m_channel_id != 2 && GetDevice(1)->IsInterruptSet())
m_Status.EXIINT = 1; // Always check memcard slots m_status.EXIINT = 1; // Always check memcard slots
else if (GetDevice(m_Status.CHIP_SELECT)) else if (GetDevice(m_status.CHIP_SELECT))
if (GetDevice(m_Status.CHIP_SELECT)->IsInterruptSet()) if (GetDevice(m_status.CHIP_SELECT)->IsInterruptSet())
m_Status.EXIINT = 1; m_status.EXIINT = 1;
if ((m_Status.EXIINT & m_Status.EXIINTMASK) || (m_Status.TCINT & m_Status.TCINTMASK) || if ((m_status.EXIINT & m_status.EXIINTMASK) || (m_status.TCINT & m_status.TCINTMASK) ||
(m_Status.EXTINT & m_Status.EXTINTMASK)) (m_status.EXTINT & m_status.EXTINTMASK))
{ {
return true; return true;
} }
@ -226,11 +222,11 @@ IEXIDevice* CEXIChannel::GetDevice(const u8 chip_select)
void CEXIChannel::DoState(PointerWrap& p) void CEXIChannel::DoState(PointerWrap& p)
{ {
p.DoPOD(m_Status); p.DoPOD(m_status);
p.Do(m_DMAMemoryAddress); p.Do(m_dma_memory_address);
p.Do(m_DMALength); p.Do(m_dma_length);
p.Do(m_Control); p.Do(m_control);
p.Do(m_ImmData); p.Do(m_imm_data);
for (int device_index = 0; device_index < NUM_DEVICES; ++device_index) for (int device_index = 0; device_index < NUM_DEVICES; ++device_index)
{ {
@ -244,24 +240,29 @@ void CEXIChannel::DoState(PointerWrap& p)
} }
else else
{ {
std::unique_ptr<IEXIDevice> save_device = EXIDevice_Create(type, m_ChannelId); std::unique_ptr<IEXIDevice> save_device = EXIDevice_Create(type, m_channel_id);
save_device->DoState(p); save_device->DoState(p);
AddDevice(std::move(save_device), device_index, false); AddDevice(std::move(save_device), device_index, false);
} }
} }
} }
void CEXIChannel::PauseAndLock(bool doLock, bool unpauseOnUnlock) void CEXIChannel::PauseAndLock(bool do_lock, bool resume_on_unlock)
{ {
for (auto& device : m_devices) for (auto& device : m_devices)
device->PauseAndLock(doLock, unpauseOnUnlock); device->PauseAndLock(do_lock, resume_on_unlock);
} }
IEXIDevice* CEXIChannel::FindDevice(TEXIDevices device_type, int customIndex) void CEXIChannel::SetEXIINT(bool exiint)
{
m_status.EXIINT = !!exiint;
}
IEXIDevice* CEXIChannel::FindDevice(TEXIDevices device_type, int custom_index)
{ {
for (auto& sup : m_devices) for (auto& sup : m_devices)
{ {
IEXIDevice* device = sup->FindDevice(device_type, customIndex); IEXIDevice* device = sup->FindDevice(device_type, custom_index);
if (device) if (device)
return device; return device;
} }

View File

@ -18,20 +18,46 @@ class Mapping;
class CEXIChannel class CEXIChannel
{ {
public:
explicit CEXIChannel(u32 channel_id);
~CEXIChannel();
// get device
IEXIDevice* GetDevice(u8 chip_select);
IEXIDevice* FindDevice(TEXIDevices device_type, int custom_index = -1);
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
void SendTransferComplete();
void AddDevice(TEXIDevices device_type, int device_num);
void AddDevice(std::unique_ptr<IEXIDevice> device, int device_num,
bool notify_presence_changed = true);
// Remove all devices
void RemoveDevices();
bool IsCausingInterrupt();
void DoState(PointerWrap& p);
void PauseAndLock(bool do_lock, bool resume_on_unlock);
// This should only be used to transition interrupts from SP1 to Channel 2
void SetEXIINT(bool exiint);
private: private:
enum enum
{ {
EXI_STATUS = 0x00, EXI_STATUS = 0x00,
EXI_DMAADDR = 0x04, EXI_DMA_ADDRESS = 0x04,
EXI_DMALENGTH = 0x08, EXI_DMA_LENGTH = 0x08,
EXI_DMACONTROL = 0x0C, EXI_DMA_CONTROL = 0x0C,
EXI_IMMDATA = 0x10 EXI_IMM_DATA = 0x10
}; };
// EXI Status Register - "Channel Parameter Register" // EXI Status Register - "Channel Parameter Register"
union UEXI_STATUS union UEXI_STATUS
{ {
u32 Hex; u32 Hex = 0;
// DO NOT obey the warning and give this struct a name. Things will fail. // DO NOT obey the warning and give this struct a name. Things will fail.
struct struct
{ {
@ -51,14 +77,14 @@ private:
u32 ROMDIS : 1; // ROM Disable u32 ROMDIS : 1; // ROM Disable
u32 : 18; u32 : 18;
}; };
UEXI_STATUS() { Hex = 0; } UEXI_STATUS() = default;
UEXI_STATUS(u32 _hex) { Hex = _hex; } explicit UEXI_STATUS(u32 hex) : Hex{hex} {}
}; };
// EXI Control Register // EXI Control Register
union UEXI_CONTROL union UEXI_CONTROL
{ {
u32 Hex; u32 Hex = 0;
struct struct
{ {
u32 TSTART : 1; u32 TSTART : 1;
@ -70,11 +96,11 @@ private:
}; };
// STATE_TO_SAVE // STATE_TO_SAVE
UEXI_STATUS m_Status; UEXI_STATUS m_status;
u32 m_DMAMemoryAddress; u32 m_dma_memory_address = 0;
u32 m_DMALength; u32 m_dma_length = 0;
UEXI_CONTROL m_Control; UEXI_CONTROL m_control;
u32 m_ImmData; u32 m_imm_data = 0;
// Devices // Devices
enum enum
@ -85,31 +111,5 @@ private:
std::array<std::unique_ptr<IEXIDevice>, NUM_DEVICES> m_devices; std::array<std::unique_ptr<IEXIDevice>, NUM_DEVICES> m_devices;
// Since channels operate a bit differently from each other // Since channels operate a bit differently from each other
u32 m_ChannelId; u32 m_channel_id;
public:
// get device
IEXIDevice* GetDevice(const u8 _CHIP_SELECT);
IEXIDevice* FindDevice(TEXIDevices device_type, int customIndex = -1);
CEXIChannel(u32 ChannelId);
~CEXIChannel();
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
void SendTransferComplete();
void AddDevice(const TEXIDevices device_type, const int device_num);
void AddDevice(std::unique_ptr<IEXIDevice> device, const int device_num,
bool notify_presence_changed = true);
// Remove all devices
void RemoveDevices();
bool IsCausingInterrupt();
void DoState(PointerWrap& p);
void PauseAndLock(bool doLock, bool unpauseOnUnlock);
// This should only be used to transition interrupts from SP1 to Channel 2
void SetEXIINT(bool exiint) { m_Status.EXIINT = !!exiint; }
}; };