From 8a0093de231c399c712bf1e15a94ae393195dc7b Mon Sep 17 00:00:00 2001 From: TotalNerd Date: Tue, 8 Jul 2014 12:06:11 -0500 Subject: [PATCH] Emulate GameCube memory card speeds --- Source/Core/Core/HW/EXI_DeviceMemoryCard.cpp | 44 +++++++++++++++++--- Source/Core/Core/HW/EXI_DeviceMemoryCard.h | 11 +++++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/HW/EXI_DeviceMemoryCard.cpp b/Source/Core/Core/HW/EXI_DeviceMemoryCard.cpp index 809e1c79ba..d311feff74 100644 --- a/Source/Core/Core/HW/EXI_DeviceMemoryCard.cpp +++ b/Source/Core/Core/HW/EXI_DeviceMemoryCard.cpp @@ -18,6 +18,7 @@ #include "Core/HW/GCMemcardRaw.h" #include "Core/HW/Memmap.h" #include "Core/HW/Sram.h" +#include "Core/HW/SystemTimers.h" #include "DiscIO/NANDContentLoader.h" #define MC_STATUS_BUSY 0x80 @@ -28,6 +29,12 @@ #define MC_STATUS_READY 0x01 #define SIZE_TO_Mb (1024 * 8 * 16) +// These are rough estimates based on GameCube video evidence of memory card "speeds" +// This will need to be refined, and perhaps the idea behind the speed thing is wrong +// But it works with (near?) perfect speed as far as saving goes +static const float MC_TRANSFER_RATE_WRITE = 22.0f * 1024.0f; +static const float MC_TRANSFER_RATE_READ = 73.84f * 1024.0f; + void CEXIMemoryCard::FlushCallback(u64 userdata, int cyclesLate) { // note that userdata is forbidden to be a pointer, due to the implementation of EventDoState @@ -227,26 +234,47 @@ void CEXIMemoryCard::SetCS(int cs) //??? - CmdDoneLater(5000); + if (address >= MC_DATA_FILES) + CmdDoneLater(BLOCK_SIZE * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_WRITE)); + else + CmdDoneLater(5000); } break; case cmdChipErase: if (m_uPosition > 2) { - // TODO: Investigate on HW, I (LPFaint99) believe that this only erases the system area (Blocks 0-4) - memorycard->ClearAll(); + // Clear only the system blocks + for (int i = 0; i < 5; i++) + memorycard->ClearBlock(BLOCK_SIZE * i); + status &= ~MC_STATUS_BUSY; m_bDirty = true; + + if (address >= MC_DATA_FILES) + CmdDoneLater((BLOCK_SIZE * 5) * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_WRITE)); + else + CmdDoneLater(5000); + } + break; + + case cmdReadArray: + if (m_uPosition > 8) + { + // Each read is 512 bytes + if (address >= MC_DATA_FILES) + CmdDoneLater(512 * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_READ)); + else + CmdDoneLater(5000); } break; case cmdPageProgram: - if (m_uPosition >= 5) + if (m_uPosition > 4) { int count = m_uPosition - 5; int i=0; - status &= ~0x80; + status &= ~MC_STATUS_BUSY; while (count--) { @@ -255,7 +283,11 @@ void CEXIMemoryCard::SetCS(int cs) address = (address & ~0x1FF) | ((address+1) & 0x1FF); } - CmdDoneLater(5000); + // Each write is 128 bytes + if (address >= MC_DATA_FILES) + CmdDoneLater(128 * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_WRITE)); + else + CmdDoneLater(5000); } break; } diff --git a/Source/Core/Core/HW/EXI_DeviceMemoryCard.h b/Source/Core/Core/HW/EXI_DeviceMemoryCard.h index 12747268ed..ce7bdc87d8 100644 --- a/Source/Core/Core/HW/EXI_DeviceMemoryCard.h +++ b/Source/Core/Core/HW/EXI_DeviceMemoryCard.h @@ -39,6 +39,17 @@ private: // Variant of CmdDone which schedules an event later in the future to complete the command. void CmdDoneLater(u64 cycles); + // Memory card data layout + enum + { + MC_DATA_HEADER = 0x0000, + MC_DATA_DIRECTORY = 0x2000, + MC_DATA_DIRECTORYBACKUP = 0x4000, + MC_DATA_BLOCKALLOCMAP = 0x6000, + MC_DATA_BLOCKALLOCMAPBACKUP = 0x8000, + MC_DATA_FILES = 0xA000, + }; + enum { cmdNintendoID = 0x00,