From 93b83f8d65962a10a2776bf9fb6c39ce1eb03f2d Mon Sep 17 00:00:00 2001 From: Shawn Hoffman Date: Mon, 19 Oct 2009 15:14:48 +0000 Subject: [PATCH] Add tmbinc's patch for triforce emulation. This adds triforce-specific SI and EXI devices, as well as changes DI behavior when in triforce mode. (Selecting both AM devices from main config will force the DI into triforce mode) Also fixes up a few EXI bugs dealing with interrupts and the like (memcard insertion should work well now, and maybe BBA can progress farther :> ) Also adds real "null" EXI devices, so software won't think the dummy device is some strange unknown device anymore. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4437 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Core/Core.vcproj | 16 + Source/Core/Core/Src/HW/AudioInterface.cpp | 2 +- Source/Core/Core/Src/HW/DVDInterface.cpp | 803 ++++++++++-------- Source/Core/Core/Src/HW/DVDInterface.h | 5 +- Source/Core/Core/Src/HW/EXI.cpp | 88 +- Source/Core/Core/Src/HW/EXI_Channel.cpp | 135 ++- Source/Core/Core/Src/HW/EXI_Channel.h | 61 +- Source/Core/Core/Src/HW/EXI_Device.cpp | 19 +- Source/Core/Core/Src/HW/EXI_Device.h | 5 +- .../Core/Src/HW/EXI_DeviceAMBaseboard.cpp | 130 +++ .../Core/Core/Src/HW/EXI_DeviceAMBaseboard.h | 37 + .../Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp | 18 +- .../Core/Core/Src/HW/EXI_DeviceMemoryCard.h | 4 +- Source/Core/Core/Src/HW/SI.cpp | 27 +- Source/Core/Core/Src/HW/SI_Device.cpp | 15 +- Source/Core/Core/Src/HW/SI_Device.h | 1 + .../Core/Core/Src/HW/SI_DeviceAMBaseboard.cpp | 469 ++++++++++ .../Core/Core/Src/HW/SI_DeviceAMBaseboard.h | 45 + Source/Core/Core/Src/SConscript | 2 + Source/Core/DolphinWX/Src/ConfigMain.cpp | 89 +- 20 files changed, 1421 insertions(+), 550 deletions(-) create mode 100644 Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.cpp create mode 100644 Source/Core/Core/Src/HW/EXI_DeviceAMBaseboard.h create mode 100644 Source/Core/Core/Src/HW/SI_DeviceAMBaseboard.cpp create mode 100644 Source/Core/Core/Src/HW/SI_DeviceAMBaseboard.h diff --git a/Source/Core/Core/Core.vcproj b/Source/Core/Core/Core.vcproj index c005d8c2cb..368304870d 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 699257e4ec..fd8ba2363f 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 435520ee2c..e7b59e963a 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;} }; -// DI DMA Address Register -union UDIDMAAddressRegister +union UDICMDBUF { u32 Hex; - struct + struct + { + u8 CMDBYTE3; + u8 CMDBYTE2; + u8 CMDBYTE1; + u8 CMDBYTE0; + }; +}; + +// DI DMA Address Register +union UDIMAR +{ + u32 Hex; + 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 + { + u8 REGVAL3; + u8 REGVAL2; + u8 REGVAL1; + u8 REGVAL0; + }; +}; + +// DI Config Register +union UDICFG +{ + u32 Hex; + struct { unsigned CONFIG : 8; unsigned : 24; }; - UDIConfigRegister() {Hex = 0;} - UDIConfigRegister(u32 _hex) {Hex = _hex;} + UDICFG() {Hex = 0;} + UDICFG(u32 _hex) {Hex = _hex;} }; -// HACK to allow multi-command debug-mode transfers -struct SDIDebugTransfer -{ - u32 Address; - u16 Length; - bool InProgress; -}; - -// 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; + 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 - et_GenerateDVDInterrupt = CoreTiming::RegisterEvent("DVDint", GenerateDVDInterrupt_Wrapper); + 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]; - - 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); - - if (!DVDRead(iDVDOffset, dvdMem.DMAAddress.Address, dvdMem.DMALength.Length)) + 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; + + 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; + + // 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) + { + 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); - } - } - break; - - //========================================================================================================= - // REQUEST AUDIO STATUS (Immediate) - // Command/Subcommand/Padding <- E2000000 - //========================================================================================================= - case 0xE2: - { - if (m_bStream) - dvdMem.Immediate = 1; + WARN_LOG(DVDINTERFACE, "(Audio) Stream subcmd = %02x offset = %08x length=%08x", + m_DICMDBUF[0].CMDBYTE1, AudioPos, AudioLength); + } else - dvdMem.Immediate = 0; + WARN_LOG(DVDINTERFACE, "(Audio) Off?"); } - DEBUG_LOG(DVDINTERFACE, "DVD(Audio): Request Audio status"); break; - //========================================================================================================= - // STOP MOTOR (Immediate) - // Command/Subcommand/Padding <- E3000000 - //========================================================================================================= + // Request Audio Status (Immediate) + case 0xE2: + m_DIIMMBUF.Hex = g_bStream ? 1 : 0; + WARN_LOG(DVDINTERFACE, "(Audio): Request Audio status %s", g_bStream? "on":"off"); + break; + 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 ee7ef2ea9e..1fa4d32dec 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 8c360091e6..44a1200146 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; + for (u32 i = 0; i < NUM_CHANNELS; i++) + g_Channels[i] = new CEXIChannel(i); - // m_EXIDevice[0] = SlotA - // m_EXIDevice[1] = SlotB - // m_EXIDevice[2] = Serial Port 1 (ETH) - g_Channels[0].AddDevice(SConfig::GetInstance().m_EXIDevice[0], 0); - g_Channels[0].AddDevice(EXIDEVICE_IPL, 1); - g_Channels[0].AddDevice(SConfig::GetInstance().m_EXIDevice[2], 2); - g_Channels[1].AddDevice(SConfig::GetInstance().m_EXIDevice[1], 0); - g_Channels[2].AddDevice(EXIDEVICE_AD16, 0); + g_Channels[0]->AddDevice(SConfig::GetInstance().m_EXIDevice[0], 0); // SlotA + g_Channels[0]->AddDevice(EXIDEVICE_MASKROM, 1); + g_Channels[0]->AddDevice(SConfig::GetInstance().m_EXIDevice[2], 2); // Serial Port 1 + g_Channels[1]->AddDevice(SConfig::GetInstance().m_EXIDevice[1], 0); // SlotB + g_Channels[2]->AddDevice(EXIDEVICE_AD16, 0); changeDevice = CoreTiming::RegisterEvent("ChangeEXIDevice", ChangeDeviceCallback); } void Shutdown() { - delete [] g_Channels; - g_Channels = 0; + for (u32 i = 0; i < NUM_CHANNELS; i++) + { + delete g_Channels[i]; + g_Channels[i] = NULL; + } } void DoState(PointerWrap &p) { // TODO: Complete DoState for each IEXIDevice - g_Channels[0].GetDevice(1)->DoState(p); - g_Channels[0].GetDevice(2)->DoState(p); - g_Channels[0].GetDevice(4)->DoState(p); - g_Channels[1].GetDevice(1)->DoState(p); - g_Channels[2].GetDevice(1)->DoState(p); + g_Channels[0]->GetDevice(1)->DoState(p); + g_Channels[0]->GetDevice(2)->DoState(p); + g_Channels[0]->GetDevice(4)->DoState(p); + g_Channels[1]->GetDevice(1)->DoState(p); + g_Channels[2]->GetDevice(1)->DoState(p); } void ChangeDeviceCallback(u64 userdata, int cyclesLate) @@ -78,35 +76,37 @@ void ChangeDeviceCallback(u64 userdata, int cyclesLate) u8 device = (u8)(userdata >> 16); u8 slot = (u8)userdata; - g_Channels[channel].AddDevice((TEXIDevices)device, slot); + g_Channels[channel]->AddDevice((TEXIDevices)device, slot); } void ChangeDevice(u8 channel, TEXIDevices device, u8 slot) { // Called from GUI, so we need to make it thread safe. // Let the hardware see no device for .5b cycles - CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | ((u64)EXIDEVICE_DUMMY << 16) | slot); + CoreTiming::ScheduleEvent_Threadsafe(0, changeDevice, ((u64)channel << 32) | ((u64)EXIDEVICE_NONE << 16) | slot); CoreTiming::ScheduleEvent_Threadsafe(500000000, changeDevice, ((u64)channel << 32) | ((u64)device << 16) | slot); } +// Unused (?!) void Update() { - g_Channels[0].Update(); - g_Channels[1].Update(); - g_Channels[2].Update(); + g_Channels[0]->Update(); + g_Channels[1]->Update(); + g_Channels[2]->Update(); } void Read32(u32& _uReturnValue, const u32 _iAddress) { - unsigned int iAddr = _iAddress & 0x3FF; - unsigned int iRegister = (iAddr >> 2) % 5; - unsigned int iChannel = (iAddr >> 2) / 5; + // TODO 0xfff00000 is mapped to EXI -> mapped to first MB of maskrom + u32 iAddr = _iAddress & 0x3FF; + u32 iRegister = (iAddr >> 2) % 5; + u32 iChannel = (iAddr >> 2) / 5; _dbg_assert_(EXPANSIONINTERFACE, iChannel < NUM_CHANNELS); if (iChannel < NUM_CHANNELS) { - g_Channels[iChannel].Read32(_uReturnValue, iRegister); + g_Channels[iChannel]->Read32(_uReturnValue, iRegister); } else { @@ -116,28 +116,30 @@ void Read32(u32& _uReturnValue, const u32 _iAddress) void Write32(const u32 _iValue, const u32 _iAddress) { - int iAddr = _iAddress & 0x3FF; - int iRegister = (iAddr >> 2) % 5; - int iChannel = (iAddr >> 2) / 5; + // TODO 0xfff00000 is mapped to EXI -> mapped to first MB of maskrom + u32 iAddr = _iAddress & 0x3FF; + u32 iRegister = (iAddr >> 2) % 5; + u32 iChannel = (iAddr >> 2) / 5; - _dbg_assert_(EXPANSIONINTERFACE, iChannel < NUM_CHANNELS) + _dbg_assert_(EXPANSIONINTERFACE, iChannel < NUM_CHANNELS); if (iChannel < NUM_CHANNELS) - g_Channels[iChannel].Write32(_iValue, iRegister); + g_Channels[iChannel]->Write32(_iValue, iRegister); } void UpdateInterrupts() { - for(int i=0; iSetEXIINT(g_Channels[0]->GetDevice(4)->IsInterruptSet()); - ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_EXI, false); + bool causeInt = false; + for (int i = 0; i < NUM_CHANNELS; i++) + causeInt |= g_Channels[i]->IsCausingInterrupt(); + + ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_EXI, causeInt); } } // end of namespace ExpansionInterface diff --git a/Source/Core/Core/Src/HW/EXI_Channel.cpp b/Source/Core/Core/Src/HW/EXI_Channel.cpp index 3143757a3a..c73ed0b275 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 (pDevice != NULL) - m_Status.EXT = pDevice->IsPresent() ? 1 : 0; - else - m_Status.EXT = 0; + if (m_ChannelId == 0) + m_Status.ROMDIS = newStatus.ROMDIS; + + IEXIDevice* pDevice = GetDevice(m_Status.CHIP_SELECT ^ newStatus.CHIP_SELECT); + m_Status.CHIP_SELECT = newStatus.CHIP_SELECT; + if (pDevice != NULL) + pDevice->SetCS(m_Status.CHIP_SELECT); - // interrupt - if (newStatus.EXIINT) m_Status.EXIINT = 0; - if (newStatus.TCINT) m_Status.TCINT = 0; - if (newStatus.EXTINT) m_Status.EXTINT = 0; UpdateInterrupts(); } break; case EXI_DMAADDR: - INFO_LOG(EXPANSIONINTERFACE, "EXI: Wrote DMABuf, chan %i", m_ChannelId); + INFO_LOG(EXPANSIONINTERFACE, "Wrote DMAAddr, chan %i", m_ChannelId); m_DMAMemoryAddress = _iValue; break; case EXI_DMALENGTH: - INFO_LOG(EXPANSIONINTERFACE, "EXI: Wrote DMASize, chan %i", m_ChannelId); + INFO_LOG(EXPANSIONINTERFACE, "Wrote DMALength, chan %i", m_ChannelId); m_DMALength = _iValue; break; case EXI_DMACONTROL: - INFO_LOG(EXPANSIONINTERFACE, "EXI: Wrote DMAControl, chan %i", m_ChannelId); - m_Control.hex = _iValue; + INFO_LOG(EXPANSIONINTERFACE, "Wrote DMAControl, chan %i", m_ChannelId); + m_Control.Hex = _iValue; if (m_Control.TSTART) { @@ -289,7 +264,7 @@ void CEXIChannel::Write32(const u32 _iValue, const u32 _iRegister) break; case EXI_IMMDATA: - INFO_LOG(EXPANSIONINTERFACE, "EXI: Wrote IMMData, chan %i", m_ChannelId); + INFO_LOG(EXPANSIONINTERFACE, "Wrote IMMData, chan %i", m_ChannelId); m_ImmData = _iValue; break; } diff --git a/Source/Core/Core/Src/HW/EXI_Channel.h b/Source/Core/Core/Src/HW/EXI_Channel.h index bf77907d22..436fb05b26 100644 --- a/Source/Core/Core/Src/HW/EXI_Channel.h +++ b/Source/Core/Core/Src/HW/EXI_Channel.h @@ -38,33 +38,50 @@ private: EXI_DMACONTROL = 3, EXI_IMMDATA = 4 }; + const char* Debug_GetRegisterName(u32 _register) + { + switch (_register) + { + case EXI_STATUS: return "STATUS"; + case EXI_DMAADDR: return "DMAADDR"; + case EXI_DMALENGTH: return "DMALENGTH"; + case EXI_DMACONTROL: return "DMACONTROL"; + case EXI_IMMDATA: return "IMMDATA"; + default: return "!!! Unknown EXI Register !!!"; + } + } - // EXI Status Register + // EXI Status Register - "Channel Parameter Register" union UEXI_STATUS { - u32 hex; + u32 Hex; + // DO NOT obey the warning and give this struct a name. Things will fail. struct { - unsigned EXIINTMASK : 1; //31 - unsigned EXIINT : 1; //30 - unsigned TCINTMASK : 1; //29 - unsigned TCINT : 1; //28 - unsigned CLK : 3; //27 - unsigned CHIP_SELECT : 3; //24 - unsigned EXTINTMASK : 1; //21 - unsigned EXTINT : 1; //20 - unsigned EXT : 1; //19 // External Insertion Status (1: External EXI device present) - unsigned ROMDIS : 1; //18 // ROM Disable + // Indentation Meaning: + // Channels 0, 1, 2 + // Channels 0, 1 only + // Channel 0 only + unsigned EXIINTMASK : 1; + unsigned EXIINT : 1; + unsigned TCINTMASK : 1; + unsigned TCINT : 1; + unsigned CLK : 3; + unsigned CHIP_SELECT : 3; // CS1 and CS2 are Channel 0 only + unsigned EXTINTMASK : 1; + unsigned EXTINT : 1; + unsigned EXT : 1; // External Insertion Status (1: External EXI device present) + unsigned ROMDIS : 1; // ROM Disable unsigned :18; - }; // DO NOT obey the warning and give this struct a name. Things will fail. - UEXI_STATUS() {hex = 0;} - UEXI_STATUS(u32 _hex) {hex = _hex;} + }; + UEXI_STATUS() {Hex = 0;} + UEXI_STATUS(u32 _hex) {Hex = _hex;} }; // EXI Control Register union UEXI_CONTROL { - u32 hex; + u32 Hex; struct { unsigned TSTART : 1; @@ -77,9 +94,9 @@ private: // STATE_TO_SAVE UEXI_STATUS m_Status; - UEXI_CONTROL m_Control; u32 m_DMAMemoryAddress; u32 m_DMALength; + UEXI_CONTROL m_Control; u32 m_ImmData; // Devices @@ -90,13 +107,14 @@ private: IEXIDevice* m_pDevices[NUM_DEVICES]; + // Since channels operate a bit differently from each other + u32 m_ChannelId; + public: // get device IEXIDevice* GetDevice(u8 _CHIP_SELECT); - // channelId for debugging - u32 m_ChannelId; - CEXIChannel(); + CEXIChannel(u32 ChannelId); ~CEXIChannel(); void AddDevice(const TEXIDevices _device, const unsigned int _iSlot); @@ -110,6 +128,9 @@ public: void Update(); bool IsCausingInterrupt(); void UpdateInterrupts(); + + // This should only be used to transition interrupts from SP1 to Channel 2 + void SetEXIINT(bool exiint) { m_Status.EXIINT = !!exiint; } }; #endif diff --git a/Source/Core/Core/Src/HW/EXI_Device.cpp b/Source/Core/Core/Src/HW/EXI_Device.cpp index 52da128ac1..83a766ad93 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 @@ public: virtual ~CEXIDummy(){} void ImmWrite(u32 data, u32 size) {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmWrite: %08x", m_strName.c_str(), data);} - u32 ImmRead (u32 size) {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmRead", m_strName.c_str()); return 0;} + u32 ImmRead (u32 size) {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmRead", m_strName.c_str()); return 0;} void DMAWrite(u32 addr, u32 size) {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s DMAWrite: %08x bytes, from %08x to device", m_strName.c_str(), size, addr);} void DMARead (u32 addr, u32 size) {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s DMARead: %08x bytes, from device to %08x", m_strName.c_str(), size, addr);} }; // F A C T O R Y - - IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice) { switch(_EXIDevice) @@ -119,7 +117,7 @@ IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice) return new CEXIMemoryCard("MemoryCardB", SConfig::GetInstance().m_strMemoryCardB, 1); break; - case EXIDEVICE_IPL: + case EXIDEVICE_MASKROM: return new CEXIIPL(); break; @@ -135,6 +133,13 @@ IEXIDevice* EXIDevice_Create(TEXIDevices _EXIDevice) return new CEXIETHERNET(); break; + case EXIDEVICE_AM_BASEBOARD: + return new CEXIAMBaseboard(); + break; + + case EXIDEVICE_NONE: + default: + return new IEXIDevice(); + break; } - return NULL; } diff --git a/Source/Core/Core/Src/HW/EXI_Device.h b/Source/Core/Core/Src/HW/EXI_Device.h index 3a09717219..ae79f213a4 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 0000000000..4a04a3dbb3 --- /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 0000000000..3e91580e44 --- /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 e77fc2a93c..e61542184a 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 46420e6616..2acc4d7577 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h +++ b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.h @@ -57,11 +57,11 @@ private: cmdArrayToBuffer = 0x53, cmdSetInterrupt = 0x81, cmdWriteBuffer = 0x82, - cmdReadStatus = 0x83, + cmdReadStatus = 0x83, cmdReadID = 0x85, cmdReadErrorBuffer = 0x86, cmdWakeUp = 0x87, - cmdSleep = 0x88, + cmdSleep = 0x88, cmdClearStatus = 0x89, cmdSectorErase = 0xF1, cmdPageProgram = 0xF2, diff --git a/Source/Core/Core/Src/HW/SI.cpp b/Source/Core/Core/Src/HW/SI.cpp index 868262742b..33317f4065 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 228d722b3d..c747c1a368 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 @@ public: return 4; } - bool GetData(u32& _Hi, u32& _Low) {INFO_LOG(SERIALINTERFACE, "SI DUMMY %i GetData", this->m_iDeviceNumber); return false;} - void SendCommand(u32 _Cmd, u8 _Poll){INFO_LOG(SERIALINTERFACE, "SI DUMMY %i SendCommand: %08x", this->m_iDeviceNumber, _Cmd);} + bool GetData(u32& _Hi, u32& _Low) {DEBUG_LOG(SERIALINTERFACE, "SI DUMMY %i GetData", this->m_iDeviceNumber); return false;} + void SendCommand(u32 _Cmd, u8 _Poll){DEBUG_LOG(SERIALINTERFACE, "SI DUMMY %i SendCommand: %08x", this->m_iDeviceNumber, _Cmd);} }; // F A C T O R Y - - ISIDevice* SIDevice_Create(TSIDevices _SIDevice, int _iDeviceNumber) { switch(_SIDevice) @@ -95,6 +92,10 @@ ISIDevice* SIDevice_Create(TSIDevices _SIDevice, int _iDeviceNumber) return new CSIDevice_GBA(_iDeviceNumber); break; + case SI_AM_BASEBOARD: + return new CSIDevice_AMBaseboard(_iDeviceNumber); + break; + default: return new CSIDevice_Dummy(_iDeviceNumber); break; diff --git a/Source/Core/Core/Src/HW/SI_Device.h b/Source/Core/Core/Src/HW/SI_Device.h index 389cdb2dc5..65d7e4bfb0 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 0000000000..0138f44563 --- /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;