From 18cee2dcc72bf3b049b4d80498408f6fe4edd5a7 Mon Sep 17 00:00:00 2001 From: skidau Date: Mon, 19 Jan 2015 23:36:19 +1100 Subject: [PATCH 1/4] Added second parameter for the eject disc via StopMotor DI command. The AGP disc expects the disc to still be readable after sending an eject command. --- Source/Core/Core/HW/DVDInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Core/HW/DVDInterface.cpp b/Source/Core/Core/HW/DVDInterface.cpp index 860c0ce4d4..3a25ce97b5 100644 --- a/Source/Core/Core/HW/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVDInterface.cpp @@ -1136,7 +1136,7 @@ DVDCommandResult ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, INFO_LOG(DVDINTERFACE, "DVDLowStopMotor %s %s", command_1 ? "eject" : "", command_2 ? "kill!" : ""); - if (command_1) + if (command_1 && !command_2) EjectDiscCallback(0, 0); break; From a7299a7ffff9180a3414c5da48c27aa08571e66c Mon Sep 17 00:00:00 2001 From: skidau Date: Tue, 20 Jan 2015 23:41:46 +1100 Subject: [PATCH 2/4] Added support for AGP. Original patch by GreyRogue. --- Source/Core/Core/CMakeLists.txt | 1 + Source/Core/Core/ConfigManager.cpp | 4 + Source/Core/Core/ConfigManager.h | 2 + Source/Core/Core/Core.vcxproj | 2 + Source/Core/Core/Core.vcxproj.filters | 8 +- Source/Core/Core/HW/EXI_Device.cpp | 6 + Source/Core/Core/HW/EXI_Device.h | 1 + Source/Core/Core/HW/EXI_DeviceAGP.cpp | 253 ++++++++++++++++++++++++++ Source/Core/Core/HW/EXI_DeviceAGP.h | 61 +++++++ Source/Core/DolphinWX/ConfigMain.cpp | 107 +++++++---- Source/Core/DolphinWX/ConfigMain.h | 2 +- 11 files changed, 410 insertions(+), 37 deletions(-) create mode 100644 Source/Core/Core/HW/EXI_DeviceAGP.cpp create mode 100644 Source/Core/Core/HW/EXI_DeviceAGP.h diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index ab0eff73f3..dad625101b 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -91,6 +91,7 @@ set(SRCS ActionReplay.cpp HW/EXI.cpp HW/EXI_Device.cpp HW/EXI_DeviceAD16.cpp + HW/EXI_DeviceAGP.cpp HW/EXI_DeviceAMBaseboard.cpp HW/EXI_DeviceEthernet.cpp HW/EXI_DeviceGecko.cpp diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 1ad45b2083..3080610cbb 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -329,6 +329,8 @@ void SConfig::SaveCoreSettings(IniFile& ini) core->Set("Latency", m_LocalCoreStartupParameter.iLatency); core->Set("MemcardAPath", m_strMemoryCardA); core->Set("MemcardBPath", m_strMemoryCardB); + core->Set("AgpCartAPath", m_strGbaCartA); + core->Set("AgpCartBPath", m_strGbaCartB); core->Set("SlotA", m_EXIDevice[0]); core->Set("SlotB", m_EXIDevice[1]); core->Set("SerialPort1", m_EXIDevice[2]); @@ -559,6 +561,8 @@ void SConfig::LoadCoreSettings(IniFile& ini) core->Get("Latency", &m_LocalCoreStartupParameter.iLatency, 2); core->Get("MemcardAPath", &m_strMemoryCardA); core->Get("MemcardBPath", &m_strMemoryCardB); + core->Get("AgpCartAPath", &m_strGbaCartA); + core->Get("AgpCartBPath", &m_strGbaCartB); core->Get("SlotA", (int*)&m_EXIDevice[0], EXIDEVICE_MEMORYCARD); core->Get("SlotB", (int*)&m_EXIDevice[1], EXIDEVICE_NONE); core->Get("SerialPort1", (int*)&m_EXIDevice[2], EXIDEVICE_NONE); diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index 5341ec61e0..a65aca6b05 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -41,6 +41,8 @@ struct SConfig : NonCopyable std::string m_strMemoryCardA; std::string m_strMemoryCardB; + std::string m_strGbaCartA; + std::string m_strGbaCartB; TEXIDevices m_EXIDevice[3]; SIDevices m_SIDevice[4]; std::string m_bba_mac; diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index bf34fbabbe..6a64d89a5a 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -122,6 +122,7 @@ + @@ -330,6 +331,7 @@ + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index d8213794ae..39f1aea85b 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -385,6 +385,9 @@ HW %28Flipper/Hollywood%29\EXI - Expansion Interface + + HW %28Flipper/Hollywood%29\EXI - Expansion Interface + HW %28Flipper/Hollywood%29\EXI - Expansion Interface @@ -914,6 +917,9 @@ HW %28Flipper/Hollywood%29\EXI - Expansion Interface + + HW %28Flipper/Hollywood%29\EXI - Expansion Interface + HW %28Flipper/Hollywood%29\EXI - Expansion Interface @@ -1229,4 +1235,4 @@ - \ No newline at end of file + diff --git a/Source/Core/Core/HW/EXI_Device.cpp b/Source/Core/Core/HW/EXI_Device.cpp index ccc1fbb968..611534921e 100644 --- a/Source/Core/Core/HW/EXI_Device.cpp +++ b/Source/Core/Core/HW/EXI_Device.cpp @@ -7,6 +7,7 @@ #include "Core/Core.h" #include "Core/HW/EXI_Device.h" #include "Core/HW/EXI_DeviceAD16.h" +#include "Core/HW/EXI_DeviceAGP.h" #include "Core/HW/EXI_DeviceAMBaseboard.h" #include "Core/HW/EXI_DeviceEthernet.h" #include "Core/HW/EXI_DeviceGecko.h" @@ -84,6 +85,7 @@ public: u32 ImmRead (u32 size) override {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s ImmRead", m_strName.c_str()); return 0;} void DMAWrite(u32 addr, u32 size) override {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) override {INFO_LOG(EXPANSIONINTERFACE, "EXI DUMMY %s DMARead: %08x bytes, from device to %08x", m_strName.c_str(), size, addr);} + bool IsPresent() override { return true; } }; @@ -129,6 +131,10 @@ IEXIDevice* EXIDevice_Create(TEXIDevices device_type, const int channel_num) result = new CEXIGecko(); break; + case EXIDEVICE_AGP: + result = new CEXIAgp(channel_num); + break; + case EXIDEVICE_NONE: default: result = new IEXIDevice(); diff --git a/Source/Core/Core/HW/EXI_Device.h b/Source/Core/Core/HW/EXI_Device.h index b09732eb06..faea05dd42 100644 --- a/Source/Core/Core/HW/EXI_Device.h +++ b/Source/Core/Core/HW/EXI_Device.h @@ -19,6 +19,7 @@ enum TEXIDevices EXIDEVICE_GECKO, EXIDEVICE_MEMORYCARDFOLDER, // Only used when creating a device by EXIDevice_Create // Converted to EXIDEVICE_MEMORYCARD internally + EXIDEVICE_AGP, EXIDEVICE_NONE = (u8)-1 }; diff --git a/Source/Core/Core/HW/EXI_DeviceAGP.cpp b/Source/Core/Core/HW/EXI_DeviceAGP.cpp new file mode 100644 index 0000000000..bcd3027a93 --- /dev/null +++ b/Source/Core/Core/HW/EXI_DeviceAGP.cpp @@ -0,0 +1,253 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "Common/FileUtil.h" +#include "Common/MemoryUtil.h" +#include "Common/StdMakeUnique.h" +#include "Core/ConfigManager.h" +#include "Core/Core.h" +#include "Core/HW/EXI_Device.h" +#include "Core/HW/EXI_DeviceAGP.h" +#include "Core/HW/Memmap.h" + +CEXIAgp::CEXIAgp(int index) : + m_slot(index) +{ + // Create the ROM + m_pHashArray = (u8*)AllocateMemoryPages(HASH_SIZE); + m_rom_size = 0; + + LoadRom(); + + m_address = 0; + m_rom_hash_loaded = false; +} + +CEXIAgp::~CEXIAgp() +{ + m_pROM = nullptr; + m_pHashArray = nullptr; +} + +void CEXIAgp::DoHash(u8* data, u32 size) +{ + for (u32 it = 0; it < size; it++) + { + m_hash = m_hash ^ data[it]; + m_hash = m_pHashArray[m_hash]; + } +} + +void CEXIAgp::LoadRom() +{ + // Load whole ROM dump + std::string path; + std::string filename; + std::string ext; + std::string gbapath; + SplitPath(m_slot == 0 ? SConfig::GetInstance().m_strGbaCartA : SConfig::GetInstance().m_strGbaCartB, &path, &filename, &ext); + gbapath = path + filename; + LoadFileToROM(gbapath + ext); + INFO_LOG(EXPANSIONINTERFACE, "Loaded gba rom: %s card: %d", gbapath.c_str(), m_slot); + LoadFileToEEPROM(gbapath + ".sav"); + INFO_LOG(EXPANSIONINTERFACE, "Loaded gba sav: %s card: %d", gbapath.c_str(), m_slot); +} + +void CEXIAgp::LoadFileToROM(std::string filename) +{ + File::IOFile pStream(filename, "rb"); + if (pStream) + { + u64 filesize = pStream.GetSize(); + m_rom_size = filesize & 0xFFFFFFFF; + m_rom_mask = (m_rom_size - 1); + + m_pROM = (u8*)AllocateMemoryPages(m_rom_size); + + pStream.ReadBytes(m_pROM, filesize); + } + else + { + // dummy rom data + m_pROM = (u8*)AllocateMemoryPages(0x2000); + } +} + +void CEXIAgp::LoadFileToEEPROM(std::string filename) +{ + File::IOFile pStream(filename, "rb"); + if (pStream) + { + u64 filesize = pStream.GetSize(); + m_eeprom_size = filesize & 0xFFFFFFFF; + m_eeprom_mask = (m_eeprom_size - 1); + + m_pEEPROM = (u8*)AllocateMemoryPages(m_eeprom_size); + + pStream.ReadBytes(m_pEEPROM, filesize); + } +} + +void CEXIAgp::LoadHash() +{ + if (!m_rom_hash_loaded && m_rom_size > 0) + { + for (int i = 0; i < 0x100; i++) + { + m_pHashArray[i] = Memory::ReadUnchecked_U8(0x0017e908 + i); + } + m_rom_hash_loaded = true; + } +} + +u32 CEXIAgp::ImmRead(u32 _uSize) +{ + // We don't really care about _uSize + (void)_uSize; + u32 uData = 0; + u8 RomVal1, RomVal2, RomVal3, RomVal4; + + switch (m_currrent_cmd) + { + case 0xAE000000: + uData = 0x5AAA5517; // 17 is precalculated hash + m_currrent_cmd = 0; + break; + case 0xAE010000: + uData = (m_return_pos == 0) ? 0x01020304 : 0xF0020304; // F0 is precalculated hash, 020304 is left over + if (m_return_pos == 1) + m_currrent_cmd = 0; + else + m_return_pos = 1; + break; + case 0xAE020000: + if (m_rw_offset == 0x8000000) + { + RomVal1 = 0x0; + RomVal2 = 0x1; + } + else + { + RomVal1 = m_pROM[m_rw_offset++]; + RomVal2 = m_pROM[m_rw_offset++]; + LoadHash(); + } + DoHash(&RomVal2, 1); + DoHash(&RomVal1, 1); + uData = (RomVal2 << 24) | (RomVal1 << 16) | (m_hash << 8); + m_currrent_cmd = 0; + break; + case 0xAE030000: + if (_uSize == 1) + { + uData = 0xFF000000; + m_currrent_cmd = 0; + } + else + { + RomVal1 = m_pROM[m_rw_offset++]; + RomVal2 = m_pROM[m_rw_offset++]; + RomVal3 = m_pROM[m_rw_offset++]; + RomVal4 = m_pROM[m_rw_offset++]; + LoadHash(); + DoHash(&RomVal2, 1); + DoHash(&RomVal1, 1); + DoHash(&RomVal4, 1); + DoHash(&RomVal3, 1); + uData = (RomVal2 << 24) | (RomVal1 << 16) | (RomVal4 << 8) | (RomVal3); + } + break; + case 0xAE0B0000: + RomVal1 = m_eeprom_pos < 4 ? 0xA : (((u64*)m_pEEPROM)[(m_eeprom_cmd >> 1) & 0x3F] >> (m_eeprom_pos - 4)) & 0x1; + RomVal2 = 0; + DoHash(&RomVal2, 1); + DoHash(&RomVal1, 1); + uData = (RomVal2 << 24) | (RomVal1 << 16) | (m_hash << 8); + m_eeprom_pos++; + m_currrent_cmd = 0; + break; + case 0xAE0C0000: + uData = m_hash << 24; + m_currrent_cmd = 0; + break; + default: + uData = 0x0; + m_currrent_cmd = 0; + break; + } + INFO_LOG(EXPANSIONINTERFACE, "AGP read %x", uData); + return uData; +} + +void CEXIAgp::ImmWrite(u32 _uData, u32 _uSize) +{ + if ((_uSize == 1) && ((_uData & 0xFF000000) == 0)) + return; + + u8 HashCmd; + u64 Mask; + INFO_LOG(EXPANSIONINTERFACE, "AGP command %x", _uData); + switch (m_currrent_cmd) + { + case 0xAE020000: + case 0xAE030000: + m_rw_offset = ((_uData & 0xFFFFFF00) >> 7) & m_rom_mask; + m_return_pos = 0; + HashCmd = (_uData & 0xFF000000) >> 24; + DoHash(&HashCmd, 1); + HashCmd = (_uData & 0x00FF0000) >> 16; + DoHash(&HashCmd, 1); + HashCmd = (_uData & 0x0000FF00) >> 8; + DoHash(&HashCmd, 1); + break; + case 0xAE0C0000: + if ((m_eeprom_pos < 0x8) || (m_eeprom_pos == ((m_eeprom_cmd & EE_READ) ? 0x8 : 0x48))) + { + Mask = (u64)(1 << (0x8-(m_eeprom_pos > 0x8 ? 0x8 : m_eeprom_pos))); + if ((_uData >> 16) & 0x1) + m_eeprom_cmd |= Mask; + else + m_eeprom_cmd &= ~Mask; + if (m_eeprom_pos == 0x48) + ((u64*)(m_pEEPROM))[(m_eeprom_cmd >> 1) & 0x3F] = m_eeprom_data; + } + else + { + Mask = (u64)(1 << (0x47 - m_eeprom_pos)); + if ((_uData >> 16) & 0x1) + m_eeprom_data |= Mask; + else + m_eeprom_data &= ~Mask; + } + m_eeprom_pos++; + m_return_pos = 0; + HashCmd = (_uData & 0xFF000000) >> 24; + DoHash(&HashCmd, 1); + HashCmd = (_uData & 0x00FF0000) >> 16; + DoHash(&HashCmd, 1); + break; + case 0xAE0B0000: + break; + case 0xAE000000: + case 0xAE010000: + case 0xAE090000: + case 0xAE0A0000: + default: + m_eeprom_pos = 0; + m_currrent_cmd = _uData; + m_return_pos = 0; + m_hash = 0xFF; + HashCmd = (_uData & 0x00FF0000) >> 16; + DoHash(&HashCmd, 1); + break; + } +} + +void CEXIAgp::DoState(PointerWrap &p) +{ + p.Do(m_position); + p.Do(m_address); + p.Do(m_rw_offset); + p.Do(m_hash); +} diff --git a/Source/Core/Core/HW/EXI_DeviceAGP.h b/Source/Core/Core/HW/EXI_DeviceAGP.h new file mode 100644 index 0000000000..1b6f10052d --- /dev/null +++ b/Source/Core/Core/HW/EXI_DeviceAGP.h @@ -0,0 +1,61 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "Core/HW/EXI_Device.h" + +class CEXIAgp + : public IEXIDevice +{ +public: + CEXIAgp(const int index); + virtual ~CEXIAgp() override; + bool IsPresent() override { return true; } + void ImmWrite(u32 _uData, u32 _uSize) override; + u32 ImmRead(u32 _uSize) override; + void DoState(PointerWrap &p) override; + +private: + enum + { + HASH_SIZE = 256, + HASH_MASK = (HASH_SIZE - 1), + EE_READ = 0x80 + }; + + int m_slot; + + //! ROM + u32 m_rom_size = 0; + u32 m_rom_mask = 0; + u32 m_eeprom_size = 0; + u32 m_eeprom_mask = 0; + u8* m_pROM; + u8* m_pEEPROM; + u8* m_pHashArray; + + //! Helper + u32 m_position = 0; + u32 m_address = 0; + u32 m_rw_offset = 0; + u64 m_eeprom_data = 0; + u8 m_eeprom_pos = 0; + u16 m_eeprom_cmd = 0; + + void LoadFileToROM(std::string filename); + void LoadFileToEEPROM(std::string filename); + void LoadHash(); + void LoadRom(); + void DoHash(u8* data, u32 size); + + u8 m_hash = 0; + u32 m_currrent_cmd = 0; + u32 m_return_pos = 0; + + bool m_rom_hash_loaded = false; +}; diff --git a/Source/Core/DolphinWX/ConfigMain.cpp b/Source/Core/DolphinWX/ConfigMain.cpp index 3c2f775723..1f5d4b1913 100644 --- a/Source/Core/DolphinWX/ConfigMain.cpp +++ b/Source/Core/DolphinWX/ConfigMain.cpp @@ -111,6 +111,7 @@ static const wxLanguage langIds[] = #define EXIDEV_MEMDIR_STR _trans("GCI Folder") #define EXIDEV_MIC_STR _trans("Mic") #define EXIDEV_BBA_STR "BBA" +#define EXIDEV_AGP_STR "Advance Game Port" #define EXIDEV_AM_BB_STR _trans("AM-Baseboard") #define EXIDEV_GECKO_STR "USBGecko" @@ -382,8 +383,9 @@ void CConfigMain::InitializeGUIValues() SlotDevices.Add(_(DEV_NONE_STR)); SlotDevices.Add(_(DEV_DUMMY_STR)); SlotDevices.Add(_(EXIDEV_MEMCARD_STR)); - SlotDevices.Add(_(EXIDEV_GECKO_STR)); SlotDevices.Add(_(EXIDEV_MEMDIR_STR)); + SlotDevices.Add(_(EXIDEV_GECKO_STR)); + SlotDevices.Add(_(EXIDEV_AGP_STR)); #if HAVE_PORTAUDIO SlotDevices.Add(_(EXIDEV_MIC_STR)); @@ -415,10 +417,16 @@ void CConfigMain::InitializeGUIValues() isMemcard = GCEXIDevice[i]->SetStringSelection(SlotDevices[2]); break; case EXIDEVICE_MEMORYCARDFOLDER: + GCEXIDevice[i]->SetStringSelection(SlotDevices[3]); + break; + case EXIDEVICE_GECKO: GCEXIDevice[i]->SetStringSelection(SlotDevices[4]); break; + case EXIDEVICE_AGP: + isMemcard = GCEXIDevice[i]->SetStringSelection(SlotDevices[5]); + break; case EXIDEVICE_MIC: - GCEXIDevice[i]->SetStringSelection(SlotDevices[5]); + GCEXIDevice[i]->SetStringSelection(SlotDevices[6]); break; case EXIDEVICE_ETH: GCEXIDevice[i]->SetStringSelection(SP1Devices[2]); @@ -426,9 +434,6 @@ void CConfigMain::InitializeGUIValues() case EXIDEVICE_AM_BASEBOARD: GCEXIDevice[i]->SetStringSelection(SP1Devices[3]); break; - case EXIDEVICE_GECKO: - GCEXIDevice[i]->SetStringSelection(SlotDevices[3]); - break; case EXIDEVICE_DUMMY: default: GCEXIDevice[i]->SetStringSelection(SlotDevices[1]); @@ -1015,68 +1020,98 @@ void CConfigMain::GCSettingsChanged(wxCommandEvent& event) ChooseEXIDevice(event.GetString(), exidevice); break; case ID_GC_EXIDEVICE_SLOTA_PATH: - ChooseMemcardPath(SConfig::GetInstance().m_strMemoryCardA, true); + ChooseSlotPath(true, SConfig::GetInstance().m_EXIDevice[0]); break; case ID_GC_EXIDEVICE_SLOTB_PATH: - ChooseMemcardPath(SConfig::GetInstance().m_strMemoryCardB, false); + ChooseSlotPath(false, SConfig::GetInstance().m_EXIDevice[0]); break; } } -void CConfigMain::ChooseMemcardPath(std::string& strMemcard, bool isSlotA) +void CConfigMain::ChooseSlotPath(bool isSlotA, TEXIDevices device_type) { + bool memcard = (device_type == EXIDEVICE_MEMORYCARD); + std::string path; + std::string cardname; + std::string ext; + std::string pathA = SConfig::GetInstance().m_strMemoryCardA; + std::string pathB = SConfig::GetInstance().m_strMemoryCardB; + if (!memcard) + { + pathA = SConfig::GetInstance().m_strGbaCartA; + pathB = SConfig::GetInstance().m_strGbaCartB; + } + SplitPath(isSlotA ? pathA : pathB, &path, &cardname, &ext); std::string filename = WxStrToStr(wxFileSelector( _("Choose a file to open"), - StrToWxStr(File::GetUserPath(D_GCUSER_IDX)), - isSlotA ? GC_MEMCARDA : GC_MEMCARDB, - wxEmptyString, - _("GameCube Memory Cards (*.raw,*.gcp)") + "|*.raw;*.gcp")); + StrToWxStr(path), + StrToWxStr(cardname), + StrToWxStr(ext), + memcard ? _("GameCube Memory Cards (*.raw,*.gcp)") + "|*.raw;*.gcp" : _("Game Boy Advance Carts (*.gba)") + "|*.gba")); if (!filename.empty()) { if (File::Exists(filename)) { - GCMemcard memorycard(filename); - if (!memorycard.IsValid()) + if (memcard) + { + GCMemcard memorycard(filename); + if (!memorycard.IsValid()) + { + WxUtils::ShowErrorDialog(wxString::Format(_("Cannot use that file as a memory card.\n%s\n" \ + "is not a valid gamecube memory card file"), filename.c_str())); + return; + } + } + else { - WxUtils::ShowErrorDialog(wxString::Format(_("Cannot use that file as a memory card.\n%s\n" \ - "is not a valid gamecube memory card file"), filename.c_str())); return; } } - #ifdef _WIN32 - if (!strncmp(File::GetExeDirectory().c_str(), filename.c_str(), File::GetExeDirectory().size())) +#ifdef _WIN32 + if (!strncmp(File::GetExeDirectory().c_str(), filename.c_str(), File::GetExeDirectory().size())) + { + // If the Exe Directory Matches the prefix of the filename, we still need to verify + // that the next character is a directory separator character, otherwise we may create an invalid path + char next_char = filename.at(File::GetExeDirectory().size()) + 1; + if (next_char == '/' || next_char == '\\') { - // If the Exe Directory Matches the prefix of the filename, we still need to verify - // that the next character is a directory separator character, otherwise we may create an invalid path - char next_char = filename.at(File::GetExeDirectory().size())+1; - if (next_char == '/' || next_char == '\\') - { - filename.erase(0, File::GetExeDirectory().size() +1); - filename = "./" + filename; - } + filename.erase(0, File::GetExeDirectory().size() + 1); + filename = "./" + filename; } - #endif + } +#endif // also check that the path isn't used for the other memcard... - if (filename.compare(isSlotA ? SConfig::GetInstance().m_strMemoryCardB - : SConfig::GetInstance().m_strMemoryCardA) != 0) + if (filename.compare(isSlotA ? pathB : pathA) != 0) { - strMemcard = filename; + if (memcard) + { + if (isSlotA) + SConfig::GetInstance().m_strMemoryCardA = filename; + else + SConfig::GetInstance().m_strMemoryCardB = filename; + } + else + { + if (isSlotA) + SConfig::GetInstance().m_strGbaCartA = filename; + else + SConfig::GetInstance().m_strGbaCartB = filename; + } if (Core::IsRunning()) { // Change memcard to the new file ExpansionInterface::ChangeDevice( isSlotA ? 0 : 1, // SlotA: channel 0, SlotB channel 1 - EXIDEVICE_MEMORYCARD, + device_type, 0); // SP1 is device 2, slots are device 0 } } else { - WxUtils::ShowErrorDialog(_("Cannot use that file as a memory card.\n" - "Are you trying to use the same file in both slots?")); + WxUtils::ShowErrorDialog(_("Are you trying to use the same file in both slots?")); } } } @@ -1093,6 +1128,8 @@ void CConfigMain::ChooseEXIDevice(wxString deviceName, int deviceNum) tempType = EXIDEVICE_MIC; else if (!deviceName.compare(EXIDEV_BBA_STR)) tempType = EXIDEVICE_ETH; + else if (!deviceName.compare(EXIDEV_AGP_STR)) + tempType = EXIDEVICE_AGP; else if (!deviceName.compare(_(EXIDEV_AM_BB_STR))) tempType = EXIDEVICE_AM_BASEBOARD; else if (!deviceName.compare(EXIDEV_GECKO_STR)) @@ -1102,8 +1139,8 @@ void CConfigMain::ChooseEXIDevice(wxString deviceName, int deviceNum) else tempType = EXIDEVICE_DUMMY; - // Gray out the memcard path button if we're not on a memcard - if (tempType == EXIDEVICE_MEMORYCARD) + // Gray out the memcard path button if we're not on a memcard or AGP + if (tempType == EXIDEVICE_MEMORYCARD || tempType == EXIDEVICE_AGP) GCMemcardPath[deviceNum]->Enable(); else if (deviceNum == 0 || deviceNum == 1) GCMemcardPath[deviceNum]->Disable(); diff --git a/Source/Core/DolphinWX/ConfigMain.h b/Source/Core/DolphinWX/ConfigMain.h index 85e4b67c27..08f69fec40 100644 --- a/Source/Core/DolphinWX/ConfigMain.h +++ b/Source/Core/DolphinWX/ConfigMain.h @@ -254,7 +254,7 @@ private: void AddAudioBackends(); void GCSettingsChanged(wxCommandEvent& event); - void ChooseMemcardPath(std::string& strMemcard, bool isSlotA); + void ChooseSlotPath(bool isSlotA, TEXIDevices device_type); void ChooseEXIDevice(wxString deviceName, int deviceNum); void WiiSettingsChanged(wxCommandEvent& event); From 8a561b57c35f9b5c76efbf73a7bbf14e622440b0 Mon Sep 17 00:00:00 2001 From: skidau Date: Sat, 24 Jan 2015 12:09:35 +1100 Subject: [PATCH 3/4] Added EEPROM saving to file. --- Source/Core/Core/HW/EXI_DeviceAGP.cpp | 108 +++++++++++++++++--------- Source/Core/Core/HW/EXI_DeviceAGP.h | 9 ++- Source/Core/Core/State.cpp | 2 +- Source/Core/DolphinWX/ConfigMain.cpp | 6 +- 4 files changed, 78 insertions(+), 47 deletions(-) diff --git a/Source/Core/Core/HW/EXI_DeviceAGP.cpp b/Source/Core/Core/HW/EXI_DeviceAGP.cpp index bcd3027a93..5b1e5038b0 100644 --- a/Source/Core/Core/HW/EXI_DeviceAGP.cpp +++ b/Source/Core/Core/HW/EXI_DeviceAGP.cpp @@ -11,11 +11,11 @@ #include "Core/HW/EXI_DeviceAGP.h" #include "Core/HW/Memmap.h" -CEXIAgp::CEXIAgp(int index) : - m_slot(index) +CEXIAgp::CEXIAgp(int index) { + m_slot = index; + // Create the ROM - m_pHashArray = (u8*)AllocateMemoryPages(HASH_SIZE); m_rom_size = 0; LoadRom(); @@ -26,16 +26,25 @@ CEXIAgp::CEXIAgp(int index) : CEXIAgp::~CEXIAgp() { - m_pROM = nullptr; - m_pHashArray = nullptr; + std::string path; + std::string filename; + std::string ext; + std::string gbapath; + SplitPath(m_slot == 0 ? SConfig::GetInstance().m_strGbaCartA : SConfig::GetInstance().m_strGbaCartB, &path, &filename, &ext); + gbapath = path + filename; + + SaveFileFromEEPROM(gbapath + ".sav"); } void CEXIAgp::DoHash(u8* data, u32 size) { + if (!m_rom_hash_loaded) + LoadHash(); + for (u32 it = 0; it < size; it++) { m_hash = m_hash ^ data[it]; - m_hash = m_pHashArray[m_hash]; + m_hash = m_hash_array[m_hash]; } } @@ -49,9 +58,9 @@ void CEXIAgp::LoadRom() SplitPath(m_slot == 0 ? SConfig::GetInstance().m_strGbaCartA : SConfig::GetInstance().m_strGbaCartB, &path, &filename, &ext); gbapath = path + filename; LoadFileToROM(gbapath + ext); - INFO_LOG(EXPANSIONINTERFACE, "Loaded gba rom: %s card: %d", gbapath.c_str(), m_slot); + INFO_LOG(EXPANSIONINTERFACE, "Loaded GBA rom: %s card: %d", gbapath.c_str(), m_slot); LoadFileToEEPROM(gbapath + ".sav"); - INFO_LOG(EXPANSIONINTERFACE, "Loaded gba sav: %s card: %d", gbapath.c_str(), m_slot); + INFO_LOG(EXPANSIONINTERFACE, "Loaded GBA sav: %s card: %d", gbapath.c_str(), m_slot); } void CEXIAgp::LoadFileToROM(std::string filename) @@ -63,14 +72,14 @@ void CEXIAgp::LoadFileToROM(std::string filename) m_rom_size = filesize & 0xFFFFFFFF; m_rom_mask = (m_rom_size - 1); - m_pROM = (u8*)AllocateMemoryPages(m_rom_size); + m_rom.resize(m_rom_size); - pStream.ReadBytes(m_pROM, filesize); + pStream.ReadBytes(m_rom.data(), filesize); } else { // dummy rom data - m_pROM = (u8*)AllocateMemoryPages(0x2000); + m_rom.resize(0x2000); } } @@ -83,9 +92,18 @@ void CEXIAgp::LoadFileToEEPROM(std::string filename) m_eeprom_size = filesize & 0xFFFFFFFF; m_eeprom_mask = (m_eeprom_size - 1); - m_pEEPROM = (u8*)AllocateMemoryPages(m_eeprom_size); + m_eeprom.resize(m_eeprom_size); - pStream.ReadBytes(m_pEEPROM, filesize); + pStream.ReadBytes(m_eeprom.data(), filesize); + } +} + +void CEXIAgp::SaveFileFromEEPROM(std::string filename) +{ + File::IOFile pStream(filename, "wb"); + if (pStream) + { + pStream.WriteBytes(m_eeprom.data(), m_eeprom_size); } } @@ -95,9 +113,14 @@ void CEXIAgp::LoadHash() { for (int i = 0; i < 0x100; i++) { - m_pHashArray[i] = Memory::ReadUnchecked_U8(0x0017e908 + i); + // Load the ROM hash expected by the AGP + m_hash_array[i] = Memory::ReadUnchecked_U8(0x0017e908 + i); + } + // Verify the hash + if (m_hash_array[HASH_SIZE - 1] == 0x35) + { + m_rom_hash_loaded = true; } - m_rom_hash_loaded = true; } } @@ -108,16 +131,16 @@ u32 CEXIAgp::ImmRead(u32 _uSize) u32 uData = 0; u8 RomVal1, RomVal2, RomVal3, RomVal4; - switch (m_currrent_cmd) + switch (m_current_cmd) { case 0xAE000000: uData = 0x5AAA5517; // 17 is precalculated hash - m_currrent_cmd = 0; + m_current_cmd = 0; break; case 0xAE010000: uData = (m_return_pos == 0) ? 0x01020304 : 0xF0020304; // F0 is precalculated hash, 020304 is left over if (m_return_pos == 1) - m_currrent_cmd = 0; + m_current_cmd = 0; else m_return_pos = 1; break; @@ -129,28 +152,26 @@ u32 CEXIAgp::ImmRead(u32 _uSize) } else { - RomVal1 = m_pROM[m_rw_offset++]; - RomVal2 = m_pROM[m_rw_offset++]; - LoadHash(); + RomVal1 = m_rom[m_rw_offset++]; + RomVal2 = m_rom[m_rw_offset++]; } DoHash(&RomVal2, 1); DoHash(&RomVal1, 1); uData = (RomVal2 << 24) | (RomVal1 << 16) | (m_hash << 8); - m_currrent_cmd = 0; + m_current_cmd = 0; break; case 0xAE030000: if (_uSize == 1) { uData = 0xFF000000; - m_currrent_cmd = 0; + m_current_cmd = 0; } else { - RomVal1 = m_pROM[m_rw_offset++]; - RomVal2 = m_pROM[m_rw_offset++]; - RomVal3 = m_pROM[m_rw_offset++]; - RomVal4 = m_pROM[m_rw_offset++]; - LoadHash(); + RomVal1 = m_rom[m_rw_offset++]; + RomVal2 = m_rom[m_rw_offset++]; + RomVal3 = m_rom[m_rw_offset++]; + RomVal4 = m_rom[m_rw_offset++]; DoHash(&RomVal2, 1); DoHash(&RomVal1, 1); DoHash(&RomVal4, 1); @@ -159,21 +180,21 @@ u32 CEXIAgp::ImmRead(u32 _uSize) } break; case 0xAE0B0000: - RomVal1 = m_eeprom_pos < 4 ? 0xA : (((u64*)m_pEEPROM)[(m_eeprom_cmd >> 1) & 0x3F] >> (m_eeprom_pos - 4)) & 0x1; + RomVal1 = m_eeprom_pos < 4 ? 0xA : (((u64*)m_eeprom.data())[(m_eeprom_cmd >> 1) & 0x3F] >> (m_eeprom_pos - 4)) & 0x1; RomVal2 = 0; DoHash(&RomVal2, 1); DoHash(&RomVal1, 1); uData = (RomVal2 << 24) | (RomVal1 << 16) | (m_hash << 8); m_eeprom_pos++; - m_currrent_cmd = 0; + m_current_cmd = 0; break; case 0xAE0C0000: uData = m_hash << 24; - m_currrent_cmd = 0; + m_current_cmd = 0; break; default: uData = 0x0; - m_currrent_cmd = 0; + m_current_cmd = 0; break; } INFO_LOG(EXPANSIONINTERFACE, "AGP read %x", uData); @@ -188,7 +209,7 @@ void CEXIAgp::ImmWrite(u32 _uData, u32 _uSize) u8 HashCmd; u64 Mask; INFO_LOG(EXPANSIONINTERFACE, "AGP command %x", _uData); - switch (m_currrent_cmd) + switch (m_current_cmd) { case 0xAE020000: case 0xAE030000: @@ -210,7 +231,7 @@ void CEXIAgp::ImmWrite(u32 _uData, u32 _uSize) else m_eeprom_cmd &= ~Mask; if (m_eeprom_pos == 0x48) - ((u64*)(m_pEEPROM))[(m_eeprom_cmd >> 1) & 0x3F] = m_eeprom_data; + ((u64*)(m_eeprom.data()))[(m_eeprom_cmd >> 1) & 0x3F] = m_eeprom_data; } else { @@ -235,7 +256,7 @@ void CEXIAgp::ImmWrite(u32 _uData, u32 _uSize) case 0xAE0A0000: default: m_eeprom_pos = 0; - m_currrent_cmd = _uData; + m_current_cmd = _uData; m_return_pos = 0; m_hash = 0xFF; HashCmd = (_uData & 0x00FF0000) >> 16; @@ -246,8 +267,21 @@ void CEXIAgp::ImmWrite(u32 _uData, u32 _uSize) void CEXIAgp::DoState(PointerWrap &p) { - p.Do(m_position); + p.Do(m_slot); p.Do(m_address); - p.Do(m_rw_offset); + p.Do(m_current_cmd); + p.Do(m_eeprom); + p.Do(m_eeprom_cmd); + p.Do(m_eeprom_data); + p.Do(m_eeprom_mask); + p.Do(m_eeprom_pos); + p.Do(m_eeprom_size); p.Do(m_hash); + p.Do(m_hash_array); + p.Do(m_position); + p.Do(m_return_pos); + p.Do(m_rom); + p.Do(m_rom_mask); + p.Do(m_rom_size); + p.Do(m_rw_offset); } diff --git a/Source/Core/Core/HW/EXI_DeviceAGP.h b/Source/Core/Core/HW/EXI_DeviceAGP.h index 1b6f10052d..77b88b09fa 100644 --- a/Source/Core/Core/HW/EXI_DeviceAGP.h +++ b/Source/Core/Core/HW/EXI_DeviceAGP.h @@ -35,9 +35,9 @@ private: u32 m_rom_mask = 0; u32 m_eeprom_size = 0; u32 m_eeprom_mask = 0; - u8* m_pROM; - u8* m_pEEPROM; - u8* m_pHashArray; + std::vector m_rom; + std::vector m_eeprom; + std::array m_hash_array; //! Helper u32 m_position = 0; @@ -49,12 +49,13 @@ private: void LoadFileToROM(std::string filename); void LoadFileToEEPROM(std::string filename); + void SaveFileFromEEPROM(std::string filename); void LoadHash(); void LoadRom(); void DoHash(u8* data, u32 size); u8 m_hash = 0; - u32 m_currrent_cmd = 0; + u32 m_current_cmd = 0; u32 m_return_pos = 0; bool m_rom_hash_loaded = false; diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index a63fafc2a5..2b3ce95e08 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -64,7 +64,7 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -static const u32 STATE_VERSION = 38; +static const u32 STATE_VERSION = 39; enum { diff --git a/Source/Core/DolphinWX/ConfigMain.cpp b/Source/Core/DolphinWX/ConfigMain.cpp index 1f5d4b1913..9a642a9a74 100644 --- a/Source/Core/DolphinWX/ConfigMain.cpp +++ b/Source/Core/DolphinWX/ConfigMain.cpp @@ -1023,7 +1023,7 @@ void CConfigMain::GCSettingsChanged(wxCommandEvent& event) ChooseSlotPath(true, SConfig::GetInstance().m_EXIDevice[0]); break; case ID_GC_EXIDEVICE_SLOTB_PATH: - ChooseSlotPath(false, SConfig::GetInstance().m_EXIDevice[0]); + ChooseSlotPath(false, SConfig::GetInstance().m_EXIDevice[1]); break; } } @@ -1063,10 +1063,6 @@ void CConfigMain::ChooseSlotPath(bool isSlotA, TEXIDevices device_type) return; } } - else - { - return; - } } #ifdef _WIN32 if (!strncmp(File::GetExeDirectory().c_str(), filename.c_str(), File::GetExeDirectory().size())) From 7dafad5a8bdf0c600e1baeb95c11f6f009590999 Mon Sep 17 00:00:00 2001 From: skidau Date: Sat, 24 Jan 2015 12:19:33 +1100 Subject: [PATCH 4/4] On DCBZ, mask the memory address to ensure that the address is within physical memory. The AGP disc DCBZ's against an out of bounds physical address. --- Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp index 0c0a23acfc..1425a95211 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp @@ -331,6 +331,10 @@ void Jit64::dcbz(UGeckoInstruction inst) FixupBranch exit = J(true); SwitchToNearCode(); + // Mask out the address so we don't write to MEM1 out of bounds + // FIXME: Work out why the AGP disc writes out of bounds + if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bWii) + AND(32, R(RSCRATCH), Imm32(Memory::RAM_MASK)); PXOR(XMM0, R(XMM0)); MOVAPS(MComplex(RMEM, RSCRATCH, SCALE_1, 0), XMM0); MOVAPS(MComplex(RMEM, RSCRATCH, SCALE_1, 16), XMM0);