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);

	for (int d = 0; d < NUM_DEVICES; ++d)
	{
		IEXIDevice* pDevice = m_pDevices[d].get();
		TEXIDevices type = pDevice->m_deviceType;
		p.Do(type);
		IEXIDevice* pSaveDevice = (type == pDevice->m_deviceType) ? pDevice : EXIDevice_Create(type, m_ChannelId);
		pSaveDevice->DoState(p);
		if(pSaveDevice != pDevice)
		{
			// if we had to create a temporary device, discard it if we're not loading.
			// also, if no movie is active, we'll assume the user wants to keep their current devices
			// instead of the ones they had when the savestate was created,
			// unless the device is NONE (since ChangeDevice sets that temporarily).
			if(p.GetMode() != PointerWrap::MODE_READ)
			{
				delete pSaveDevice;
			}
			else
			{
				AddDevice(pSaveDevice, d, false);
			}
		}
	}
}
Beispiel #2
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));
}
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;
	}
}