diff --git a/Source/Core/Core/Core.vcproj b/Source/Core/Core/Core.vcproj index c005d8c2cbd0..368304870db6 100644 --- a/Source/Core/Core/Core.vcproj +++ b/Source/Core/Core/Core.vcproj @@ -710,6 +710,14 @@ RelativePath=".\Src\Hw\EXI_DeviceAD16.h" > + + + + @@ -782,6 +790,14 @@ RelativePath=".\Src\HW\SI_Device.h" > + + + + diff --git a/Source/Core/Core/Src/HW/AudioInterface.cpp b/Source/Core/Core/Src/HW/AudioInterface.cpp index 699257e4ec5a..fd8ba2363ffd 100644 --- a/Source/Core/Core/Src/HW/AudioInterface.cpp +++ b/Source/Core/Core/Src/HW/AudioInterface.cpp @@ -196,7 +196,7 @@ void Write32(const u32 _Value, const u32 _Address) // This is the only new code in this ~3,326 revision, it seems to avoid hanging Crazy Taxi, // while the 1080 and Wave Race music still works - if (!tmpAICtrl.PSTAT) DVDInterface::m_bStream = false; + if (!tmpAICtrl.PSTAT) DVDInterface::g_bStream = false; } // AI Interrupt diff --git a/Source/Core/Core/Src/HW/DVDInterface.cpp b/Source/Core/Core/Src/HW/DVDInterface.cpp index 435520ee2c51..e7b59e963a48 100644 --- a/Source/Core/Core/Src/HW/DVDInterface.cpp +++ b/Source/Core/Core/Src/HW/DVDInterface.cpp @@ -31,26 +31,6 @@ namespace DVDInterface { -/* -20975: 00000000 DVD (zzz_80146b84 ??, 0x80146bf8) : DVD(r): 0xcc006004 -20976: 00000000 DVD (zzz_80146b84 ??, 0x80146c00) : DVD(w): 0x00000000 @ 0xcc006004 -20977: 00000000 DVD (DVDLowRead, 0x801448a8) : DVD(w): 0x00000020 @ 0xcc006018 -20978: 00000000 DVD (Read, 0x80144744) : DVD(w): 0xa8000000 @ 0xcc006008 -20979: 00000000 DVD (Read, 0x80144750) : DVD(w): 0x01094227 @ 0xcc00600c -20980: 00000000 DVD (Read, 0x80144758) : DVD(w): 0x00000020 @ 0xcc006010 -20981: 00000000 DVD (Read, 0x8014475c) : DVD(w): 0x8167cc80 @ 0xcc006014 -20982: 00000000 DVD (Read, 0x80144760) : DVD(w): 0x00000020 @ 0xcc006018 -20983: 00000000 DVD (Read, 0x80144768) : DVD(w): 0x00000003 @ 0xcc00601c -20984: 00000000 DVD: DVD: Read ISO: DVDOffset=0425089c, DMABuffer=0167cc80, SrcLength=00000020, DMALength=00000020 -20989: 00000000 DVD (zzz_801442fc ??, 0x80144388) : DVD(r): 0xcc006000 -20990: 00000000 DVD (zzz_801442fc ??, 0x801443d8) : DVD(w): 0x0000003a @ 0xcc006000 -20992: 00000000 DVD (zzz_801442fc ??, 0x801444d0) : DVD(w): 0x00000000 @ 0xcc006004 -20993: 00000000 DVD (zzz_80146e44 ??, 0x80146fcc) : DVD(r): 0xcc006018 - -After this, Cubivore infinitely calls DVDGetDriveStatus, which does not even -bother to check any DVD regs. Waiting for interrupt? -*/ - // internal hardware addresses enum { @@ -89,15 +69,15 @@ enum union UDISR { u32 Hex; - struct - { - unsigned BREAK : 1; // Stop the Device + Interrupt - unsigned DEINITMASK : 1; // Access Device Error Int Mask - unsigned DEINT : 1; // Access Device Error Int - unsigned TCINTMASK : 1; // Transfer Complete Int Mask - unsigned TCINT : 1; // Transfer Complete Int + struct + { + unsigned BREAK : 1; // Stop the Device + Interrupt + unsigned DEINITMASK : 1; // Access Device Error Int Mask + unsigned DEINT : 1; // Access Device Error Int + unsigned TCINTMASK : 1; // Transfer Complete Int Mask + unsigned TCINT : 1; // Transfer Complete Int unsigned BRKINTMASK : 1; - unsigned BRKINT : 1; // w 1: clear brkint + unsigned BRKINT : 1; // w 1: clear brkint unsigned : 25; }; UDISR() {Hex = 0;} @@ -108,22 +88,39 @@ union UDISR union UDICVR { u32 Hex; - struct - { - unsigned CVR : 1; // 0: Cover closed 1: Cover open - unsigned CVRINTMASK : 1; // 1: Interrupt enabled; - unsigned CVRINT : 1; // r 1: Interrupt requested w 1: Interrupt clear + struct + { + unsigned CVR : 1; // 0: Cover closed 1: Cover open + unsigned CVRINTMASK : 1; // 1: Interrupt enabled + unsigned CVRINT : 1; // r 1: Interrupt requested w 1: Interrupt clear unsigned : 29; }; UDICVR() {Hex = 0;} UDICVR(u32 _hex) {Hex = _hex;} }; +union UDICMDBUF +{ + u32 Hex; + struct + { + u8 CMDBYTE3; + u8 CMDBYTE2; + u8 CMDBYTE1; + u8 CMDBYTE0; + }; +}; + // DI DMA Address Register -union UDIDMAAddressRegister +union UDIMAR { u32 Hex; - struct + struct + { + unsigned Zerobits : 5; // Must be zero (32byte aligned) + unsigned : 27; + }; + struct { unsigned Address : 26; unsigned : 6; @@ -131,71 +128,81 @@ union UDIDMAAddressRegister }; // DI DMA Address Length Register -union UDIDMAAddressLength +union UDILENGTH { u32 Hex; - struct + struct { - unsigned Length : 26; + unsigned Zerobits : 5; // Must be zero (32byte aligned) + unsigned : 27; + }; + struct + { + unsigned Length : 26; unsigned : 6; }; }; // DI DMA Control Register -union UDIDMAControlRegister +union UDICR { u32 Hex; - struct + struct { - unsigned TSTART : 1; // w:1 start r:0 ready - unsigned DMA : 1; // 1: DMA Mode 0: Immediate Mode (can only do Access Register Command) - unsigned RW : 1; // 0: Read Command (DVD to Memory) 1: Write COmmand (Memory to DVD) + unsigned TSTART : 1; // w:1 start r:0 ready + unsigned DMA : 1; // 1: DMA Mode 0: Immediate Mode (can only do Access Register Command) + unsigned RW : 1; // 0: Read Command (DVD to Memory) 1: Write COmmand (Memory to DVD) unsigned : 29; }; }; -// DI Config Register -union UDIConfigRegister +union UDIIMMBUF { u32 Hex; - struct + struct { - unsigned CONFIG : 8; - unsigned : 24; + u8 REGVAL3; + u8 REGVAL2; + u8 REGVAL1; + u8 REGVAL0; }; - UDIConfigRegister() {Hex = 0;} - UDIConfigRegister(u32 _hex) {Hex = _hex;} }; -// HACK to allow multi-command debug-mode transfers -struct SDIDebugTransfer +// DI Config Register +union UDICFG { - u32 Address; - u16 Length; - bool InProgress; + u32 Hex; + struct + { + unsigned CONFIG : 8; + unsigned : 24; + }; + UDICFG() {Hex = 0;} + UDICFG(u32 _hex) {Hex = _hex;} }; -// hardware registers -struct DVDMemStruct -{ - UDISR StatusReg; - UDICVR CoverReg; - u32 Command[3]; - UDIDMAAddressRegister DMAAddress; - UDIDMAAddressLength DMALength; - UDIDMAControlRegister DMAControlReg; - u32 Immediate; - UDIConfigRegister ConfigReg; - u32 AudioStart; - u32 AudioPos; - u32 AudioLength; - SDIDebugTransfer DebugTransfer; -}; // STATE_TO_SAVE -DVDMemStruct dvdMem; -u32 g_ErrorCode = 0x00; +// hardware registers +static UDISR m_DISR; +static UDICVR m_DICVR; +static UDICMDBUF m_DICMDBUF[3]; +static UDIMAR m_DIMAR; +static UDILENGTH m_DILENGTH; +static UDICR m_DICR; +static UDIIMMBUF m_DIIMMBUF; +static UDICFG m_DICFG; + +static u32 AudioStart; +static u32 AudioPos; +static u32 AudioLength; + +u32 g_ErrorCode = 0; bool g_bDiscInside = false; +bool g_bStream = false; + +// GC-AM only +static unsigned char media_buffer[0x40]; Common::CriticalSection dvdread_section; @@ -208,23 +215,35 @@ void ChangeDiscCallback(u64 userdata, int cyclesLate); void DoState(PointerWrap &p) { - p.Do(dvdMem); + p.Do(m_DISR); + p.Do(m_DICVR); + p.DoArray(m_DICMDBUF, 3); + p.Do(m_DIMAR); + p.Do(m_DILENGTH); + p.Do(m_DICR); + p.Do(m_DIIMMBUF); + p.Do(m_DICFG); + + p.Do(AudioStart); + p.Do(AudioPos); + p.Do(AudioLength); + p.Do(g_ErrorCode); p.Do(g_bDiscInside); } void UpdateInterrupts(); void GenerateDVDInterrupt(DVDInterruptType _DVDInterrupt); -void ExecuteCommand(UDIDMAControlRegister& _DMAControlReg); +void ExecuteCommand(UDICR& _DICR); static int et_GenerateDVDInterrupt; -static void GenerateDVDInterrupt_Wrapper(u64 userdata, int cyclesLate) +static void GenerateDVDInterruptCallback(u64 userdata, int cyclesLate) { GenerateDVDInterrupt((DVDInterruptType)userdata); } -static void GenerateDVDInterruptFromDVDThread(DVDInterruptType type) +static void GenerateDVDInterrupt_Threadsafe(DVDInterruptType type) { CoreTiming::ScheduleEvent_Threadsafe(0, et_GenerateDVDInterrupt, type); } @@ -238,8 +257,8 @@ static THREAD_RETURN DVDThreadFunc(void* arg) if (g_dvdQuitSignal) break; - if (dvdMem.DMAControlReg.TSTART) - ExecuteCommand(dvdMem.DMAControlReg); + if (m_DICR.TSTART) + ExecuteCommand(m_DICR); } return 0; @@ -247,21 +266,23 @@ static THREAD_RETURN DVDThreadFunc(void* arg) void Init() { - dvdMem.StatusReg.Hex = 0; - dvdMem.CoverReg.Hex = 0; - dvdMem.Command[0] = 0; - dvdMem.Command[1] = 0; - dvdMem.Command[2] = 0; - dvdMem.DMAAddress.Hex = 0; - dvdMem.DMALength.Hex = 0; - dvdMem.DMAControlReg.Hex = 0; - dvdMem.Immediate = 0; - dvdMem.ConfigReg.Hex = 0; - dvdMem.AudioStart = 0; - dvdMem.AudioPos = 0; - dvdMem.AudioLength = 0; - - et_GenerateDVDInterrupt = CoreTiming::RegisterEvent("DVDint", GenerateDVDInterrupt_Wrapper); + m_DISR.Hex = 0; + m_DICVR.Hex = 0; + m_DICMDBUF[0].Hex= 0; + m_DICMDBUF[1].Hex= 0; + m_DICMDBUF[2].Hex= 0; + m_DIMAR.Hex = 0; + m_DILENGTH.Hex = 0; + m_DICR.Hex = 0; + m_DIIMMBUF.Hex = 0; + m_DICFG.Hex = 0; + m_DICFG.CONFIG = 1; // Disable bootrom descrambler + + AudioStart = 0; + AudioPos = 0; + AudioLength = 0; + + et_GenerateDVDInterrupt = CoreTiming::RegisterEvent("DVDint", GenerateDVDInterruptCallback); g_dvdAlert.Init(); g_dvdThread = new Common::Thread(DVDThreadFunc, NULL); @@ -291,7 +312,7 @@ void Shutdown() void SetDiscInside(bool _DiscInside) { - g_bDiscInside = _DiscInside; + g_bDiscInside = _DiscInside; } bool IsDiscInside() @@ -346,19 +367,19 @@ void ChangeDisc(const char* _FileName) void SetLidOpen(bool _bOpen) { - dvdMem.CoverReg.CVR = _bOpen ? 1 : 0; + m_DICVR.CVR = _bOpen ? 1 : 0; - GenerateDVDInterrupt(INT_CVRINT); + GenerateDVDInterrupt_Threadsafe(INT_CVRINT); } bool IsLidOpen() { - return (dvdMem.CoverReg.CVR == 1); + return (m_DICVR.CVR == 1); } void ClearCoverInterrupt() { - dvdMem.CoverReg.CVRINT = 0; + m_DICVR.CVRINT = 0; } bool DVDRead(u32 _iDVDOffset, u32 _iRamAddress, u32 _iLength) @@ -372,7 +393,7 @@ bool DVDRead(u32 _iDVDOffset, u32 _iRamAddress, u32 _iLength) bool DVDReadADPCM(u8* _pDestBuffer, u32 _iNumSamples) { - if (dvdMem.AudioPos == 0) + if (AudioPos == 0) { //MessageBox(0,"DVD: Trying to stream from 0", "bah", 0); memset(_pDestBuffer, 0, _iNumSamples); // probably __AI_SRC_INIT :P @@ -380,7 +401,7 @@ bool DVDReadADPCM(u8* _pDestBuffer, u32 _iNumSamples) } _iNumSamples &= ~31; dvdread_section.Enter(); - VolumeHandler::ReadToPtr(_pDestBuffer, dvdMem.AudioPos, _iNumSamples); + VolumeHandler::ReadToPtr(_pDestBuffer, AudioPos, _iNumSamples); dvdread_section.Leave(); // @@ -388,63 +409,57 @@ bool DVDReadADPCM(u8* _pDestBuffer, u32 _iNumSamples) // // loop check // - dvdMem.AudioPos += _iNumSamples; - if (dvdMem.AudioPos >= dvdMem.AudioStart + dvdMem.AudioLength) + AudioPos += _iNumSamples; + if (AudioPos >= AudioStart + AudioLength) { - dvdMem.AudioPos = dvdMem.AudioStart; + AudioPos = AudioStart; NGCADPCM::InitFilter(); } - //LOG(DVDINTERFACE,"ReadADPCM"); + //WARN_LOG(DVDINTERFACE,"ReadADPCM"); return true; } void Read32(u32& _uReturnValue, const u32 _iAddress) { - DEBUG_LOG(DVDINTERFACE, "DVD(r): 0x%08x", _iAddress); - - switch (_iAddress & 0xFFF) + switch (_iAddress & 0xFF) { - case DI_STATUS_REGISTER: _uReturnValue = dvdMem.StatusReg.Hex; return; - case DI_COVER_REGISTER: _uReturnValue = dvdMem.CoverReg.Hex; return; - case DI_COMMAND_0: _uReturnValue = dvdMem.Command[0]; return; - case DI_COMMAND_1: _uReturnValue = dvdMem.Command[1]; return; - case DI_COMMAND_2: _uReturnValue = dvdMem.Command[2]; return; - case DI_DMA_ADDRESS_REGISTER: _uReturnValue = dvdMem.DMAAddress.Hex; return; - case DI_DMA_LENGTH_REGISTER: _uReturnValue = dvdMem.DMALength.Hex; return; - case DI_DMA_CONTROL_REGISTER: _uReturnValue = dvdMem.DMAControlReg.Hex; return; - case DI_IMMEDIATE_DATA_BUFFER: _uReturnValue = dvdMem.Immediate; return; - case DI_CONFIG_REGISTER: - { - dvdMem.ConfigReg.Hex = 0x000000FF; - _uReturnValue = dvdMem.ConfigReg.Hex; - return; - } + case DI_STATUS_REGISTER: _uReturnValue = m_DISR.Hex; break; + case DI_COVER_REGISTER: _uReturnValue = m_DICVR.Hex; break; + case DI_COMMAND_0: _uReturnValue = m_DICMDBUF[0].Hex; break; + case DI_COMMAND_1: _uReturnValue = m_DICMDBUF[1].Hex; break; + case DI_COMMAND_2: _uReturnValue = m_DICMDBUF[2].Hex; break; + case DI_DMA_ADDRESS_REGISTER: _uReturnValue = m_DIMAR.Hex; break; + case DI_DMA_LENGTH_REGISTER: _uReturnValue = m_DILENGTH.Hex; break; + case DI_DMA_CONTROL_REGISTER: _uReturnValue = m_DICR.Hex; break; + case DI_IMMEDIATE_DATA_BUFFER: _uReturnValue = m_DIIMMBUF.Hex; break; + case DI_CONFIG_REGISTER: _uReturnValue = m_DICFG.Hex; break; default: - _dbg_assert_(DVDINTERFACE,0); + _dbg_assert_(DVDINTERFACE, 0); + _uReturnValue = 0; + break; } - - _uReturnValue = 0; + DEBUG_LOG(DVDINTERFACE, "(r32): 0x%08x - 0x%08x", _iAddress, _uReturnValue); } void Write32(const u32 _iValue, const u32 _iAddress) { - DEBUG_LOG(DVDINTERFACE, "DVD(w): 0x%08x @ 0x%08x", _iValue, _iAddress); + DEBUG_LOG(DVDINTERFACE, "(w32): 0x%08x @ 0x%08x", _iValue, _iAddress); - switch (_iAddress & 0x3FF) + switch (_iAddress & 0xFF) { case DI_STATUS_REGISTER: { UDISR tmpStatusReg(_iValue); - dvdMem.StatusReg.DEINITMASK = tmpStatusReg.DEINITMASK; - dvdMem.StatusReg.TCINTMASK = tmpStatusReg.TCINTMASK; - dvdMem.StatusReg.BRKINTMASK = tmpStatusReg.BRKINTMASK; - - if (tmpStatusReg.DEINT) dvdMem.StatusReg.DEINT = 0; - if (tmpStatusReg.TCINT) dvdMem.StatusReg.TCINT = 0; - if (tmpStatusReg.BRKINT) dvdMem.StatusReg.BRKINT = 0; + m_DISR.DEINITMASK = tmpStatusReg.DEINITMASK; + m_DISR.TCINTMASK = tmpStatusReg.TCINTMASK; + m_DISR.BRKINTMASK = tmpStatusReg.BRKINTMASK; + + if (tmpStatusReg.DEINT) m_DISR.DEINT = 0; + if (tmpStatusReg.TCINT) m_DISR.TCINT = 0; + if (tmpStatusReg.BRKINT) m_DISR.BRKINT = 0; if (tmpStatusReg.BREAK) { @@ -459,38 +474,45 @@ void Write32(const u32 _iValue, const u32 _iAddress) { UDICVR tmpCoverReg(_iValue); - dvdMem.CoverReg.CVRINTMASK = tmpCoverReg.CVRINTMASK; + m_DICVR.CVRINTMASK = tmpCoverReg.CVRINTMASK; + + if (tmpCoverReg.CVRINT) m_DICVR.CVRINT = 0; - if (tmpCoverReg.CVRINT) dvdMem.CoverReg.CVRINT = 0; - UpdateInterrupts(); } break; - case DI_COMMAND_0: dvdMem.Command[0] = _iValue; break; - case DI_COMMAND_1: dvdMem.Command[1] = _iValue; break; - case DI_COMMAND_2: dvdMem.Command[2] = _iValue; break; + case DI_COMMAND_0: m_DICMDBUF[0].Hex = _iValue; break; + case DI_COMMAND_1: m_DICMDBUF[1].Hex = _iValue; break; + case DI_COMMAND_2: m_DICMDBUF[2].Hex = _iValue; break; case DI_DMA_ADDRESS_REGISTER: { - dvdMem.DMAAddress.Hex = _iValue; - _dbg_assert_(DVDINTERFACE, ((dvdMem.DMAAddress.Hex & 0x1F) == 0)); + m_DIMAR.Hex = _iValue; + _dbg_assert_msg_(DVDINTERFACE, m_DIMAR.Zerobits == 0, "DMA Addr not 32byte aligned!"); + } + break; + case DI_DMA_LENGTH_REGISTER: + { + m_DILENGTH.Hex = _iValue; + _dbg_assert_msg_(DVDINTERFACE, m_DILENGTH.Zerobits == 0, "DMA Length not 32byte aligned!"); } break; - case DI_DMA_LENGTH_REGISTER: dvdMem.DMALength.Hex = _iValue; break; case DI_DMA_CONTROL_REGISTER: { - dvdMem.DMAControlReg.Hex = _iValue; + m_DICR.Hex = _iValue; + // The thread loop checks if TSTART is set, don't need to check here g_dvdAlert.Set(); } break; - case DI_IMMEDIATE_DATA_BUFFER: dvdMem.Immediate = _iValue; break; + case DI_IMMEDIATE_DATA_BUFFER: m_DIIMMBUF.Hex = _iValue; break; + case DI_CONFIG_REGISTER: { - UDIConfigRegister tmpConfigReg(_iValue); - - dvdMem.ConfigReg.CONFIG = tmpConfigReg.CONFIG; + UDICFG tmpConfigReg(_iValue); + m_DICFG.CONFIG = tmpConfigReg.CONFIG; + WARN_LOG(DVDINTERFACE, "Write to DICFG, should be read-only"); } break; @@ -502,10 +524,10 @@ void Write32(const u32 _iValue, const u32 _iAddress) void UpdateInterrupts() { - if ((dvdMem.StatusReg.DEINT & dvdMem.StatusReg.DEINITMASK) || - (dvdMem.StatusReg.TCINT & dvdMem.StatusReg.TCINTMASK) || - (dvdMem.StatusReg.BRKINT & dvdMem.StatusReg.BRKINTMASK) || - (dvdMem.CoverReg.CVRINT & dvdMem.CoverReg.CVRINTMASK)) + if ((m_DISR.DEINT & m_DISR.DEINITMASK) || + (m_DISR.TCINT & m_DISR.TCINTMASK) || + (m_DISR.BRKINT & m_DISR.BRKINTMASK) || + (m_DICVR.CVRINT & m_DICVR.CVRINTMASK)) { ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_DI, true); } @@ -519,53 +541,47 @@ void GenerateDVDInterrupt(DVDInterruptType _DVDInterrupt) { switch(_DVDInterrupt) { - case INT_DEINT: dvdMem.StatusReg.DEINT = 1; break; - case INT_TCINT: dvdMem.StatusReg.TCINT = 1; break; - case INT_BRKINT: dvdMem.StatusReg.BRKINT = 1; break; - case INT_CVRINT: dvdMem.CoverReg.CVRINT = 1; break; + case INT_DEINT: m_DISR.DEINT = 1; break; + case INT_TCINT: m_DISR.TCINT = 1; break; + case INT_BRKINT: m_DISR.BRKINT = 1; break; + case INT_CVRINT: m_DICVR.CVRINT = 1; break; } UpdateInterrupts(); } -bool m_bStream = false; - -void ExecuteCommand(UDIDMAControlRegister& _DMAControlReg) +void ExecuteCommand(UDICR& _DICR) { - _dbg_assert_(DVDINTERFACE, _DMAControlReg.RW == 0); // only DVD to Memory +// _dbg_assert_(DVDINTERFACE, _DICR.RW == 0); // only DVD to Memory + int GCAM = ((SConfig::GetInstance().m_SIDevice[0] == SI_AM_BASEBOARD) + && (SConfig::GetInstance().m_EXIDevice[2] == EXIDEVICE_AM_BASEBOARD)) + ? 1 : 0; - // Catch multi-command transfers here - if (dvdMem.DebugTransfer.InProgress) + if (GCAM) { - dvdMem.DebugTransfer.InProgress = false; - // If we ever need to actually read/write the drive ram/cache, here would be the place - // Up to 12bytes can be written at once (dvdMem.Command[0] through dvdMem.Command[2]) - INFO_LOG(DVDINTERFACE, "\t queued cmd: 0x%08x @ 0x%08x NOT IMPLEMENTED", - dvdMem.Command[0], dvdMem.DebugTransfer.Address); + ERROR_LOG(DVDINTERFACE, "DVD: %08x, %08x, %08x, DMA=addr:%08x,len:%08x,ctrl:%08x", + m_DICMDBUF[0], m_DICMDBUF[1], m_DICMDBUF[2], m_DIMAR, m_DILENGTH, m_DICR); + // decrypt command. But we have a zero key, that simplifies things a lot. + // If you get crazy dvd command errors, make sure 0x80000000 - 0x8000000c is zero'd + m_DICMDBUF[0].Hex <<= 24; } - else - { // The huge switch is in this else! - switch ((dvdMem.Command[0] & 0xFF000000) >> 24) + + + switch (m_DICMDBUF[0].CMDBYTE0) { - //========================================================================================================= - // DRIVE INFO (DMA) - // Command/Subcommand/Padding <- 12000000 - // Command0 <- 0 - // Command1 <- 0x20 - // Command2 <- Address in ram of the buffer - // - // output buffer: - // 0000-0001 revisionLevel - // 0002-0003 deviceCode - // 0004-0007 releaseDate - // 0008-001F padding(0) - //========================================================================================================= case DVDLowInquiry: + if (GCAM) + { + // 0x29484100... + // was 21 i'm not entirely sure about this, but it works well. + m_DIIMMBUF.Hex = 0x21000000; + } + else { // small safety check, dunno if it's needed - if ((dvdMem.Command[1] == 0) && (dvdMem.DMALength.Length == 0x20)) + if ((m_DICMDBUF[1].Hex == 0) && (m_DILENGTH.Length == 0x20)) { - u8* driveInfo = Memory::GetPointer(dvdMem.DMAAddress.Address); + u8* driveInfo = Memory::GetPointer(m_DIMAR.Address); // gives the correct output in GCOS - 06 2001/08 (61) // there may be other stuff missing ? driveInfo[4] = 0x20; @@ -581,218 +597,317 @@ void ExecuteCommand(UDIDMAControlRegister& _DMAControlReg) } break; - //========================================================================================================= - // SET EXTENSION - // Apparently the drive needs certain flags set explicitly? - //========================================================================================================= + // "Set Extension"...not sure what it does case 0x55: - INFO_LOG(DVDINTERFACE, "SetExtension %x", _DMAControlReg); + INFO_LOG(DVDINTERFACE, "SetExtension"); break; - //========================================================================================================= - // READ (DMA) - // Command/Subcommand/Padding <- A8000000 - // Command0 <- Position on DVD shr 2 - // Command1 <- Length of the read - // Command2 <- Address in ram of the buffer - //========================================================================================================= + // DMA Read from Disc case 0xA8: + if (g_bDiscInside) { - if (g_bDiscInside) + switch (m_DICMDBUF[0].CMDBYTE3) { - u32 iDVDOffset = dvdMem.Command[1] << 2; - u32 iSrcLength = dvdMem.Command[2]; + case 0x00: // Read Sector + { + u32 iDVDOffset = m_DICMDBUF[1].Hex << 2; + u32 iSrcLength = m_DICMDBUF[2].Hex; + + DEBUG_LOG(DVDINTERFACE, "Read: DVDOffset=%08x, DMABuffer=%08x, SrcLength=%08x, DMALength=%08x", + iDVDOffset, m_DIMAR.Address, iSrcLength, m_DILENGTH.Length); + _dbg_assert_(DVDINTERFACE, iSrcLength == m_DILENGTH.Length); + + if (GCAM) + { + if (iDVDOffset & 0x80000000) // read request to hardware buffer + { + switch (iDVDOffset) + { + case 0x80000000: + ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (80000000)"); + for (unsigned int i = 0; i < m_DILENGTH.Length / 4; i++) + Memory::Write_U32(0, m_DIMAR.Address + i * 4); + break; + case 0x80000040: + ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (2) (80000040)"); + for (unsigned int i = 0; i < m_DILENGTH.Length / 4; i++) + Memory::Write_U32(~0, m_DIMAR.Address + i * 4); + Memory::Write_U32(0x00000020, m_DIMAR.Address); // DIMM SIZE, LE + Memory::Write_U32(0x4743414D, m_DIMAR.Address + 4); // GCAM signature + break; + case 0x80000120: + ERROR_LOG(DVDINTERFACE, "GC-AM: READ FIRMWARE STATUS (80000120)"); + for (unsigned int i = 0; i < m_DILENGTH.Length / 4; i++) + Memory::Write_U32(0x01010101, m_DIMAR.Address + i * 4); + break; + case 0x80000140: + ERROR_LOG(DVDINTERFACE, "GC-AM: READ FIRMWARE STATUS (80000140)"); + for (unsigned int i = 0; i < m_DILENGTH.Length / 4; i++) + Memory::Write_U32(0x01010101, m_DIMAR.Address + i * 4); + break; + case 0x84000020: + ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (1) (84000020)"); + for (unsigned int i = 0; i < m_DILENGTH.Length / 4; i++) + Memory::Write_U32(0x00000000, m_DIMAR.Address + i * 4); + break; + default: + ERROR_LOG(DVDINTERFACE, "GC-AM: UNKNOWN MEDIA BOARD LOCATION %x", iDVDOffset); + break; + } + break; + } + else if ((iDVDOffset == 0x1f900000) || (iDVDOffset == 0x1f900020)) + { + ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD COMM AREA (1f900020)"); + memcpy(Memory::GetPointer(m_DIMAR.Address), media_buffer + iDVDOffset - 0x1f900000, m_DILENGTH.Length); + unsigned int i; + for (i = 0; i < m_DILENGTH.Length; i += 4) + ERROR_LOG(DVDINTERFACE, "GC-AM: %08x", Memory::Read_U32(m_DIMAR.Address + i)); + break; + } + } + + // Here is the actual Disk Reading + if (!DVDRead(iDVDOffset, m_DIMAR.Address, m_DILENGTH.Length)) + { + PanicAlert("Cant read from DVD_Plugin - DVD-Interface: Fatal Error"); + } + } + break; - INFO_LOG(DVDINTERFACE, "Read ISO: DVDOffset=%08x, DMABuffer=%08x, SrcLength=%08x, DMALength=%08x", - iDVDOffset, dvdMem.DMAAddress.Address, iSrcLength, dvdMem.DMALength.Length); - _dbg_assert_(DVDINTERFACE, iSrcLength == dvdMem.DMALength.Length); + case 0x40: // Read DiscID + _dbg_assert_(DVDINTERFACE, m_DICMDBUF[1].Hex == 0); + _dbg_assert_(DVDINTERFACE, m_DICMDBUF[1].Hex == m_DILENGTH.Length); + _dbg_assert_(DVDINTERFACE, m_DILENGTH.Length == 0x20); + if (!DVDRead(m_DICMDBUF[1].Hex, m_DIMAR.Address, m_DILENGTH.Length)) + PanicAlert("Cant read from DVD_Plugin - DVD-Interface: Fatal Error"); + break; + + default: + _dbg_assert_msg_(DVDINTERFACE, 0, "Unknown Read Subcommand"); + break; + } + } + else + { + // there is no disc to read + _DICR.TSTART = 0; + m_DILENGTH.Length = 0; + g_ErrorCode = ERROR_NO_DISK | ERROR_COVER_H; + GenerateDVDInterrupt_Threadsafe(INT_DEINT); + return; + } + break; - if (!DVDRead(iDVDOffset, dvdMem.DMAAddress.Address, dvdMem.DMALength.Length)) + // GC-AM + case 0xAA: + if (GCAM) + { + ERROR_LOG(DVDINTERFACE, "GC-AM: 0xAA, DMABuffer=%08x, DMALength=%08x", m_DIMAR.Address, m_DILENGTH.Length); + u32 iDVDOffset = m_DICMDBUF[1].Hex << 2; + unsigned int len = m_DILENGTH.Length; + int offset = iDVDOffset - 0x1F900000; + /* + if (iDVDOffset == 0x84800000) + { + ERROR_LOG(DVDINTERFACE, "firmware upload"); + } + else*/ + if ((offset < 0) || ((offset + len) > 0x40) || len > 0x40) + { + unsigned long addr = m_DIMAR.Address; + if (iDVDOffset == 0x84800000) { + ERROR_LOG(DVDINTERFACE, "FIRMWARE UPLOAD"); + } else { + ERROR_LOG(DVDINTERFACE, "ILLEGAL MEDIA WRITE"); + } + while (len >= 4) { - PanicAlert("Cant read from DVD_Plugin - DVD-Interface: Fatal Error"); + ERROR_LOG(DVDINTERFACE, "GC-AM Media Board WRITE (0xAA): %08x: %08x", iDVDOffset, Memory::Read_U32(addr)); + addr += 4; + len -= 4; + iDVDOffset += 4; } } else { - // there is no disc to read - _DMAControlReg.TSTART = 0; - dvdMem.DMALength.Length = 0; - GenerateDVDInterruptFromDVDThread(INT_DEINT); - g_ErrorCode = ERROR_NO_DISK | ERROR_COVER_H; - return; + unsigned long addr = m_DIMAR.Address; + memcpy(media_buffer + offset, Memory::GetPointer(addr), len); + while (len >= 4) + { + ERROR_LOG(DVDINTERFACE, "GC-AM Media Board WRITE (0xAA): %08x: %08x", iDVDOffset, Memory::Read_U32(addr)); + addr += 4; + len -= 4; + iDVDOffset += 4; + } } } break; - //========================================================================================================= - // SEEK (Immediate) - // Command/Subcommand/Padding <- AB000000 - // Command0 <- Position on DVD shr 2 - //========================================================================================================= + // Seek (immediate) case DVDLowSeek: + if (!GCAM) { -#if MAX_LOGLEVEL >= DEBUG_LEVEL - u32 offset = dvdMem.Command[1] << 2; + // We don't care :) + DEBUG_LOG(DVDINTERFACE, "Seek: offset=%08x (ignoring)", m_DICMDBUF[1].Hex << 2); + } + else + { + memset(media_buffer, 0, 0x20); + media_buffer[0] = media_buffer[0x20]; // ID + media_buffer[2] = media_buffer[0x22]; + media_buffer[3] = media_buffer[0x23] | 0x80; + int cmd = (media_buffer[0x23]<<8)|media_buffer[0x22]; + ERROR_LOG(DVDINTERFACE, "GC-AM: execute buffer, cmd=%04x", cmd); + switch (cmd) + { + case 0x00: + media_buffer[4] = 1; + break; + case 0x1: + media_buffer[7] = 0x20; // DIMM Size + break; + case 0x100: + { + static int percentage; + static int status = 0; + percentage++; + if (percentage > 100) + { + status++; + percentage = 0; + } + media_buffer[4] = status; + /* status: + 0 - "Initializing media board. Please wait.." + 1 - "Checking network. Please wait..." + 2 - "Found a system disc. Insert a game disc" + 3 - "Testing a game program. %d%%" + 4 - "Loading a game program. %d%%" + 5 - go + 6 - error xx + */ + media_buffer[8] = percentage; + media_buffer[4] = 0x05; + media_buffer[8] = 0x64; + break; + } + case 0x101: + media_buffer[4] = 3; // version + media_buffer[5] = 3; + media_buffer[6] = 1; // xxx + media_buffer[8] = 1; + media_buffer[16] = 0xFF; + media_buffer[17] = 0xFF; + media_buffer[18] = 0xFF; + media_buffer[19] = 0xFF; + break; + case 0x102: // get error code + media_buffer[4] = 1; // 0: download incomplete (31), 1: corrupted, other error 1 + media_buffer[5] = 0; + break; + case 0x103: + memcpy(media_buffer + 4, "A89E27A50364511", 15); // serial + break; +#if 0 + case 0x301: // unknown + memcpy(media_buffer + 4, media_buffer + 0x24, 0x1c); + break; + case 0x302: + break; #endif - DEBUG_LOG(DVDINTERFACE, "Seek: offset=%08x (ignoring)", offset); - } + default: + ERROR_LOG(DVDINTERFACE, "GC-AM: execute buffer (unknown)"); + break; + } + memset(media_buffer + 0x20, 0, 0x20); + m_DIIMMBUF.Hex = 0x66556677; // just a random value that works. + } break; case DVDLowOffset: DEBUG_LOG(DVDINTERFACE, "DVDLowOffset: ignoring..."); break; - //========================================================================================================= - // REQUEST ERROR (Immediate) - // Command/Subcommand/Padding <- E0000000 - //========================================================================================================= + // Request Error Code case DVDLowRequestError: - ERROR_LOG(DVDINTERFACE, "Requesting error"); - dvdMem.Immediate = g_ErrorCode; + ERROR_LOG(DVDINTERFACE, "Requesting error... (0x%08x)", g_ErrorCode); + m_DIIMMBUF.Hex = g_ErrorCode; break; - //========================================================================================================= - // AUDIOSTREAM (Immediate) - // Command/Subcommand/Padding <- E1??0000 ?? = subcommand - // Command0 <- Position on DVD shr 2 - // Command1 <- Length of the stream - //========================================================================================================= + // Audio Stream (Immediate) + // m_DICMDBUF[0].CMDBYTE1 = subcommand + // m_DICMDBUF[1].Hex << 2 = offset on disc + // m_DICMDBUF[2].Hex = Length of the stream case 0xE1: { - // i dunno if we need this check - // if (m_bStream) - // MessageBox(NULL, "dont overwrite a stream while you play it", "FATAL ERROR", MB_OK); - - // subcommand - // ugly hack to catch the disable command - if (dvdMem.Command[1]!=0) + if (m_DICMDBUF[1].Hex != 0) { -#if MAX_LOGLEVEL >= DEBUG_LEVEL - u8 subCommand = (dvdMem.Command[0] & 0x00FF0000) >> 16; -#endif - - dvdMem.AudioPos = dvdMem.Command[1] << 2; - dvdMem.AudioStart = dvdMem.AudioPos; - dvdMem.AudioLength = dvdMem.Command[2]; + AudioPos = m_DICMDBUF[1].Hex << 2; + AudioStart = AudioPos; + AudioLength = m_DICMDBUF[2].Hex; NGCADPCM::InitFilter(); - m_bStream = true; + g_bStream = true; - DEBUG_LOG(DVDINTERFACE, "DVD(Audio) Stream subcmd = %02x offset = %08x length=%08x", - subCommand, dvdMem.AudioPos, dvdMem.AudioLength); - } - } + WARN_LOG(DVDINTERFACE, "(Audio) Stream subcmd = %02x offset = %08x length=%08x", + m_DICMDBUF[0].CMDBYTE1, AudioPos, AudioLength); + } + else + WARN_LOG(DVDINTERFACE, "(Audio) Off?"); + } break; - //========================================================================================================= - // REQUEST AUDIO STATUS (Immediate) - // Command/Subcommand/Padding <- E2000000 - //========================================================================================================= + // Request Audio Status (Immediate) case 0xE2: - { - if (m_bStream) - dvdMem.Immediate = 1; - else - dvdMem.Immediate = 0; - } - DEBUG_LOG(DVDINTERFACE, "DVD(Audio): Request Audio status"); + m_DIIMMBUF.Hex = g_bStream ? 1 : 0; + WARN_LOG(DVDINTERFACE, "(Audio): Request Audio status %s", g_bStream? "on":"off"); break; - //========================================================================================================= - // STOP MOTOR (Immediate) - // Command/Subcommand/Padding <- E3000000 - //========================================================================================================= case DVDLowStopMotor: DEBUG_LOG(DVDINTERFACE, "Stop motor"); break; - //========================================================================================================= - // DVD AUDIO DISABLE (Immediate)` - // Command/Subcommand/Padding <- E4000000 (disable) - // Command/Subcommand/Padding <- E4010000 (enable) - //========================================================================================================= + // DVD Audio Enable/Disable (Immediate) case DVDLowAudioBufferConfig: - if (((dvdMem.Command[0] & 0x00FF0000) >> 16) == 1) + if (m_DICMDBUF[0].CMDBYTE1 == 1) { - m_bStream = true; - DEBUG_LOG(DVDINTERFACE, "DVD(Audio): Audio enabled"); + g_bStream = true; + WARN_LOG(DVDINTERFACE, "(Audio): Audio enabled"); } else { - m_bStream = false; - DEBUG_LOG(DVDINTERFACE, "DVD(Audio): Audio disabled"); + g_bStream = false; + WARN_LOG(DVDINTERFACE, "(Audio): Audio disabled"); } break; - //========================================================================================================= - // SET STATUS - //========================================================================================================= + // yet another command we prolly don't care about case 0xEE: - INFO_LOG(DVDINTERFACE, "SetStatus %x", _DMAControlReg); + DEBUG_LOG(DVDINTERFACE, "SetStatus - Unimplemented"); break; - //========================================================================================================= - // DEBUG COMMANDS - // Subcommands: - // 0x00: ? - // 0x01: read/write memory/cache - // 0x10: ? - // 0x11: stop/start/accept copy/disk check CAN BE OR'd! - // 0x12: jump (jsr) to address - //========================================================================================================= + // Debug commands; see yagcd. We don't really care + // NOTE: commands to stream data will send...a raw data stream + // This will appear as unknown commands, unless the check is re-instated to catch such data. case 0xFE: - { - u8 subCommand = (dvdMem.Command[0] & 0x00FF0000) >> 16; - u16 argument = (u16)(dvdMem.Command[0] & 0x0000FFFF); - - switch (subCommand) - { - case 0x01: - { - dvdMem.DebugTransfer.Address = dvdMem.Command[1]; - dvdMem.DebugTransfer.Length = dvdMem.Command[2] >> 16; // can be up to 12 bytes - - INFO_LOG(DVDINTERFACE, "Next cmd will %s %i bytes to drive %s @ 0x%08x", - (argument & 0x100) ? "write" : "read", dvdMem.DebugTransfer.Length, - (argument & 0x8000) ? "cache" : "mem", dvdMem.DebugTransfer.Address); - - dvdMem.DebugTransfer.InProgress = true; - } - break; - - case 0x11: - char flags[256]; - sprintf(flags, "%s%s%s%s", - (argument & STOP_DRIVE) ? "StopDrive " : "", - (argument & START_DRIVE) ? "StartDrive " : "", - (argument & ACCEPT_COPY) ? "AcceptCopy " : "", - (argument & DISC_CHECK) ? "DiscCheck" : ""); - INFO_LOG(DVDINTERFACE, "Debug cmd(s): %s", flags); - break; - - default: - WARN_LOG(DVDINTERFACE, "Unsupported DVD Drive debug command 0x%08x", dvdMem.Command[0]); - break; - } - } + INFO_LOG(DVDINTERFACE, "Unsupported DVD Drive debug command 0x%08x", m_DICMDBUF[0].Hex); break; - //========================================================================================================= - // UNLOCK COMMANDS 1: "MATSHITA" 2: "DVD-GAME" - // LOL - //========================================================================================================= + // Unlock Commands. 1: "MATSHITA" 2: "DVD-GAME" + // Just for fun case 0xFF: { - if (dvdMem.Command[0] == 0xFF014D41 - && dvdMem.Command[1] == 0x54534849 - && dvdMem.Command[2] == 0x54410200) + if (m_DICMDBUF[0].Hex == 0xFF014D41 + && m_DICMDBUF[1].Hex == 0x54534849 + && m_DICMDBUF[2].Hex == 0x54410200) { INFO_LOG(DVDINTERFACE, "Unlock test 1 passed"); } - else if (dvdMem.Command[0] == 0xFF004456 - && dvdMem.Command[1] == 0x442D4741 - && dvdMem.Command[2] == 0x4D450300) + else if (m_DICMDBUF[0].Hex == 0xFF004456 + && m_DICMDBUF[1].Hex == 0x442D4741 + && m_DICMDBUF[2].Hex == 0x4D450300) { INFO_LOG(DVDINTERFACE, "Unlock test 2 passed"); } @@ -803,21 +918,17 @@ void ExecuteCommand(UDIDMAControlRegister& _DMAControlReg) } break; - //========================================================================================================= - // UNKNOWN DVD COMMAND - //========================================================================================================= default: - PanicAlert("Unknown DVD command %08x - fatal error", dvdMem.Command[0]); + PanicAlert("Unknown DVD command %08x - fatal error", m_DICMDBUF[0].Hex); _dbg_assert_(DVDINTERFACE, 0); break; } - } // end of if(dvdMem.DebugTransfer.InProgress) // transfer is done - _DMAControlReg.TSTART = 0; - dvdMem.DMALength.Length = 0; - GenerateDVDInterruptFromDVDThread(INT_TCINT); - g_ErrorCode = 0x00; + _DICR.TSTART = 0; + m_DILENGTH.Length = 0; + GenerateDVDInterrupt_Threadsafe(INT_TCINT); + g_ErrorCode = 0; } } // namespace diff --git a/Source/Core/Core/Src/HW/DVDInterface.h b/Source/Core/Core/Src/HW/DVDInterface.h index ee7ef2ea9ef1..1fa4d32decd6 100644 --- a/Source/Core/Core/Src/HW/DVDInterface.h +++ b/Source/Core/Core/Src/HW/DVDInterface.h @@ -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 - - diff --git a/Source/Core/Core/Src/HW/EXI.cpp b/Source/Core/Core/Src/HW/EXI.cpp index 8c360091e674..44a12001463b 100644 --- a/Source/Core/Core/Src/HW/EXI.cpp +++ b/Source/Core/Core/Src/HW/EXI.cpp @@ -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; - - // 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); + for (u32 i = 0; i < NUM_CHANNELS; i++) + g_Channels[i] = new CEXIChannel(i); + + 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; iSetEXIINT(g_Channels[0]->GetDevice(4)->IsInterruptSet()); + + bool causeInt = false; + for (int i = 0; i < NUM_CHANNELS; i++) + causeInt |= g_Channels[i]->IsCausingInterrupt(); - ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_EXI, false); + ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_EXI, causeInt); } } // end of namespace ExpansionInterface diff --git a/Source/Core/Core/Src/HW/EXI_Channel.cpp b/Source/Core/Core/Src/HW/EXI_Channel.cpp index 3143757a3a2b..c73ed0b27511 100644 --- a/Source/Core/Core/Src/HW/EXI_Channel.cpp +++ b/Source/Core/Core/Src/HW/EXI_Channel.cpp @@ -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 (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) - m_Status.EXT = pDevice->IsPresent() ? 1 : 0; - else - m_Status.EXT = 0; + 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; } diff --git a/Source/Core/Core/Src/HW/EXI_Channel.h b/Source/Core/Core/Src/HW/EXI_Channel.h index bf77907d22ae..436fb05b263b 100644 --- a/Source/Core/Core/Src/HW/EXI_Channel.h +++ b/Source/Core/Core/Src/HW/EXI_Channel.h @@ -38,33 +38,50 @@ class CEXIChannel EXI_DMACONTROL = 3, EXI_IMMDATA = 4 }; - - // EXI Status Register + 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 - "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 @@ class CEXIChannel // 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 @@ class CEXIChannel 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 @@ class CEXIChannel 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 diff --git a/Source/Core/Core/Src/HW/EXI_Device.cpp b/Source/Core/Core/Src/HW/EXI_Device.cpp index 52da128ac1d7..83a766ad93a7 100644 --- a/Source/Core/Core/Src/HW/EXI_Device.cpp +++ b/Source/Core/Core/Src/HW/EXI_Device.cpp @@ -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 @@ class CEXIDummy : public IEXIDevice 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; } diff --git a/Source/Core/Core/Src/HW/EXI_Device.h b/Source/Core/Core/Src/HW/EXI_Device.h index 3a0971721926..ae79f213a4d4 100644 --- a/Source/Core/Core/Src/HW/EXI_Device.h +++ b/Source/Core/Core/Src/HW/EXI_Device.h @@ -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 - diff --git a/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.cpp b/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.cpp new file mode 100644 index 000000000000..4a04a3dbb3a2 --- /dev/null +++ b/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.cpp @@ -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; +} diff --git a/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.h b/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.h new file mode 100644 index 000000000000..3e91580e4457 --- /dev/null +++ b/Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.h @@ -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 diff --git a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp index e77fc2a93cdc..e61542184a1d 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp +++ b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp @@ -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: diff --git a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h index 46420e6616ef..2acc4d75772e 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h +++ b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h @@ -57,11 +57,11 @@ class CEXIMemoryCard : public IEXIDevice 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, diff --git a/Source/Core/Core/Src/HW/SI.cpp b/Source/Core/Core/Src/HW/SI.cpp index 868262742b7f..33317f406515 100644 --- a/Source/Core/Core/Src/HW/SI.cpp +++ b/Source/Core/Core/Src/HW/SI.cpp @@ -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; diff --git a/Source/Core/Core/Src/HW/SI_Device.cpp b/Source/Core/Core/Src/HW/SI_Device.cpp index 228d722b3d1b..c747c1a368a0 100644 --- a/Source/Core/Core/Src/HW/SI_Device.cpp +++ b/Source/Core/Core/Src/HW/SI_Device.cpp @@ -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 @@ class CSIDevice_Dummy : public ISIDevice 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; diff --git a/Source/Core/Core/Src/HW/SI_Device.h b/Source/Core/Core/Src/HW/SI_Device.h index 389cdb2dc5b8..65d7e4bfb0b6 100644 --- a/Source/Core/Core/Src/HW/SI_Device.h +++ b/Source/Core/Core/Src/HW/SI_Device.h @@ -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); diff --git a/Source/Core/Core/Src/HW/SI_DeviceAMBaseboard.cpp b/Source/Core/Core/Src/HW/SI_DeviceAMBaseboard.cpp new file mode 100644 index 000000000000..0138f445639d --- /dev/null +++ b/Source/Core/Core/Src/HW/SI_DeviceAMBaseboard.cpp @@ -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(_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; iPAD_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; jPAD_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" +#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(""),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(""),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("")); + 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(""), 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;