diff --git a/Source/Core/Core/HW/EXI/EXI.cpp b/Source/Core/Core/HW/EXI/EXI.cpp index 131c69b092..7616e2f0af 100644 --- a/Source/Core/Core/HW/EXI/EXI.cpp +++ b/Source/Core/Core/HW/EXI/EXI.cpp @@ -9,17 +9,21 @@ #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" +#include "Common/IniFile.h" #include "Core/ConfigManager.h" #include "Core/CoreTiming.h" #include "Core/HW/EXI/EXI_Channel.h" #include "Core/HW/EXI/EXI_DeviceMemoryCard.h" +#include "Core/HW/GCMemcard/GCMemcard.h" #include "Core/HW/MMIO.h" #include "Core/HW/ProcessorInterface.h" #include "Core/HW/Sram.h" #include "Core/HW/SystemTimers.h" #include "Core/Movie.h" +#include "DiscIO/Enums.h" + Sram g_SRAM; bool g_SRAM_netplay_initialized = false; @@ -69,8 +73,29 @@ void Init() } CEXIMemoryCard::Init(); - for (u32 i = 0; i < MAX_EXI_CHANNELS; i++) - g_Channels[i] = std::make_unique(i); + + { + bool use_memcard_251; + IniFile gameIni = SConfig::GetInstance().LoadGameIni(); + gameIni.GetOrCreateSection("Core")->Get("MemoryCard251", &use_memcard_251, false); + const u16 size_mbits = + use_memcard_251 ? Memcard::MBIT_SIZE_MEMORY_CARD_251 : Memcard::MBIT_SIZE_MEMORY_CARD_2043; + const bool shift_jis = + SConfig::ToGameCubeRegion(SConfig::GetInstance().m_region) == DiscIO::Region::NTSC_J; + const CardFlashId& flash_id = g_SRAM.settings_ex.flash_id[Memcard::SLOT_A]; + const u32 rtc_bias = g_SRAM.settings.rtc_bias; + const u32 sram_language = static_cast(g_SRAM.settings.language); + const u64 format_time = + Common::Timer::GetLocalTimeSinceJan1970() - ExpansionInterface::CEXIIPL::GC_EPOCH; + + for (u32 i = 0; i < MAX_EXI_CHANNELS; i++) + { + Memcard::HeaderData header_data; + Memcard::InitializeHeaderData(&header_data, flash_id, size_mbits, shift_jis, rtc_bias, + sram_language, format_time + i); + g_Channels[i] = std::make_unique(i, header_data); + } + } for (int i = 0; i < MAX_MEMORYCARD_SLOTS; i++) AddMemoryCards(i); diff --git a/Source/Core/Core/HW/EXI/EXI_Channel.cpp b/Source/Core/Core/HW/EXI/EXI_Channel.cpp index b31d97fc54..1f0e3480c6 100644 --- a/Source/Core/Core/HW/EXI/EXI_Channel.cpp +++ b/Source/Core/Core/HW/EXI/EXI_Channel.cpp @@ -22,7 +22,8 @@ enum EXI_READWRITE }; -CEXIChannel::CEXIChannel(u32 channel_id) : m_channel_id(channel_id) +CEXIChannel::CEXIChannel(u32 channel_id, const Memcard::HeaderData& memcard_header_data) + : m_channel_id(channel_id), m_memcard_header_data(memcard_header_data) { if (m_channel_id == 0 || m_channel_id == 1) m_status.EXTINT = 1; @@ -30,7 +31,7 @@ CEXIChannel::CEXIChannel(u32 channel_id) : m_channel_id(channel_id) m_status.CHIP_SELECT = 1; for (auto& device : m_devices) - device = EXIDevice_Create(EXIDEVICE_NONE, m_channel_id); + device = EXIDevice_Create(EXIDEVICE_NONE, m_channel_id, m_memcard_header_data); } CEXIChannel::~CEXIChannel() @@ -166,7 +167,7 @@ void CEXIChannel::RemoveDevices() void CEXIChannel::AddDevice(const TEXIDevices device_type, const int device_num) { - AddDevice(EXIDevice_Create(device_type, m_channel_id), device_num); + AddDevice(EXIDevice_Create(device_type, m_channel_id, m_memcard_header_data), device_num); } void CEXIChannel::AddDevice(std::unique_ptr device, const int device_num, @@ -229,6 +230,7 @@ void CEXIChannel::DoState(PointerWrap& p) p.Do(m_dma_length); p.Do(m_control); p.Do(m_imm_data); + p.DoPOD(m_memcard_header_data); for (int device_index = 0; device_index < NUM_DEVICES; ++device_index) { @@ -242,7 +244,8 @@ void CEXIChannel::DoState(PointerWrap& p) } else { - std::unique_ptr save_device = EXIDevice_Create(type, m_channel_id); + std::unique_ptr save_device = + EXIDevice_Create(type, m_channel_id, m_memcard_header_data); save_device->DoState(p); AddDevice(std::move(save_device), device_index, false); } diff --git a/Source/Core/Core/HW/EXI/EXI_Channel.h b/Source/Core/Core/HW/EXI/EXI_Channel.h index b8fa6b1ffc..26b681d74b 100644 --- a/Source/Core/Core/HW/EXI/EXI_Channel.h +++ b/Source/Core/Core/HW/EXI/EXI_Channel.h @@ -6,8 +6,11 @@ #include #include + #include "Common/CommonTypes.h" +#include "Core/HW/GCMemcard/GCMemcard.h" + class PointerWrap; namespace MMIO @@ -23,7 +26,7 @@ enum TEXIDevices : int; class CEXIChannel { public: - explicit CEXIChannel(u32 channel_id); + explicit CEXIChannel(u32 channel_id, const Memcard::HeaderData& memcard_header_data); ~CEXIChannel(); // get device @@ -106,6 +109,12 @@ private: UEXI_CONTROL m_control; u32 m_imm_data = 0; + // This data is needed in order to reinitialize a GCI folder memory card when switching between + // GCI folder and other devices in the memory card slot or after loading a savestate. Even though + // this data is only vaguely related to the EXI_Channel, this seems to be the best place to store + // it, as this class creates the CEXIMemoryCard instances. + Memcard::HeaderData m_memcard_header_data; + // Devices enum { diff --git a/Source/Core/Core/HW/EXI/EXI_Device.cpp b/Source/Core/Core/HW/EXI/EXI_Device.cpp index be4a7029c8..83d1362be9 100644 --- a/Source/Core/Core/HW/EXI/EXI_Device.cpp +++ b/Source/Core/Core/HW/EXI/EXI_Device.cpp @@ -102,7 +102,8 @@ void IEXIDevice::TransferByte(u8& byte) } // F A C T O R Y -std::unique_ptr EXIDevice_Create(const TEXIDevices device_type, const int channel_num) +std::unique_ptr EXIDevice_Create(const TEXIDevices device_type, const int channel_num, + const Memcard::HeaderData& memcard_header_data) { std::unique_ptr result; @@ -116,7 +117,7 @@ std::unique_ptr EXIDevice_Create(const TEXIDevices device_type, cons case EXIDEVICE_MEMORYCARDFOLDER: { bool gci_folder = (device_type == EXIDEVICE_MEMORYCARDFOLDER); - result = std::make_unique(channel_num, gci_folder); + result = std::make_unique(channel_num, gci_folder, memcard_header_data); break; } case EXIDEVICE_MASKROM: diff --git a/Source/Core/Core/HW/EXI/EXI_Device.h b/Source/Core/Core/HW/EXI/EXI_Device.h index 0eb30904ca..9312643945 100644 --- a/Source/Core/Core/HW/EXI/EXI_Device.h +++ b/Source/Core/Core/HW/EXI/EXI_Device.h @@ -9,6 +9,11 @@ class PointerWrap; +namespace Memcard +{ +struct HeaderData; +} + namespace ExpansionInterface { enum TEXIDevices : int @@ -65,5 +70,6 @@ private: virtual void TransferByte(u8& byte); }; -std::unique_ptr EXIDevice_Create(TEXIDevices device_type, int channel_num); +std::unique_ptr EXIDevice_Create(TEXIDevices device_type, int channel_num, + const Memcard::HeaderData& memcard_header_data); } // namespace ExpansionInterface diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceMemoryCard.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceMemoryCard.cpp index b39b6963d7..4f0b3830f3 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceMemoryCard.cpp +++ b/Source/Core/Core/HW/EXI/EXI_DeviceMemoryCard.cpp @@ -106,7 +106,9 @@ void CEXIMemoryCard::Shutdown() s_et_transfer_complete.fill(nullptr); } -CEXIMemoryCard::CEXIMemoryCard(const int index, bool gciFolder) : card_index(index) +CEXIMemoryCard::CEXIMemoryCard(const int index, bool gciFolder, + const Memcard::HeaderData& header_data) + : card_index(index) { ASSERT_MSG(EXPANSIONINTERFACE, static_cast(index) < s_et_cmd_done.size(), "Trying to create invalid memory card index %d.", index); @@ -132,25 +134,13 @@ CEXIMemoryCard::CEXIMemoryCard(const int index, bool gciFolder) : card_index(ind // card_id = 0xc243; card_id = 0xc221; // It's a Nintendo brand memcard - // The following games have issues with memory cards bigger than 16Mb - // Darkened Skye GDQE6S GDQP6S - // WTA Tour Tennis GWTEA4 GWTJA4 GWTPA4 - // Disney Sports : Skate Boarding GDXEA4 GDXPA4 GDXJA4 - // Disney Sports : Soccer GDKEA4 - // Wallace and Gromit in Pet Zoo GWLE6L GWLX6L - // Use a 16Mb (251 block) memory card for these games - bool useMC251; - IniFile gameIni = SConfig::GetInstance().LoadGameIni(); - gameIni.GetOrCreateSection("Core")->Get("MemoryCard251", &useMC251, false); - u16 sizeMb = useMC251 ? Memcard::MBIT_SIZE_MEMORY_CARD_251 : Memcard::MBIT_SIZE_MEMORY_CARD_2043; - if (gciFolder) { - SetupGciFolder(sizeMb); + SetupGciFolder(header_data); } else { - SetupRawMemcard(sizeMb); + SetupRawMemcard(header_data.m_size_mb); } memory_card_size = memorycard->GetCardId() * SIZE_TO_Mb; @@ -185,7 +175,7 @@ CEXIMemoryCard::GetGCIFolderPath(int card_index, AllowMovieFolder allow_movie_fo return {std::move(path), !use_movie_folder}; } -void CEXIMemoryCard::SetupGciFolder(u16 sizeMb) +void CEXIMemoryCard::SetupGciFolder(const Memcard::HeaderData& header_data) { const std::string& game_id = SConfig::GetInstance().GetGameID(); u32 CurrentGameId = 0; @@ -195,8 +185,7 @@ void CEXIMemoryCard::SetupGciFolder(u16 sizeMb) CurrentGameId = Common::swap32(reinterpret_cast(game_id.c_str())); } - const bool shift_jis = - SConfig::ToGameCubeRegion(SConfig::GetInstance().m_region) == DiscIO::Region::NTSC_J; + const bool shift_jis = header_data.m_encoding != 0; const auto [strDirectoryName, migrate] = GetGCIFolderPath(card_index, AllowMovieFolder::Yes); @@ -228,8 +217,8 @@ void CEXIMemoryCard::SetupGciFolder(u16 sizeMb) } } - memorycard = std::make_unique(strDirectoryName + DIR_SEP, card_index, sizeMb, - shift_jis, CurrentGameId); + memorycard = std::make_unique(strDirectoryName + DIR_SEP, card_index, + header_data, CurrentGameId); } void CEXIMemoryCard::SetupRawMemcard(u16 sizeMb) diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceMemoryCard.h b/Source/Core/Core/HW/EXI/EXI_DeviceMemoryCard.h index 4075637f25..f0c9411309 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceMemoryCard.h +++ b/Source/Core/Core/HW/EXI/EXI_DeviceMemoryCard.h @@ -14,6 +14,11 @@ class MemoryCardBase; class PointerWrap; +namespace Memcard +{ +struct HeaderData; +} + namespace ExpansionInterface { enum class AllowMovieFolder @@ -25,7 +30,7 @@ enum class AllowMovieFolder class CEXIMemoryCard : public IEXIDevice { public: - CEXIMemoryCard(const int index, bool gciFolder); + CEXIMemoryCard(const int index, bool gciFolder, const Memcard::HeaderData& header_data); virtual ~CEXIMemoryCard(); void SetCS(int cs) override; bool IsInterruptSet() override; @@ -46,7 +51,7 @@ public: GetGCIFolderPath(int card_index, AllowMovieFolder allow_movie_folder); private: - void SetupGciFolder(u16 sizeMb); + void SetupGciFolder(const Memcard::HeaderData& header_data); void SetupRawMemcard(u16 sizeMb); static void EventCompleteFindInstance(u64 userdata, std::function callback); diff --git a/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.cpp b/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.cpp index 9fe0c0dccb..7af9e44778 100644 --- a/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.cpp +++ b/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.cpp @@ -149,13 +149,11 @@ std::vector GCMemcardDirectory::GetFileNamesForGameID(const std::st return filenames; } -GCMemcardDirectory::GCMemcardDirectory(const std::string& directory, int slot, u16 size_mbits, - bool shift_jis, int game_id) - : MemoryCardBase(slot, size_mbits), m_game_id(game_id), m_last_block(-1), - m_hdr(g_SRAM.settings_ex.flash_id[slot], size_mbits, shift_jis, g_SRAM.settings.rtc_bias, - static_cast(g_SRAM.settings.language), - Common::Timer::GetLocalTimeSinceJan1970() - ExpansionInterface::CEXIIPL::GC_EPOCH), - m_bat1(size_mbits), m_saves(0), m_save_directory(directory), m_exiting(false) +GCMemcardDirectory::GCMemcardDirectory(const std::string& directory, int slot, + const Memcard::HeaderData& header_data, u32 game_id) + : MemoryCardBase(slot, header_data.m_size_mb), m_game_id(game_id), m_last_block(-1), + m_hdr(header_data), m_bat1(header_data.m_size_mb), m_saves(0), m_save_directory(directory), + m_exiting(false) { // Use existing header data if available { diff --git a/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.h b/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.h index dbda7b3778..374221de23 100644 --- a/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.h +++ b/Source/Core/Core/HW/GCMemcard/GCMemcardDirectory.h @@ -21,8 +21,8 @@ void MigrateFromMemcardFile(const std::string& directory_name, int card_index); class GCMemcardDirectory : public MemoryCardBase { public: - GCMemcardDirectory(const std::string& directory, int slot, u16 size_mbits, bool shift_jis, - int game_id); + GCMemcardDirectory(const std::string& directory, int slot, const Memcard::HeaderData& header_data, + u32 game_id); ~GCMemcardDirectory(); GCMemcardDirectory(const GCMemcardDirectory&) = delete; diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 84de8d864b..b12a5f1462 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -74,7 +74,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 -constexpr u32 STATE_VERSION = 115; // Last changed in PR 8722 +constexpr u32 STATE_VERSION = 116; // Last changed in PR 8879 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list,