Add tmbinc's patch for triforce emulation.
This adds triforce-specific SI and EXI devices, as well as changes DI behavior when in triforce mode. (Selecting both AM devices from main config will force the DI into triforce mode) Also fixes up a few EXI bugs dealing with interrupts and the like (memcard insertion should work well now, and maybe BBA can progress farther :> ) Also adds real "null" EXI devices, so software won't think the dummy device is some strange unknown device anymore. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4437 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
f5f0823867
commit
93b83f8d65
|
@ -710,6 +710,14 @@
|
|||
RelativePath=".\Src\Hw\EXI_DeviceAD16.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\HW\EXI_DeviceAMBaseboard.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\HW\EXI_DeviceAMBaseboard.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\HW\EXI_DeviceEthernet.cpp"
|
||||
>
|
||||
|
@ -782,6 +790,14 @@
|
|||
RelativePath=".\Src\HW\SI_Device.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\HW\SI_DeviceAMBaseboard.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\HW\SI_DeviceAMBaseboard.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\HW\SI_DeviceGBA.cpp"
|
||||
>
|
||||
|
|
|
@ -196,7 +196,7 @@ void Write32(const u32 _Value, const u32 _Address)
|
|||
|
||||
// This is the only new code in this ~3,326 revision, it seems to avoid hanging Crazy Taxi,
|
||||
// while the 1080 and Wave Race music still works
|
||||
if (!tmpAICtrl.PSTAT) DVDInterface::m_bStream = false;
|
||||
if (!tmpAICtrl.PSTAT) DVDInterface::g_bStream = false;
|
||||
}
|
||||
|
||||
// AI Interrupt
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -42,8 +42,9 @@ void ClearCoverInterrupt();
|
|||
|
||||
// DVD Access Functions
|
||||
bool DVDRead(u32 _iDVDOffset, u32 _iRamAddress, u32 _iLength);
|
||||
// For AudioInterface
|
||||
bool DVDReadADPCM(u8* _pDestBuffer, u32 _iNumSamples);
|
||||
extern bool m_bStream;
|
||||
extern bool g_bStream;
|
||||
|
||||
// Read32
|
||||
void Read32(u32& _uReturnValue, const u32 _iAddress);
|
||||
|
@ -119,5 +120,3 @@ enum DICommand
|
|||
} // end of namespace DVDInterface
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -35,41 +35,39 @@ enum
|
|||
NUM_CHANNELS = 3
|
||||
};
|
||||
|
||||
CEXIChannel *g_Channels;
|
||||
CEXIChannel *g_Channels[NUM_CHANNELS];
|
||||
|
||||
void Init()
|
||||
{
|
||||
g_Channels = new CEXIChannel[NUM_CHANNELS];
|
||||
g_Channels[0].m_ChannelId = 0;
|
||||
g_Channels[1].m_ChannelId = 1;
|
||||
g_Channels[2].m_ChannelId = 2;
|
||||
for (u32 i = 0; i < NUM_CHANNELS; i++)
|
||||
g_Channels[i] = new CEXIChannel(i);
|
||||
|
||||
// m_EXIDevice[0] = SlotA
|
||||
// m_EXIDevice[1] = SlotB
|
||||
// m_EXIDevice[2] = Serial Port 1 (ETH)
|
||||
g_Channels[0].AddDevice(SConfig::GetInstance().m_EXIDevice[0], 0);
|
||||
g_Channels[0].AddDevice(EXIDEVICE_IPL, 1);
|
||||
g_Channels[0].AddDevice(SConfig::GetInstance().m_EXIDevice[2], 2);
|
||||
g_Channels[1].AddDevice(SConfig::GetInstance().m_EXIDevice[1], 0);
|
||||
g_Channels[2].AddDevice(EXIDEVICE_AD16, 0);
|
||||
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()
|
||||
{
|
||||
delete [] g_Channels;
|
||||
g_Channels = 0;
|
||||
for (u32 i = 0; i < NUM_CHANNELS; i++)
|
||||
{
|
||||
delete g_Channels[i];
|
||||
g_Channels[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
// TODO: Complete DoState for each IEXIDevice
|
||||
g_Channels[0].GetDevice(1)->DoState(p);
|
||||
g_Channels[0].GetDevice(2)->DoState(p);
|
||||
g_Channels[0].GetDevice(4)->DoState(p);
|
||||
g_Channels[1].GetDevice(1)->DoState(p);
|
||||
g_Channels[2].GetDevice(1)->DoState(p);
|
||||
g_Channels[0]->GetDevice(1)->DoState(p);
|
||||
g_Channels[0]->GetDevice(2)->DoState(p);
|
||||
g_Channels[0]->GetDevice(4)->DoState(p);
|
||||
g_Channels[1]->GetDevice(1)->DoState(p);
|
||||
g_Channels[2]->GetDevice(1)->DoState(p);
|
||||
}
|
||||
|
||||
void ChangeDeviceCallback(u64 userdata, int cyclesLate)
|
||||
|
@ -78,35 +76,37 @@ void ChangeDeviceCallback(u64 userdata, int cyclesLate)
|
|||
u8 device = (u8)(userdata >> 16);
|
||||
u8 slot = (u8)userdata;
|
||||
|
||||
g_Channels[channel].AddDevice((TEXIDevices)device, slot);
|
||||
g_Channels[channel]->AddDevice((TEXIDevices)device, slot);
|
||||
}
|
||||
|
||||
void ChangeDevice(u8 channel, TEXIDevices device, u8 slot)
|
||||
{
|
||||
// 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_DUMMY << 16) | slot);
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | ((u64)EXIDEVICE_NONE << 16) | slot);
|
||||
CoreTiming::ScheduleEvent_Threadsafe(500000000, changeDevice, ((u64)channel << 32) | ((u64)device << 16) | slot);
|
||||
}
|
||||
|
||||
// Unused (?!)
|
||||
void Update()
|
||||
{
|
||||
g_Channels[0].Update();
|
||||
g_Channels[1].Update();
|
||||
g_Channels[2].Update();
|
||||
g_Channels[0]->Update();
|
||||
g_Channels[1]->Update();
|
||||
g_Channels[2]->Update();
|
||||
}
|
||||
|
||||
void Read32(u32& _uReturnValue, const u32 _iAddress)
|
||||
{
|
||||
unsigned int iAddr = _iAddress & 0x3FF;
|
||||
unsigned int iRegister = (iAddr >> 2) % 5;
|
||||
unsigned int iChannel = (iAddr >> 2) / 5;
|
||||
// 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 < NUM_CHANNELS);
|
||||
|
||||
if (iChannel < NUM_CHANNELS)
|
||||
{
|
||||
g_Channels[iChannel].Read32(_uReturnValue, iRegister);
|
||||
g_Channels[iChannel]->Read32(_uReturnValue, iRegister);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -116,28 +116,30 @@ void Read32(u32& _uReturnValue, const u32 _iAddress)
|
|||
|
||||
void Write32(const u32 _iValue, const u32 _iAddress)
|
||||
{
|
||||
int iAddr = _iAddress & 0x3FF;
|
||||
int iRegister = (iAddr >> 2) % 5;
|
||||
int iChannel = (iAddr >> 2) / 5;
|
||||
// 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 < NUM_CHANNELS)
|
||||
_dbg_assert_(EXPANSIONINTERFACE, iChannel < NUM_CHANNELS);
|
||||
|
||||
if (iChannel < NUM_CHANNELS)
|
||||
g_Channels[iChannel].Write32(_iValue, iRegister);
|
||||
g_Channels[iChannel]->Write32(_iValue, iRegister);
|
||||
}
|
||||
|
||||
void UpdateInterrupts()
|
||||
{
|
||||
for(int i=0; i<NUM_CHANNELS; i++)
|
||||
{
|
||||
if(g_Channels[i].IsCausingInterrupt())
|
||||
{
|
||||
ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_EXI, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 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());
|
||||
|
||||
ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_EXI, false);
|
||||
bool causeInt = false;
|
||||
for (int i = 0; i < NUM_CHANNELS; i++)
|
||||
causeInt |= g_Channels[i]->IsCausingInterrupt();
|
||||
|
||||
ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_EXI, causeInt);
|
||||
}
|
||||
|
||||
} // end of namespace ExpansionInterface
|
||||
|
|
|
@ -27,24 +27,22 @@
|
|||
#include "ProcessorInterface.h"
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
|
||||
CEXIChannel::CEXIChannel() :
|
||||
CEXIChannel::CEXIChannel(u32 ChannelId) :
|
||||
m_DMAMemoryAddress(0),
|
||||
m_DMALength(0),
|
||||
m_ImmData(0),
|
||||
m_ChannelId(-1)
|
||||
m_ChannelId(ChannelId)
|
||||
{
|
||||
m_Control.hex = 0;
|
||||
m_Status.hex = 0;
|
||||
m_Control.Hex = 0;
|
||||
m_Status.Hex = 0;
|
||||
|
||||
m_Status.CHIP_SELECT = 1;
|
||||
if (m_ChannelId == 0 || m_ChannelId == 1)
|
||||
m_Status.EXTINT = 1;
|
||||
if (m_ChannelId == 1)
|
||||
m_Status.CHIP_SELECT = 1;
|
||||
|
||||
for (int i = 0; i < NUM_DEVICES; i++)
|
||||
{
|
||||
m_pDevices[i] = EXIDevice_Create(EXIDEVICE_DUMMY);
|
||||
_dbg_assert_(EXPANSIONINTERFACE, m_pDevices[i] != NULL);
|
||||
}
|
||||
|
||||
m_Status.TCINTMASK = 1;
|
||||
m_pDevices[i] = EXIDevice_Create(EXIDEVICE_NONE);
|
||||
}
|
||||
|
||||
CEXIChannel::~CEXIChannel()
|
||||
|
@ -56,11 +54,8 @@ void CEXIChannel::RemoveDevices()
|
|||
{
|
||||
for (int i = 0; i < NUM_DEVICES; i++)
|
||||
{
|
||||
if (m_pDevices[i] != NULL)
|
||||
{
|
||||
delete m_pDevices[i];
|
||||
m_pDevices[i] = NULL;
|
||||
}
|
||||
delete m_pDevices[i];
|
||||
m_pDevices[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,7 +72,14 @@ void CEXIChannel::AddDevice(const TEXIDevices _device, const unsigned int _iSlot
|
|||
|
||||
// create the new one
|
||||
m_pDevices[_iSlot] = EXIDevice_Create(_device);
|
||||
_dbg_assert_(EXPANSIONINTERFACE, m_pDevices[_iSlot] != NULL);
|
||||
|
||||
// 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.EXTINT = 1;
|
||||
UpdateInterrupts();
|
||||
}
|
||||
}
|
||||
|
||||
void CEXIChannel::UpdateInterrupts()
|
||||
|
@ -87,18 +89,11 @@ void CEXIChannel::UpdateInterrupts()
|
|||
|
||||
bool CEXIChannel::IsCausingInterrupt()
|
||||
{
|
||||
if (m_ChannelId != 2) /* Channels 0 and 1: Memcard slot (device 0) produces interrupt */
|
||||
{
|
||||
for (int i = 0; i < NUM_DEVICES; i++)
|
||||
if (m_pDevices[i]->IsInterruptSet())
|
||||
m_Status.EXIINT = 1;
|
||||
}
|
||||
else /* Channel 2: In fact, Channel 0, Device 2 (Serial A) produces interrupt */
|
||||
{
|
||||
// WTF? this[-2]??? EVIL HACK
|
||||
if (this[-2].m_pDevices[2]->IsInterruptSet())
|
||||
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_Status.EXIINT & m_Status.EXIINTMASK) ||
|
||||
(m_Status.TCINT & m_Status.TCINTMASK) ||
|
||||
|
@ -134,22 +129,18 @@ void CEXIChannel::Update()
|
|||
|
||||
void CEXIChannel::Read32(u32& _uReturnValue, const u32 _iRegister)
|
||||
{
|
||||
DEBUG_LOG(EXPANSIONINTERFACE, "ExtensionInterface(R): channel: %i reg: %i", m_ChannelId, _iRegister);
|
||||
|
||||
switch (_iRegister)
|
||||
{
|
||||
case EXI_STATUS:
|
||||
{
|
||||
// check if a device is present
|
||||
for (int i = 0; i < NUM_DEVICES; i++)
|
||||
{
|
||||
if (m_pDevices[i]->IsPresent())
|
||||
{
|
||||
m_Status.EXT = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_uReturnValue = m_Status.hex;
|
||||
// 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;
|
||||
|
||||
_uReturnValue = m_Status.Hex;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -162,7 +153,7 @@ void CEXIChannel::Read32(u32& _uReturnValue, const u32 _iRegister)
|
|||
break;
|
||||
|
||||
case EXI_DMACONTROL:
|
||||
_uReturnValue = m_Control.hex;
|
||||
_uReturnValue = m_Control.Hex;
|
||||
break;
|
||||
|
||||
case EXI_IMMDATA:
|
||||
|
@ -174,11 +165,14 @@ void CEXIChannel::Read32(u32& _uReturnValue, const u32 _iRegister)
|
|||
_uReturnValue = 0xDEADBEEF;
|
||||
}
|
||||
|
||||
DEBUG_LOG(EXPANSIONINTERFACE, "(r32) 0x%08x channel: %i reg: %s",
|
||||
_uReturnValue, m_ChannelId, Debug_GetRegisterName(_iRegister));
|
||||
}
|
||||
|
||||
void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
|
||||
{
|
||||
INFO_LOG(EXPANSIONINTERFACE, "ExtensionInterface(W): 0x%08x channel: %i reg: %i", _iValue, m_ChannelId, _iRegister);
|
||||
DEBUG_LOG(EXPANSIONINTERFACE, "(w32) 0x%08x channel: %i reg: %s",
|
||||
_iValue, m_ChannelId, Debug_GetRegisterName(_iRegister));
|
||||
|
||||
switch (_iRegister)
|
||||
{
|
||||
|
@ -186,64 +180,45 @@ void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
|
|||
{
|
||||
UEXI_STATUS newStatus(_iValue);
|
||||
|
||||
// static
|
||||
m_Status.EXIINTMASK = newStatus.EXIINTMASK;
|
||||
if (newStatus.EXIINT) m_Status.EXIINT = 0;
|
||||
|
||||
m_Status.TCINTMASK = newStatus.TCINTMASK;
|
||||
m_Status.EXTINTMASK = newStatus.EXTINTMASK;
|
||||
if (newStatus.TCINT) m_Status.TCINT = 0;
|
||||
|
||||
m_Status.CLK = newStatus.CLK;
|
||||
m_Status.ROMDIS = newStatus.ROMDIS;
|
||||
|
||||
// Device
|
||||
if (m_Status.CHIP_SELECT != newStatus.CHIP_SELECT)
|
||||
if (m_ChannelId == 0 || m_ChannelId == 1)
|
||||
{
|
||||
for (int i = 0; i < NUM_DEVICES; i++)
|
||||
{
|
||||
u8 dwDeviceMask = 1 << i;
|
||||
IEXIDevice* pDevice = GetDevice(dwDeviceMask);
|
||||
if (pDevice != NULL)
|
||||
{
|
||||
if (((newStatus.CHIP_SELECT & dwDeviceMask) == dwDeviceMask) &&
|
||||
((m_Status.CHIP_SELECT & dwDeviceMask) == 0))
|
||||
// device gets activated
|
||||
pDevice->SetCS(1);
|
||||
|
||||
if (((newStatus.CHIP_SELECT & dwDeviceMask) == 0) &&
|
||||
((m_Status.CHIP_SELECT & dwDeviceMask) == dwDeviceMask))
|
||||
// device gets deactivated
|
||||
pDevice->SetCS(0);
|
||||
}
|
||||
}
|
||||
m_Status.CHIP_SELECT = newStatus.CHIP_SELECT;
|
||||
m_Status.EXTINTMASK = newStatus.EXTINTMASK;
|
||||
if (newStatus.EXTINT) m_Status.EXTINT = 0;
|
||||
}
|
||||
|
||||
// External Status
|
||||
IEXIDevice* pDevice = GetDevice(newStatus.CHIP_SELECT);
|
||||
if (pDevice != NULL)
|
||||
m_Status.EXT = pDevice->IsPresent() ? 1 : 0;
|
||||
else
|
||||
m_Status.EXT = 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);
|
||||
|
||||
// interrupt
|
||||
if (newStatus.EXIINT) m_Status.EXIINT = 0;
|
||||
if (newStatus.TCINT) m_Status.TCINT = 0;
|
||||
if (newStatus.EXTINT) m_Status.EXTINT = 0;
|
||||
UpdateInterrupts();
|
||||
}
|
||||
break;
|
||||
|
||||
case EXI_DMAADDR:
|
||||
INFO_LOG(EXPANSIONINTERFACE, "EXI: Wrote DMABuf, chan %i", m_ChannelId);
|
||||
INFO_LOG(EXPANSIONINTERFACE, "Wrote DMAAddr, chan %i", m_ChannelId);
|
||||
m_DMAMemoryAddress = _iValue;
|
||||
break;
|
||||
|
||||
case EXI_DMALENGTH:
|
||||
INFO_LOG(EXPANSIONINTERFACE, "EXI: Wrote DMASize, chan %i", m_ChannelId);
|
||||
INFO_LOG(EXPANSIONINTERFACE, "Wrote DMALength, chan %i", m_ChannelId);
|
||||
m_DMALength = _iValue;
|
||||
break;
|
||||
|
||||
case EXI_DMACONTROL:
|
||||
INFO_LOG(EXPANSIONINTERFACE, "EXI: Wrote DMAControl, chan %i", m_ChannelId);
|
||||
m_Control.hex = _iValue;
|
||||
INFO_LOG(EXPANSIONINTERFACE, "Wrote DMAControl, chan %i", m_ChannelId);
|
||||
m_Control.Hex = _iValue;
|
||||
|
||||
if (m_Control.TSTART)
|
||||
{
|
||||
|
@ -289,7 +264,7 @@ void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister)
|
|||
break;
|
||||
|
||||
case EXI_IMMDATA:
|
||||
INFO_LOG(EXPANSIONINTERFACE, "EXI: Wrote IMMData, chan %i", m_ChannelId);
|
||||
INFO_LOG(EXPANSIONINTERFACE, "Wrote IMMData, chan %i", m_ChannelId);
|
||||
m_ImmData = _iValue;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -38,33 +38,50 @@ private:
|
|||
EXI_DMACONTROL = 3,
|
||||
EXI_IMMDATA = 4
|
||||
};
|
||||
const char* Debug_GetRegisterName(u32 _register)
|
||||
{
|
||||
switch (_register)
|
||||
{
|
||||
case EXI_STATUS: return "STATUS";
|
||||
case EXI_DMAADDR: return "DMAADDR";
|
||||
case EXI_DMALENGTH: return "DMALENGTH";
|
||||
case EXI_DMACONTROL: return "DMACONTROL";
|
||||
case EXI_IMMDATA: return "IMMDATA";
|
||||
default: return "!!! Unknown EXI Register !!!";
|
||||
}
|
||||
}
|
||||
|
||||
// EXI Status Register
|
||||
// EXI Status Register - "Channel Parameter Register"
|
||||
union UEXI_STATUS
|
||||
{
|
||||
u32 hex;
|
||||
u32 Hex;
|
||||
// DO NOT obey the warning and give this struct a name. Things will fail.
|
||||
struct
|
||||
{
|
||||
unsigned EXIINTMASK : 1; //31
|
||||
unsigned EXIINT : 1; //30
|
||||
unsigned TCINTMASK : 1; //29
|
||||
unsigned TCINT : 1; //28
|
||||
unsigned CLK : 3; //27
|
||||
unsigned CHIP_SELECT : 3; //24
|
||||
unsigned EXTINTMASK : 1; //21
|
||||
unsigned EXTINT : 1; //20
|
||||
unsigned EXT : 1; //19 // External Insertion Status (1: External EXI device present)
|
||||
unsigned ROMDIS : 1; //18 // ROM Disable
|
||||
// Indentation Meaning:
|
||||
// Channels 0, 1, 2
|
||||
// Channels 0, 1 only
|
||||
// Channel 0 only
|
||||
unsigned EXIINTMASK : 1;
|
||||
unsigned EXIINT : 1;
|
||||
unsigned TCINTMASK : 1;
|
||||
unsigned TCINT : 1;
|
||||
unsigned CLK : 3;
|
||||
unsigned CHIP_SELECT : 3; // CS1 and CS2 are Channel 0 only
|
||||
unsigned EXTINTMASK : 1;
|
||||
unsigned EXTINT : 1;
|
||||
unsigned EXT : 1; // External Insertion Status (1: External EXI device present)
|
||||
unsigned ROMDIS : 1; // ROM Disable
|
||||
unsigned :18;
|
||||
}; // DO NOT obey the warning and give this struct a name. Things will fail.
|
||||
UEXI_STATUS() {hex = 0;}
|
||||
UEXI_STATUS(u32 _hex) {hex = _hex;}
|
||||
};
|
||||
UEXI_STATUS() {Hex = 0;}
|
||||
UEXI_STATUS(u32 _hex) {Hex = _hex;}
|
||||
};
|
||||
|
||||
// EXI Control Register
|
||||
union UEXI_CONTROL
|
||||
{
|
||||
u32 hex;
|
||||
u32 Hex;
|
||||
struct
|
||||
{
|
||||
unsigned TSTART : 1;
|
||||
|
@ -77,9 +94,9 @@ private:
|
|||
|
||||
// STATE_TO_SAVE
|
||||
UEXI_STATUS m_Status;
|
||||
UEXI_CONTROL m_Control;
|
||||
u32 m_DMAMemoryAddress;
|
||||
u32 m_DMALength;
|
||||
UEXI_CONTROL m_Control;
|
||||
u32 m_ImmData;
|
||||
|
||||
// Devices
|
||||
|
@ -90,13 +107,14 @@ private:
|
|||
|
||||
IEXIDevice* m_pDevices[NUM_DEVICES];
|
||||
|
||||
// Since channels operate a bit differently from each other
|
||||
u32 m_ChannelId;
|
||||
|
||||
public:
|
||||
// get device
|
||||
IEXIDevice* GetDevice(u8 _CHIP_SELECT);
|
||||
// channelId for debugging
|
||||
u32 m_ChannelId;
|
||||
|
||||
CEXIChannel();
|
||||
CEXIChannel(u32 ChannelId);
|
||||
~CEXIChannel();
|
||||
|
||||
void AddDevice(const TEXIDevices _device, const unsigned int _iSlot);
|
||||
|
@ -110,6 +128,9 @@ public:
|
|||
void Update();
|
||||
bool IsCausingInterrupt();
|
||||
void UpdateInterrupts();
|
||||
|
||||
// This should only be used to transition interrupts from SP1 to Channel 2
|
||||
void SetEXIINT(bool exiint) { m_Status.EXIINT = !!exiint; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -23,13 +23,13 @@
|
|||
#include "EXI_DeviceAD16.h"
|
||||
#include "EXI_DeviceMic.h"
|
||||
#include "EXI_DeviceEthernet.h"
|
||||
#include "EXI_DeviceAMBaseboard.h"
|
||||
|
||||
#include "../Core.h"
|
||||
#include "../ConfigManager.h"
|
||||
|
||||
|
||||
// --- interface IEXIDevice ---
|
||||
|
||||
void IEXIDevice::ImmWrite(u32 _uData, u32 _uSize)
|
||||
{
|
||||
while (_uSize--)
|
||||
|
@ -76,9 +76,9 @@ void IEXIDevice::DMARead(u32 _uAddr, u32 _uSize)
|
|||
|
||||
|
||||
// --- class CEXIDummy ---
|
||||
|
||||
// Just a dummy that logs reads and writes
|
||||
// to be used for EXI devices we haven't emulated
|
||||
// DOES NOT FUNCTION AS "NO DEVICE INSERTED" -> Appears as unknown device
|
||||
class CEXIDummy : public IEXIDevice
|
||||
{
|
||||
std::string m_strName;
|
||||
|
@ -94,15 +94,13 @@ public:
|
|||
virtual ~CEXIDummy(){}
|
||||
|
||||
void ImmWrite(u32 data, u32 size) {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmWrite: %08x", m_strName.c_str(), data);}
|
||||
u32 ImmRead (u32 size) {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmRead", m_strName.c_str()); return 0;}
|
||||
u32 ImmRead (u32 size) {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmRead", m_strName.c_str()); return 0;}
|
||||
void DMAWrite(u32 addr, u32 size) {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s DMAWrite: %08x bytes, from %08x to device", m_strName.c_str(), size, addr);}
|
||||
void DMARead (u32 addr, u32 size) {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s DMARead: %08x bytes, from device to %08x", m_strName.c_str(), size, addr);}
|
||||
};
|
||||
|
||||
|
||||
// F A C T O R Y
|
||||
|
||||
|
||||
IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice)
|
||||
{
|
||||
switch(_EXIDevice)
|
||||
|
@ -119,7 +117,7 @@ IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice)
|
|||
return new CEXIMemoryCard("MemoryCardB", SConfig::GetInstance().m_strMemoryCardB, 1);
|
||||
break;
|
||||
|
||||
case EXIDEVICE_IPL:
|
||||
case EXIDEVICE_MASKROM:
|
||||
return new CEXIIPL();
|
||||
break;
|
||||
|
||||
|
@ -135,6 +133,13 @@ IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice)
|
|||
return new CEXIETHERNET();
|
||||
break;
|
||||
|
||||
case EXIDEVICE_AM_BASEBOARD:
|
||||
return new CEXIAMBaseboard();
|
||||
break;
|
||||
|
||||
case EXIDEVICE_NONE:
|
||||
default:
|
||||
return new IEXIDevice();
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -53,13 +53,14 @@ enum TEXIDevices
|
|||
EXIDEVICE_DUMMY,
|
||||
EXIDEVICE_MEMORYCARD_A,
|
||||
EXIDEVICE_MEMORYCARD_B,
|
||||
EXIDEVICE_IPL,
|
||||
EXIDEVICE_MASKROM,
|
||||
EXIDEVICE_AD16,
|
||||
EXIDEVICE_MIC,
|
||||
EXIDEVICE_ETH,
|
||||
EXIDEVICE_AM_BASEBOARD,
|
||||
EXIDEVICE_NONE = (u8)-1
|
||||
};
|
||||
|
||||
extern IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "../Core.h"
|
||||
|
||||
#include "EXI_Device.h"
|
||||
#include "EXI_DeviceAMBaseboard.h"
|
||||
|
||||
CEXIAMBaseboard::CEXIAMBaseboard()
|
||||
: m_position(0)
|
||||
, m_have_irq(false)
|
||||
{
|
||||
}
|
||||
|
||||
void CEXIAMBaseboard::SetCS(int cs)
|
||||
{
|
||||
ERROR_LOG(SP1, "AM-BB ChipSelect=%d", cs);
|
||||
if (cs)
|
||||
m_position = 0;
|
||||
}
|
||||
|
||||
bool CEXIAMBaseboard::IsPresent()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void CEXIAMBaseboard::TransferByte(u8& _byte)
|
||||
{
|
||||
/*
|
||||
ID:
|
||||
00 00 xx xx xx xx
|
||||
xx xx 06 04 10 00
|
||||
CMD:
|
||||
01 00 00 b3 xx
|
||||
xx xx xx xx 04
|
||||
exi_lanctl_write:
|
||||
ff 02 01 63 xx
|
||||
xx xx xx xx 04
|
||||
exi_imr_read:
|
||||
86 00 00 f5 xx xx xx
|
||||
xx xx xx xx 04 rr rr
|
||||
exi_imr_write:
|
||||
87 80 5c 17 xx
|
||||
xx xx xx xx 04
|
||||
|
||||
exi_isr_read:
|
||||
82 .. .. .. xx xx xx
|
||||
xx xx xx xx 04 rr rr
|
||||
3 byte command, 1 byte checksum
|
||||
*/
|
||||
DEBUG_LOG(SP1, "AM-BB > %02x", _byte);
|
||||
if (m_position < 4)
|
||||
{
|
||||
m_command[m_position] = _byte;
|
||||
_byte = 0xFF;
|
||||
}
|
||||
|
||||
if ((m_position >= 2) && (m_command[0] == 0 && m_command[1] == 0))
|
||||
_byte = "\x06\x04\x10\x00"[(m_position-2)&3];
|
||||
else if (m_position == 3)
|
||||
{
|
||||
unsigned int checksum = (m_command[0] << 24) | (m_command[1] << 16) | (m_command[2] << 8);
|
||||
unsigned int bit = 0x80000000UL;
|
||||
unsigned int check = 0x8D800000UL;
|
||||
while (bit >= 0x100)
|
||||
{
|
||||
if (checksum & bit)
|
||||
checksum ^= check;
|
||||
check >>= 1;
|
||||
bit >>= 1;
|
||||
}
|
||||
if (m_command[3] != (checksum & 0xFF))
|
||||
ERROR_LOG(SP1, "AM-BB cs: %02x, w: %02x", m_command[3], checksum & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_position == 4)
|
||||
{
|
||||
_byte = 4;
|
||||
ERROR_LOG(SP1, "AM-BB COMMAND: %02x %02x %02x", m_command[0], m_command[1], m_command[2]);
|
||||
if ((m_command[0] == 0xFF) && (m_command[1] == 0) && (m_command[2] == 0))
|
||||
m_have_irq = true;
|
||||
else if (m_command[0] == 0x82)
|
||||
m_have_irq = false;
|
||||
}
|
||||
else if (m_position > 4)
|
||||
{
|
||||
switch (m_command[0])
|
||||
{
|
||||
case 0xFF: // lan
|
||||
_byte = 0xFF;
|
||||
break;
|
||||
case 0x86: // imr
|
||||
_byte = 0x00;
|
||||
break;
|
||||
case 0x82: // isr
|
||||
_byte = m_have_irq ? 0xFF : 0;
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(SP1, 0, "Unknown AM-BB cmd");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
_byte = 0xFF;
|
||||
}
|
||||
DEBUG_LOG(SP1, "AM-BB < %02x", _byte);
|
||||
m_position++;
|
||||
}
|
||||
|
||||
bool CEXIAMBaseboard::IsInterruptSet()
|
||||
{
|
||||
if (m_have_irq)
|
||||
ERROR_LOG(SP1, "AM-BB IRQ");
|
||||
return m_have_irq;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _EXIDEVICE_AMBASEBOARD_H
|
||||
#define _EXIDEVICE_AMBASEBOARD_H
|
||||
|
||||
class CEXIAMBaseboard : public IEXIDevice
|
||||
{
|
||||
public:
|
||||
CEXIAMBaseboard();
|
||||
|
||||
virtual void SetCS(int _iCS);
|
||||
virtual bool IsPresent();
|
||||
virtual bool IsInterruptSet();
|
||||
|
||||
private:
|
||||
virtual void TransferByte(u8& _uByte);
|
||||
int m_position;
|
||||
bool m_have_irq;
|
||||
unsigned char m_command[4];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -286,9 +286,23 @@ void CEXIMemoryCard::TransferByte(u8 &byte)
|
|||
command = byte; // first byte is command
|
||||
byte = 0xFF; // would be tristate, but we don't care.
|
||||
|
||||
switch (command)
|
||||
switch (command) // This seems silly, do we really need it?
|
||||
{
|
||||
case 0x52:
|
||||
case cmdNintendoID:
|
||||
case cmdReadArray:
|
||||
case cmdArrayToBuffer:
|
||||
case cmdSetInterrupt:
|
||||
case cmdWriteBuffer:
|
||||
case cmdReadStatus:
|
||||
case cmdReadID:
|
||||
case cmdReadErrorBuffer:
|
||||
case cmdWakeUp:
|
||||
case cmdSleep:
|
||||
case cmdClearStatus:
|
||||
case cmdSectorErase:
|
||||
case cmdPageProgram:
|
||||
case cmdExtraByteProgram:
|
||||
case cmdChipErase:
|
||||
INFO_LOG(EXPANSIONINTERFACE, "EXI MEMCARD: command %02x at position 0. seems normal.", command);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -57,11 +57,11 @@ private:
|
|||
cmdArrayToBuffer = 0x53,
|
||||
cmdSetInterrupt = 0x81,
|
||||
cmdWriteBuffer = 0x82,
|
||||
cmdReadStatus = 0x83,
|
||||
cmdReadStatus = 0x83,
|
||||
cmdReadID = 0x85,
|
||||
cmdReadErrorBuffer = 0x86,
|
||||
cmdWakeUp = 0x87,
|
||||
cmdSleep = 0x88,
|
||||
cmdSleep = 0x88,
|
||||
cmdClearStatus = 0x89,
|
||||
cmdSectorErase = 0xF1,
|
||||
cmdPageProgram = 0xF2,
|
||||
|
|
|
@ -275,9 +275,9 @@ void Read32(u32& _uReturnValue, const u32 _iAddress)
|
|||
// registers
|
||||
switch (_iAddress & 0x3FF)
|
||||
{
|
||||
|
||||
// Channel 0
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Channel 0
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
case SI_CHANNEL_0_OUT:
|
||||
_uReturnValue = g_Channel[0].m_Out.Hex;
|
||||
return;
|
||||
|
@ -294,9 +294,9 @@ void Read32(u32& _uReturnValue, const u32 _iAddress)
|
|||
_uReturnValue = g_Channel[0].m_InLo.Hex;
|
||||
return;
|
||||
|
||||
|
||||
// Channel 1
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Channel 1
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
case SI_CHANNEL_1_OUT:
|
||||
_uReturnValue = g_Channel[1].m_Out.Hex;
|
||||
return;
|
||||
|
@ -313,9 +313,9 @@ void Read32(u32& _uReturnValue, const u32 _iAddress)
|
|||
_uReturnValue = g_Channel[1].m_InLo.Hex;
|
||||
return;
|
||||
|
||||
|
||||
// Channel 2
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Channel 2
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
case SI_CHANNEL_2_OUT:
|
||||
_uReturnValue = g_Channel[2].m_Out.Hex;
|
||||
return;
|
||||
|
@ -332,9 +332,9 @@ void Read32(u32& _uReturnValue, const u32 _iAddress)
|
|||
_uReturnValue = g_Channel[2].m_InLo.Hex;
|
||||
return;
|
||||
|
||||
|
||||
// Channel 3
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Channel 3
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
case SI_CHANNEL_3_OUT:
|
||||
_uReturnValue = g_Channel[3].m_Out.Hex;
|
||||
return;
|
||||
|
@ -351,6 +351,9 @@ void Read32(u32& _uReturnValue, const u32 _iAddress)
|
|||
_uReturnValue = g_Channel[3].m_InLo.Hex;
|
||||
return;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Other
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
case SI_POLL: _uReturnValue = g_Poll.Hex; return;
|
||||
case SI_COM_CSR: _uReturnValue = g_ComCSR.Hex; return;
|
||||
case SI_STATUS_REG: _uReturnValue = g_StatusReg.Hex; return;
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
#include "SI_Device.h"
|
||||
#include "SI_DeviceGCController.h"
|
||||
#include "SI_DeviceGBA.h"
|
||||
#include "SI_DeviceAMBaseboard.h"
|
||||
|
||||
|
||||
// --- interface ISIDevice ---
|
||||
|
||||
int ISIDevice::RunBuffer(u8* _pBuffer, int _iLength)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
|
@ -49,10 +49,9 @@ int ISIDevice::RunBuffer(u8* _pBuffer, int _iLength)
|
|||
|
||||
|
||||
// --- class CSIDummy ---
|
||||
|
||||
// Just a dummy that logs reads and writes
|
||||
// to be used for SI devices we haven't emulated
|
||||
// and hopefully as an "emtpy" device
|
||||
// DOES NOT FUNCTION AS "NO DEVICE INSERTED" -> Appears as unknown device
|
||||
class CSIDevice_Dummy : public ISIDevice
|
||||
{
|
||||
public:
|
||||
|
@ -71,14 +70,12 @@ public:
|
|||
return 4;
|
||||
}
|
||||
|
||||
bool GetData(u32& _Hi, u32& _Low) {INFO_LOG(SERIALINTERFACE, "SI DUMMY %i GetData", this->m_iDeviceNumber); return false;}
|
||||
void SendCommand(u32 _Cmd, u8 _Poll){INFO_LOG(SERIALINTERFACE, "SI DUMMY %i SendCommand: %08x", this->m_iDeviceNumber, _Cmd);}
|
||||
bool GetData(u32& _Hi, u32& _Low) {DEBUG_LOG(SERIALINTERFACE, "SI DUMMY %i GetData", this->m_iDeviceNumber); return false;}
|
||||
void SendCommand(u32 _Cmd, u8 _Poll){DEBUG_LOG(SERIALINTERFACE, "SI DUMMY %i SendCommand: %08x", this->m_iDeviceNumber, _Cmd);}
|
||||
};
|
||||
|
||||
|
||||
// F A C T O R Y
|
||||
|
||||
|
||||
ISIDevice* SIDevice_Create(TSIDevices _SIDevice, int _iDeviceNumber)
|
||||
{
|
||||
switch(_SIDevice)
|
||||
|
@ -95,6 +92,10 @@ ISIDevice* SIDevice_Create(TSIDevices _SIDevice, int _iDeviceNumber)
|
|||
return new CSIDevice_GBA(_iDeviceNumber);
|
||||
break;
|
||||
|
||||
case SI_AM_BASEBOARD:
|
||||
return new CSIDevice_AMBaseboard(_iDeviceNumber);
|
||||
break;
|
||||
|
||||
default:
|
||||
return new CSIDevice_Dummy(_iDeviceNumber);
|
||||
break;
|
||||
|
|
|
@ -69,6 +69,7 @@ enum TSIDevices
|
|||
SI_GC_CONTROLLER = (SI_TYPE_GC | SI_GC_STANDARD),
|
||||
SI_GC_KEYBOARD = (SI_TYPE_GC | 0x00200000),
|
||||
SI_GC_STEERING = SI_TYPE_GC, // (shuffle2)I think the "chainsaw" is the same (Or else it's just standard)
|
||||
SI_AM_BASEBOARD = 0x10110800 // gets ORd with dipswitch state
|
||||
};
|
||||
|
||||
extern ISIDevice* SIDevice_Create(TSIDevices _SIDevice, int _iDeviceNumber);
|
||||
|
|
|
@ -0,0 +1,469 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include "SI.h"
|
||||
#include "SI_Device.h"
|
||||
#include "SI_DeviceAMBaseboard.h"
|
||||
|
||||
#include "../PluginManager.h" // for pad state
|
||||
|
||||
// where to put baseboard debug
|
||||
#define AMBASEBOARDDEBUG OSREPORT
|
||||
|
||||
class JVSIOMessage
|
||||
{
|
||||
public:
|
||||
int m_ptr, m_last_start, m_csum;
|
||||
unsigned char m_msg[0x80];
|
||||
|
||||
JVSIOMessage()
|
||||
{
|
||||
m_ptr = 0;
|
||||
m_last_start = 0;
|
||||
}
|
||||
|
||||
void start(int node)
|
||||
{
|
||||
m_last_start = m_ptr;
|
||||
unsigned char hdr[3] = {0xe0, node, 0};
|
||||
m_csum = 0;
|
||||
addData(hdr, 3, 1);
|
||||
}
|
||||
void addData(void *data, int len)
|
||||
{
|
||||
addData((unsigned char*)data, len);
|
||||
}
|
||||
void addData(char *data)
|
||||
{
|
||||
addData(data, strlen(data));
|
||||
}
|
||||
void addData(int n)
|
||||
{
|
||||
unsigned char cs = n;
|
||||
addData(&cs, 1);
|
||||
}
|
||||
|
||||
void end()
|
||||
{
|
||||
int len = m_ptr - m_last_start;
|
||||
m_msg[m_last_start + 2] = len - 2; // assuming len <0xD0
|
||||
addData(m_csum + len - 2);
|
||||
}
|
||||
|
||||
void addData(unsigned char *dst, int len, int sync = 0)
|
||||
{
|
||||
while (len--)
|
||||
{
|
||||
int c = *dst++;
|
||||
if (!sync && ((c == 0xE0) || (c == 0xD0)))
|
||||
{
|
||||
m_msg[m_ptr++] = 0xD0;
|
||||
m_msg[m_ptr++] = c - 1;
|
||||
} else
|
||||
m_msg[m_ptr++] = c;
|
||||
if (!sync)
|
||||
m_csum += c;
|
||||
sync = 0;
|
||||
if (m_ptr >= 0x80)
|
||||
PanicAlert("JVSIOMessage overrun!");
|
||||
}
|
||||
}
|
||||
}; // end class JVSIOMessage
|
||||
|
||||
CSIDevice_AMBaseboard::CSIDevice_AMBaseboard(int _iDeviceNumber)
|
||||
: ISIDevice(_iDeviceNumber)
|
||||
{
|
||||
}
|
||||
|
||||
int CSIDevice_AMBaseboard::RunBuffer(u8* _pBuffer, int _iLength)
|
||||
{
|
||||
// for debug logging only
|
||||
ISIDevice::RunBuffer(_pBuffer, _iLength);
|
||||
|
||||
int iPosition = 0;
|
||||
while(iPosition < _iLength)
|
||||
{
|
||||
// read the command
|
||||
EBufferCommands command = static_cast<EBufferCommands>(_pBuffer[iPosition ^ 3]);
|
||||
iPosition ++;
|
||||
|
||||
// handle it
|
||||
switch(command)
|
||||
{
|
||||
case CMD_RESET: // returns ID and dip switches
|
||||
{
|
||||
*(u32*)&_pBuffer[0] = SI_AM_BASEBOARD|0x100; // 0x100 is progressive flag according to dip switch
|
||||
iPosition = _iLength; // break the while loop
|
||||
}
|
||||
break;
|
||||
case CMD_GCAM:
|
||||
{
|
||||
int i;
|
||||
|
||||
// calculate checksum over buffer
|
||||
int csum = 0;
|
||||
for (i=0; i<_iLength; ++i)
|
||||
csum += _pBuffer[i];
|
||||
|
||||
unsigned char res[0x80];
|
||||
int resp = 0;
|
||||
|
||||
int real_len = _pBuffer[1^3];
|
||||
int p = 2;
|
||||
|
||||
static int d10_1 = 0xfe;
|
||||
|
||||
memset(res, 0, 0x80);
|
||||
res[resp++] = 1;
|
||||
res[resp++] = 1;
|
||||
|
||||
#define ptr(x) _pBuffer[(p + x)^3]
|
||||
while (p < real_len+2)
|
||||
{
|
||||
switch (ptr(0))
|
||||
{
|
||||
case 0x10:
|
||||
{
|
||||
DEBUG_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 10, %02x (READ STATUS&SWITCHES)", ptr(1));
|
||||
SPADStatus PadStatus;
|
||||
memset(&PadStatus, 0 ,sizeof(PadStatus));
|
||||
CPluginManager::GetInstance().GetPad(ISIDevice::m_iDeviceNumber)
|
||||
->PAD_GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus);
|
||||
res[resp++] = 0x10;
|
||||
res[resp++] = 0x2;
|
||||
int d10_0 = 0xdf;
|
||||
|
||||
if (PadStatus.triggerLeft)
|
||||
d10_0 &= ~0x80;
|
||||
if (PadStatus.triggerRight)
|
||||
d10_0 &= ~0x40;
|
||||
|
||||
res[resp++] = d10_0;
|
||||
res[resp++] = d10_1;
|
||||
break;
|
||||
}
|
||||
case 0x12:
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 12, %02x %02x", ptr(1), ptr(2));
|
||||
res[resp++] = 0x12;
|
||||
res[resp++] = 0x00;
|
||||
break;
|
||||
case 0x11:
|
||||
{
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 11, %02x (READ SERIAL NR)", ptr(1));
|
||||
char string[] = "AADE-01A14964511";
|
||||
res[resp++] = 0x11;
|
||||
res[resp++] = 0x10;
|
||||
memcpy(res + resp, string, 0x10);
|
||||
resp += 0x10;
|
||||
break;
|
||||
}
|
||||
case 0x15:
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 15, %02x (READ FIRM VERSION)", ptr(1));
|
||||
res[resp++] = 0x15;
|
||||
res[resp++] = 0x02;
|
||||
res[resp++] = 0x00;
|
||||
res[resp++] = 0x29; // FIRM VERSION
|
||||
break;
|
||||
case 0x16:
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 16, %02x (READ FPGA VERSION)", ptr(1));
|
||||
res[resp++] = 0x16;
|
||||
res[resp++] = 0x02;
|
||||
res[resp++] = 0x07;
|
||||
res[resp++] = 0x06; // FPGAVERSION
|
||||
/*
|
||||
res[resp++] = 0x16;
|
||||
res[resp++] = 0x00;
|
||||
p += 2;
|
||||
*/
|
||||
break;
|
||||
case 0x1f:
|
||||
{
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 1f, %02x %02x %02x %02x %02x (REGION)", ptr(1), ptr(2), ptr(3), ptr(4), ptr(5));
|
||||
unsigned char string[] =
|
||||
"\x00\x00\x30\x00"
|
||||
//"\x01\xfe\x00\x00" // JAPAN
|
||||
"\x02\xfd\x00\x00" // USA
|
||||
//"\x03\xfc\x00\x00" // export
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
|
||||
res[resp++] = 0x1f;
|
||||
res[resp++] = 0x14;
|
||||
|
||||
for (i=0; i<0x14; ++i)
|
||||
res[resp++] = string[i];
|
||||
break;
|
||||
}
|
||||
case 0x31:
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 31 (UNKNOWN)");
|
||||
res[resp++] = 0x31;
|
||||
res[resp++] = 0x02;
|
||||
res[resp++] = 0x00;
|
||||
res[resp++] = 0x00;
|
||||
break;
|
||||
case 0x32:
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 32 (UNKNOWN)");
|
||||
res[resp++] = 0x32;
|
||||
res[resp++] = 0x02;
|
||||
res[resp++] = 0x00;
|
||||
res[resp++] = 0x00;
|
||||
break;
|
||||
case 0x40:
|
||||
case 0x41:
|
||||
case 0x42:
|
||||
case 0x43:
|
||||
case 0x44:
|
||||
case 0x45:
|
||||
case 0x46:
|
||||
case 0x47:
|
||||
case 0x48:
|
||||
case 0x49:
|
||||
case 0x4a:
|
||||
case 0x4b:
|
||||
case 0x4c:
|
||||
case 0x4d:
|
||||
case 0x4e:
|
||||
case 0x4f:
|
||||
{
|
||||
DEBUG_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD %02x, %02x %02x %02x %02x %02x %02x %02x (JVS IO)",
|
||||
ptr(0), ptr(1), ptr(2), ptr(3), ptr(4), ptr(5), ptr(6), ptr(7));
|
||||
int total_length = ptr(1);
|
||||
int pptr = 2;
|
||||
JVSIOMessage msg;
|
||||
|
||||
msg.start(0);
|
||||
msg.addData(1);
|
||||
|
||||
unsigned char jvs_io_buffer[0x80];
|
||||
int nr_bytes = ptr(pptr + 2); // byte after e0 xx
|
||||
int jvs_io_length = 0;
|
||||
for (i=0; i<nr_bytes + 3; ++i)
|
||||
jvs_io_buffer[jvs_io_length++] = ptr(pptr + i);
|
||||
int ptr = 0;
|
||||
int node = jvs_io_buffer[1];
|
||||
|
||||
unsigned char *jvs_io = jvs_io_buffer + 3;
|
||||
jvs_io_length--; // checksum
|
||||
while (jvs_io < (jvs_io_buffer + jvs_io_length))
|
||||
{
|
||||
|
||||
int cmd = *jvs_io++;
|
||||
int unknown = 0;
|
||||
DEBUG_LOG(AMBASEBOARDDEBUG, "JVS IO, node=%d, cmd=%02x", node, cmd);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case 0x10: // get ID
|
||||
msg.addData(1);
|
||||
{
|
||||
char buffer[12];
|
||||
sprintf(buffer, "JVS-node %02x", node);
|
||||
//msg.addData(buffer);
|
||||
msg.addData("JAMMA I/O CONTROLLER");
|
||||
}
|
||||
msg.addData(0);
|
||||
break;
|
||||
case 0x11: // cmd revision
|
||||
msg.addData(1);
|
||||
msg.addData(0x11);
|
||||
break;
|
||||
case 0x12: // jvs revision
|
||||
msg.addData(1);
|
||||
msg.addData(0x12);
|
||||
break;
|
||||
case 0x13: // com revision
|
||||
msg.addData(1);
|
||||
msg.addData(0x13);
|
||||
break;
|
||||
case 0x14: // get features
|
||||
msg.addData(1);
|
||||
msg.addData("\x01\x02\x0a\x00", 4); // 2 player, 10 bit
|
||||
msg.addData("\x02\x02\x00\x00", 4); // 2 coin slots
|
||||
//msg.addData("\x03\x02\x08\x00", 4);
|
||||
msg.addData("\x00\x00\x00\x00", 4);
|
||||
break;
|
||||
case 0x15:
|
||||
while (*jvs_io++);
|
||||
msg.addData(1);
|
||||
break;
|
||||
case 0x20:
|
||||
{
|
||||
int nr_players = *jvs_io++;
|
||||
int bytes_per_player = *jvs_io++; /* ??? */
|
||||
int i, j;
|
||||
msg.addData(1);
|
||||
|
||||
msg.addData(0); // tilt
|
||||
for (i=0; i<nr_players; ++i)
|
||||
{
|
||||
SPADStatus PadStatus;
|
||||
CPluginManager::GetInstance().GetPad(i)
|
||||
->PAD_GetStatus(i, &PadStatus);
|
||||
unsigned char player_data[2] = {0,0};
|
||||
if (PadStatus.button & PAD_BUTTON_START)
|
||||
player_data[0] |= 0x80;
|
||||
if (PadStatus.button & PAD_BUTTON_UP)
|
||||
player_data[0] |= 0x20;
|
||||
if (PadStatus.button & PAD_BUTTON_DOWN)
|
||||
player_data[0] |= 0x10;
|
||||
if (PadStatus.button & PAD_BUTTON_LEFT)
|
||||
player_data[0] |= 0x08;
|
||||
if (PadStatus.button & PAD_BUTTON_RIGHT)
|
||||
player_data[0] |= 0x04;
|
||||
|
||||
if (PadStatus.button & PAD_BUTTON_A)
|
||||
player_data[0] |= 0x02;
|
||||
if (PadStatus.button & PAD_BUTTON_B)
|
||||
player_data[0] |= 0x01;
|
||||
|
||||
if (PadStatus.button & PAD_BUTTON_X)
|
||||
player_data[1] |= 0x80;
|
||||
if (PadStatus.button & PAD_BUTTON_Y)
|
||||
player_data[1] |= 0x40;
|
||||
if (PadStatus.button & PAD_TRIGGER_L)
|
||||
player_data[1] |= 0x20;
|
||||
if (PadStatus.button & PAD_TRIGGER_R)
|
||||
player_data[1] |= 0x10;
|
||||
|
||||
for (j=0; j<bytes_per_player; ++j)
|
||||
msg.addData(player_data[j&1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x21: // coin
|
||||
{
|
||||
int slots = *jvs_io++;
|
||||
msg.addData(1);
|
||||
SPADStatus PadStatus;
|
||||
CPluginManager::GetInstance().GetPad(0)
|
||||
->PAD_GetStatus(0, &PadStatus);
|
||||
while (slots--)
|
||||
{
|
||||
msg.addData(0);
|
||||
msg.addData((PadStatus.button & PAD_BUTTON_START) ? 1 : 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x22: // analog
|
||||
{
|
||||
break;
|
||||
}
|
||||
case 0xf0:
|
||||
if (*jvs_io++ == 0xD9)
|
||||
{
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "JVS RESET");
|
||||
} else
|
||||
unknown = 1;
|
||||
msg.addData(1);
|
||||
|
||||
d10_1 |= 1;
|
||||
break;
|
||||
case 0xf1:
|
||||
node = *jvs_io++;
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "JVS SET ADDRESS, node=%d", node);
|
||||
msg.addData(node == 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
pptr += jvs_io_length;
|
||||
|
||||
}
|
||||
|
||||
msg.end();
|
||||
|
||||
res[resp++] = ptr(0);
|
||||
|
||||
unsigned char *buf = msg.m_msg;
|
||||
int len = msg.m_ptr;
|
||||
res[resp++] = len;
|
||||
for (i=0; i<len; ++i)
|
||||
res[resp++] = buf[i];
|
||||
break;
|
||||
}
|
||||
case 0x60:
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD 60, %02x %02x %02x", ptr(1), ptr(2), ptr(3));
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(AMBASEBOARDDEBUG, "GC-AM: CMD %02x (unknown) %02x %02x %02x %02x %02x", ptr(0), ptr(1), ptr(2), ptr(3), ptr(4), ptr(5));
|
||||
break;
|
||||
}
|
||||
p += ptr(1) + 2;
|
||||
}
|
||||
memset(_pBuffer, 0, _iLength);
|
||||
|
||||
int len = resp - 2;
|
||||
|
||||
p = 0;
|
||||
res[1] = len;
|
||||
csum = 0;
|
||||
char logptr[1024];
|
||||
char *log = logptr;
|
||||
for (i=0; i<0x7F; ++i)
|
||||
{
|
||||
csum += ptr(i) = res[i];
|
||||
log += sprintf(log, "%02x ", ptr(i));
|
||||
}
|
||||
ptr(0x7f) = ~csum;
|
||||
DEBUG_LOG(AMBASEBOARDDEBUG, "command send back: %s", logptr);
|
||||
#undef ptr
|
||||
|
||||
|
||||
// (tmbinc) hotfix: delay output by one command to work around their broken parser. this took me a month to find. ARG!
|
||||
static unsigned char last[2][0x80];
|
||||
static int lastptr[2];
|
||||
|
||||
{
|
||||
memcpy(last + 1, _pBuffer, 0x80);
|
||||
memcpy(_pBuffer, last, 0x80);
|
||||
memcpy(last, last + 1, 0x80);
|
||||
|
||||
lastptr[1] = _iLength;
|
||||
_iLength = lastptr[0];
|
||||
lastptr[0] = lastptr[1];
|
||||
}
|
||||
|
||||
iPosition = _iLength;
|
||||
break;
|
||||
}
|
||||
// DEFAULT
|
||||
default:
|
||||
{
|
||||
ERROR_LOG(SERIALINTERFACE, "unknown SI command (0x%x)", command);
|
||||
PanicAlert("SI: Unknown command");
|
||||
iPosition = _iLength;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return iPosition;
|
||||
}
|
||||
|
||||
// Not really used on GC-AM
|
||||
bool CSIDevice_AMBaseboard::GetData(u32& _Hi, u32& _Low)
|
||||
{
|
||||
_Low = 0;
|
||||
_Hi = 0x00800000;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSIDevice_AMBaseboard::SendCommand(u32 _Cmd, u8 _Poll)
|
||||
{
|
||||
ERROR_LOG(SERIALINTERFACE, "unknown direct command (0x%x)", _Cmd);
|
||||
PanicAlert("SI: (GCAM) Unknown direct command");
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _SIDEVICE_AMBASEBOARD_H
|
||||
#define _SIDEVICE_AMBASEBOARD_H
|
||||
|
||||
// triforce (GC-AM) baseboard
|
||||
class CSIDevice_AMBaseboard : public ISIDevice
|
||||
{
|
||||
private:
|
||||
enum EBufferCommands
|
||||
{
|
||||
CMD_RESET = 0x00,
|
||||
CMD_GCAM = 0x70,
|
||||
};
|
||||
|
||||
public:
|
||||
// constructor
|
||||
CSIDevice_AMBaseboard(int _iDeviceNumber);
|
||||
|
||||
// run the SI Buffer
|
||||
virtual int RunBuffer(u8* _pBuffer, int _iLength);
|
||||
|
||||
// return true on new data
|
||||
virtual bool GetData(u32& _Hi, u32& _Low);
|
||||
|
||||
// send a command directly
|
||||
virtual void SendCommand(u32 _Cmd, u8 _Poll);
|
||||
};
|
||||
|
||||
#endif // _SIDEVICE_AMBASEBOARD_H
|
|
@ -37,6 +37,7 @@ files = ["ActionReplay.cpp",
|
|||
"HW/EXI_Device.cpp",
|
||||
"HW/EXI_DeviceIPL.cpp",
|
||||
"HW/EXI_DeviceAD16.cpp",
|
||||
"HW/EXI_DeviceAMBaseboard.cpp",
|
||||
"HW/EXI_DeviceMemoryCard.cpp",
|
||||
"HW/EXI_DeviceMic.cpp",
|
||||
"HW/EXI_DeviceEthernet.cpp",
|
||||
|
@ -48,6 +49,7 @@ files = ["ActionReplay.cpp",
|
|||
"HW/ProcessorInterface.cpp",
|
||||
"HW/SI.cpp",
|
||||
"HW/SI_Device.cpp",
|
||||
"HW/SI_DeviceAMBaseboard.cpp",
|
||||
"HW/SI_DeviceGBA.cpp",
|
||||
"HW/GBAPipe.cpp", # TEMPORARY
|
||||
"HW/SI_DeviceGCController.cpp",
|
||||
|
|
|
@ -32,6 +32,19 @@
|
|||
|
||||
extern CFrame* main_frame;
|
||||
|
||||
// Strings for Device Selections
|
||||
#define DEV_NONE_STR "<Nothing>"
|
||||
#define DEV_DUMMY_STR "Dummy"
|
||||
|
||||
#define SIDEV_STDCONT_STR "Standard Controller"
|
||||
#define SIDEV_GBA_STR "GBA"
|
||||
#define SIDEV_AM_BB_STR "AM-Baseboard"
|
||||
|
||||
#define EXIDEV_MEMCARD_STR "Memory Card"
|
||||
#define EXIDEV_MIC_STR "Mic"
|
||||
#define EXIDEV_BBA_STR "BBA"
|
||||
#define EXIDEV_AM_BB_STR "AM-Baseboard"
|
||||
|
||||
|
||||
BEGIN_EVENT_TABLE(CConfigMain, wxDialog)
|
||||
|
||||
|
@ -352,10 +365,10 @@ void CConfigMain::CreateGUIControls()
|
|||
GCEXIDeviceText[0] = new wxStaticText(GamecubePage, ID_GC_EXIDEVICE_SLOTA_TEXT, wxT("Slot A"), wxDefaultPosition, wxDefaultSize);
|
||||
GCEXIDeviceText[1] = new wxStaticText(GamecubePage, ID_GC_EXIDEVICE_SLOTB_TEXT, wxT("Slot B"), wxDefaultPosition, wxDefaultSize);
|
||||
GCEXIDeviceText[2] = new wxStaticText(GamecubePage, ID_GC_EXIDEVICE_SP1_TEXT, wxT("SP1 "), wxDefaultPosition, wxDefaultSize);
|
||||
GCEXIDeviceText[2]->SetToolTip(wxT("Serial Port 1 - This is the port the network adapter uses"));
|
||||
const wxString SlotDevices[] = {wxT("<Nothing>"),wxT("Memory Card"), wxT("Mic")};
|
||||
GCEXIDeviceText[2]->SetToolTip(wxT("Serial Port 1 - This is the port which devices such as the net adapter use"));
|
||||
const wxString SlotDevices[] = {wxT(DEV_NONE_STR),wxT(DEV_DUMMY_STR),wxT(EXIDEV_MEMCARD_STR), wxT(EXIDEV_MIC_STR)};
|
||||
static const int numSlotDevices = sizeof(SlotDevices)/sizeof(wxString);
|
||||
const wxString SP1Devices[] = {wxT("<Nothing>"),wxT("BBA")};
|
||||
const wxString SP1Devices[] = {wxT(DEV_NONE_STR),wxT(DEV_DUMMY_STR),wxT(EXIDEV_BBA_STR),wxT(EXIDEV_AM_BB_STR)};
|
||||
static const int numSP1Devices = sizeof(SP1Devices)/sizeof(wxString);
|
||||
GCEXIDevice[0] = new wxChoice(GamecubePage, ID_GC_EXIDEVICE_SLOTA, wxDefaultPosition, wxDefaultSize, numSlotDevices, SlotDevices, 0, wxDefaultValidator);
|
||||
GCEXIDevice[1] = new wxChoice(GamecubePage, ID_GC_EXIDEVICE_SLOTB, wxDefaultPosition, wxDefaultSize, numSlotDevices, SlotDevices, 0, wxDefaultValidator);
|
||||
|
@ -365,16 +378,29 @@ void CConfigMain::CreateGUIControls()
|
|||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
bool isMemcard = false;
|
||||
if (SConfig::GetInstance().m_EXIDevice[i] == EXIDEVICE_MEMORYCARD_A)
|
||||
isMemcard = GCEXIDevice[i]->SetStringSelection(SlotDevices[1]);
|
||||
else if (SConfig::GetInstance().m_EXIDevice[i] == EXIDEVICE_MEMORYCARD_B)
|
||||
isMemcard = GCEXIDevice[i]->SetStringSelection(SlotDevices[1]);
|
||||
else if (SConfig::GetInstance().m_EXIDevice[i] == EXIDEVICE_MIC)
|
||||
GCEXIDevice[i]->SetStringSelection(SlotDevices[2]);
|
||||
else if (SConfig::GetInstance().m_EXIDevice[i] == EXIDEVICE_ETH)
|
||||
GCEXIDevice[i]->SetStringSelection(SP1Devices[1]);
|
||||
else
|
||||
GCEXIDevice[i]->SetStringSelection(wxT("<Nothing>"));
|
||||
switch (SConfig::GetInstance().m_EXIDevice[i])
|
||||
{
|
||||
case EXIDEVICE_NONE:
|
||||
GCEXIDevice[i]->SetStringSelection(SlotDevices[0]);
|
||||
break;
|
||||
case EXIDEVICE_MEMORYCARD_A:
|
||||
case EXIDEVICE_MEMORYCARD_B:
|
||||
isMemcard = GCEXIDevice[i]->SetStringSelection(SlotDevices[2]);
|
||||
break;
|
||||
case EXIDEVICE_MIC:
|
||||
GCEXIDevice[i]->SetStringSelection(SlotDevices[3]);
|
||||
break;
|
||||
case EXIDEVICE_ETH:
|
||||
GCEXIDevice[i]->SetStringSelection(SP1Devices[2]);
|
||||
break;
|
||||
case EXIDEVICE_AM_BASEBOARD:
|
||||
GCEXIDevice[i]->SetStringSelection(SP1Devices[3]);
|
||||
break;
|
||||
case EXIDEVICE_DUMMY:
|
||||
default:
|
||||
GCEXIDevice[i]->SetStringSelection(SlotDevices[1]);
|
||||
break;
|
||||
}
|
||||
if (!isMemcard && i < 2)
|
||||
GCMemcardPath[i]->Disable();
|
||||
}
|
||||
|
@ -384,7 +410,7 @@ void CConfigMain::CreateGUIControls()
|
|||
GCSIDeviceText[1] = new wxStaticText(GamecubePage, ID_GC_SIDEVICE_TEXT, wxT("Port 2"), wxDefaultPosition, wxDefaultSize);
|
||||
GCSIDeviceText[2] = new wxStaticText(GamecubePage, ID_GC_SIDEVICE_TEXT, wxT("Port 3"), wxDefaultPosition, wxDefaultSize);
|
||||
GCSIDeviceText[3] = new wxStaticText(GamecubePage, ID_GC_SIDEVICE_TEXT, wxT("Port 4"), wxDefaultPosition, wxDefaultSize);
|
||||
const wxString SIDevices[] = {wxT("<Nothing>"), wxT("Standard Controller"), wxT("GBA")};
|
||||
const wxString SIDevices[] = {wxT(DEV_DUMMY_STR),wxT(SIDEV_STDCONT_STR),wxT(SIDEV_GBA_STR),wxT(SIDEV_AM_BB_STR)};
|
||||
static const int numSIDevices = sizeof(SIDevices)/sizeof(wxString);
|
||||
GCSIDevice[0] = new wxChoice(GamecubePage, ID_GC_SIDEVICE0, wxDefaultPosition, wxDefaultSize, numSIDevices, SIDevices, 0, wxDefaultValidator);
|
||||
GCSIDevice[1] = new wxChoice(GamecubePage, ID_GC_SIDEVICE1, wxDefaultPosition, wxDefaultSize, numSIDevices, SIDevices, 0, wxDefaultValidator);
|
||||
|
@ -392,12 +418,21 @@ void CConfigMain::CreateGUIControls()
|
|||
GCSIDevice[3] = new wxChoice(GamecubePage, ID_GC_SIDEVICE3, wxDefaultPosition, wxDefaultSize, numSIDevices, SIDevices, 0, wxDefaultValidator);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (SConfig::GetInstance().m_SIDevice[i] == SI_GC_CONTROLLER)
|
||||
switch (SConfig::GetInstance().m_SIDevice[i])
|
||||
{
|
||||
case SI_GC_CONTROLLER:
|
||||
GCSIDevice[i]->SetStringSelection(SIDevices[1]);
|
||||
else if (SConfig::GetInstance().m_SIDevice[i] == SI_GBA)
|
||||
break;
|
||||
case SI_GBA:
|
||||
GCSIDevice[i]->SetStringSelection(SIDevices[2]);
|
||||
else
|
||||
break;
|
||||
case SI_AM_BASEBOARD:
|
||||
GCSIDevice[i]->SetStringSelection(SIDevices[3]);
|
||||
break;
|
||||
default:
|
||||
GCSIDevice[i]->SetStringSelection(SIDevices[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sGamecube = new wxBoxSizer(wxVERTICAL);
|
||||
|
@ -678,7 +713,7 @@ void CConfigMain::GCSettingsChanged(wxCommandEvent& event)
|
|||
SConfig::GetInstance().m_LocalCoreStartupParameter.SelectedLanguage = GCSystemLang->GetSelection();
|
||||
break;
|
||||
|
||||
case ID_GC_EXIDEVICE_SP1: // The only thing we emulate on SP1 is the BBA
|
||||
case ID_GC_EXIDEVICE_SP1:
|
||||
exidevice++;
|
||||
case ID_GC_EXIDEVICE_SLOTB:
|
||||
exidevice++;
|
||||
|
@ -741,10 +776,12 @@ void CConfigMain::ChooseMemcardPath(std::string& strMemcard, bool isSlotA)
|
|||
void CConfigMain::ChooseSIDevice(std::string deviceName, int deviceNum)
|
||||
{
|
||||
TSIDevices tempType;
|
||||
if (deviceName.compare("Standard Controller") == 0)
|
||||
if (!deviceName.compare(SIDEV_STDCONT_STR))
|
||||
tempType = SI_GC_CONTROLLER;
|
||||
else if (deviceName.compare("GBA") == 0)
|
||||
else if (!deviceName.compare(SIDEV_GBA_STR))
|
||||
tempType = SI_GBA;
|
||||
else if (!deviceName.compare(SIDEV_AM_BB_STR))
|
||||
tempType = SI_AM_BASEBOARD;
|
||||
else
|
||||
tempType = SI_DUMMY;
|
||||
|
||||
|
@ -761,12 +798,16 @@ void CConfigMain::ChooseEXIDevice(std::string deviceName, int deviceNum)
|
|||
{
|
||||
TEXIDevices tempType;
|
||||
|
||||
if (deviceName.compare("Memory Card") == 0)
|
||||
if (!deviceName.compare(EXIDEV_MEMCARD_STR))
|
||||
tempType = deviceNum ? EXIDEVICE_MEMORYCARD_B : EXIDEVICE_MEMORYCARD_A;
|
||||
else if (deviceName.compare("Mic") == 0)
|
||||
else if (!deviceName.compare(EXIDEV_MIC_STR))
|
||||
tempType = EXIDEVICE_MIC;
|
||||
else if (deviceName.compare("BBA") == 0)
|
||||
else if (!deviceName.compare(EXIDEV_BBA_STR))
|
||||
tempType = EXIDEVICE_ETH;
|
||||
else if (!deviceName.compare(EXIDEV_AM_BB_STR))
|
||||
tempType = EXIDEVICE_AM_BASEBOARD;
|
||||
else if (!deviceName.compare(DEV_NONE_STR))
|
||||
tempType = EXIDEVICE_NONE;
|
||||
else
|
||||
tempType = EXIDEVICE_DUMMY;
|
||||
|
||||
|
@ -939,8 +980,6 @@ void CConfigMain::CallConfig(wxChoice* _pChoice)
|
|||
|
||||
void CConfigMain::FillChoiceBox(wxChoice* _pChoice, int _PluginType, const std::string& _SelectFilename)
|
||||
{
|
||||
INFO_LOG(CONSOLE, "FillChoiceBox\n");
|
||||
|
||||
_pChoice->Clear();
|
||||
|
||||
int Index = -1;
|
||||
|
|
Loading…
Reference in New Issue