mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2025-01-19 14:55:38 +00:00
MemoryCard: Batch sector writes together 5 seconds at a time
Reduces disk writes for SSDs (assuming the OS didn't just cache all the writes), and limits OSD spam. Fixes #146.
This commit is contained in:
parent
0a004361fc
commit
3c45603cb4
|
@ -11,17 +11,28 @@ Log_SetChannel(MemoryCard);
|
||||||
MemoryCard::MemoryCard(System* system) : m_system(system)
|
MemoryCard::MemoryCard(System* system) : m_system(system)
|
||||||
{
|
{
|
||||||
m_FLAG.no_write_yet = true;
|
m_FLAG.no_write_yet = true;
|
||||||
|
|
||||||
|
m_save_event =
|
||||||
|
system->CreateTimingEvent("Memory Card Host Flush", SAVE_DELAY_IN_SYSCLK_TICKS, SAVE_DELAY_IN_SYSCLK_TICKS,
|
||||||
|
std::bind(&MemoryCard::SaveIfChanged, this, true), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryCard::~MemoryCard() = default;
|
MemoryCard::~MemoryCard()
|
||||||
|
{
|
||||||
|
SaveIfChanged(false);
|
||||||
|
}
|
||||||
|
|
||||||
void MemoryCard::Reset()
|
void MemoryCard::Reset()
|
||||||
{
|
{
|
||||||
ResetTransferState();
|
ResetTransferState();
|
||||||
|
SaveIfChanged(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MemoryCard::DoState(StateWrapper& sw)
|
bool MemoryCard::DoState(StateWrapper& sw)
|
||||||
{
|
{
|
||||||
|
if (sw.IsReading())
|
||||||
|
SaveIfChanged(true);
|
||||||
|
|
||||||
sw.Do(&m_state);
|
sw.Do(&m_state);
|
||||||
sw.Do(&m_address);
|
sw.Do(&m_address);
|
||||||
sw.Do(&m_sector_offset);
|
sw.Do(&m_sector_offset);
|
||||||
|
@ -40,7 +51,6 @@ void MemoryCard::ResetTransferState()
|
||||||
m_sector_offset = 0;
|
m_sector_offset = 0;
|
||||||
m_checksum = 0;
|
m_checksum = 0;
|
||||||
m_last_byte = 0;
|
m_last_byte = 0;
|
||||||
m_changed = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MemoryCard::Transfer(const u8 data_in, u8* data_out)
|
bool MemoryCard::Transfer(const u8 data_in, u8* data_out)
|
||||||
|
@ -131,7 +141,7 @@ bool MemoryCard::Transfer(const u8 data_in, u8* data_out)
|
||||||
{
|
{
|
||||||
if (m_sector_offset == 0)
|
if (m_sector_offset == 0)
|
||||||
{
|
{
|
||||||
Log_DevPrintf("Writing memory card sector %u", ZeroExtend32(m_address));
|
Log_InfoPrintf("Writing memory card sector %u", ZeroExtend32(m_address));
|
||||||
m_checksum = Truncate8(m_address >> 8) ^ Truncate8(m_address) ^ data_in;
|
m_checksum = Truncate8(m_address >> 8) ^ Truncate8(m_address) ^ data_in;
|
||||||
m_FLAG.no_write_yet = false;
|
m_FLAG.no_write_yet = false;
|
||||||
}
|
}
|
||||||
|
@ -141,9 +151,7 @@ bool MemoryCard::Transfer(const u8 data_in, u8* data_out)
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 offset = ZeroExtend32(m_address) * SECTOR_SIZE + m_sector_offset;
|
const u32 offset = ZeroExtend32(m_address) * SECTOR_SIZE + m_sector_offset;
|
||||||
if (m_data[offset] != data_in)
|
m_changed |= (m_data[offset] != data_in);
|
||||||
m_changed = true;
|
|
||||||
|
|
||||||
m_data[offset] = data_in;
|
m_data[offset] = data_in;
|
||||||
|
|
||||||
*data_out = m_last_byte;
|
*data_out = m_last_byte;
|
||||||
|
@ -155,10 +163,7 @@ bool MemoryCard::Transfer(const u8 data_in, u8* data_out)
|
||||||
m_state = State::WriteChecksum;
|
m_state = State::WriteChecksum;
|
||||||
m_sector_offset = 0;
|
m_sector_offset = 0;
|
||||||
if (m_changed)
|
if (m_changed)
|
||||||
{
|
QueueFileSave();
|
||||||
m_changed = false;
|
|
||||||
SaveToFile();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -317,6 +322,8 @@ void MemoryCard::Format()
|
||||||
|
|
||||||
// write test frame
|
// write test frame
|
||||||
std::memcpy(GetSectorPtr(63), GetSectorPtr(0), SECTOR_SIZE);
|
std::memcpy(GetSectorPtr(63), GetSectorPtr(0), SECTOR_SIZE);
|
||||||
|
|
||||||
|
m_changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* MemoryCard::GetSectorPtr(u32 sector)
|
u8* MemoryCard::GetSectorPtr(u32 sector)
|
||||||
|
@ -342,8 +349,15 @@ bool MemoryCard::LoadFromFile()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MemoryCard::SaveToFile()
|
bool MemoryCard::SaveIfChanged(bool display_osd_message)
|
||||||
{
|
{
|
||||||
|
m_save_event->Deactivate();
|
||||||
|
|
||||||
|
if (!m_changed)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
m_changed = false;
|
||||||
|
|
||||||
if (m_filename.empty())
|
if (m_filename.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -364,6 +378,19 @@ bool MemoryCard::SaveToFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
Log_InfoPrintf("Saved memory card to '%s'", m_filename.c_str());
|
Log_InfoPrintf("Saved memory card to '%s'", m_filename.c_str());
|
||||||
m_system->GetHostInterface()->AddOSDMessage(SmallString::FromFormat("Saved memory card to '%s'", m_filename.c_str()));
|
if (display_osd_message)
|
||||||
|
m_system->GetHostInterface()->AddOSDMessage(
|
||||||
|
SmallString::FromFormat("Saved memory card to '%s'", m_filename.c_str()));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MemoryCard::QueueFileSave()
|
||||||
|
{
|
||||||
|
// skip if the event is already pending, or we don't have a backing file
|
||||||
|
if (m_save_event->IsActive() || m_filename.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// save in one second, that should be long enough for everything to finish writing
|
||||||
|
m_save_event->Schedule(SAVE_DELAY_IN_SYSCLK_TICKS);
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
class System;
|
class System;
|
||||||
|
class TimingEvent;
|
||||||
|
|
||||||
class MemoryCard final
|
class MemoryCard final
|
||||||
{
|
{
|
||||||
|
@ -33,6 +34,13 @@ public:
|
||||||
void Format();
|
void Format();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum : u32
|
||||||
|
{
|
||||||
|
// save in three seconds, that should be long enough for everything to finish writing
|
||||||
|
SAVE_DELAY_IN_SECONDS = 5,
|
||||||
|
SAVE_DELAY_IN_SYSCLK_TICKS = MASTER_CLOCK * SAVE_DELAY_IN_SECONDS,
|
||||||
|
};
|
||||||
|
|
||||||
union FLAG
|
union FLAG
|
||||||
{
|
{
|
||||||
u8 bits;
|
u8 bits;
|
||||||
|
@ -76,9 +84,11 @@ private:
|
||||||
u8* GetSectorPtr(u32 sector);
|
u8* GetSectorPtr(u32 sector);
|
||||||
|
|
||||||
bool LoadFromFile();
|
bool LoadFromFile();
|
||||||
bool SaveToFile();
|
bool SaveIfChanged(bool display_osd_message);
|
||||||
|
void QueueFileSave();
|
||||||
|
|
||||||
System* m_system;
|
System* m_system;
|
||||||
|
std::unique_ptr<TimingEvent> m_save_event;
|
||||||
|
|
||||||
State m_state = State::Idle;
|
State m_state = State::Idle;
|
||||||
u16 m_address = 0;
|
u16 m_address = 0;
|
||||||
|
|
Loading…
Reference in a new issue