move memorycard handling to its own class
This commit is contained in:
parent
3d66e859d4
commit
404e9ce3ee
|
@ -97,6 +97,7 @@ set(SRCS ActionReplay.cpp
|
|||
HW/EXI_DeviceGecko.cpp
|
||||
HW/EXI_DeviceIPL.cpp
|
||||
HW/EXI_DeviceMemoryCard.cpp
|
||||
HW/EXI_DeviceMemoryCardRaw.cpp
|
||||
HW/EXI_DeviceMic.cpp
|
||||
HW/GCMemcard.cpp
|
||||
HW/GCPad.cpp
|
||||
|
|
|
@ -135,6 +135,7 @@
|
|||
<ClCompile Include="HW\EXI_DeviceGecko.cpp" />
|
||||
<ClCompile Include="HW\EXI_DeviceIPL.cpp" />
|
||||
<ClCompile Include="HW\EXI_DeviceMemoryCard.cpp" />
|
||||
<ClCompile Include="HW\EXI_DeviceMemoryCardRaw.cpp" />
|
||||
<ClCompile Include="HW\EXI_DeviceMic.cpp" />
|
||||
<ClCompile Include="HW\GCMemcard.cpp" />
|
||||
<ClCompile Include="HW\GCPad.cpp" />
|
||||
|
@ -331,6 +332,7 @@
|
|||
<ClInclude Include="HW\EXI_DeviceGecko.h" />
|
||||
<ClInclude Include="HW\EXI_DeviceIPL.h" />
|
||||
<ClInclude Include="HW\EXI_DeviceMemoryCard.h" />
|
||||
<ClInclude Include="HW\EXI_DeviceMemoryCardRaw.h" />
|
||||
<ClInclude Include="HW\EXI_DeviceMic.h" />
|
||||
<ClInclude Include="HW\GCMemcard.h" />
|
||||
<ClInclude Include="HW\GCPad.h" />
|
||||
|
|
|
@ -702,6 +702,9 @@
|
|||
<ClCompile Include="PowerPC\JitILCommon\IR.cpp">
|
||||
<Filter>PowerPC\JitILCommon</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\EXI_DeviceMemoryCardRaw.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="BootManager.h" />
|
||||
|
@ -1207,6 +1210,9 @@
|
|||
<ClInclude Include="PowerPC\JitILCommon\IR.h">
|
||||
<Filter>PowerPC\JitILCommon</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\EXI_DeviceMemoryCardRaw.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\EXI - Expansion Interface</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "Core/HW/EXI.h"
|
||||
#include "Core/HW/EXI_Device.h"
|
||||
#include "Core/HW/EXI_DeviceMemoryCard.h"
|
||||
#include "Core/HW/EXI_DeviceMemoryCardRaw.h"
|
||||
#include "Core/HW/GCMemcard.h"
|
||||
#include "Core/HW/Sram.h"
|
||||
|
||||
|
@ -25,13 +26,14 @@
|
|||
#define SIZE_TO_Mb (1024 * 8 * 16)
|
||||
#define MC_HDR_SIZE 0xA000
|
||||
|
||||
|
||||
void CEXIMemoryCard::FlushCallback(u64 userdata, int cyclesLate)
|
||||
{
|
||||
// note that userdata is forbidden to be a pointer, due to the implementation of EventDoState
|
||||
int card_index = (int)userdata;
|
||||
CEXIMemoryCard* pThis = (CEXIMemoryCard*)ExpansionInterface::FindDevice(EXIDEVICE_MEMORYCARD, card_index);
|
||||
if (pThis)
|
||||
pThis->Flush();
|
||||
if (pThis && pThis->memorycard)
|
||||
pThis->memorycard->Flush();
|
||||
}
|
||||
|
||||
void CEXIMemoryCard::CmdDoneCallback(u64 userdata, int cyclesLate)
|
||||
|
@ -46,13 +48,13 @@ CEXIMemoryCard::CEXIMemoryCard(const int index)
|
|||
: card_index(index)
|
||||
, m_bDirty(false)
|
||||
{
|
||||
m_strFilename = (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA : SConfig::GetInstance().m_strMemoryCardB;
|
||||
std::string filename = (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA : SConfig::GetInstance().m_strMemoryCardB;
|
||||
if (Movie::IsPlayingInput() && Movie::IsConfigSaved() && Movie::IsUsingMemcard() && Movie::IsStartingFromClearSave())
|
||||
m_strFilename = File::GetUserPath(D_GCUSER_IDX) + "Movie.raw";
|
||||
filename = File::GetUserPath(D_GCUSER_IDX) + "Movie.raw";
|
||||
|
||||
// we're potentially leaking events here, since there's no UnregisterEvent until emu shutdown, but I guess it's inconsequential
|
||||
et_this_card = CoreTiming::RegisterEvent((card_index == 0) ? "memcardFlushA" : "memcardFlushB", FlushCallback);
|
||||
et_cmd_done = CoreTiming::RegisterEvent((card_index == 0) ? "memcardDoneA" : "memcardDoneB", CmdDoneCallback);
|
||||
et_this_card = CoreTiming::RegisterEvent((index == 0) ? "memcardFlushA" : "memcardFlushB", FlushCallback);
|
||||
et_cmd_done = CoreTiming::RegisterEvent((index == 0) ? "memcardDoneA" : "memcardDoneB", CmdDoneCallback);
|
||||
|
||||
interruptSwitch = 0;
|
||||
m_bInterruptSet = 0;
|
||||
|
@ -81,110 +83,25 @@ CEXIMemoryCard::CEXIMemoryCard(const int index)
|
|||
bool useMC251;
|
||||
IniFile gameIni = Core::g_CoreStartupParameter.LoadGameIni();
|
||||
gameIni.GetOrCreateSection("Core")->Get("MemoryCard251", &useMC251, false);
|
||||
nintendo_card_id = MemCard2043Mb;
|
||||
u16 sizeMb = MemCard2043Mb;
|
||||
if (useMC251)
|
||||
{
|
||||
nintendo_card_id = MemCard251Mb;
|
||||
m_strFilename.insert(m_strFilename.find_last_of("."), ".251");
|
||||
sizeMb = MemCard251Mb;
|
||||
filename.insert(filename.find_last_of("."), ".251");
|
||||
}
|
||||
card_id = 0xc221; // It's a Nintendo brand memcard
|
||||
|
||||
File::IOFile pFile(m_strFilename, "rb");
|
||||
if (pFile)
|
||||
{
|
||||
// Measure size of the memcard file.
|
||||
memory_card_size = (int)pFile.GetSize();
|
||||
nintendo_card_id = memory_card_size / SIZE_TO_Mb;
|
||||
memory_card_content = new u8[memory_card_size];
|
||||
memset(memory_card_content, 0xFF, memory_card_size);
|
||||
|
||||
INFO_LOG(EXPANSIONINTERFACE, "Reading memory card %s", m_strFilename.c_str());
|
||||
pFile.ReadBytes(memory_card_content, memory_card_size);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a new memcard
|
||||
memory_card_size = nintendo_card_id * SIZE_TO_Mb;
|
||||
|
||||
memory_card_content = new u8[memory_card_size];
|
||||
GCMemcard::Format(memory_card_content, m_strFilename.find(".JAP.raw") != std::string::npos, nintendo_card_id);
|
||||
memset(memory_card_content+MC_HDR_SIZE, 0xFF, memory_card_size-MC_HDR_SIZE);
|
||||
WARN_LOG(EXPANSIONINTERFACE, "No memory card found. Will create a new one.");
|
||||
}
|
||||
SetCardFlashID(memory_card_content, card_index);
|
||||
}
|
||||
|
||||
void innerFlush(FlushData* data)
|
||||
{
|
||||
File::IOFile pFile(data->filename, "r+b");
|
||||
if (!pFile)
|
||||
{
|
||||
std::string dir;
|
||||
SplitPath(data->filename, &dir, nullptr, nullptr);
|
||||
if (!File::IsDirectory(dir))
|
||||
File::CreateFullPath(dir);
|
||||
pFile.Open(data->filename, "wb");
|
||||
}
|
||||
|
||||
if (!pFile) // Note - pFile changed inside above if
|
||||
{
|
||||
PanicAlertT("Could not write memory card file %s.\n\n"
|
||||
"Are you running Dolphin from a CD/DVD, or is the save file maybe write protected?\n\n"
|
||||
"Are you receiving this after moving the emulator directory?\nIf so, then you may "
|
||||
"need to re-specify your memory card location in the options.", data->filename.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
pFile.WriteBytes(data->memcardContent, data->memcardSize);
|
||||
|
||||
if (!data->bExiting)
|
||||
Core::DisplayMessage(StringFromFormat("Wrote memory card %c contents to %s",
|
||||
data->memcardIndex ? 'B' : 'A', data->filename.c_str()).c_str(), 4000);
|
||||
return;
|
||||
}
|
||||
|
||||
// Flush memory card contents to disc
|
||||
void CEXIMemoryCard::Flush(bool exiting)
|
||||
{
|
||||
if (!m_bDirty)
|
||||
return;
|
||||
|
||||
if (!Core::g_CoreStartupParameter.bEnableMemcardSaving)
|
||||
return;
|
||||
|
||||
if (flushThread.joinable())
|
||||
{
|
||||
flushThread.join();
|
||||
}
|
||||
|
||||
if (!exiting)
|
||||
Core::DisplayMessage(StringFromFormat("Writing to memory card %c", card_index ? 'B' : 'A'), 1000);
|
||||
|
||||
flushData.filename = m_strFilename;
|
||||
flushData.memcardContent = memory_card_content;
|
||||
flushData.memcardIndex = card_index;
|
||||
flushData.memcardSize = memory_card_size;
|
||||
flushData.bExiting = exiting;
|
||||
|
||||
flushThread = std::thread(innerFlush, &flushData);
|
||||
if (exiting)
|
||||
flushThread.join();
|
||||
|
||||
m_bDirty = false;
|
||||
memorycard = new MemoryCard(filename, card_index, sizeMb);
|
||||
memory_card_size = memorycard->GetCardId() * SIZE_TO_Mb;
|
||||
u8 header[20] = { 0 };
|
||||
memorycard->Read(0, 20, header);
|
||||
SetCardFlashID(header, card_index);
|
||||
}
|
||||
|
||||
CEXIMemoryCard::~CEXIMemoryCard()
|
||||
{
|
||||
CoreTiming::RemoveEvent(et_this_card);
|
||||
Flush(true);
|
||||
delete[] memory_card_content;
|
||||
memory_card_content = nullptr;
|
||||
|
||||
if (flushThread.joinable())
|
||||
{
|
||||
flushThread.join();
|
||||
}
|
||||
memorycard->Flush(true);
|
||||
delete memorycard;
|
||||
}
|
||||
|
||||
bool CEXIMemoryCard::IsPresent()
|
||||
|
@ -210,10 +127,7 @@ void CEXIMemoryCard::CmdDoneLater(u64 cycles)
|
|||
void CEXIMemoryCard::SetCS(int cs)
|
||||
{
|
||||
// So that memory card won't be invalidated during flushing
|
||||
if (flushThread.joinable())
|
||||
{
|
||||
flushThread.join();
|
||||
}
|
||||
memorycard->joinThread();
|
||||
|
||||
if (cs) // not-selected to selected
|
||||
{
|
||||
|
@ -226,7 +140,7 @@ void CEXIMemoryCard::SetCS(int cs)
|
|||
case cmdSectorErase:
|
||||
if (m_uPosition > 2)
|
||||
{
|
||||
memset(memory_card_content + (address & (memory_card_size-1)), 0xFF, 0x2000);
|
||||
memorycard->ClearBlock(address & (memory_card_size - 1));
|
||||
status |= MC_STATUS_BUSY;
|
||||
status &= ~MC_STATUS_READY;
|
||||
|
||||
|
@ -239,7 +153,8 @@ void CEXIMemoryCard::SetCS(int cs)
|
|||
case cmdChipErase:
|
||||
if (m_uPosition > 2)
|
||||
{
|
||||
memset(memory_card_content, 0xFF, memory_card_size);
|
||||
// TODO: Investigate on HW, I (LPFaint99) believe that this only erases the system area (Blocks 0-4)
|
||||
memorycard->ClearAll();
|
||||
status &= ~MC_STATUS_BUSY;
|
||||
m_bDirty = true;
|
||||
}
|
||||
|
@ -254,7 +169,7 @@ void CEXIMemoryCard::SetCS(int cs)
|
|||
|
||||
while (count--)
|
||||
{
|
||||
memory_card_content[address] = programming_buffer[i++];
|
||||
memorycard->Write(address, 1, &(programming_buffer[i++]));
|
||||
i &= 127;
|
||||
address = (address & ~0x1FF) | ((address+1) & 0x1FF);
|
||||
}
|
||||
|
@ -336,7 +251,7 @@ void CEXIMemoryCard::TransferByte(u8 &byte)
|
|||
if (m_uPosition == 1)
|
||||
byte = 0x80; // dummy cycle
|
||||
else
|
||||
byte = (u8)(nintendo_card_id >> (24-(((m_uPosition-2) & 3) * 8)));
|
||||
byte = (u8)(memorycard->GetCardId() >> (24 - (((m_uPosition - 2) & 3) * 8)));
|
||||
break;
|
||||
|
||||
case cmdReadArray:
|
||||
|
@ -358,7 +273,7 @@ void CEXIMemoryCard::TransferByte(u8 &byte)
|
|||
}
|
||||
if (m_uPosition > 1) // not specified for 1..8, anyway
|
||||
{
|
||||
byte = memory_card_content[address & (memory_card_size-1)];
|
||||
memorycard->Read(address & (memory_card_size - 1), 1, &byte);
|
||||
// after 9 bytes, we start incrementing the address,
|
||||
// but only the sector offset - the pointer wraps around
|
||||
if (m_uPosition >= 9)
|
||||
|
@ -441,10 +356,7 @@ void CEXIMemoryCard::PauseAndLock(bool doLock, bool unpauseOnUnlock)
|
|||
{
|
||||
// we don't exactly have anything to pause,
|
||||
// but let's make sure the flush thread isn't running.
|
||||
if (flushThread.joinable())
|
||||
{
|
||||
flushThread.join();
|
||||
}
|
||||
memorycard->joinThread();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -466,11 +378,7 @@ void CEXIMemoryCard::DoState(PointerWrap &p)
|
|||
p.Do(programming_buffer);
|
||||
p.Do(m_bDirty);
|
||||
p.Do(address);
|
||||
|
||||
p.Do(nintendo_card_id);
|
||||
p.Do(card_id);
|
||||
p.Do(memory_card_size);
|
||||
p.DoArray(memory_card_content, memory_card_size);
|
||||
memorycard->DoState(p);
|
||||
p.Do(card_index);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,18 +3,7 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/Thread.h"
|
||||
|
||||
// Data structure to be passed to the flushing thread.
|
||||
struct FlushData
|
||||
{
|
||||
bool bExiting;
|
||||
std::string filename;
|
||||
u8 *memcardContent;
|
||||
int memcardSize, memcardIndex;
|
||||
};
|
||||
|
||||
class MemoryCardBase;
|
||||
class CEXIMemoryCard : public IEXIDevice
|
||||
{
|
||||
public:
|
||||
|
@ -63,7 +52,6 @@ private:
|
|||
cmdChipErase = 0xF4,
|
||||
};
|
||||
|
||||
std::string m_strFilename;
|
||||
int card_index;
|
||||
int et_this_card, et_cmd_done;
|
||||
//! memory card state
|
||||
|
@ -77,13 +65,10 @@ private:
|
|||
u8 programming_buffer[128];
|
||||
bool m_bDirty;
|
||||
//! memory card parameters
|
||||
unsigned int nintendo_card_id, card_id;
|
||||
unsigned int card_id;
|
||||
unsigned int address;
|
||||
int memory_card_size; //! in bytes, must be power of 2.
|
||||
u8 *memory_card_content;
|
||||
|
||||
FlushData flushData;
|
||||
std::thread flushThread;
|
||||
u32 memory_card_size;
|
||||
MemoryCardBase * memorycard;
|
||||
|
||||
protected:
|
||||
virtual void TransferByte(u8 &byte) override;
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HW/EXI_DeviceMemoryCardRaw.h"
|
||||
#include "Core/HW/GCMemcard.h"
|
||||
#define SIZE_TO_Mb (1024 * 8 * 16)
|
||||
#define MC_HDR_SIZE 0xA000
|
||||
|
||||
void innerFlush(FlushData* data)
|
||||
{
|
||||
File::IOFile pFile(data->filename, "r+b");
|
||||
if (!pFile)
|
||||
{
|
||||
std::string dir;
|
||||
SplitPath(data->filename, &dir, nullptr, nullptr);
|
||||
if (!File::IsDirectory(dir))
|
||||
File::CreateFullPath(dir);
|
||||
pFile.Open(data->filename, "wb");
|
||||
}
|
||||
|
||||
if (!pFile) // Note - pFile changed inside above if
|
||||
{
|
||||
PanicAlertT("Could not write memory card file %s.\n\n"
|
||||
"Are you running Dolphin from a CD/DVD, or is the save file maybe write protected?\n\n"
|
||||
"Are you receiving this after moving the emulator directory?\nIf so, then you may "
|
||||
"need to re-specify your memory card location in the options.", data->filename.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
pFile.WriteBytes(data->memcardContent, data->memcardSize);
|
||||
|
||||
if (!data->bExiting)
|
||||
Core::DisplayMessage(StringFromFormat("Wrote memory card %c contents to %s",
|
||||
data->memcardIndex ? 'B' : 'A', data->filename.c_str()).c_str(), 4000);
|
||||
return;
|
||||
}
|
||||
|
||||
MemoryCard::MemoryCard(std::string filename, int _card_index, u16 sizeMb) : MemoryCardBase(_card_index, sizeMb), m_strFilename(filename), m_bDirty(false)
|
||||
{
|
||||
|
||||
std::string ;
|
||||
File::IOFile pFile(m_strFilename, "rb");
|
||||
if (pFile)
|
||||
{
|
||||
// Measure size of the memcard file.
|
||||
memory_card_size = (int)pFile.GetSize();
|
||||
nintendo_card_id = memory_card_size / SIZE_TO_Mb;
|
||||
memory_card_content = new u8[memory_card_size];
|
||||
memset(memory_card_content, 0xFF, memory_card_size);
|
||||
|
||||
INFO_LOG(EXPANSIONINTERFACE, "Reading memory card %s", m_strFilename.c_str());
|
||||
pFile.ReadBytes(memory_card_content, memory_card_size);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a new 128Mb memcard
|
||||
nintendo_card_id = sizeMb;
|
||||
memory_card_size = sizeMb * SIZE_TO_Mb;
|
||||
|
||||
memory_card_content = new u8[memory_card_size];
|
||||
GCMemcard::Format(memory_card_content, m_strFilename.find(".JAP.raw") != std::string::npos, sizeMb);
|
||||
memset(memory_card_content + MC_HDR_SIZE, 0xFF, memory_card_size - MC_HDR_SIZE);
|
||||
|
||||
WARN_LOG(EXPANSIONINTERFACE, "No memory card found. Will create a new one.");
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryCard::joinThread()
|
||||
{
|
||||
if (flushThread.joinable())
|
||||
{
|
||||
flushThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
// Flush memory card contents to disc
|
||||
void MemoryCard::Flush(bool exiting)
|
||||
{
|
||||
if (!m_bDirty)
|
||||
return;
|
||||
|
||||
if (!Core::g_CoreStartupParameter.bEnableMemcardSaving)
|
||||
return;
|
||||
|
||||
if (flushThread.joinable())
|
||||
{
|
||||
flushThread.join();
|
||||
}
|
||||
|
||||
if (!exiting)
|
||||
Core::DisplayMessage(StringFromFormat("Writing to memory card %c", card_index ? 'B' : 'A'), 1000);
|
||||
|
||||
flushData.filename = m_strFilename;
|
||||
flushData.memcardContent = memory_card_content;
|
||||
flushData.memcardIndex = card_index;
|
||||
flushData.memcardSize = memory_card_size;
|
||||
flushData.bExiting = exiting;
|
||||
|
||||
flushThread = std::thread(innerFlush, &flushData);
|
||||
if (exiting)
|
||||
flushThread.join();
|
||||
|
||||
m_bDirty = false;
|
||||
}
|
||||
|
||||
s32 MemoryCard::Read(u32 srcaddress, s32 length, u8* destaddress)
|
||||
{
|
||||
if (!memory_card_content)
|
||||
return -1;
|
||||
if (srcaddress > (memory_card_size - 1))
|
||||
{
|
||||
PanicAlertT("MemoryCard: Read called with invalid source address, %x", srcaddress);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(destaddress, &(memory_card_content[srcaddress]), length);
|
||||
return length;
|
||||
}
|
||||
|
||||
s32 MemoryCard::Write(u32 destaddress, s32 length, u8* srcaddress)
|
||||
{
|
||||
if (!memory_card_content)
|
||||
return -1;
|
||||
|
||||
if (destaddress > (memory_card_size - 1))
|
||||
{
|
||||
PanicAlertT("MemoryCard: Write called with invalid destination address, %x", destaddress);
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_bDirty = true;
|
||||
memcpy(&(memory_card_content[destaddress]), srcaddress, length);
|
||||
return length;
|
||||
}
|
||||
|
||||
void MemoryCard::ClearBlock(u32 address)
|
||||
{
|
||||
if (address & (BLOCK_SIZE - 1) || address > (memory_card_size - 1))
|
||||
PanicAlertT("MemoryCard: ClearBlock called on invalid address %x", address);
|
||||
else
|
||||
{
|
||||
m_bDirty = true;
|
||||
memset(memory_card_content + address, 0xFF, BLOCK_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryCard::ClearAll()
|
||||
{
|
||||
m_bDirty = true;
|
||||
memset(memory_card_content, 0xFF, memory_card_size);
|
||||
}
|
||||
|
||||
void MemoryCard::DoState(PointerWrap &p)
|
||||
{
|
||||
p.Do(card_index);
|
||||
p.Do(memory_card_size);
|
||||
p.DoArray(memory_card_content, memory_card_size);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/Thread.h"
|
||||
#include "Core/HW/GCMemcard.h"
|
||||
|
||||
// Data structure to be passed to the flushing thread.
|
||||
struct FlushData
|
||||
{
|
||||
bool bExiting;
|
||||
std::string filename;
|
||||
u8 *memcardContent;
|
||||
int memcardSize, memcardIndex;
|
||||
};
|
||||
|
||||
class MemoryCardBase
|
||||
{
|
||||
public:
|
||||
MemoryCardBase(int _card_index = 0, int sizeMb = MemCard2043Mb) :card_index(_card_index), nintendo_card_id(sizeMb) { ; }
|
||||
virtual void Flush(bool exiting = false) = 0;
|
||||
virtual s32 Read(u32 address, s32 length, u8* destaddress) = 0;
|
||||
virtual s32 Write(u32 destaddress, s32 length, u8* srcaddress) = 0;
|
||||
virtual void ClearBlock(u32 address) = 0;
|
||||
virtual void ClearAll() = 0;
|
||||
virtual void DoState(PointerWrap &p) = 0;
|
||||
virtual void joinThread() {};
|
||||
u32 GetCardId() { return nintendo_card_id; }
|
||||
protected:
|
||||
int card_index;
|
||||
u16 nintendo_card_id;
|
||||
u32 memory_card_size;
|
||||
};
|
||||
|
||||
class MemoryCard : public MemoryCardBase
|
||||
{
|
||||
public:
|
||||
MemoryCard(std::string filename, int _card_index, u16 sizeMb = MemCard2043Mb);
|
||||
~MemoryCard() { Flush(true); }
|
||||
void Flush(bool exiting = false) override;
|
||||
|
||||
s32 Read(u32 address, s32 length, u8* destaddress) override;
|
||||
s32 Write(u32 destaddress, s32 length, u8* srcaddress) override;
|
||||
void ClearBlock(u32 address) override;
|
||||
void ClearAll() override;
|
||||
void DoState(PointerWrap &p) override;
|
||||
void joinThread() override;
|
||||
private:
|
||||
u8 *memory_card_content;
|
||||
bool m_bDirty;
|
||||
std::string m_strFilename;
|
||||
|
||||
FlushData flushData;
|
||||
std::thread flushThread;
|
||||
};
|
Loading…
Reference in New Issue