EXI: Store data for regenerating a GCI folder memory card header in EXI_Channel and pass it down to the memory card device.

This commit is contained in:
Admiral H. Curtiss 2020-06-16 02:10:14 +02:00
parent e810d492f2
commit 8b13e1882a
10 changed files with 78 additions and 42 deletions

View File

@ -9,17 +9,21 @@
#include "Common/ChunkFile.h" #include "Common/ChunkFile.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/IniFile.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/CoreTiming.h" #include "Core/CoreTiming.h"
#include "Core/HW/EXI/EXI_Channel.h" #include "Core/HW/EXI/EXI_Channel.h"
#include "Core/HW/EXI/EXI_DeviceMemoryCard.h" #include "Core/HW/EXI/EXI_DeviceMemoryCard.h"
#include "Core/HW/GCMemcard/GCMemcard.h"
#include "Core/HW/MMIO.h" #include "Core/HW/MMIO.h"
#include "Core/HW/ProcessorInterface.h" #include "Core/HW/ProcessorInterface.h"
#include "Core/HW/Sram.h" #include "Core/HW/Sram.h"
#include "Core/HW/SystemTimers.h" #include "Core/HW/SystemTimers.h"
#include "Core/Movie.h" #include "Core/Movie.h"
#include "DiscIO/Enums.h"
Sram g_SRAM; Sram g_SRAM;
bool g_SRAM_netplay_initialized = false; bool g_SRAM_netplay_initialized = false;
@ -69,8 +73,29 @@ void Init()
} }
CEXIMemoryCard::Init(); CEXIMemoryCard::Init();
for (u32 i = 0; i < MAX_EXI_CHANNELS; i++)
g_Channels[i] = std::make_unique<CEXIChannel>(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<u32>(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<CEXIChannel>(i, header_data);
}
}
for (int i = 0; i < MAX_MEMORYCARD_SLOTS; i++) for (int i = 0; i < MAX_MEMORYCARD_SLOTS; i++)
AddMemoryCards(i); AddMemoryCards(i);

View File

@ -22,7 +22,8 @@ enum
EXI_READWRITE 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) if (m_channel_id == 0 || m_channel_id == 1)
m_status.EXTINT = 1; m_status.EXTINT = 1;
@ -30,7 +31,7 @@ CEXIChannel::CEXIChannel(u32 channel_id) : m_channel_id(channel_id)
m_status.CHIP_SELECT = 1; m_status.CHIP_SELECT = 1;
for (auto& device : m_devices) 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() CEXIChannel::~CEXIChannel()
@ -166,7 +167,7 @@ void CEXIChannel::RemoveDevices()
void CEXIChannel::AddDevice(const TEXIDevices device_type, const int device_num) 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<IEXIDevice> device, const int device_num, void CEXIChannel::AddDevice(std::unique_ptr<IEXIDevice> device, const int device_num,
@ -229,6 +230,7 @@ void CEXIChannel::DoState(PointerWrap& p)
p.Do(m_dma_length); p.Do(m_dma_length);
p.Do(m_control); p.Do(m_control);
p.Do(m_imm_data); p.Do(m_imm_data);
p.DoPOD(m_memcard_header_data);
for (int device_index = 0; device_index < NUM_DEVICES; ++device_index) for (int device_index = 0; device_index < NUM_DEVICES; ++device_index)
{ {
@ -242,7 +244,8 @@ void CEXIChannel::DoState(PointerWrap& p)
} }
else else
{ {
std::unique_ptr<IEXIDevice> save_device = EXIDevice_Create(type, m_channel_id); std::unique_ptr<IEXIDevice> save_device =
EXIDevice_Create(type, m_channel_id, m_memcard_header_data);
save_device->DoState(p); save_device->DoState(p);
AddDevice(std::move(save_device), device_index, false); AddDevice(std::move(save_device), device_index, false);
} }

View File

@ -6,8 +6,11 @@
#include <array> #include <array>
#include <memory> #include <memory>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Core/HW/GCMemcard/GCMemcard.h"
class PointerWrap; class PointerWrap;
namespace MMIO namespace MMIO
@ -23,7 +26,7 @@ enum TEXIDevices : int;
class CEXIChannel class CEXIChannel
{ {
public: public:
explicit CEXIChannel(u32 channel_id); explicit CEXIChannel(u32 channel_id, const Memcard::HeaderData& memcard_header_data);
~CEXIChannel(); ~CEXIChannel();
// get device // get device
@ -106,6 +109,12 @@ private:
UEXI_CONTROL m_control; UEXI_CONTROL m_control;
u32 m_imm_data = 0; 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 // Devices
enum enum
{ {

View File

@ -102,7 +102,8 @@ void IEXIDevice::TransferByte(u8& byte)
} }
// F A C T O R Y // F A C T O R Y
std::unique_ptr<IEXIDevice> EXIDevice_Create(const TEXIDevices device_type, const int channel_num) std::unique_ptr<IEXIDevice> EXIDevice_Create(const TEXIDevices device_type, const int channel_num,
const Memcard::HeaderData& memcard_header_data)
{ {
std::unique_ptr<IEXIDevice> result; std::unique_ptr<IEXIDevice> result;
@ -116,7 +117,7 @@ std::unique_ptr<IEXIDevice> EXIDevice_Create(const TEXIDevices device_type, cons
case EXIDEVICE_MEMORYCARDFOLDER: case EXIDEVICE_MEMORYCARDFOLDER:
{ {
bool gci_folder = (device_type == EXIDEVICE_MEMORYCARDFOLDER); bool gci_folder = (device_type == EXIDEVICE_MEMORYCARDFOLDER);
result = std::make_unique<CEXIMemoryCard>(channel_num, gci_folder); result = std::make_unique<CEXIMemoryCard>(channel_num, gci_folder, memcard_header_data);
break; break;
} }
case EXIDEVICE_MASKROM: case EXIDEVICE_MASKROM:

View File

@ -9,6 +9,11 @@
class PointerWrap; class PointerWrap;
namespace Memcard
{
struct HeaderData;
}
namespace ExpansionInterface namespace ExpansionInterface
{ {
enum TEXIDevices : int enum TEXIDevices : int
@ -65,5 +70,6 @@ private:
virtual void TransferByte(u8& byte); virtual void TransferByte(u8& byte);
}; };
std::unique_ptr<IEXIDevice> EXIDevice_Create(TEXIDevices device_type, int channel_num); std::unique_ptr<IEXIDevice> EXIDevice_Create(TEXIDevices device_type, int channel_num,
const Memcard::HeaderData& memcard_header_data);
} // namespace ExpansionInterface } // namespace ExpansionInterface

View File

@ -106,7 +106,9 @@ void CEXIMemoryCard::Shutdown()
s_et_transfer_complete.fill(nullptr); 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<std::size_t>(index) < s_et_cmd_done.size(), ASSERT_MSG(EXPANSIONINTERFACE, static_cast<std::size_t>(index) < s_et_cmd_done.size(),
"Trying to create invalid memory card index %d.", index); "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 = 0xc243;
card_id = 0xc221; // It's a Nintendo brand memcard 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) if (gciFolder)
{ {
SetupGciFolder(sizeMb); SetupGciFolder(header_data);
} }
else else
{ {
SetupRawMemcard(sizeMb); SetupRawMemcard(header_data.m_size_mb);
} }
memory_card_size = memorycard->GetCardId() * SIZE_TO_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}; 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(); const std::string& game_id = SConfig::GetInstance().GetGameID();
u32 CurrentGameId = 0; u32 CurrentGameId = 0;
@ -195,8 +185,7 @@ void CEXIMemoryCard::SetupGciFolder(u16 sizeMb)
CurrentGameId = Common::swap32(reinterpret_cast<const u8*>(game_id.c_str())); CurrentGameId = Common::swap32(reinterpret_cast<const u8*>(game_id.c_str()));
} }
const bool shift_jis = const bool shift_jis = header_data.m_encoding != 0;
SConfig::ToGameCubeRegion(SConfig::GetInstance().m_region) == DiscIO::Region::NTSC_J;
const auto [strDirectoryName, migrate] = GetGCIFolderPath(card_index, AllowMovieFolder::Yes); const auto [strDirectoryName, migrate] = GetGCIFolderPath(card_index, AllowMovieFolder::Yes);
@ -228,8 +217,8 @@ void CEXIMemoryCard::SetupGciFolder(u16 sizeMb)
} }
} }
memorycard = std::make_unique<GCMemcardDirectory>(strDirectoryName + DIR_SEP, card_index, sizeMb, memorycard = std::make_unique<GCMemcardDirectory>(strDirectoryName + DIR_SEP, card_index,
shift_jis, CurrentGameId); header_data, CurrentGameId);
} }
void CEXIMemoryCard::SetupRawMemcard(u16 sizeMb) void CEXIMemoryCard::SetupRawMemcard(u16 sizeMb)

