Merge pull request #9268 from leoetlino/devicememcard-minor-cleanup

EXI_DeviceMemoryCard: Medium cleanup
This commit is contained in:
Léo Lam 2020-11-25 10:07:44 +01:00 committed by GitHub
commit 140daf5960
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 195 additions and 191 deletions

View File

@ -34,7 +34,6 @@
#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 "Core/NetPlayProto.h"
#include "DiscIO/Enums.h" #include "DiscIO/Enums.h"
namespace ExpansionInterface namespace ExpansionInterface
@ -48,7 +47,7 @@ namespace ExpansionInterface
#define SIZE_TO_Mb (1024 * 8 * 16) #define SIZE_TO_Mb (1024 * 8 * 16)
static const u32 MC_TRANSFER_RATE_READ = 512 * 1024; static const u32 MC_TRANSFER_RATE_READ = 512 * 1024;
static const u32 MC_TRANSFER_RATE_WRITE = (u32)(96.125f * 1024.0f); static const auto MC_TRANSFER_RATE_WRITE = static_cast<u32>(96.125f * 1024.0f);
static std::array<CoreTiming::EventType*, 2> s_et_cmd_done; static std::array<CoreTiming::EventType*, 2> s_et_cmd_done;
static std::array<CoreTiming::EventType*, 2> s_et_transfer_complete; static std::array<CoreTiming::EventType*, 2> s_et_transfer_complete;
@ -59,24 +58,25 @@ void CEXIMemoryCard::EventCompleteFindInstance(u64 userdata,
std::function<void(CEXIMemoryCard*)> callback) std::function<void(CEXIMemoryCard*)> callback)
{ {
int card_index = (int)userdata; int card_index = (int)userdata;
CEXIMemoryCard* pThis = auto* self = static_cast<CEXIMemoryCard*>(
(CEXIMemoryCard*)ExpansionInterface::FindDevice(EXIDEVICE_MEMORYCARD, card_index); ExpansionInterface::FindDevice(EXIDEVICE_MEMORYCARD, card_index));
if (pThis == nullptr) if (self == nullptr)
{ {
pThis = (CEXIMemoryCard*)ExpansionInterface::FindDevice(EXIDEVICE_MEMORYCARDFOLDER, card_index); self = static_cast<CEXIMemoryCard*>(
ExpansionInterface::FindDevice(EXIDEVICE_MEMORYCARDFOLDER, card_index));
} }
if (pThis) if (self)
{ {
callback(pThis); callback(self);
} }
} }
void CEXIMemoryCard::CmdDoneCallback(u64 userdata, s64 cyclesLate) void CEXIMemoryCard::CmdDoneCallback(u64 userdata, s64)
{ {
EventCompleteFindInstance(userdata, [](CEXIMemoryCard* instance) { instance->CmdDone(); }); EventCompleteFindInstance(userdata, [](CEXIMemoryCard* instance) { instance->CmdDone(); });
} }
void CEXIMemoryCard::TransferCompleteCallback(u64 userdata, s64 cyclesLate) void CEXIMemoryCard::TransferCompleteCallback(u64 userdata, s64)
{ {
EventCompleteFindInstance(userdata, EventCompleteFindInstance(userdata,
[](CEXIMemoryCard* instance) { instance->TransferComplete(); }); [](CEXIMemoryCard* instance) { instance->TransferComplete(); });
@ -106,9 +106,9 @@ void CEXIMemoryCard::Shutdown()
s_et_transfer_complete.fill(nullptr); s_et_transfer_complete.fill(nullptr);
} }
CEXIMemoryCard::CEXIMemoryCard(const int index, bool gciFolder, CEXIMemoryCard::CEXIMemoryCard(const int index, bool gci_folder,
const Memcard::HeaderData& header_data) const Memcard::HeaderData& header_data)
: card_index(index) : m_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);
@ -116,12 +116,12 @@ CEXIMemoryCard::CEXIMemoryCard(const int index, bool gciFolder,
// NOTE: When loading a save state, DMA completion callbacks (s_et_transfer_complete) and such // NOTE: When loading a save state, DMA completion callbacks (s_et_transfer_complete) and such
// may have been restored, we need to anticipate those arriving. // may have been restored, we need to anticipate those arriving.
interruptSwitch = 0; m_interrupt_switch = 0;
m_bInterruptSet = 0; m_interrupt_set = false;
command = 0; m_command = Command::NintendoID;
status = MC_STATUS_BUSY | MC_STATUS_UNLOCKED | MC_STATUS_READY; m_status = MC_STATUS_BUSY | MC_STATUS_UNLOCKED | MC_STATUS_READY;
m_uPosition = 0; m_position = 0;
memset(programming_buffer, 0, sizeof(programming_buffer)); m_programming_buffer.fill(0);
// Nintendo Memory Card EXI IDs // Nintendo Memory Card EXI IDs
// 0x00000004 Memory Card 59 4Mbit // 0x00000004 Memory Card 59 4Mbit
// 0x00000008 Memory Card 123 8Mb // 0x00000008 Memory Card 123 8Mb
@ -132,9 +132,9 @@ CEXIMemoryCard::CEXIMemoryCard(const int index, bool gciFolder,
// 0x00000510 16Mb "bigben" card // 0x00000510 16Mb "bigben" card
// card_id = 0xc243; // card_id = 0xc243;
card_id = 0xc221; // It's a Nintendo brand memcard m_card_id = 0xc221; // It's a Nintendo brand memcard
if (gciFolder) if (gci_folder)
{ {
SetupGciFolder(header_data); SetupGciFolder(header_data);
} }
@ -143,10 +143,10 @@ CEXIMemoryCard::CEXIMemoryCard(const int index, bool gciFolder,
SetupRawMemcard(header_data.m_size_mb); SetupRawMemcard(header_data.m_size_mb);
} }
memory_card_size = memorycard->GetCardId() * SIZE_TO_Mb; m_memory_card_size = m_memory_card->GetCardId() * SIZE_TO_Mb;
std::array<u8, 20> header{}; std::array<u8, 20> header{};
memorycard->Read(0, static_cast<s32>(header.size()), header.data()); m_memory_card->Read(0, static_cast<s32>(header.size()), header.data());
SetCardFlashID(header.data(), card_index); SetCardFlashID(header.data(), m_card_index);
} }
std::pair<std::string /* path */, bool /* migrate */> std::pair<std::string /* path */, bool /* migrate */>
@ -178,57 +178,57 @@ CEXIMemoryCard::GetGCIFolderPath(int card_index, AllowMovieFolder allow_movie_fo
void CEXIMemoryCard::SetupGciFolder(const Memcard::HeaderData& header_data) 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 current_game_id = 0;
if (game_id.length() >= 4 && game_id != "00000000" && if (game_id.length() >= 4 && game_id != "00000000" &&
SConfig::GetInstance().GetTitleID() != Titles::SYSTEM_MENU) SConfig::GetInstance().GetTitleID() != Titles::SYSTEM_MENU)
{ {
CurrentGameId = Common::swap32(reinterpret_cast<const u8*>(game_id.c_str())); current_game_id = Common::swap32(reinterpret_cast<const u8*>(game_id.c_str()));
} }
// TODO(C++20): Use structured bindings when we can use C++20 and refer to structured bindings // TODO(C++20): Use structured bindings when we can use C++20 and refer to structured bindings
// in lambda captures // in lambda captures
const auto folder_path = GetGCIFolderPath(card_index, AllowMovieFolder::Yes); const auto folder_path_pair = GetGCIFolderPath(m_card_index, AllowMovieFolder::Yes);
const auto& strDirectoryName = folder_path.first; const std::string& dir_path = folder_path_pair.first;
const bool migrate = folder_path.second; const bool migrate = folder_path_pair.second;
const File::FileInfo file_info(strDirectoryName); const File::FileInfo file_info(dir_path);
if (!file_info.Exists()) if (!file_info.Exists())
{ {
if (migrate) // first use of memcard folder, migrate automatically if (migrate) // first use of memcard folder, migrate automatically
MigrateFromMemcardFile(strDirectoryName + DIR_SEP, card_index); MigrateFromMemcardFile(dir_path + DIR_SEP, m_card_index);
else else
File::CreateFullPath(strDirectoryName + DIR_SEP); File::CreateFullPath(dir_path + DIR_SEP);
} }
else if (!file_info.IsDirectory()) else if (!file_info.IsDirectory())
{ {
if (File::Rename(strDirectoryName, strDirectoryName + ".original")) if (File::Rename(dir_path, dir_path + ".original"))
{ {
PanicAlertFmtT("{0} was not a directory, moved to *.original", strDirectoryName); PanicAlertFmtT("{0} was not a directory, moved to *.original", dir_path);
if (migrate) if (migrate)
MigrateFromMemcardFile(strDirectoryName + DIR_SEP, card_index); MigrateFromMemcardFile(dir_path + DIR_SEP, m_card_index);
else else
File::CreateFullPath(strDirectoryName + DIR_SEP); File::CreateFullPath(dir_path + DIR_SEP);
} }
else // we tried but the user wants to crash else // we tried but the user wants to crash
{ {
// TODO more user friendly abort // TODO more user friendly abort
PanicAlertFmtT("{0} is not a directory, failed to move to *.original.\n Verify your " PanicAlertFmtT("{0} is not a directory, failed to move to *.original.\n Verify your "
"write permissions or move the file outside of Dolphin", "write permissions or move the file outside of Dolphin",
strDirectoryName); dir_path);
std::exit(0); std::exit(0);
} }
} }
memorycard = std::make_unique<GCMemcardDirectory>(strDirectoryName + DIR_SEP, card_index, m_memory_card = std::make_unique<GCMemcardDirectory>(dir_path + DIR_SEP, m_card_index,
header_data, CurrentGameId); header_data, current_game_id);
} }
void CEXIMemoryCard::SetupRawMemcard(u16 sizeMb) void CEXIMemoryCard::SetupRawMemcard(u16 size_mb)
{ {
const bool is_slot_a = card_index == 0; const bool is_slot_a = m_card_index == 0;
std::string filename = is_slot_a ? Config::Get(Config::MAIN_MEMCARD_A_PATH) : std::string filename = is_slot_a ? Config::Get(Config::MAIN_MEMCARD_A_PATH) :
Config::Get(Config::MAIN_MEMCARD_B_PATH); Config::Get(Config::MAIN_MEMCARD_B_PATH);
if (Movie::IsPlayingInput() && Movie::IsConfigSaved() && Movie::IsUsingMemcard(card_index) && if (Movie::IsPlayingInput() && Movie::IsConfigSaved() && Movie::IsUsingMemcard(m_card_index) &&
Movie::IsStartingFromClearSave()) Movie::IsStartingFromClearSave())
filename = File::GetUserPath(D_GCUSER_IDX) + fmt::format("Movie{}.raw", is_slot_a ? 'A' : 'B'); filename = File::GetUserPath(D_GCUSER_IDX) + fmt::format("Movie{}.raw", is_slot_a ? 'A' : 'B');
@ -236,16 +236,16 @@ void CEXIMemoryCard::SetupRawMemcard(u16 sizeMb)
SConfig::GetDirectoryForRegion(SConfig::ToGameCubeRegion(SConfig::GetInstance().m_region)); SConfig::GetDirectoryForRegion(SConfig::ToGameCubeRegion(SConfig::GetInstance().m_region));
MemoryCard::CheckPath(filename, region_dir, is_slot_a); MemoryCard::CheckPath(filename, region_dir, is_slot_a);
if (sizeMb == Memcard::MBIT_SIZE_MEMORY_CARD_251) if (size_mb == Memcard::MBIT_SIZE_MEMORY_CARD_251)
filename.insert(filename.find_last_of("."), ".251"); filename.insert(filename.find_last_of('.'), ".251");
memorycard = std::make_unique<MemoryCard>(filename, card_index, sizeMb); m_memory_card = std::make_unique<MemoryCard>(filename, m_card_index, size_mb);
} }
CEXIMemoryCard::~CEXIMemoryCard() CEXIMemoryCard::~CEXIMemoryCard()
{ {
CoreTiming::RemoveEvent(s_et_cmd_done[card_index]); CoreTiming::RemoveEvent(s_et_cmd_done[m_card_index]);
CoreTiming::RemoveEvent(s_et_transfer_complete[card_index]); CoreTiming::RemoveEvent(s_et_transfer_complete[m_card_index]);
} }
bool CEXIMemoryCard::UseDelayedTransferCompletion() const bool CEXIMemoryCard::UseDelayedTransferCompletion() const
@ -260,41 +260,41 @@ bool CEXIMemoryCard::IsPresent() const
void CEXIMemoryCard::CmdDone() void CEXIMemoryCard::CmdDone()
{ {
status |= MC_STATUS_READY; m_status |= MC_STATUS_READY;
status &= ~MC_STATUS_BUSY; m_status &= ~MC_STATUS_BUSY;
m_bInterruptSet = 1; m_interrupt_set = true;
ExpansionInterface::UpdateInterrupts(); ExpansionInterface::UpdateInterrupts();
} }
void CEXIMemoryCard::TransferComplete() void CEXIMemoryCard::TransferComplete()
{ {
// Transfer complete, send interrupt // Transfer complete, send interrupt
ExpansionInterface::GetChannel(card_index)->SendTransferComplete(); ExpansionInterface::GetChannel(m_card_index)->SendTransferComplete();
} }
void CEXIMemoryCard::CmdDoneLater(u64 cycles) void CEXIMemoryCard::CmdDoneLater(u64 cycles)
{ {
CoreTiming::RemoveEvent(s_et_cmd_done[card_index]); CoreTiming::RemoveEvent(s_et_cmd_done[m_card_index]);
CoreTiming::ScheduleEvent((int)cycles, s_et_cmd_done[card_index], (u64)card_index); CoreTiming::ScheduleEvent(cycles, s_et_cmd_done[m_card_index], m_card_index);
} }
void CEXIMemoryCard::SetCS(int cs) void CEXIMemoryCard::SetCS(int cs)
{ {
if (cs) // not-selected to selected if (cs) // not-selected to selected
{ {
m_uPosition = 0; m_position = 0;
} }
else else
{ {
switch (command) switch (m_command)
{ {
case cmdSectorErase: case Command::SectorErase:
if (m_uPosition > 2) if (m_position > 2)
{ {
memorycard->ClearBlock(address & (memory_card_size - 1)); m_memory_card->ClearBlock(m_address & (m_memory_card_size - 1));
status |= MC_STATUS_BUSY; m_status |= MC_STATUS_BUSY;
status &= ~MC_STATUS_READY; m_status &= ~MC_STATUS_READY;
//??? //???
@ -302,189 +302,192 @@ void CEXIMemoryCard::SetCS(int cs)
} }
break; break;
case cmdChipErase: case Command::ChipErase:
if (m_uPosition > 2) if (m_position > 2)
{ {
// TODO: Investigate on HW, I (LPFaint99) believe that this only // TODO: Investigate on HW, I (LPFaint99) believe that this only
// erases the system area (Blocks 0-4) // erases the system area (Blocks 0-4)
memorycard->ClearAll(); m_memory_card->ClearAll();
status &= ~MC_STATUS_BUSY; m_status &= ~MC_STATUS_BUSY;
} }
break; break;
case cmdPageProgram: case Command::PageProgram:
if (m_uPosition >= 5) if (m_position >= 5)
{ {
int count = m_uPosition - 5; int count = m_position - 5;
int i = 0; int i = 0;
status &= ~MC_STATUS_BUSY; m_status &= ~MC_STATUS_BUSY;
while (count--) while (count--)
{ {
memorycard->Write(address, 1, &(programming_buffer[i++])); m_memory_card->Write(m_address, 1, &(m_programming_buffer[i++]));
i &= 127; i &= 127;
address = (address & ~0x1FF) | ((address + 1) & 0x1FF); m_address = (m_address & ~0x1FF) | ((m_address + 1) & 0x1FF);
} }
CmdDoneLater(5000); CmdDoneLater(5000);
} }
break; break;
default:
break;
} }
} }
} }
bool CEXIMemoryCard::IsInterruptSet() bool CEXIMemoryCard::IsInterruptSet()
{ {
if (interruptSwitch) if (m_interrupt_switch)
return m_bInterruptSet; return m_interrupt_set;
return false; return false;
} }
void CEXIMemoryCard::TransferByte(u8& byte) void CEXIMemoryCard::TransferByte(u8& byte)
{ {
DEBUG_LOG_FMT(EXPANSIONINTERFACE, "EXI MEMCARD: > {:02x}", byte); DEBUG_LOG_FMT(EXPANSIONINTERFACE, "EXI MEMCARD: > {:02x}", byte);
if (m_uPosition == 0) if (m_position == 0)
{ {
command = byte; // first byte is command m_command = static_cast<Command>(byte); // first byte is command
byte = 0xFF; // would be tristate, but we don't care. byte = 0xFF; // would be tristate, but we don't care.
switch (command) // This seems silly, do we really need it? switch (m_command) // This seems silly, do we really need it?
{ {
case cmdNintendoID: case Command::NintendoID:
case cmdReadArray: case Command::ReadArray:
case cmdArrayToBuffer: case Command::ArrayToBuffer:
case cmdSetInterrupt: case Command::SetInterrupt:
case cmdWriteBuffer: case Command::WriteBuffer:
case cmdReadStatus: case Command::ReadStatus:
case cmdReadID: case Command::ReadID:
case cmdReadErrorBuffer: case Command::ReadErrorBuffer:
case cmdWakeUp: case Command::WakeUp:
case cmdSleep: case Command::Sleep:
case cmdClearStatus: case Command::ClearStatus:
case cmdSectorErase: case Command::SectorErase:
case cmdPageProgram: case Command::PageProgram:
case cmdExtraByteProgram: case Command::ExtraByteProgram:
case cmdChipErase: case Command::ChipErase:
DEBUG_LOG_FMT(EXPANSIONINTERFACE, "EXI MEMCARD: command {:02x} at position 0. seems normal.", DEBUG_LOG_FMT(EXPANSIONINTERFACE, "EXI MEMCARD: command {:02x} at position 0. seems normal.",
command); m_command);
break; break;
default: default:
WARN_LOG_FMT(EXPANSIONINTERFACE, "EXI MEMCARD: command {:02x} at position 0", command); WARN_LOG_FMT(EXPANSIONINTERFACE, "EXI MEMCARD: command {:02x} at position 0", m_command);
break; break;
} }
if (command == cmdClearStatus) if (m_command == Command::ClearStatus)
{ {
status &= ~MC_STATUS_PROGRAMEERROR; m_status &= ~MC_STATUS_PROGRAMEERROR;
status &= ~MC_STATUS_ERASEERROR; m_status &= ~MC_STATUS_ERASEERROR;
status |= MC_STATUS_READY; m_status |= MC_STATUS_READY;
m_bInterruptSet = 0; m_interrupt_set = false;
byte = 0xFF; byte = 0xFF;
m_uPosition = 0; m_position = 0;
} }
} }
else else
{ {
switch (command) switch (m_command)
{ {
case cmdNintendoID: case Command::NintendoID:
// //
// Nintendo card: // Nintendo card:
// 00 | 80 00 00 00 10 00 00 00 // 00 | 80 00 00 00 10 00 00 00
// "bigben" card: // "bigben" card:
// 00 | ff 00 00 05 10 00 00 00 00 00 00 00 00 00 00 // 00 | ff 00 00 05 10 00 00 00 00 00 00 00 00 00 00
// we do it the Nintendo way. // we do it the Nintendo way.
if (m_uPosition == 1) if (m_position == 1)
byte = 0x80; // dummy cycle byte = 0x80; // dummy cycle
else else
byte = (u8)(memorycard->GetCardId() >> (24 - (((m_uPosition - 2) & 3) * 8))); byte = static_cast<u8>(m_memory_card->GetCardId() >> (24 - (((m_position - 2) & 3) * 8)));
break; break;
case cmdReadArray: case Command::ReadArray:
switch (m_uPosition) switch (m_position)
{ {
case 1: // AD1 case 1: // AD1
address = byte << 17; m_address = byte << 17;
byte = 0xFF; byte = 0xFF;
break; break;
case 2: // AD2 case 2: // AD2
address |= byte << 9; m_address |= byte << 9;
break; break;
case 3: // AD3 case 3: // AD3
address |= (byte & 3) << 7; m_address |= (byte & 3) << 7;
break; break;
case 4: // BA case 4: // BA
address |= (byte & 0x7F); m_address |= (byte & 0x7F);
break; break;
} }
if (m_uPosition > 1) // not specified for 1..8, anyway if (m_position > 1) // not specified for 1..8, anyway
{ {
memorycard->Read(address & (memory_card_size - 1), 1, &byte); m_memory_card->Read(m_address & (m_memory_card_size - 1), 1, &byte);
// after 9 bytes, we start incrementing the address, // after 9 bytes, we start incrementing the address,
// but only the sector offset - the pointer wraps around // but only the sector offset - the pointer wraps around
if (m_uPosition >= 9) if (m_position >= 9)
address = (address & ~0x1FF) | ((address + 1) & 0x1FF); m_address = (m_address & ~0x1FF) | ((m_address + 1) & 0x1FF);
} }
break; break;
case cmdReadStatus: case Command::ReadStatus:
// (unspecified for byte 1) // (unspecified for byte 1)
byte = status; byte = m_status;
break; break;
case cmdReadID: case Command::ReadID:
if (m_uPosition == 1) // (unspecified) if (m_position == 1) // (unspecified)
byte = (u8)(card_id >> 8); byte = static_cast<u8>(m_card_id >> 8);
else else
byte = (u8)((m_uPosition & 1) ? (card_id) : (card_id >> 8)); byte = static_cast<u8>((m_position & 1) ? (m_card_id) : (m_card_id >> 8));
break; break;
case cmdSectorErase: case Command::SectorErase:
switch (m_uPosition) switch (m_position)
{ {
case 1: // AD1 case 1: // AD1
address = byte << 17; m_address = byte << 17;
break; break;
case 2: // AD2 case 2: // AD2
address |= byte << 9; m_address |= byte << 9;
break; break;
} }
byte = 0xFF; byte = 0xFF;
break; break;
case cmdSetInterrupt: case Command::SetInterrupt:
if (m_uPosition == 1) if (m_position == 1)
{ {
interruptSwitch = byte; m_interrupt_switch = byte;
} }
byte = 0xFF; byte = 0xFF;
break; break;
case cmdChipErase: case Command::ChipErase:
byte = 0xFF; byte = 0xFF;
break; break;
case cmdPageProgram: case Command::PageProgram:
switch (m_uPosition) switch (m_position)
{ {
case 1: // AD1 case 1: // AD1
address = byte << 17; m_address = byte << 17;
break; break;
case 2: // AD2 case 2: // AD2
address |= byte << 9; m_address |= byte << 9;
break; break;
case 3: // AD3 case 3: // AD3
address |= (byte & 3) << 7; m_address |= (byte & 3) << 7;
break; break;
case 4: // BA case 4: // BA
address |= (byte & 0x7F); m_address |= (byte & 0x7F);
break; break;
} }
if (m_uPosition >= 5) if (m_position >= 5)
programming_buffer[((m_uPosition - 5) & 0x7F)] = byte; // wrap around after 128 bytes m_programming_buffer[((m_position - 5) & 0x7F)] = byte; // wrap around after 128 bytes
byte = 0xFF; byte = 0xFF;
break; break;
@ -494,7 +497,7 @@ void CEXIMemoryCard::TransferByte(u8& byte)
byte = 0xFF; byte = 0xFF;
} }
} }
m_uPosition++; m_position++;
DEBUG_LOG_FMT(EXPANSIONINTERFACE, "EXI MEMCARD: < {:02x}", byte); DEBUG_LOG_FMT(EXPANSIONINTERFACE, "EXI MEMCARD: < {:02x}", byte);
} }
@ -509,56 +512,56 @@ void CEXIMemoryCard::DoState(PointerWrap& p)
if (storeContents) if (storeContents)
{ {
p.Do(interruptSwitch); p.Do(m_interrupt_switch);
p.Do(m_bInterruptSet); p.Do(m_interrupt_set);
p.Do(command); p.Do(m_command);
p.Do(status); p.Do(m_status);
p.Do(m_uPosition); p.Do(m_position);
p.Do(programming_buffer); p.Do(m_programming_buffer);
p.Do(address); p.Do(m_address);
memorycard->DoState(p); m_memory_card->DoState(p);
p.Do(card_index); p.Do(m_card_index);
} }
} }
IEXIDevice* CEXIMemoryCard::FindDevice(TEXIDevices device_type, int customIndex) IEXIDevice* CEXIMemoryCard::FindDevice(TEXIDevices device_type, int custom_index)
{ {
if (device_type != m_device_type) if (device_type != m_device_type)
return nullptr; return nullptr;
if (customIndex != card_index) if (custom_index != m_card_index)
return nullptr; return nullptr;
return this; return this;
} }
// DMA reads are preceded by all of the necessary setup via IMMRead // DMA reads are preceded by all of the necessary setup via IMMRead
// read all at once instead of single byte at a time as done by IEXIDevice::DMARead // read all at once instead of single byte at a time as done by IEXIDevice::DMARead
void CEXIMemoryCard::DMARead(u32 _uAddr, u32 _uSize) void CEXIMemoryCard::DMARead(u32 addr, u32 size)
{ {
memorycard->Read(address, _uSize, Memory::GetPointer(_uAddr)); m_memory_card->Read(m_address, size, Memory::GetPointer(addr));
if ((address + _uSize) % Memcard::BLOCK_SIZE == 0) if ((m_address + size) % Memcard::BLOCK_SIZE == 0)
{ {
INFO_LOG_FMT(EXPANSIONINTERFACE, "reading from block: {:x}", address / Memcard::BLOCK_SIZE); INFO_LOG_FMT(EXPANSIONINTERFACE, "reading from block: {:x}", m_address / Memcard::BLOCK_SIZE);
} }
// Schedule transfer complete later based on read speed // Schedule transfer complete later based on read speed
CoreTiming::ScheduleEvent(_uSize * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_READ), CoreTiming::ScheduleEvent(size * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_READ),
s_et_transfer_complete[card_index], (u64)card_index); s_et_transfer_complete[m_card_index], m_card_index);
} }
// DMA write are preceded by all of the necessary setup via IMMWrite // DMA write are preceded by all of the necessary setup via IMMWrite
// write all at once instead of single byte at a time as done by IEXIDevice::DMAWrite // write all at once instead of single byte at a time as done by IEXIDevice::DMAWrite
void CEXIMemoryCard::DMAWrite(u32 _uAddr, u32 _uSize) void CEXIMemoryCard::DMAWrite(u32 addr, u32 size)
{ {
memorycard->Write(address, _uSize, Memory::GetPointer(_uAddr)); m_memory_card->Write(m_address, size, Memory::GetPointer(addr));
if (((address + _uSize) % Memcard::BLOCK_SIZE) == 0) if (((m_address + size) % Memcard::BLOCK_SIZE) == 0)
{ {
INFO_LOG_FMT(EXPANSIONINTERFACE, "writing to block: {:x}", address / Memcard::BLOCK_SIZE); INFO_LOG_FMT(EXPANSIONINTERFACE, "writing to block: {:x}", m_address / Memcard::BLOCK_SIZE);
} }
// Schedule transfer complete later based on write speed // Schedule transfer complete later based on write speed
CoreTiming::ScheduleEvent(_uSize * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_WRITE), CoreTiming::ScheduleEvent(size * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_WRITE),
s_et_transfer_complete[card_index], (u64)card_index); s_et_transfer_complete[m_card_index], m_card_index);
} }
} // namespace ExpansionInterface } // namespace ExpansionInterface

