diff --git a/Source/Core/Core/Core.vcproj b/Source/Core/Core/Core.vcproj index d1075b7a21..552b8d27cc 100644 --- a/Source/Core/Core/Core.vcproj +++ b/Source/Core/Core/Core.vcproj @@ -607,19 +607,35 @@ Name="SI - Serial Interface" > + + + + + + + + diff --git a/Source/Core/Core/Src/HW/HW.cpp b/Source/Core/Core/Src/HW/HW.cpp index 1321e6786f..a59452476b 100644 --- a/Source/Core/Core/Src/HW/HW.cpp +++ b/Source/Core/Core/Src/HW/HW.cpp @@ -29,7 +29,7 @@ #include "Memmap.h" #include "PeripheralInterface.h" #include "PixelEngine.h" -#include "SerialInterface.h" +#include "SI.h" #include "AudioInterface.h" #include "VideoInterface.h" #include "WII_IPC.h" diff --git a/Source/Core/Core/Src/HW/Memmap.cpp b/Source/Core/Core/Src/HW/Memmap.cpp index a59fa816e1..5e630e6152 100644 --- a/Source/Core/Core/Src/HW/Memmap.cpp +++ b/Source/Core/Core/Src/HW/Memmap.cpp @@ -31,7 +31,7 @@ #include "DVDInterface.h" #include "GPFifo.h" #include "VideoInterface.h" -#include "SerialInterface.h" +#include "SI.h" #include "EXI.h" #include "PixelEngine.h" #include "CommandProcessor.h" diff --git a/Source/Core/Core/Src/HW/SerialInterface.cpp b/Source/Core/Core/Src/HW/SI.cpp similarity index 96% rename from Source/Core/Core/Src/HW/SerialInterface.cpp rename to Source/Core/Core/Src/HW/SI.cpp index 5757f4e0a7..fb1fe3741b 100644 --- a/Source/Core/Core/Src/HW/SerialInterface.cpp +++ b/Source/Core/Core/Src/HW/SI.cpp @@ -1,557 +1,553 @@ -// Copyright (C) 2003-2008 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 - -#include "Common.h" -#include "ChunkFile.h" - -#include "SerialInterface.h" -#include "SerialInterface_Devices.h" - -#include "PeripheralInterface.h" -#include "CPU.h" - -#include "../PowerPC/PowerPC.h" -#include "../Plugins/Plugin_PAD.h" - -namespace SerialInterface -{ - -// SI Interrupt Types -enum SIInterruptType -{ - INT_RDSTINT = 0, - INT_TCINT = 1, -}; - -// SI number of channels -enum -{ - NUMBER_OF_CHANNELS = 0x04 -}; - -// SI Internal Hardware Addresses -enum -{ - SI_CHANNEL_0_OUT = 0x00, - SI_CHANNEL_0_IN_HI = 0x04, - SI_CHANNEL_0_IN_LO = 0x08, - SI_CHANNEL_1_OUT = 0x0C, - SI_CHANNEL_1_IN_HI = 0x10, - SI_CHANNEL_1_IN_LO = 0x14, - SI_CHANNEL_2_OUT = 0x18, - SI_CHANNEL_2_IN_HI = 0x1C, - SI_CHANNEL_2_IN_LO = 0x20, - SI_CHANNEL_3_OUT = 0x24, - SI_CHANNEL_3_IN_HI = 0x28, - SI_CHANNEL_3_IN_LO = 0x2C, - SI_POLL = 0x30, - SI_COM_CSR = 0x34, - SI_STATUS_REG = 0x38, - SI_EXI_CLOCK_COUNT = 0x3C, -}; - -// SI Channel Output -union USIChannelOut -{ - u32 Hex; - struct - { - unsigned OUTPUT1 : 8; - unsigned OUTPUT0 : 8; - unsigned CMD : 8; - unsigned : 8; - }; -}; - -// SI Channel Input High u32 -union USIChannelIn_Hi -{ - u32 Hex; - struct - { - unsigned INPUT3 : 8; - unsigned INPUT2 : 8; - unsigned INPUT1 : 8; - unsigned INPUT0 : 6; - unsigned ERRLATCH : 1; // 0: no error 1: Error latched. Check SISR. - unsigned ERRSTAT : 1; // 0: no error 1: error on last transfer - }; -}; - -// SI Channel Input Low u32 -union USIChannelIn_Lo -{ - u32 Hex; - struct - { - unsigned INPUT7 : 8; - unsigned INPUT6 : 8; - unsigned INPUT5 : 8; - unsigned INPUT4 : 8; - }; -}; - -// SI Channel -struct SSIChannel -{ - USIChannelOut m_Out; - USIChannelIn_Hi m_InHi; - USIChannelIn_Lo m_InLo; - ISIDevice* m_pDevice; -}; - -// SI Poll: Controls how often a device is polled -union USIPoll -{ - u32 Hex; - struct - { - unsigned VBCPY3 : 1; - unsigned VBCPY2 : 1; - unsigned VBCPY1 : 1; - unsigned VBCPY0 : 1; - unsigned EN3 : 1; - unsigned EN2 : 1; - unsigned EN1 : 1; - unsigned EN0 : 1; - unsigned Y : 10; - unsigned X : 10; - unsigned : 6; - }; -}; - -// SI Communication Control Status Register -union USIComCSR -{ - u32 Hex; - struct - { - unsigned TSTART : 1; - unsigned CHANNEL : 2; // determines which SI channel will be used the communication interface. - unsigned : 5; - unsigned INLNGTH : 7; - unsigned : 1; - unsigned OUTLNGTH : 7; // Communication Channel Output Length in bytes - unsigned : 4; - unsigned RDSTINTMSK : 1; // Read Status Interrupt Status Mask - unsigned RDSTINT : 1; // Read Status Interrupt Status - unsigned COMERR : 1; // Communication Error (set 0) - unsigned TCINTMSK : 1; // Transfer Complete Interrupt Mask - unsigned TCINT : 1; // Transfer Complete Interrupt - }; - USIComCSR() {Hex = 0;} - USIComCSR(u32 _hex) {Hex = _hex;} -}; - -// SI Status Register -union USIStatusReg -{ - u32 Hex; - struct - { - unsigned UNRUN3 : 1; // (RWC) write 1: bit cleared read 1 main proc underrun error - unsigned OVRUN3 : 1; // (RWC) write 1: bit cleared read 1 overrun error - unsigned COLL3 : 1; // (RWC) write 1: bit cleared read 1 collision error - unsigned NOREP3 : 1; // (RWC) write 1: bit cleared read 1 response error - unsigned WRST3 : 1; // (R) 1: buffer channel0 not copied - unsigned RDST3 : 1; // (R) 1: new Data available - unsigned : 2; // 7:6 - unsigned UNRUN2 : 1; // (RWC) write 1: bit cleared read 1 main proc underrun error - unsigned OVRUN2 : 1; // (RWC) write 1: bit cleared read 1 overrun error - unsigned COLL2 : 1; // (RWC) write 1: bit cleared read 1 collision error - unsigned NOREP2 : 1; // (RWC) write 1: bit cleared read 1 response error - unsigned WRST2 : 1; // (R) 1: buffer channel0 not copied - unsigned RDST2 : 1; // (R) 1: new Data available - unsigned : 2; // 15:14 - unsigned UNRUN1 : 1; // (RWC) write 1: bit cleared read 1 main proc underrun error - unsigned OVRUN1 : 1; // (RWC) write 1: bit cleared read 1 overrun error - unsigned COLL1 : 1; // (RWC) write 1: bit cleared read 1 collision error - unsigned NOREP1 : 1; // (RWC) write 1: bit cleared read 1 response error - unsigned WRST1 : 1; // (R) 1: buffer channel0 not copied - unsigned RDST1 : 1; // (R) 1: new Data available - unsigned : 2; // 23:22 - unsigned UNRUN0 : 1; // (RWC) write 1: bit cleared read 1 main proc underrun error - unsigned OVRUN0 : 1; // (RWC) write 1: bit cleared read 1 overrun error - unsigned COLL0 : 1; // (RWC) write 1: bit cleared read 1 collision error - unsigned NOREP0 : 1; // (RWC) write 1: bit cleared read 1 response error - unsigned WRST0 : 1; // (R) 1: buffer channel0 not copied - unsigned RDST0 : 1; // (R) 1: new Data available - unsigned : 1; - unsigned WR : 1; // (RW) write 1 start copy, read 0 copy done - }; - USIStatusReg() {Hex = 0;} - USIStatusReg(u32 _hex) {Hex = _hex;} -}; - -// SI EXI Clock Count -union USIEXIClockCount -{ - u32 Hex; - struct - { - unsigned LOCK : 1; - unsigned : 30; - }; -}; - -// STATE_TO_SAVE -static SSIChannel g_Channel[NUMBER_OF_CHANNELS]; -static USIPoll g_Poll; -static USIComCSR g_ComCSR; -static USIStatusReg g_StatusReg; -static USIEXIClockCount g_EXIClockCount; -static u8 g_SIBuffer[128]; - -void DoState(PointerWrap &p) -{ - // p.DoArray(g_Channel); - p.Do(g_Poll); - p.Do(g_ComCSR); - p.Do(g_StatusReg); - p.Do(g_EXIClockCount); - p.Do(g_SIBuffer); -} - -static void GenerateSIInterrupt(SIInterruptType _SIInterrupt); -void RunSIBuffer(); -void UpdateInterrupts(); - -void Init() -{ - for (int i = 0; i < NUMBER_OF_CHANNELS; i++) - { - g_Channel[i].m_Out.Hex = 0; - g_Channel[i].m_InHi.Hex = 0; - g_Channel[i].m_InLo.Hex = 0; - } - - unsigned int AttachedPadMask = PluginPAD::PAD_GetAttachedPads ? PluginPAD::PAD_GetAttachedPads() : 1; - for (int i = 0; i < 4; i++) - { - if (AttachedPadMask & (1 << i)) - g_Channel[i].m_pDevice = new CSIDevice_GCController(i); - else - g_Channel[i].m_pDevice = new CSIDevice_Dummy(i); - } - - g_Poll.Hex = 0; - g_ComCSR.Hex = 0; - g_StatusReg.Hex = 0; - g_EXIClockCount.Hex = 0; - memset(g_SIBuffer, 0xce, 128); -} - -void Shutdown() -{ - for (int i = 0; i < NUMBER_OF_CHANNELS; i++) - { - delete g_Channel[i].m_pDevice; - g_Channel[i].m_pDevice = NULL; - } -} - -void Read32(u32& _uReturnValue, const u32 _iAddress) -{ - LOGV(SERIALINTERFACE, 3, "(r32): 0x%08x", _iAddress); - - // SIBuffer - if ((_iAddress >= 0xCC006480 && _iAddress < 0xCC006500) || - (_iAddress >= 0xCD006480 && _iAddress < 0xCD006500)) - { - _uReturnValue = *(u32*)&g_SIBuffer[_iAddress & 0x7F]; - return; - } - - // registers - switch (_iAddress & 0x3FF) - { - //=================================================================================================== - // Channel 0 - //=================================================================================================== - case SI_CHANNEL_0_OUT: - _uReturnValue = g_Channel[0].m_Out.Hex; - return; - - case SI_CHANNEL_0_IN_HI: - g_StatusReg.RDST0 = 0; - UpdateInterrupts(); - _uReturnValue = g_Channel[0].m_InHi.Hex; - return; - - case SI_CHANNEL_0_IN_LO: - g_StatusReg.RDST0 = 0; - UpdateInterrupts(); - _uReturnValue = g_Channel[0].m_InLo.Hex; - return; - - //=================================================================================================== - // Channel 1 - //=================================================================================================== - case SI_CHANNEL_1_OUT: - _uReturnValue = g_Channel[1].m_Out.Hex; - return; - - case SI_CHANNEL_1_IN_HI: - g_StatusReg.RDST1 = 0; - UpdateInterrupts(); - _uReturnValue = g_Channel[1].m_InHi.Hex; - return; - - case SI_CHANNEL_1_IN_LO: - g_StatusReg.RDST1 = 0; - UpdateInterrupts(); - _uReturnValue = g_Channel[1].m_InLo.Hex; - return; - - //=================================================================================================== - // Channel 2 - //=================================================================================================== - case SI_CHANNEL_2_OUT: - _uReturnValue = g_Channel[2].m_Out.Hex; - return; - - case SI_CHANNEL_2_IN_HI: - g_StatusReg.RDST2 = 0; - UpdateInterrupts(); - _uReturnValue = g_Channel[2].m_InHi.Hex; - return; - - case SI_CHANNEL_2_IN_LO: - g_StatusReg.RDST2 = 0; - UpdateInterrupts(); - _uReturnValue = g_Channel[2].m_InLo.Hex; - return; - - //=================================================================================================== - // Channel 3 - //=================================================================================================== - case SI_CHANNEL_3_OUT: - _uReturnValue = g_Channel[3].m_Out.Hex; - return; - - case SI_CHANNEL_3_IN_HI: - g_StatusReg.RDST3 = 0; - UpdateInterrupts(); - _uReturnValue = g_Channel[3].m_InHi.Hex; - return; - - case SI_CHANNEL_3_IN_LO: - g_StatusReg.RDST3 = 0; - UpdateInterrupts(); - _uReturnValue = g_Channel[3].m_InLo.Hex; - return; - - 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; - - case SI_EXI_CLOCK_COUNT: _uReturnValue = g_EXIClockCount.Hex; return; - - default: - LOG(SERIALINTERFACE, "(r32-unk): 0x%08x", _iAddress); - _dbg_assert_(SERIALINTERFACE,0); - break; - } - - // error - _uReturnValue = 0xdeadbeef; -} - -void Write32(const u32 _iValue, const u32 _iAddress) -{ - LOGV(SERIALINTERFACE, 3, "(w32): 0x%08x 0x%08x", _iValue,_iAddress); - - // SIBuffer - if ((_iAddress >= 0xCC006480 && _iAddress < 0xCC006500) || - (_iAddress >= 0xCD006480 && _iAddress < 0xCD006500)) - { - *(u32*)&g_SIBuffer[_iAddress & 0x7F] = _iValue; - return; - } - - // registers - switch (_iAddress & 0x3FF) - { - case SI_CHANNEL_0_OUT: g_Channel[0].m_Out.Hex = _iValue; break; - case SI_CHANNEL_0_IN_HI: g_Channel[0].m_InHi.Hex = _iValue; break; - case SI_CHANNEL_0_IN_LO: g_Channel[0].m_InLo.Hex = _iValue; break; - case SI_CHANNEL_1_OUT: g_Channel[1].m_Out.Hex = _iValue; break; - case SI_CHANNEL_1_IN_HI: g_Channel[1].m_InHi.Hex = _iValue; break; - case SI_CHANNEL_1_IN_LO: g_Channel[1].m_InLo.Hex = _iValue; break; - case SI_CHANNEL_2_OUT: g_Channel[2].m_Out.Hex = _iValue; break; - case SI_CHANNEL_2_IN_HI: g_Channel[2].m_InHi.Hex = _iValue; break; - case SI_CHANNEL_2_IN_LO: g_Channel[2].m_InLo.Hex = _iValue; break; - case SI_CHANNEL_3_OUT: g_Channel[3].m_Out.Hex = _iValue; break; - case SI_CHANNEL_3_IN_HI: g_Channel[3].m_InHi.Hex = _iValue; break; - case SI_CHANNEL_3_IN_LO: g_Channel[3].m_InLo.Hex = _iValue; break; - - case SI_POLL: - g_Poll.Hex = _iValue; - break; - - case SI_COM_CSR: - { - USIComCSR tmpComCSR(_iValue); - - g_ComCSR.CHANNEL = tmpComCSR.CHANNEL; - g_ComCSR.INLNGTH = tmpComCSR.INLNGTH; - g_ComCSR.OUTLNGTH = tmpComCSR.OUTLNGTH; - g_ComCSR.RDSTINTMSK = tmpComCSR.RDSTINTMSK; - g_ComCSR.TCINTMSK = tmpComCSR.TCINTMSK; - - g_ComCSR.COMERR = 0; - - if (tmpComCSR.RDSTINT) g_ComCSR.RDSTINT = 0; - if (tmpComCSR.TCINT) g_ComCSR.TCINT = 0; - - // be careful: runsi-buffer after updating the INT flags - if (tmpComCSR.TSTART) RunSIBuffer(); - UpdateInterrupts(); - } - break; - - case SI_STATUS_REG: - { - USIStatusReg tmpStatus(_iValue); - - // just update the writable bits - g_StatusReg.NOREP0 = tmpStatus.NOREP0 ? 1 : 0; - g_StatusReg.COLL0 = tmpStatus.COLL0 ? 1 : 0; - g_StatusReg.OVRUN0 = tmpStatus.OVRUN0 ? 1 : 0; - g_StatusReg.UNRUN0 = tmpStatus.UNRUN0 ? 1 : 0; - - g_StatusReg.NOREP1 = tmpStatus.NOREP1 ? 1 : 0; - g_StatusReg.COLL1 = tmpStatus.COLL1 ? 1 : 0; - g_StatusReg.OVRUN1 = tmpStatus.OVRUN1 ? 1 : 0; - g_StatusReg.UNRUN1 = tmpStatus.UNRUN1 ? 1 : 0; - - g_StatusReg.NOREP2 = tmpStatus.NOREP2 ? 1 : 0; - g_StatusReg.COLL2 = tmpStatus.COLL2 ? 1 : 0; - g_StatusReg.OVRUN2 = tmpStatus.OVRUN2 ? 1 : 0; - g_StatusReg.UNRUN2 = tmpStatus.UNRUN2 ? 1 : 0; - - g_StatusReg.NOREP3 = tmpStatus.NOREP3 ? 1 : 0; - g_StatusReg.COLL3 = tmpStatus.COLL3 ? 1 : 0; - g_StatusReg.OVRUN3 = tmpStatus.OVRUN3 ? 1 : 0; - g_StatusReg.UNRUN3 = tmpStatus.UNRUN3 ? 1 : 0; - - // send command to devices - if (tmpStatus.WR) - { - g_StatusReg.WR = 0; - g_Channel[0].m_pDevice->SendCommand(g_Channel[0].m_Out.Hex); - g_Channel[1].m_pDevice->SendCommand(g_Channel[1].m_Out.Hex); - g_Channel[2].m_pDevice->SendCommand(g_Channel[2].m_Out.Hex); - g_Channel[3].m_pDevice->SendCommand(g_Channel[3].m_Out.Hex); - - g_StatusReg.WRST0 = 0; - g_StatusReg.WRST1 = 0; - g_StatusReg.WRST2 = 0; - g_StatusReg.WRST3 = 0; - } - } - break; - - case SI_EXI_CLOCK_COUNT: - g_EXIClockCount.Hex = _iValue; - break; - - case 0x80: - LOG(SERIALINTERFACE, "WII something at 0xCD006480"); - break; - - default: - _dbg_assert_(SERIALINTERFACE,0); - break; - } -} - -void UpdateInterrupts() -{ - // check if we have to update the RDSTINT flag - if (g_StatusReg.RDST0 || g_StatusReg.RDST1 || - g_StatusReg.RDST2 || g_StatusReg.RDST3) - g_ComCSR.RDSTINT = 1; - else - g_ComCSR.RDSTINT = 0; - - // check if we have to generate an interrupt - if ((g_ComCSR.RDSTINT & g_ComCSR.RDSTINTMSK) || - (g_ComCSR.TCINT & g_ComCSR.TCINTMSK)) - { - CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_SI, true); - } - else - { - CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_SI, false); - } -} - -void GenerateSIInterrupt(SIInterruptType _SIInterrupt) -{ - switch(_SIInterrupt) - { - case INT_RDSTINT: g_ComCSR.RDSTINT = 1; break; - case INT_TCINT: g_ComCSR.TCINT = 1; break; - } - - UpdateInterrupts(); -} - -void UpdateDevices() -{ - // update channels - g_StatusReg.RDST0 = g_Channel[0].m_pDevice->GetData(g_Channel[0].m_InHi.Hex, g_Channel[0].m_InLo.Hex) ? 1 : 0; - g_StatusReg.RDST1 = g_Channel[1].m_pDevice->GetData(g_Channel[1].m_InHi.Hex, g_Channel[1].m_InLo.Hex) ? 1 : 0; - g_StatusReg.RDST2 = g_Channel[2].m_pDevice->GetData(g_Channel[2].m_InHi.Hex, g_Channel[2].m_InLo.Hex) ? 1 : 0; - g_StatusReg.RDST3 = g_Channel[3].m_pDevice->GetData(g_Channel[3].m_InHi.Hex, g_Channel[3].m_InLo.Hex) ? 1 : 0; - - // update interrupts - UpdateInterrupts(); -} - -void RunSIBuffer() -{ - // math inLength - int inLength = g_ComCSR.INLNGTH; - if (inLength == 0) - inLength = 128; - else - inLength++; - - // math outLength - int outLength = g_ComCSR.OUTLNGTH; - if (outLength == 0) - outLength = 128; - else - outLength++; - -#ifdef LOGGING - int numOutput = -#endif - g_Channel[g_ComCSR.CHANNEL].m_pDevice->RunBuffer(g_SIBuffer, inLength); - LOGV(SERIALINTERFACE, 2, "RunSIBuffer (intLen: %i outLen: %i) (processed: %i)", inLength, outLength, numOutput); - - // Transfer completed - GenerateSIInterrupt(INT_TCINT); - g_ComCSR.TSTART = 0; -} - -} // end of namespace SerialInterface - +// Copyright (C) 2003-2008 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 "Common.h" +#include "ChunkFile.h" + +#include "PeripheralInterface.h" + +#include "../Plugins/Plugin_PAD.h" + +#include "SI.h" +#include "SI_Device.h" +#include "SI_DeviceGCController.h" + +namespace SerialInterface +{ + +// SI Interrupt Types +enum SIInterruptType +{ + INT_RDSTINT = 0, + INT_TCINT = 1, +}; + +// SI number of channels +enum +{ + NUMBER_OF_CHANNELS = 0x04 +}; + +// SI Internal Hardware Addresses +enum +{ + SI_CHANNEL_0_OUT = 0x00, + SI_CHANNEL_0_IN_HI = 0x04, + SI_CHANNEL_0_IN_LO = 0x08, + SI_CHANNEL_1_OUT = 0x0C, + SI_CHANNEL_1_IN_HI = 0x10, + SI_CHANNEL_1_IN_LO = 0x14, + SI_CHANNEL_2_OUT = 0x18, + SI_CHANNEL_2_IN_HI = 0x1C, + SI_CHANNEL_2_IN_LO = 0x20, + SI_CHANNEL_3_OUT = 0x24, + SI_CHANNEL_3_IN_HI = 0x28, + SI_CHANNEL_3_IN_LO = 0x2C, + SI_POLL = 0x30, + SI_COM_CSR = 0x34, + SI_STATUS_REG = 0x38, + SI_EXI_CLOCK_COUNT = 0x3C, +}; + +// SI Channel Output +union USIChannelOut +{ + u32 Hex; + struct + { + unsigned OUTPUT1 : 8; + unsigned OUTPUT0 : 8; + unsigned CMD : 8; + unsigned : 8; + }; +}; + +// SI Channel Input High u32 +union USIChannelIn_Hi +{ + u32 Hex; + struct + { + unsigned INPUT3 : 8; + unsigned INPUT2 : 8; + unsigned INPUT1 : 8; + unsigned INPUT0 : 6; + unsigned ERRLATCH : 1; // 0: no error 1: Error latched. Check SISR. + unsigned ERRSTAT : 1; // 0: no error 1: error on last transfer + }; +}; + +// SI Channel Input Low u32 +union USIChannelIn_Lo +{ + u32 Hex; + struct + { + unsigned INPUT7 : 8; + unsigned INPUT6 : 8; + unsigned INPUT5 : 8; + unsigned INPUT4 : 8; + }; +}; + +// SI Channel +struct SSIChannel +{ + USIChannelOut m_Out; + USIChannelIn_Hi m_InHi; + USIChannelIn_Lo m_InLo; + ISIDevice* m_pDevice; +}; + +// SI Poll: Controls how often a device is polled +union USIPoll +{ + u32 Hex; + struct + { + unsigned VBCPY3 : 1; + unsigned VBCPY2 : 1; + unsigned VBCPY1 : 1; + unsigned VBCPY0 : 1; + unsigned EN3 : 1; + unsigned EN2 : 1; + unsigned EN1 : 1; + unsigned EN0 : 1; + unsigned Y : 10; + unsigned X : 10; + unsigned : 6; + }; +}; + +// SI Communication Control Status Register +union USIComCSR +{ + u32 Hex; + struct + { + unsigned TSTART : 1; + unsigned CHANNEL : 2; // determines which SI channel will be used the communication interface. + unsigned : 5; + unsigned INLNGTH : 7; + unsigned : 1; + unsigned OUTLNGTH : 7; // Communication Channel Output Length in bytes + unsigned : 4; + unsigned RDSTINTMSK : 1; // Read Status Interrupt Status Mask + unsigned RDSTINT : 1; // Read Status Interrupt Status + unsigned COMERR : 1; // Communication Error (set 0) + unsigned TCINTMSK : 1; // Transfer Complete Interrupt Mask + unsigned TCINT : 1; // Transfer Complete Interrupt + }; + USIComCSR() {Hex = 0;} + USIComCSR(u32 _hex) {Hex = _hex;} +}; + +// SI Status Register +union USIStatusReg +{ + u32 Hex; + struct + { + unsigned UNRUN3 : 1; // (RWC) write 1: bit cleared read 1 main proc underrun error + unsigned OVRUN3 : 1; // (RWC) write 1: bit cleared read 1 overrun error + unsigned COLL3 : 1; // (RWC) write 1: bit cleared read 1 collision error + unsigned NOREP3 : 1; // (RWC) write 1: bit cleared read 1 response error + unsigned WRST3 : 1; // (R) 1: buffer channel0 not copied + unsigned RDST3 : 1; // (R) 1: new Data available + unsigned : 2; // 7:6 + unsigned UNRUN2 : 1; // (RWC) write 1: bit cleared read 1 main proc underrun error + unsigned OVRUN2 : 1; // (RWC) write 1: bit cleared read 1 overrun error + unsigned COLL2 : 1; // (RWC) write 1: bit cleared read 1 collision error + unsigned NOREP2 : 1; // (RWC) write 1: bit cleared read 1 response error + unsigned WRST2 : 1; // (R) 1: buffer channel0 not copied + unsigned RDST2 : 1; // (R) 1: new Data available + unsigned : 2; // 15:14 + unsigned UNRUN1 : 1; // (RWC) write 1: bit cleared read 1 main proc underrun error + unsigned OVRUN1 : 1; // (RWC) write 1: bit cleared read 1 overrun error + unsigned COLL1 : 1; // (RWC) write 1: bit cleared read 1 collision error + unsigned NOREP1 : 1; // (RWC) write 1: bit cleared read 1 response error + unsigned WRST1 : 1; // (R) 1: buffer channel0 not copied + unsigned RDST1 : 1; // (R) 1: new Data available + unsigned : 2; // 23:22 + unsigned UNRUN0 : 1; // (RWC) write 1: bit cleared read 1 main proc underrun error + unsigned OVRUN0 : 1; // (RWC) write 1: bit cleared read 1 overrun error + unsigned COLL0 : 1; // (RWC) write 1: bit cleared read 1 collision error + unsigned NOREP0 : 1; // (RWC) write 1: bit cleared read 1 response error + unsigned WRST0 : 1; // (R) 1: buffer channel0 not copied + unsigned RDST0 : 1; // (R) 1: new Data available + unsigned : 1; + unsigned WR : 1; // (RW) write 1 start copy, read 0 copy done + }; + USIStatusReg() {Hex = 0;} + USIStatusReg(u32 _hex) {Hex = _hex;} +}; + +// SI EXI Clock Count +union USIEXIClockCount +{ + u32 Hex; + struct + { + unsigned LOCK : 1; + unsigned : 30; + }; +}; + +// STATE_TO_SAVE +static SSIChannel g_Channel[NUMBER_OF_CHANNELS]; +static USIPoll g_Poll; +static USIComCSR g_ComCSR; +static USIStatusReg g_StatusReg; +static USIEXIClockCount g_EXIClockCount; +static u8 g_SIBuffer[128]; + +void DoState(PointerWrap &p) +{ + // p.DoArray(g_Channel); + p.Do(g_Poll); + p.Do(g_ComCSR); + p.Do(g_StatusReg); + p.Do(g_EXIClockCount); + p.Do(g_SIBuffer); +} + +static void GenerateSIInterrupt(SIInterruptType _SIInterrupt); +void RunSIBuffer(); +void UpdateInterrupts(); + +void Init() +{ + for (int i = 0; i < NUMBER_OF_CHANNELS; i++) + { + g_Channel[i].m_Out.Hex = 0; + g_Channel[i].m_InHi.Hex = 0; + g_Channel[i].m_InLo.Hex = 0; + } + + unsigned int AttachedPadMask = PluginPAD::PAD_GetAttachedPads ? PluginPAD::PAD_GetAttachedPads() : 1; + for (int i = 0; i < 4; i++) + { + if (AttachedPadMask & (1 << i)) + g_Channel[i].m_pDevice = new CSIDevice_GCController(i); + else + g_Channel[i].m_pDevice = new CSIDevice_Dummy(i); + } + + g_Poll.Hex = 0; + g_ComCSR.Hex = 0; + g_StatusReg.Hex = 0; + g_EXIClockCount.Hex = 0; + memset(g_SIBuffer, 0xce, 128); +} + +void Shutdown() +{ + for (int i = 0; i < NUMBER_OF_CHANNELS; i++) + { + delete g_Channel[i].m_pDevice; + g_Channel[i].m_pDevice = NULL; + } +} + +void Read32(u32& _uReturnValue, const u32 _iAddress) +{ + LOGV(SERIALINTERFACE, 3, "(r32): 0x%08x", _iAddress); + + // SIBuffer + if ((_iAddress >= 0xCC006480 && _iAddress < 0xCC006500) || + (_iAddress >= 0xCD006480 && _iAddress < 0xCD006500)) + { + _uReturnValue = *(u32*)&g_SIBuffer[_iAddress & 0x7F]; + return; + } + + // registers + switch (_iAddress & 0x3FF) + { + //=================================================================================================== + // Channel 0 + //=================================================================================================== + case SI_CHANNEL_0_OUT: + _uReturnValue = g_Channel[0].m_Out.Hex; + return; + + case SI_CHANNEL_0_IN_HI: + g_StatusReg.RDST0 = 0; + UpdateInterrupts(); + _uReturnValue = g_Channel[0].m_InHi.Hex; + return; + + case SI_CHANNEL_0_IN_LO: + g_StatusReg.RDST0 = 0; + UpdateInterrupts(); + _uReturnValue = g_Channel[0].m_InLo.Hex; + return; + + //=================================================================================================== + // Channel 1 + //=================================================================================================== + case SI_CHANNEL_1_OUT: + _uReturnValue = g_Channel[1].m_Out.Hex; + return; + + case SI_CHANNEL_1_IN_HI: + g_StatusReg.RDST1 = 0; + UpdateInterrupts(); + _uReturnValue = g_Channel[1].m_InHi.Hex; + return; + + case SI_CHANNEL_1_IN_LO: + g_StatusReg.RDST1 = 0; + UpdateInterrupts(); + _uReturnValue = g_Channel[1].m_InLo.Hex; + return; + + //=================================================================================================== + // Channel 2 + //=================================================================================================== + case SI_CHANNEL_2_OUT: + _uReturnValue = g_Channel[2].m_Out.Hex; + return; + + case SI_CHANNEL_2_IN_HI: + g_StatusReg.RDST2 = 0; + UpdateInterrupts(); + _uReturnValue = g_Channel[2].m_InHi.Hex; + return; + + case SI_CHANNEL_2_IN_LO: + g_StatusReg.RDST2 = 0; + UpdateInterrupts(); + _uReturnValue = g_Channel[2].m_InLo.Hex; + return; + + //=================================================================================================== + // Channel 3 + //=================================================================================================== + case SI_CHANNEL_3_OUT: + _uReturnValue = g_Channel[3].m_Out.Hex; + return; + + case SI_CHANNEL_3_IN_HI: + g_StatusReg.RDST3 = 0; + UpdateInterrupts(); + _uReturnValue = g_Channel[3].m_InHi.Hex; + return; + + case SI_CHANNEL_3_IN_LO: + g_StatusReg.RDST3 = 0; + UpdateInterrupts(); + _uReturnValue = g_Channel[3].m_InLo.Hex; + return; + + 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; + + case SI_EXI_CLOCK_COUNT: _uReturnValue = g_EXIClockCount.Hex; return; + + default: + LOG(SERIALINTERFACE, "(r32-unk): 0x%08x", _iAddress); + _dbg_assert_(SERIALINTERFACE,0); + break; + } + + // error + _uReturnValue = 0xdeadbeef; +} + +void Write32(const u32 _iValue, const u32 _iAddress) +{ + LOGV(SERIALINTERFACE, 3, "(w32): 0x%08x 0x%08x", _iValue,_iAddress); + + // SIBuffer + if ((_iAddress >= 0xCC006480 && _iAddress < 0xCC006500) || + (_iAddress >= 0xCD006480 && _iAddress < 0xCD006500)) + { + *(u32*)&g_SIBuffer[_iAddress & 0x7F] = _iValue; + return; + } + + // registers + switch (_iAddress & 0x3FF) + { + case SI_CHANNEL_0_OUT: g_Channel[0].m_Out.Hex = _iValue; break; + case SI_CHANNEL_0_IN_HI: g_Channel[0].m_InHi.Hex = _iValue; break; + case SI_CHANNEL_0_IN_LO: g_Channel[0].m_InLo.Hex = _iValue; break; + case SI_CHANNEL_1_OUT: g_Channel[1].m_Out.Hex = _iValue; break; + case SI_CHANNEL_1_IN_HI: g_Channel[1].m_InHi.Hex = _iValue; break; + case SI_CHANNEL_1_IN_LO: g_Channel[1].m_InLo.Hex = _iValue; break; + case SI_CHANNEL_2_OUT: g_Channel[2].m_Out.Hex = _iValue; break; + case SI_CHANNEL_2_IN_HI: g_Channel[2].m_InHi.Hex = _iValue; break; + case SI_CHANNEL_2_IN_LO: g_Channel[2].m_InLo.Hex = _iValue; break; + case SI_CHANNEL_3_OUT: g_Channel[3].m_Out.Hex = _iValue; break; + case SI_CHANNEL_3_IN_HI: g_Channel[3].m_InHi.Hex = _iValue; break; + case SI_CHANNEL_3_IN_LO: g_Channel[3].m_InLo.Hex = _iValue; break; + + case SI_POLL: + g_Poll.Hex = _iValue; + break; + + case SI_COM_CSR: + { + USIComCSR tmpComCSR(_iValue); + + g_ComCSR.CHANNEL = tmpComCSR.CHANNEL; + g_ComCSR.INLNGTH = tmpComCSR.INLNGTH; + g_ComCSR.OUTLNGTH = tmpComCSR.OUTLNGTH; + g_ComCSR.RDSTINTMSK = tmpComCSR.RDSTINTMSK; + g_ComCSR.TCINTMSK = tmpComCSR.TCINTMSK; + + g_ComCSR.COMERR = 0; + + if (tmpComCSR.RDSTINT) g_ComCSR.RDSTINT = 0; + if (tmpComCSR.TCINT) g_ComCSR.TCINT = 0; + + // be careful: runsi-buffer after updating the INT flags + if (tmpComCSR.TSTART) RunSIBuffer(); + UpdateInterrupts(); + } + break; + + case SI_STATUS_REG: + { + USIStatusReg tmpStatus(_iValue); + + // just update the writable bits + g_StatusReg.NOREP0 = tmpStatus.NOREP0 ? 1 : 0; + g_StatusReg.COLL0 = tmpStatus.COLL0 ? 1 : 0; + g_StatusReg.OVRUN0 = tmpStatus.OVRUN0 ? 1 : 0; + g_StatusReg.UNRUN0 = tmpStatus.UNRUN0 ? 1 : 0; + + g_StatusReg.NOREP1 = tmpStatus.NOREP1 ? 1 : 0; + g_StatusReg.COLL1 = tmpStatus.COLL1 ? 1 : 0; + g_StatusReg.OVRUN1 = tmpStatus.OVRUN1 ? 1 : 0; + g_StatusReg.UNRUN1 = tmpStatus.UNRUN1 ? 1 : 0; + + g_StatusReg.NOREP2 = tmpStatus.NOREP2 ? 1 : 0; + g_StatusReg.COLL2 = tmpStatus.COLL2 ? 1 : 0; + g_StatusReg.OVRUN2 = tmpStatus.OVRUN2 ? 1 : 0; + g_StatusReg.UNRUN2 = tmpStatus.UNRUN2 ? 1 : 0; + + g_StatusReg.NOREP3 = tmpStatus.NOREP3 ? 1 : 0; + g_StatusReg.COLL3 = tmpStatus.COLL3 ? 1 : 0; + g_StatusReg.OVRUN3 = tmpStatus.OVRUN3 ? 1 : 0; + g_StatusReg.UNRUN3 = tmpStatus.UNRUN3 ? 1 : 0; + + // send command to devices + if (tmpStatus.WR) + { + g_StatusReg.WR = 0; + g_Channel[0].m_pDevice->SendCommand(g_Channel[0].m_Out.Hex); + g_Channel[1].m_pDevice->SendCommand(g_Channel[1].m_Out.Hex); + g_Channel[2].m_pDevice->SendCommand(g_Channel[2].m_Out.Hex); + g_Channel[3].m_pDevice->SendCommand(g_Channel[3].m_Out.Hex); + + g_StatusReg.WRST0 = 0; + g_StatusReg.WRST1 = 0; + g_StatusReg.WRST2 = 0; + g_StatusReg.WRST3 = 0; + } + } + break; + + case SI_EXI_CLOCK_COUNT: + g_EXIClockCount.Hex = _iValue; + break; + + case 0x80: + LOG(SERIALINTERFACE, "WII something at 0xCD006480"); + break; + + default: + _dbg_assert_(SERIALINTERFACE,0); + break; + } +} + +void UpdateInterrupts() +{ + // check if we have to update the RDSTINT flag + if (g_StatusReg.RDST0 || g_StatusReg.RDST1 || + g_StatusReg.RDST2 || g_StatusReg.RDST3) + g_ComCSR.RDSTINT = 1; + else + g_ComCSR.RDSTINT = 0; + + // check if we have to generate an interrupt + if ((g_ComCSR.RDSTINT & g_ComCSR.RDSTINTMSK) || + (g_ComCSR.TCINT & g_ComCSR.TCINTMSK)) + { + CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_SI, true); + } + else + { + CPeripheralInterface::SetInterrupt(CPeripheralInterface::INT_CAUSE_SI, false); + } +} + +void GenerateSIInterrupt(SIInterruptType _SIInterrupt) +{ + switch(_SIInterrupt) + { + case INT_RDSTINT: g_ComCSR.RDSTINT = 1; break; + case INT_TCINT: g_ComCSR.TCINT = 1; break; + } + + UpdateInterrupts(); +} + +void UpdateDevices() +{ + // update channels + g_StatusReg.RDST0 = g_Channel[0].m_pDevice->GetData(g_Channel[0].m_InHi.Hex, g_Channel[0].m_InLo.Hex) ? 1 : 0; + g_StatusReg.RDST1 = g_Channel[1].m_pDevice->GetData(g_Channel[1].m_InHi.Hex, g_Channel[1].m_InLo.Hex) ? 1 : 0; + g_StatusReg.RDST2 = g_Channel[2].m_pDevice->GetData(g_Channel[2].m_InHi.Hex, g_Channel[2].m_InLo.Hex) ? 1 : 0; + g_StatusReg.RDST3 = g_Channel[3].m_pDevice->GetData(g_Channel[3].m_InHi.Hex, g_Channel[3].m_InLo.Hex) ? 1 : 0; + + // update interrupts + UpdateInterrupts(); +} + +void RunSIBuffer() +{ + // math inLength + int inLength = g_ComCSR.INLNGTH; + if (inLength == 0) + inLength = 128; + else + inLength++; + + // math outLength + int outLength = g_ComCSR.OUTLNGTH; + if (outLength == 0) + outLength = 128; + else + outLength++; + +#ifdef LOGGING + int numOutput = +#endif + g_Channel[g_ComCSR.CHANNEL].m_pDevice->RunBuffer(g_SIBuffer, inLength); + LOGV(SERIALINTERFACE, 2, "RunSIBuffer (intLen: %i outLen: %i) (processed: %i)", inLength, outLength, numOutput); + + // Transfer completed + GenerateSIInterrupt(INT_TCINT); + g_ComCSR.TSTART = 0; +} + +} // end of namespace SerialInterface diff --git a/Source/Core/Core/Src/HW/SerialInterface.h b/Source/Core/Core/Src/HW/SI.h similarity index 96% rename from Source/Core/Core/Src/HW/SerialInterface.h rename to Source/Core/Core/Src/HW/SI.h index 4bfb59c2ff..36a1967344 100644 --- a/Source/Core/Core/Src/HW/SerialInterface.h +++ b/Source/Core/Core/Src/HW/SI.h @@ -1,39 +1,36 @@ -// Copyright (C) 2003-2008 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 _SERIALINTERFACE_H -#define _SERIALINTERFACE_H - -#include "Common.h" -class PointerWrap; - -namespace SerialInterface -{ - -void Init(); -void Shutdown(); -void DoState(PointerWrap &p); - -void UpdateDevices(); - -void HWCALL Read32(u32& _uReturnValue, const u32 _iAddress); -void HWCALL Write32(const u32 _iValue, const u32 _iAddress); - -}; // end of namespace SerialInterface - -#endif - +// Copyright (C) 2003-2008 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 _SERIALINTERFACE_H +#define _SERIALINTERFACE_H + +#include "Common.h" +class PointerWrap; + +namespace SerialInterface +{ + +void Init(); +void Shutdown(); +void DoState(PointerWrap &p); + +void UpdateDevices(); + +void HWCALL Read32(u32& _uReturnValue, const u32 _iAddress); +void HWCALL Write32(const u32 _iValue, const u32 _iAddress); + +}; // end of namespace SerialInterface +#endif diff --git a/Source/Core/Core/Src/HW/SI_Device.cpp b/Source/Core/Core/Src/HW/SI_Device.cpp new file mode 100644 index 0000000000..2f05c2729c --- /dev/null +++ b/Source/Core/Core/Src/HW/SI_Device.cpp @@ -0,0 +1,70 @@ +// Copyright (C) 2003-2008 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_Device.h" + +// ===================================================================================================== +// --- base class --- +// ===================================================================================================== + +int ISIDevice::RunBuffer(u8* _pBuffer, int _iLength) +{ +#ifdef _DEBUG + LOG(SERIALINTERFACE, "Send Data Device(%i) - Length(%i) ", ISIDevice::m_iDeviceNumber,_iLength); + + char szTemp[256] = ""; + int num = 0; + while(num < _iLength) + { + char szTemp2[128] = ""; + sprintf(szTemp2, "0x%02x ", _pBuffer[num^3]); + strcat(szTemp, szTemp2); + num++; + + if ((num % 8) == 0) + { + LOG(SERIALINTERFACE, szTemp); + szTemp[0] = '\0'; + } + } + LOG(SERIALINTERFACE, szTemp); +#endif + return 0; +}; + +// ===================================================================================================== +// --- dummy device --- +// ===================================================================================================== + +CSIDevice_Dummy::CSIDevice_Dummy(int _iDeviceNumber) : + ISIDevice(_iDeviceNumber) +{} + +int CSIDevice_Dummy::RunBuffer(u8* _pBuffer, int _iLength) +{ + reinterpret_cast(_pBuffer)[0] = 0x00000000; // no device + return 4; +} + +bool CSIDevice_Dummy::GetData(u32& _Hi, u32& _Low) +{ + return false; +} + +void CSIDevice_Dummy::SendCommand(u32 _Cmd) +{ +} diff --git a/Source/Core/Core/Src/HW/SI_Device.h b/Source/Core/Core/Src/HW/SI_Device.h new file mode 100644 index 0000000000..b38e9df2b4 --- /dev/null +++ b/Source/Core/Core/Src/HW/SI_Device.h @@ -0,0 +1,108 @@ +// Copyright (C) 2003-2008 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_H +#define _SIDEVICE_H + +#include "Common.h" + +#define SI_ERROR_NO_RESPONSE 0x0008 // nothing is attached +#define SI_ERROR_UNKNOWN 0x0040 // unknown device is attached +#define SI_ERROR_BUSY 0x0080 // still detecting + +// Device types +#define SI_TYPE_MASK 0x18000000u +#define SI_TYPE_N64 0x00000000u +#define SI_TYPE_GC 0x08000000u + +// GameCube +#define SI_GC_WIRELESS 0x80000000u +#define SI_GC_NOMOTOR 0x20000000u // no rumble motor +#define SI_GC_STANDARD 0x01000000u + +// WaveBird +#define SI_WIRELESS_RECEIVED 0x40000000u // 0: no wireless unit +#define SI_WIRELESS_IR 0x04000000u // 0: IR 1: RF +#define SI_WIRELESS_STATE 0x02000000u // 0: variable 1: fixed +#define SI_WIRELESS_ORIGIN 0x00200000u // 0: invalid 1: valid +#define SI_WIRELESS_FIX_ID 0x00100000u // 0: not fixed 1: fixed +#define SI_WIRELESS_TYPE 0x000f0000u +#define SI_WIRELESS_LITE_MASK 0x000c0000u // 0: normal 1: lite controller +#define SI_WIRELESS_LITE 0x00040000u // 0: normal 1: lite controller +#define SI_WIRELESS_CONT_MASK 0x00080000u // 0: non-controller 1: non-controller +#define SI_WIRELESS_CONT 0x00000000u +#define SI_WIRELESS_ID 0x00c0ff00u +#define SI_WIRELESS_TYPE_ID (SI_WIRELESS_TYPE | SI_WIRELESS_ID) + +// "Complete" IDs +#define SI_N64_CONTROLLER (SI_TYPE_N64 | 0x05000000) +#define SI_N64_MIC (SI_TYPE_N64 | 0x00010000) +#define SI_N64_KEYBOARD (SI_TYPE_N64 | 0x00020000) +#define SI_N64_MOUSE (SI_TYPE_N64 | 0x02000000) +#define SI_GBA (SI_TYPE_N64 | 0x00040000) +#define SI_GC_CONTROLLER (SI_TYPE_GC | SI_GC_STANDARD) +#define SI_GC_RECEIVER (SI_TYPE_GC | SI_GC_WIRELESS) +#define SI_GC_WAVEBIRD (SI_TYPE_GC | SI_GC_WIRELESS | SI_GC_STANDARD | SI_WIRELESS_STATE | SI_WIRELESS_FIX_ID) +#define SI_GC_KEYBOARD (SI_TYPE_GC | 0x00200000) +#define SI_GC_STEERING (SI_TYPE_GC | 0x00000000) + + +class ISIDevice +{ +protected: + int m_iDeviceNumber; + +public: + + // constructor + ISIDevice(int _iDeviceNumber) : + m_iDeviceNumber(_iDeviceNumber) + { } + virtual ~ISIDevice() { } + + // run the SI Buffer + virtual int RunBuffer(u8* _pBuffer, int _iLength); + + // return true on new data + virtual bool GetData(u32& _Hi, u32& _Low) = 0; + + // send a command directly (no detour per buffer) + virtual void SendCommand(u32 _Cmd) = 0; +}; + +// ===================================================================================================== +// dummy - no device attached +// ===================================================================================================== + +class CSIDevice_Dummy : public ISIDevice +{ +public: + + // constructor + CSIDevice_Dummy(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); +}; + +#endif diff --git a/Source/Core/Core/Src/HW/SerialInterface_Devices.cpp b/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp similarity index 70% rename from Source/Core/Core/Src/HW/SerialInterface_Devices.cpp rename to Source/Core/Core/Src/HW/SI_DeviceGCController.cpp index 1719fb83fc..e767fa0c2f 100644 --- a/Source/Core/Core/Src/HW/SerialInterface_Devices.cpp +++ b/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp @@ -1,238 +1,171 @@ -// Copyright (C) 2003-2008 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 -#include - -#include "SerialInterface_Devices.h" - -#include "EXI_Device.h" -#include "EXI_DeviceMic.h" - -#include "../Plugins/Plugin_PAD.h" - -#include "../PowerPC/PowerPC.h" -#include "CPU.h" - -#define SI_TYPE_GC 0x08000000u - -#define SI_GC_STANDARD 0x01000000u // dolphin standard controller -#define SI_GC_NOMOTOR 0x20000000u // no rumble motor - -#define SI_GC_KEYBOARD (SI_TYPE_GC | 0x00200000) -#define SI_GC_CONTROLLER (SI_TYPE_GC | SI_GC_STANDARD) - -#define SI_MAX_COMCSR_INLNGTH 128 -#define SI_MAX_COMCSR_OUTLNGTH 128 - -// ===================================================================================================== -// --- base class --- -// ===================================================================================================== - -int ISIDevice::RunBuffer(u8* _pBuffer, int _iLength) -{ -#ifdef _DEBUG - LOG(SERIALINTERFACE, "Send Data Device(%i) - Length(%i) ", ISIDevice::m_iDeviceNumber,_iLength); - - char szTemp[256] = ""; - int num = 0; - while(num < _iLength) - { - char szTemp2[128] = ""; - sprintf(szTemp2, "0x%02x ", _pBuffer[num^3]); - strcat(szTemp, szTemp2); - num++; - - if ((num % 8) == 0) - { - LOG(SERIALINTERFACE, szTemp); - szTemp[0] = '\0'; - } - } - LOG(SERIALINTERFACE, szTemp); -#endif - return 0; -}; - -// ===================================================================================================== -// --- standard gamecube controller --- -// ===================================================================================================== - -CSIDevice_GCController::CSIDevice_GCController(int _iDeviceNumber) : - ISIDevice(_iDeviceNumber) -{ - memset(&m_origin, 0, sizeof(SOrigin)); - - m_origin.uCommand = 0x41; - m_origin.uOriginStickX = 0x80; - m_origin.uOriginStickY = 0x80; - m_origin.uSubStickStickX = 0x80; - m_origin.uSubStickStickY = 0x80; - m_origin.uTrigger_L = 0x1F; - m_origin.uTrigger_R = 0x1F; -} - -int CSIDevice_GCController::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(_pBuffer[iPosition ^ 3]); - iPosition++; - - // handle it - switch(command) - { - case CMD_RESET: - { - *(u32*)&_pBuffer[0] = SI_GC_CONTROLLER; // | SI_GC_NOMOTOR; - iPosition = _iLength; // break the while loop - } - break; - - case CMD_ORIGIN: - { - LOG(SERIALINTERFACE, "SI - Get Origin"); - u8* pCalibration = reinterpret_cast(&m_origin); - for (int i = 0; i < (int)sizeof(SOrigin); i++) - { - _pBuffer[i ^ 3] = *pCalibration++; - } - } - iPosition = _iLength; - break; - - // Recalibrate (FiRES: i am not 100 percent sure about this) - case CMD_RECALIBRATE: - { - LOG(SERIALINTERFACE, "SI - Recalibrate"); - u8* pCalibration = reinterpret_cast(&m_origin); - for (int i = 0; i < (int)sizeof(SOrigin); i++) - { - _pBuffer[i ^ 3] = *pCalibration++; - } - } - iPosition = _iLength; - break; - - // WII Something - case 0xCE: - LOG(SERIALINTERFACE, "Unknown Wii SI Command"); - break; - - // DEFAULT - default: - { - LOG(SERIALINTERFACE, "unknown SI command (0x%x)", command); - PanicAlert("SI: Unknown command"); - iPosition = _iLength; - } - break; - } - } - - return iPosition; -} - -// __________________________________________________________________________________________________ -// GetData -// -// return true on new data (max 7 Bytes and 6 bits ;) -// -bool -CSIDevice_GCController::GetData(u32& _Hi, u32& _Low) -{ - SPADStatus PadStatus; - memset(&PadStatus, 0 ,sizeof(PadStatus)); - PluginPAD::PAD_GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus); - - _Hi = (u32)((u8)PadStatus.stickY); - _Hi |= (u32)((u8)PadStatus.stickX << 8); - _Hi |= (u32)((u16)PadStatus.button << 16); - - _Low = (u8)PadStatus.triggerRight; - _Low |= (u32)((u8)PadStatus.triggerLeft << 8); - _Low |= (u32)((u8)PadStatus.substickY << 16); - _Low |= (u32)((u8)PadStatus.substickX << 24); - SetMic(PadStatus.MicButton); - - // F|RES: - // i dunno if i should force it here - // means that the pad must be "combined" with the origin to math the "final" OSPad-Struct - _Hi |= 0x00800000; - - return true; -} - -// __________________________________________________________________________________________________ -// SendCommand -// -void -CSIDevice_GCController::SendCommand(u32 _Cmd) -{ - UCommand command(_Cmd); - switch(command.Command) - { - // Costis sent it in some demos :) - case 0x00: - break; - - case CMD_RUMBLE: - { - unsigned int uType = command.Parameter1; // 0 = stop, 1 = rumble, 2 = stop hard - unsigned int uStrength = command.Parameter2; - if (PluginPAD::PAD_Rumble) - PluginPAD::PAD_Rumble(ISIDevice::m_iDeviceNumber, uType, uStrength); - } - break; - - default: - { - LOG(SERIALINTERFACE, "unknown direct command (0x%x)", _Cmd); - PanicAlert("SI: Unknown direct command"); - } - break; - } -} - -// ===================================================================================================== -// --- dummy device --- -// ===================================================================================================== - -CSIDevice_Dummy::CSIDevice_Dummy(int _iDeviceNumber) : - ISIDevice(_iDeviceNumber) -{} - -int CSIDevice_Dummy::RunBuffer(u8* _pBuffer, int _iLength) -{ - reinterpret_cast(_pBuffer)[0] = 0x00000000; // no device - return 4; -} - -bool CSIDevice_Dummy::GetData(u32& _Hi, u32& _Low) -{ - return false; -} - -void CSIDevice_Dummy::SendCommand(u32 _Cmd) -{ -} - +// Copyright (C) 2003-2008 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 +#include + +#include "SI_Device.h" +#include "SI_DeviceGCController.h" +#include "../Plugins/Plugin_PAD.h" + +#include "EXI_Device.h" +#include "EXI_DeviceMic.h" + +// ===================================================================================================== +// --- standard gamecube controller --- +// ===================================================================================================== + +CSIDevice_GCController::CSIDevice_GCController(int _iDeviceNumber) : + ISIDevice(_iDeviceNumber) +{ + memset(&m_origin, 0, sizeof(SOrigin)); + + m_origin.uCommand = 0x41; + m_origin.uOriginStickX = 0x80; + m_origin.uOriginStickY = 0x80; + m_origin.uSubStickStickX = 0x80; + m_origin.uSubStickStickY = 0x80; + m_origin.uTrigger_L = 0x1F; + m_origin.uTrigger_R = 0x1F; +} + +int CSIDevice_GCController::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(_pBuffer[iPosition ^ 3]); + iPosition++; + + // handle it + switch(command) + { + case CMD_RESET: + { + *(u32*)&_pBuffer[0] = SI_GC_CONTROLLER; // | SI_GC_NOMOTOR; + iPosition = _iLength; // break the while loop + } + break; + + case CMD_ORIGIN: + { + LOG(SERIALINTERFACE, "PAD - Get Origin"); + u8* pCalibration = reinterpret_cast(&m_origin); + for (int i = 0; i < (int)sizeof(SOrigin); i++) + { + _pBuffer[i ^ 3] = *pCalibration++; + } + } + iPosition = _iLength; + break; + + // Recalibrate (FiRES: i am not 100 percent sure about this) + case CMD_RECALIBRATE: + { + LOG(SERIALINTERFACE, "PAD - Recalibrate"); + u8* pCalibration = reinterpret_cast(&m_origin); + for (int i = 0; i < (int)sizeof(SOrigin); i++) + { + _pBuffer[i ^ 3] = *pCalibration++; + } + } + iPosition = _iLength; + break; + + // WII Something + case 0xCE: + LOG(SERIALINTERFACE, "Unknown Wii SI Command"); + break; + + // DEFAULT + default: + { + LOG(SERIALINTERFACE, "unknown SI command (0x%x)", command); + PanicAlert("SI: Unknown command"); + iPosition = _iLength; + } + break; + } + } + + return iPosition; +} + +// __________________________________________________________________________________________________ +// GetData +// +// return true on new data (max 7 Bytes and 6 bits ;) +// +bool +CSIDevice_GCController::GetData(u32& _Hi, u32& _Low) +{ + SPADStatus PadStatus; + memset(&PadStatus, 0 ,sizeof(PadStatus)); + PluginPAD::PAD_GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus); + + _Hi = (u32)((u8)PadStatus.stickY); + _Hi |= (u32)((u8)PadStatus.stickX << 8); + _Hi |= (u32)((u16)PadStatus.button << 16); + + _Low = (u8)PadStatus.triggerRight; + _Low |= (u32)((u8)PadStatus.triggerLeft << 8); + _Low |= (u32)((u8)PadStatus.substickY << 16); + _Low |= (u32)((u8)PadStatus.substickX << 24); + SetMic(PadStatus.MicButton); + + // F|RES: + // i dunno if i should force it here + // means that the pad must be "combined" with the origin to math the "final" OSPad-Struct + _Hi |= 0x00800000; + + return true; +} + +// __________________________________________________________________________________________________ +// SendCommand +// +void +CSIDevice_GCController::SendCommand(u32 _Cmd) +{ + UCommand command(_Cmd); + switch(command.Command) + { + // Costis sent it in some demos :) + case 0x00: + break; + + case CMD_RUMBLE: + { + unsigned int uType = command.Parameter1; // 0 = stop, 1 = rumble, 2 = stop hard + unsigned int uStrength = command.Parameter2; + if (PluginPAD::PAD_Rumble) + PluginPAD::PAD_Rumble(ISIDevice::m_iDeviceNumber, uType, uStrength); + } + break; + + default: + { + LOG(SERIALINTERFACE, "unknown direct command (0x%x)", _Cmd); + PanicAlert("SI: Unknown direct command"); + } + break; + } +} diff --git a/Source/Core/Core/Src/HW/SerialInterface_Devices.h b/Source/Core/Core/Src/HW/SI_DeviceGCController.h similarity index 64% rename from Source/Core/Core/Src/HW/SerialInterface_Devices.h rename to Source/Core/Core/Src/HW/SI_DeviceGCController.h index cae353d456..b7d9029fc5 100644 --- a/Source/Core/Core/Src/HW/SerialInterface_Devices.h +++ b/Source/Core/Core/Src/HW/SI_DeviceGCController.h @@ -1,139 +1,90 @@ -// Copyright (C) 2003-2008 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 _SERIALINTERFACE_DEVICES_H -#define _SERIALINTERFACE_DEVICES_H - -#include "Common.h" -class PointerWrap; - -class ISIDevice -{ -protected: - int m_iDeviceNumber; - -public: - - // constructor - ISIDevice(int _iDeviceNumber) : - m_iDeviceNumber(_iDeviceNumber) - { } - virtual ~ISIDevice() { } - - // run the SI Buffer - virtual int RunBuffer(u8* _pBuffer, int _iLength); - - // return true on new data - virtual bool GetData(u32& _Hi, u32& _Low) = 0; - - // send a command directly (no detour per buffer) - virtual void SendCommand(u32 _Cmd) = 0; -}; - -// ===================================================================================================== -// standard gamecube controller -// ===================================================================================================== - -class CSIDevice_GCController : public ISIDevice -{ -private: - - // commands - enum EBufferCommands - { - CMD_INVALID = 0xFFFFFFFF, - CMD_RESET = 0x00, - CMD_ORIGIN = 0x41, - CMD_RECALIBRATE = 0x42, - }; - - struct SOrigin - { - u8 uCommand; - u8 unk_1; - u8 uOriginStickX; - u8 uOriginStickY; - u8 uSubStickStickX; // ??? - u8 uSubStickStickY; // ??? - u8 uTrigger_L; // ??? - u8 uTrigger_R; // ??? - u8 unk_4; - u8 unk_5; - u8 unk_6; - u8 unk_7; - }; - - enum EDirectCommands - { - CMD_RUMBLE = 0x40 - }; - - union UCommand - { - u32 Hex; - struct - { - unsigned Parameter1 : 8; - unsigned Parameter2 : 8; - unsigned Command : 8; - unsigned : 8; - }; - UCommand() {Hex = 0;} - UCommand(u32 _iValue) {Hex = _iValue;} - }; - - SOrigin m_origin; - int DeviceNum; - -public: - - // constructor - CSIDevice_GCController(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); -}; - -// ===================================================================================================== -// dummy - no device attached -// ===================================================================================================== - -class CSIDevice_Dummy : public ISIDevice -{ -public: - - // constructor - CSIDevice_Dummy(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); -}; - -#endif - +// Copyright (C) 2003-2008 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 _SI_DEVICEGCCONTROLLER_H +#define _SI_DEVICEGCCONTROLLER_H + +// ===================================================================================================== +// standard gamecube controller +// ===================================================================================================== + +class CSIDevice_GCController : public ISIDevice +{ +private: + + // commands + enum EBufferCommands + { + CMD_INVALID = 0xFFFFFFFF, + CMD_RESET = 0x00, + CMD_ORIGIN = 0x41, + CMD_RECALIBRATE = 0x42, + }; + + struct SOrigin + { + u8 uCommand; + u8 unk_1; + u8 uOriginStickX; + u8 uOriginStickY; + u8 uSubStickStickX; // ??? + u8 uSubStickStickY; // ??? + u8 uTrigger_L; // ??? + u8 uTrigger_R; // ??? + u8 unk_4; + u8 unk_5; + u8 unk_6; + u8 unk_7; + }; + + enum EDirectCommands + { + CMD_RUMBLE = 0x40 + }; + + union UCommand + { + u32 Hex; + struct + { + unsigned Parameter1 : 8; + unsigned Parameter2 : 8; + unsigned Command : 8; + unsigned : 8; + }; + UCommand() {Hex = 0;} + UCommand(u32 _iValue) {Hex = _iValue;} + }; + + SOrigin m_origin; + int DeviceNum; + +public: + + // constructor + CSIDevice_GCController(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); +}; +#endif diff --git a/Source/Core/Core/Src/HW/SystemTimers.cpp b/Source/Core/Core/Src/HW/SystemTimers.cpp index 79f1dc60ce..d9ec74be3e 100644 --- a/Source/Core/Core/Src/HW/SystemTimers.cpp +++ b/Source/Core/Core/Src/HW/SystemTimers.cpp @@ -23,7 +23,7 @@ #include "../HW/DSP.h" #include "../HW/AudioInterface.h" #include "../HW/VideoInterface.h" -#include "../HW/SerialInterface.h" +#include "../HW/SI.h" #include "../HW/CommandProcessor.h" // for DC watchdog hack #include "../HW/EXI_DeviceIPL.h" #include "../PowerPC/PowerPC.h" diff --git a/Source/Core/Core/Src/SConscript b/Source/Core/Core/Src/SConscript index caeabf4ae9..e042d11bd8 100644 --- a/Source/Core/Core/Src/SConscript +++ b/Source/Core/Core/Src/SConscript @@ -46,7 +46,10 @@ files = ["Console.cpp", "HW/PeripheralInterface.cpp", "HW/PixelEngine.cpp", "HW/SerialInterface.cpp", - "HW/SerialInterface_Devices.cpp", + "HW/SI.cpp", + "HW/SI_Device.cpp", + "HW/SI_DeviceGBA.cpp", + "HW/SI_DeviceGCController.cpp", "HW/StreamADPCM.cpp", "HW/SystemTimers.cpp", "HW/VideoInterface.cpp", diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index f9968ed5e4..6c81d96cd6 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -134,9 +134,10 @@ void CFrame::CreateMenu() wxMenu* pOptionsMenu = new wxMenu; m_pPluginOptions = pOptionsMenu->Append(IDM_CONFIG_MAIN, _T("Co&nfigure...")); pOptionsMenu->AppendSeparator(); - pOptionsMenu->Append(IDM_CONFIG_GFX_PLUGIN, _T("&Toolbar_PluginGFX settings")); - pOptionsMenu->Append(IDM_CONFIG_DSP_PLUGIN, _T("&Toolbar_PluginDSP settings")); - pOptionsMenu->Append(IDM_CONFIG_PAD_PLUGIN, _T("&Toolbar_PluginPAD settings")); + pOptionsMenu->Append(IDM_CONFIG_GFX_PLUGIN, _T("&GFX settings")); + pOptionsMenu->Append(IDM_CONFIG_DSP_PLUGIN, _T("&DSP settings")); + pOptionsMenu->Append(IDM_CONFIG_PAD_PLUGIN, _T("&PAD settings")); + pOptionsMenu->Append(IDM_CONFIG_WIIMOTE_PLUGIN, _T("&Wiimote settings")); #ifdef _WIN32 pOptionsMenu->AppendSeparator(); pOptionsMenu->Append(IDM_TOGGLE_FULLSCREEN, _T("&Fullscreen\tAlt+Enter"));