Merge pull request #4704 from lioncash/exi-channel
EXI_Channel: Minor cleanup
This commit is contained in:
commit
d9c873bc8b
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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; }
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue