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
};
CEXIChannel::CEXIChannel(u32 ChannelId)
: m_DMAMemoryAddress(0), m_DMALength(0), m_ImmData(0), m_ChannelId(ChannelId)
CEXIChannel::CEXIChannel(u32 channel_id) : m_channel_id(channel_id)
{
m_Control.Hex = 0;
m_Status.Hex = 0;
if (m_ChannelId == 0 || m_ChannelId == 1)
m_Status.EXTINT = 1;
if (m_ChannelId == 1)
m_Status.CHIP_SELECT = 1;
if (m_channel_id == 0 || m_channel_id == 1)
m_status.EXTINT = 1;
if (m_channel_id == 1)
m_status.CHIP_SELECT = 1;
for (auto& device : m_devices)
device = EXIDevice_Create(EXIDEVICE_NONE, m_ChannelId);
device = EXIDevice_Create(EXIDEVICE_NONE, m_channel_id);
}
CEXIChannel::~CEXIChannel()
@ -48,115 +44,115 @@ void CEXIChannel::RegisterMMIO(MMIO::Mapping* mmio, u32 base)
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)
if (m_channel_id == 2)
{
m_Status.EXT = 0;
m_status.EXT = 0;
}
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) {
UEXI_STATUS newStatus(val);
UEXI_STATUS new_status(val);
m_Status.EXIINTMASK = newStatus.EXIINTMASK;
if (newStatus.EXIINT)
m_Status.EXIINT = 0;
m_status.EXIINTMASK = new_status.EXIINTMASK;
if (new_status.EXIINT)
m_status.EXIINT = 0;
m_Status.TCINTMASK = newStatus.TCINTMASK;
if (newStatus.TCINT)
m_Status.TCINT = 0;
m_status.TCINTMASK = new_status.TCINTMASK;
if (new_status.TCINT)
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)
m_Status.EXTINT = 0;
if (new_status.EXTINT)
m_status.EXTINT = 0;
}
if (m_ChannelId == 0)
m_Status.ROMDIS = newStatus.ROMDIS;
if (m_channel_id == 0)
m_status.ROMDIS = new_status.ROMDIS;
IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT ^ newStatus.CHIP_SELECT);
m_Status.CHIP_SELECT = newStatus.CHIP_SELECT;
if (pDevice != nullptr)
pDevice->SetCS(m_Status.CHIP_SELECT);
IEXIDevice* device = GetDevice(m_status.CHIP_SELECT ^ new_status.CHIP_SELECT);
m_status.CHIP_SELECT = new_status.CHIP_SELECT;
if (device != nullptr)
device->SetCS(m_status.CHIP_SELECT);
ExpansionInterface::UpdateInterrupts();
}));
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->Register(base + EXI_DMA_ADDRESS, MMIO::DirectRead<u32>(&m_dma_memory_address),
MMIO::DirectWrite<u32>(&m_dma_memory_address));
mmio->Register(base + EXI_DMA_LENGTH, MMIO::DirectRead<u32>(&m_dma_length),
MMIO::DirectWrite<u32>(&m_dma_length));
mmio->Register(base + EXI_DMA_CONTROL, MMIO::DirectRead<u32>(&m_control.Hex),
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);
if (pDevice == nullptr)
IEXIDevice* device = GetDevice(m_status.CHIP_SELECT);
if (device == nullptr)
return;
if (m_Control.DMA == 0)
if (m_control.DMA == 0)
{
// immediate data
switch (m_Control.RW)
switch (m_control.RW)
{
case EXI_READ:
m_ImmData = pDevice->ImmRead(m_Control.TLEN + 1);
m_imm_data = device->ImmRead(m_control.TLEN + 1);
break;
case EXI_WRITE:
pDevice->ImmWrite(m_ImmData, m_Control.TLEN + 1);
device->ImmWrite(m_imm_data, m_control.TLEN + 1);
break;
case EXI_READWRITE:
pDevice->ImmReadWrite(m_ImmData, m_Control.TLEN + 1);
device->ImmReadWrite(m_imm_data, m_control.TLEN + 1);
break;
default:
_dbg_assert_msg_(EXPANSIONINTERFACE, 0,
"EXI Imm: Unknown transfer type %i", m_Control.RW);
"EXI Imm: Unknown transfer type %i", m_control.RW);
}
}
else
{
// DMA
switch (m_Control.RW)
switch (m_control.RW)
{
case EXI_READ:
pDevice->DMARead(m_DMAMemoryAddress, m_DMALength);
device->DMARead(m_dma_memory_address, m_dma_length);
break;
case EXI_WRITE:
pDevice->DMAWrite(m_DMAMemoryAddress, m_DMALength);
device->DMAWrite(m_dma_memory_address, m_dma_length);
break;
default:
_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
// immediately
if (!pDevice->UseDelayedTransferCompletion())
if (!device->UseDelayedTransferCompletion())
SendTransferComplete();
}
}));
mmio->Register(base + EXI_IMMDATA, MMIO::DirectRead<u32>(&m_ImmData),
MMIO::DirectWrite<u32>(&m_ImmData));
mmio->Register(base + EXI_IMM_DATA, MMIO::DirectRead<u32>(&m_imm_data),
MMIO::DirectWrite<u32>(&m_imm_data));
}
void CEXIChannel::SendTransferComplete()
{
m_Status.TCINT = 1;
m_status.TCINT = 1;
ExpansionInterface::UpdateInterrupts();
}
@ -168,7 +164,7 @@ void CEXIChannel::RemoveDevices()
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,
@ -182,10 +178,10 @@ void CEXIChannel::AddDevice(std::unique_ptr<IEXIDevice> device, const int device
if (notify_presence_changed)
{
// This means "device presence changed", software has to check
// m_Status.EXT to see if it is now present or not
if (m_ChannelId != 2)
// m_status.EXT to see if it is now present or not
if (m_channel_id != 2)
{
m_Status.EXTINT = 1;
m_status.EXTINT = 1;
ExpansionInterface::UpdateInterrupts();
}
}
@ -193,14 +189,14 @@ void CEXIChannel::AddDevice(std::unique_ptr<IEXIDevice> device, const int device
bool CEXIChannel::IsCausingInterrupt()
{
if (m_ChannelId != 2 && GetDevice(1)->IsInterruptSet())
m_Status.EXIINT = 1; // Always check memcard slots
else if (GetDevice(m_Status.CHIP_SELECT))
if (GetDevice(m_Status.CHIP_SELECT)->IsInterruptSet())
m_Status.EXIINT = 1;
if (m_channel_id != 2 && GetDevice(1)->IsInterruptSet())
m_status.EXIINT = 1; // Always check memcard slots
else if (GetDevice(m_status.CHIP_SELECT))
if (GetDevice(m_status.CHIP_SELECT)->IsInterruptSet())
m_status.EXIINT = 1;
if ((m_Status.EXIINT & m_Status.EXIINTMASK) || (m_Status.TCINT & m_Status.TCINTMASK) ||
(m_Status.EXTINT & m_Status.EXTINTMASK))
if ((m_status.EXIINT & m_status.EXIINTMASK) || (m_status.TCINT & m_status.TCINTMASK) ||
(m_status.EXTINT & m_status.EXTINTMASK))
{
return true;
}
@ -226,11 +222,11 @@ IEXIDevice* CEXIChannel::GetDevice(const u8 chip_select)
void CEXIChannel::DoState(PointerWrap& p)
{
p.DoPOD(m_Status);
p.Do(m_DMAMemoryAddress);
p.Do(m_DMALength);
p.Do(m_Control);
p.Do(m_ImmData);
p.DoPOD(m_status);
p.Do(m_dma_memory_address);
p.Do(m_dma_length);
p.Do(m_control);
p.Do(m_imm_data);
for (int device_index = 0; device_index < NUM_DEVICES; ++device_index)
{
@ -244,24 +240,29 @@ void CEXIChannel::DoState(PointerWrap& p)
}
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);
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)
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)
{
IEXIDevice* device = sup->FindDevice(device_type, customIndex);
IEXIDevice* device = sup->FindDevice(device_type, custom_index);
if (device)
return device;
}

View File

@ -18,20 +18,46 @@ class Mapping;
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:
enum
{
EXI_STATUS = 0x00,
EXI_DMAADDR = 0x04,
EXI_DMALENGTH = 0x08,
EXI_DMACONTROL = 0x0C,
EXI_IMMDATA = 0x10
EXI_DMA_ADDRESS = 0x04,
EXI_DMA_LENGTH = 0x08,
EXI_DMA_CONTROL = 0x0C,
EXI_IMM_DATA = 0x10
};
// EXI Status Register - "Channel Parameter Register"
union UEXI_STATUS
{
u32 Hex;
u32 Hex = 0;
// DO NOT obey the warning and give this struct a name. Things will fail.
struct
{
@ -51,14 +77,14 @@ private:
u32 ROMDIS : 1; // ROM Disable
u32 : 18;
};
UEXI_STATUS() { Hex = 0; }
UEXI_STATUS(u32 _hex) { Hex = _hex; }
UEXI_STATUS() = default;
explicit UEXI_STATUS(u32 hex) : Hex{hex} {}
};
// EXI Control Register
union UEXI_CONTROL
{
u32 Hex;
u32 Hex = 0;
struct
{
u32 TSTART : 1;
@ -70,11 +96,11 @@ private:
};
// STATE_TO_SAVE
UEXI_STATUS m_Status;
u32 m_DMAMemoryAddress;
u32 m_DMALength;
UEXI_CONTROL m_Control;
u32 m_ImmData;
UEXI_STATUS m_status;
u32 m_dma_memory_address = 0;
u32 m_dma_length = 0;
UEXI_CONTROL m_control;
u32 m_imm_data = 0;
// Devices
enum
@ -85,31 +111,5 @@ private:
std::array<std::unique_ptr<IEXIDevice>, NUM_DEVICES> m_devices;
// Since channels operate a bit differently from each other
u32 m_ChannelId;
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; }
u32 m_channel_id;
};