예제 #1
0
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 != nullptr)
                     pDevice->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::ComplexWrite<u32>([this](u32, u32 val) {
                   m_Control.Hex = val;

                   if (m_Control.TSTART)
                   {
                     IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT);
                     if (pDevice == nullptr)
                       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);
                       }
                     }
                     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;

                     // Check if device needs specific timing, otherwise just complete transfer
                     // immediately
                     if (!pDevice->UseDelayedTransferCompletion())
                       SendTransferComplete();
                   }
                 }));

  mmio->Register(base + EXI_IMMDATA, MMIO::DirectRead<u32>(&m_ImmData),
                 MMIO::DirectWrite<u32>(&m_ImmData));
}