View File

@ -14,6 +14,11 @@
class MemoryCardBase; class MemoryCardBase;
class PointerWrap; class PointerWrap;
namespace Memcard
{
struct HeaderData;
}
namespace ExpansionInterface namespace ExpansionInterface
{ {
enum class AllowMovieFolder enum class AllowMovieFolder
@ -25,7 +30,7 @@ enum class AllowMovieFolder
class CEXIMemoryCard : public IEXIDevice class CEXIMemoryCard : public IEXIDevice
{ {
public: public:
CEXIMemoryCard(const int index, bool gciFolder); CEXIMemoryCard(const int index, bool gciFolder, const Memcard::HeaderData& header_data);
virtual ~CEXIMemoryCard(); virtual ~CEXIMemoryCard();
void SetCS(int cs) override; void SetCS(int cs) override;
bool IsInterruptSet() override; bool IsInterruptSet() override;
@ -46,7 +51,7 @@ public:
GetGCIFolderPath(int card_index, AllowMovieFolder allow_movie_folder); GetGCIFolderPath(int card_index, AllowMovieFolder allow_movie_folder);
private: private:
void SetupGciFolder(u16 sizeMb); void SetupGciFolder(const Memcard::HeaderData& header_data);
void SetupRawMemcard(u16 sizeMb); void SetupRawMemcard(u16 sizeMb);
static void EventCompleteFindInstance(u64 userdata, static void EventCompleteFindInstance(u64 userdata,
std::function<void(CEXIMemoryCard*)> callback); std::function<void(CEXIMemoryCard*)> callback);

View File

@ -149,13 +149,11 @@ std::vector<std::string> GCMemcardDirectory::GetFileNamesForGameID(const std::st
return filenames; return filenames;
} }
GCMemcardDirectory::GCMemcardDirectory(const std::string& directory, int slot, u16 size_mbits, GCMemcardDirectory::GCMemcardDirectory(const std::string& directory, int slot,
bool shift_jis, int game_id) const Memcard::HeaderData& header_data, u32 game_id)
: MemoryCardBase(slot, size_mbits), m_game_id(game_id), m_last_block(-1), : MemoryCardBase(slot, header_data.m_size_mb), 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, m_hdr(header_data), m_bat1(header_data.m_size_mb), m_saves(0), m_save_directory(directory),
static_cast<u32>(g_SRAM.settings.language), m_exiting(false)
Common::Timer::GetLocalTimeSinceJan1970() - ExpansionInterface::CEXIIPL::GC_EPOCH),
m_bat1(size_mbits), m_saves(0), m_save_directory(directory), m_exiting(false)
{ {
// Use existing header data if available // Use existing header data if available
{ {

View File

@ -21,8 +21,8 @@ void MigrateFromMemcardFile(const std::string& directory_name, int card_index);
class GCMemcardDirectory : public MemoryCardBase class GCMemcardDirectory : public MemoryCardBase
{ {
public: public:
GCMemcardDirectory(const std::string& directory, int slot, u16 size_mbits, bool shift_jis, GCMemcardDirectory(const std::string& directory, int slot, const Memcard::HeaderData& header_data,
int game_id); u32 game_id);
~GCMemcardDirectory(); ~GCMemcardDirectory();
GCMemcardDirectory(const GCMemcardDirectory&) = delete; GCMemcardDirectory(const GCMemcardDirectory&) = delete;

View File

@ -74,7 +74,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
static std::thread g_save_thread; static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system // 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. // Maps savestate versions to Dolphin versions.
// Versions after 42 don't need to be added to this list, // Versions after 42 don't need to be added to this list,