forked from dolphin-emu/dolphin
Move enums for max SI and EXI devices to their respective .h file, and rename them. Use only those enums in BootManager.cpp. Same thing in Movie.cpp Change one instance of MAX_BBMOTES to MAX_WIIMOTES in Movie.cpp, since movies do not support balance board.
150 lines
3.9 KiB
C++
150 lines
3.9 KiB
C++
// Copyright 2013 Dolphin Emulator Project
|
|
// Licensed under GPLv2
|
|
// Refer to the license.txt file included.
|
|
|
|
#include "Common.h"
|
|
#include "ChunkFile.h"
|
|
#include "../ConfigManager.h"
|
|
#include "../CoreTiming.h"
|
|
|
|
#include "ProcessorInterface.h"
|
|
#include "../PowerPC/PowerPC.h"
|
|
|
|
#include "EXI.h"
|
|
#include "Sram.h"
|
|
#include "../Movie.h"
|
|
SRAM g_SRAM;
|
|
|
|
namespace ExpansionInterface
|
|
{
|
|
|
|
static int changeDevice;
|
|
|
|
CEXIChannel *g_Channels[MAX_EXI_CHANNELS];
|
|
void Init()
|
|
{
|
|
initSRAM();
|
|
for (u32 i = 0; i < MAX_EXI_CHANNELS; i++)
|
|
g_Channels[i] = new CEXIChannel(i);
|
|
|
|
if (Movie::IsPlayingInput() && Movie::IsUsingMemcard() && Movie::IsConfigSaved())
|
|
g_Channels[0]->AddDevice(EXIDEVICE_MEMORYCARD, 0); // SlotA
|
|
else if(Movie::IsPlayingInput() && !Movie::IsUsingMemcard() && Movie::IsConfigSaved())
|
|
g_Channels[0]->AddDevice(EXIDEVICE_NONE, 0); // SlotA
|
|
else
|
|
g_Channels[0]->AddDevice(SConfig::GetInstance().m_EXIDevice[0], 0); // SlotA
|
|
g_Channels[0]->AddDevice(EXIDEVICE_MASKROM, 1);
|
|
g_Channels[0]->AddDevice(SConfig::GetInstance().m_EXIDevice[2], 2); // Serial Port 1
|
|
g_Channels[1]->AddDevice(SConfig::GetInstance().m_EXIDevice[1], 0); // SlotB
|
|
g_Channels[2]->AddDevice(EXIDEVICE_AD16, 0);
|
|
|
|
changeDevice = CoreTiming::RegisterEvent("ChangeEXIDevice", ChangeDeviceCallback);
|
|
}
|
|
|
|
void Shutdown()
|
|
{
|
|
for (auto& channel : g_Channels)
|
|
{
|
|
delete channel;
|
|
channel = NULL;
|
|
}
|
|
}
|
|
|
|
void DoState(PointerWrap &p)
|
|
{
|
|
for (auto& channel : g_Channels)
|
|
channel->DoState(p);
|
|
}
|
|
|
|
void PauseAndLock(bool doLock, bool unpauseOnUnlock)
|
|
{
|
|
for (auto& channel : g_Channels)
|
|
channel->PauseAndLock(doLock, unpauseOnUnlock);
|
|
}
|
|
|
|
|
|
void ChangeDeviceCallback(u64 userdata, int cyclesLate)
|
|
{
|
|
u8 channel = (u8)(userdata >> 32);
|
|
u8 type = (u8)(userdata >> 16);
|
|
u8 num = (u8)userdata;
|
|
|
|
g_Channels[channel]->AddDevice((TEXIDevices)type, num);
|
|
}
|
|
|
|
void ChangeDevice(const u8 channel, const TEXIDevices device_type, const u8 device_num)
|
|
{
|
|
// Called from GUI, so we need to make it thread safe.
|
|
// Let the hardware see no device for .5b cycles
|
|
CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | ((u64)EXIDEVICE_NONE << 16) | device_num);
|
|
CoreTiming::ScheduleEvent_Threadsafe(500000000, changeDevice, ((u64)channel << 32) | ((u64)device_type << 16) | device_num);
|
|
}
|
|
|
|
IEXIDevice* FindDevice(TEXIDevices device_type, int customIndex)
|
|
{
|
|
for (auto& channel : g_Channels)
|
|
{
|
|
IEXIDevice* device = channel->FindDevice(device_type, customIndex);
|
|
if (device)
|
|
return device;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// Unused (?!)
|
|
void Update()
|
|
{
|
|
g_Channels[0]->Update();
|
|
g_Channels[1]->Update();
|
|
g_Channels[2]->Update();
|
|
}
|
|
|
|
void Read32(u32& _uReturnValue, const u32 _iAddress)
|
|
{
|
|
// TODO 0xfff00000 is mapped to EXI -> mapped to first MB of maskrom
|
|
u32 iAddr = _iAddress & 0x3FF;
|
|
u32 iRegister = (iAddr >> 2) % 5;
|
|
u32 iChannel = (iAddr >> 2) / 5;
|
|
|
|
_dbg_assert_(EXPANSIONINTERFACE, iChannel < MAX_EXI_CHANNELS);
|
|
|
|
if (iChannel < MAX_EXI_CHANNELS)
|
|
{
|
|
g_Channels[iChannel]->Read32(_uReturnValue, iRegister);
|
|
}
|
|
else
|
|
{
|
|
_uReturnValue = 0;
|
|
}
|
|
}
|
|
|
|
void Write32(const u32 _iValue, const u32 _iAddress)
|
|
{
|
|
// TODO 0xfff00000 is mapped to EXI -> mapped to first MB of maskrom
|
|
u32 iAddr = _iAddress & 0x3FF;
|
|
u32 iRegister = (iAddr >> 2) % 5;
|
|
u32 iChannel = (iAddr >> 2) / 5;
|
|
|
|
_dbg_assert_(EXPANSIONINTERFACE, iChannel < MAX_EXI_CHANNELS);
|
|
|
|
if (iChannel < MAX_EXI_CHANNELS)
|
|
g_Channels[iChannel]->Write32(_iValue, iRegister);
|
|
}
|
|
|
|
void UpdateInterrupts()
|
|
{
|
|
// Interrupts are mapped a bit strangely:
|
|
// Channel 0 Device 0 generates interrupt on channel 0
|
|
// Channel 0 Device 2 generates interrupt on channel 2
|
|
// Channel 1 Device 0 generates interrupt on channel 1
|
|
g_Channels[2]->SetEXIINT(g_Channels[0]->GetDevice(4)->IsInterruptSet());
|
|
|
|
bool causeInt = false;
|
|
for (auto& channel : g_Channels)
|
|
causeInt |= channel->IsCausingInterrupt();
|
|
|
|
ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_EXI, causeInt);
|
|
}
|
|
|
|
} // end of namespace ExpansionInterface
|