View File

@ -4,6 +4,7 @@
#pragma once #pragma once
#include <array>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <string> #include <string>
@ -30,16 +31,16 @@ enum class AllowMovieFolder
class CEXIMemoryCard : public IEXIDevice class CEXIMemoryCard : public IEXIDevice
{ {
public: public:
CEXIMemoryCard(const int index, bool gciFolder, const Memcard::HeaderData& header_data); CEXIMemoryCard(int index, bool gci_folder, const Memcard::HeaderData& header_data);
virtual ~CEXIMemoryCard(); ~CEXIMemoryCard() override;
void SetCS(int cs) override; void SetCS(int cs) override;
bool IsInterruptSet() override; bool IsInterruptSet() override;
bool UseDelayedTransferCompletion() const override; bool UseDelayedTransferCompletion() const override;
bool IsPresent() const override; bool IsPresent() const override;
void DoState(PointerWrap& p) override; void DoState(PointerWrap& p) override;
IEXIDevice* FindDevice(TEXIDevices device_type, int customIndex = -1) override; IEXIDevice* FindDevice(TEXIDevices device_type, int custom_index) override;
void DMARead(u32 _uAddr, u32 _uSize) override; void DMARead(u32 addr, u32 size) override;
void DMAWrite(u32 _uAddr, u32 _uSize) override; void DMAWrite(u32 addr, u32 size) override;
// CoreTiming events need to be registered during boot since CoreTiming is DoState()-ed // CoreTiming events need to be registered during boot since CoreTiming is DoState()-ed
// before ExpansionInterface so we'll lose the save stated events if the callbacks are // before ExpansionInterface so we'll lose the save stated events if the callbacks are
@ -52,7 +53,7 @@ public:
private: private:
void SetupGciFolder(const Memcard::HeaderData& header_data); void SetupGciFolder(const Memcard::HeaderData& header_data);
void SetupRawMemcard(u16 sizeMb); void SetupRawMemcard(u16 size_mb);
static void EventCompleteFindInstance(u64 userdata, static void EventCompleteFindInstance(u64 userdata,
std::function<void(CEXIMemoryCard*)> callback); std::function<void(CEXIMemoryCard*)> callback);
@ -71,40 +72,40 @@ private:
// Variant of CmdDone which schedules an event later in the future to complete the command. // Variant of CmdDone which schedules an event later in the future to complete the command.
void CmdDoneLater(u64 cycles); void CmdDoneLater(u64 cycles);
enum enum class Command
{ {
cmdNintendoID = 0x00, NintendoID = 0x00,
cmdReadArray = 0x52, ReadArray = 0x52,
cmdArrayToBuffer = 0x53, ArrayToBuffer = 0x53,
cmdSetInterrupt = 0x81, SetInterrupt = 0x81,
cmdWriteBuffer = 0x82, WriteBuffer = 0x82,
cmdReadStatus = 0x83, ReadStatus = 0x83,
cmdReadID = 0x85, ReadID = 0x85,
cmdReadErrorBuffer = 0x86, ReadErrorBuffer = 0x86,
cmdWakeUp = 0x87, WakeUp = 0x87,
cmdSleep = 0x88, Sleep = 0x88,
cmdClearStatus = 0x89, ClearStatus = 0x89,
cmdSectorErase = 0xF1, SectorErase = 0xF1,
cmdPageProgram = 0xF2, PageProgram = 0xF2,
cmdExtraByteProgram = 0xF3, ExtraByteProgram = 0xF3,
cmdChipErase = 0xF4, ChipErase = 0xF4,
}; };
int card_index; int m_card_index;
//! memory card state //! memory card state
// STATE_TO_SAVE // STATE_TO_SAVE
int interruptSwitch; int m_interrupt_switch;
bool m_bInterruptSet; bool m_interrupt_set;
int command; Command m_command;
int status; int m_status;
u32 m_uPosition; u32 m_position;
u8 programming_buffer[128]; std::array<u8, 128> m_programming_buffer;
//! memory card parameters //! memory card parameters
unsigned int card_id; unsigned int m_card_id;
unsigned int address; unsigned int m_address;
u32 memory_card_size; u32 m_memory_card_size;
std::unique_ptr<MemoryCardBase> memorycard; std::unique_ptr<MemoryCardBase> m_memory_card;
protected: protected:
void TransferByte(u8& byte) override; void TransferByte(u8& byte) override;