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:
Shawn Hoffman 2009-10-19 15:14:48 +00:00
parent f5f0823867
commit 93b83f8d65
20 changed files with 1421 additions and 550 deletions

View File

@ -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"
>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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:

View File

@ -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,

View File

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

View File

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

View File

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

View File

@ -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");
}

View File

@ -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

View File

@ -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",

View File

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