diff --git a/src/NDS.cpp b/src/NDS.cpp index 346bcb7d..1bb17fee 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -1161,8 +1161,6 @@ u32 RunFrame() GPU3D::Timestamp-SysTimestamp); #endif SPU::TransferOutput(); - - //NDSCart::FlushSRAMFile(); } // In the context of TASes, frame count is traditionally the primary measure of emulated time, diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp index b78366b1..c24111a3 100644 --- a/src/NDSCart.cpp +++ b/src/NDSCart.cpp @@ -672,6 +672,7 @@ u8 CartRetail::SRAMWrite_EEPROMTiny(u8 val, u32 pos, bool last) if (pos < 2) { SRAMAddr = val; + SRAMFirstAddr = SRAMAddr; } else { @@ -679,11 +680,15 @@ u8 CartRetail::SRAMWrite_EEPROMTiny(u8 val, u32 pos, bool last) if (SRAMStatus & (1<<1)) { SRAM[(SRAMAddr + ((SRAMCmd==0x0A)?0x100:0)) & 0x1FF] = val; - SRAMFileDirty |= last; } SRAMAddr++; } - if (last) SRAMStatus &= ~(1<<1); + if (last) + { + SRAMStatus &= ~(1<<1); + Platform::WriteNDSSave(SRAM, SRAMLength, + (SRAMFirstAddr + ((SRAMCmd==0x0A)?0x100:0)) & 0x1FF, SRAMAddr-SRAMFirstAddr); + } return 0; case 0x03: // read low @@ -731,6 +736,7 @@ u8 CartRetail::SRAMWrite_EEPROM(u8 val, u32 pos, bool last) { SRAMAddr <<= 8; SRAMAddr |= val; + SRAMFirstAddr = SRAMAddr; } else { @@ -738,11 +744,15 @@ u8 CartRetail::SRAMWrite_EEPROM(u8 val, u32 pos, bool last) if (SRAMStatus & (1<<1)) { SRAM[SRAMAddr & (SRAMLength-1)] = val; - SRAMFileDirty |= last; } SRAMAddr++; } - if (last) SRAMStatus &= ~(1<<1); + if (last) + { + SRAMStatus &= ~(1<<1); + Platform::WriteNDSSave(SRAM, SRAMLength, + SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr); + } return 0; case 0x03: // read @@ -783,6 +793,7 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last) { SRAMAddr <<= 8; SRAMAddr |= val; + SRAMFirstAddr = SRAMAddr; } else { @@ -790,11 +801,15 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last) { // CHECKME: should it be &=~val ?? SRAM[SRAMAddr & (SRAMLength-1)] = 0; - SRAMFileDirty |= last; } SRAMAddr++; } - if (last) SRAMStatus &= ~(1<<1); + if (last) + { + SRAMStatus &= ~(1<<1); + Platform::WriteNDSSave(SRAM, SRAMLength, + SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr); + } return 0; case 0x03: // read @@ -816,17 +831,22 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last) { SRAMAddr <<= 8; SRAMAddr |= val; + SRAMFirstAddr = SRAMAddr; } else { if (SRAMStatus & (1<<1)) { SRAM[SRAMAddr & (SRAMLength-1)] = val; - SRAMFileDirty |= last; } SRAMAddr++; } - if (last) SRAMStatus &= ~(1<<1); + if (last) + { + SRAMStatus &= ~(1<<1); + Platform::WriteNDSSave(SRAM, SRAMLength, + SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr); + } return 0; case 0x0B: // fast read @@ -857,6 +877,7 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last) { SRAMAddr <<= 8; SRAMAddr |= val; + SRAMFirstAddr = SRAMAddr; } if ((pos == 3) && (SRAMStatus & (1<<1))) { @@ -865,9 +886,13 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last) SRAM[SRAMAddr & (SRAMLength-1)] = 0; SRAMAddr++; } - SRAMFileDirty = true; } - if (last) SRAMStatus &= ~(1<<1); + if (last) + { + SRAMStatus &= ~(1<<1); + Platform::WriteNDSSave(SRAM, SRAMLength, + SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr); + } return 0; case 0xDB: // page erase @@ -875,6 +900,7 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last) { SRAMAddr <<= 8; SRAMAddr |= val; + SRAMFirstAddr = SRAMAddr; } if ((pos == 3) && (SRAMStatus & (1<<1))) { @@ -883,9 +909,13 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last) SRAM[SRAMAddr & (SRAMLength-1)] = 0; SRAMAddr++; } - SRAMFileDirty = true; } - if (last) SRAMStatus &= ~(1<<1); + if (last) + { + SRAMStatus &= ~(1<<1); + Platform::WriteNDSSave(SRAM, SRAMLength, + SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr); + } return 0; default: @@ -974,7 +1004,7 @@ int CartRetailNAND::ROMCommandStart(u8* cmd, u8* data, u32 len) if (SRAMLength && SRAMAddr < (SRAMBase+SRAMLength-0x20000)) { memcpy(&SRAM[SRAMAddr - SRAMBase], SRAMWriteBuffer, 0x800); - SRAMFileDirty = true; + Platform::WriteNDSSave(SRAM, SRAMLength, SRAMAddr - SRAMBase, 0x800); } SRAMAddr = 0; diff --git a/src/NDSCart.h b/src/NDSCart.h index a059b2db..37290ee1 100644 --- a/src/NDSCart.h +++ b/src/NDSCart.h @@ -99,11 +99,9 @@ protected: u32 SRAMLength; u32 SRAMType; - char SRAMPath[1024]; - bool SRAMFileDirty; - u8 SRAMCmd; u32 SRAMAddr; + u32 SRAMFirstAddr; u8 SRAMStatus; }; diff --git a/src/Platform.h b/src/Platform.h index ec3e0022..aefbf4b0 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -145,8 +145,11 @@ void Mutex_Unlock(Mutex* mutex); bool Mutex_TryLock(Mutex* mutex); -void WriteNDSSave(const u8* savedata, u32 savelen); -void WriteGBASave(const u8* savedata, u32 savelen); +// functions called when the NDS or GBA save files need to be written back to storage +// savedata and savelen are always the entire save memory buffer and its full length +// writeoffset and writelen indicate which part of the memory was altered +void WriteNDSSave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen); +void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen); // local multiplayer comm interface diff --git a/src/frontend/qt_sdl/CMakeLists.txt b/src/frontend/qt_sdl/CMakeLists.txt index 634a2c88..2207e4d5 100644 --- a/src/frontend/qt_sdl/CMakeLists.txt +++ b/src/frontend/qt_sdl/CMakeLists.txt @@ -25,7 +25,7 @@ SET(SOURCES_QT_SDL font.h Platform.cpp QPathInput.h - ROMLoader.cpp + ROMManager.cpp SaveManager.cpp ArchiveUtil.h diff --git a/src/frontend/qt_sdl/Platform.cpp b/src/frontend/qt_sdl/Platform.cpp index 843a228b..ebfe6af6 100644 --- a/src/frontend/qt_sdl/Platform.cpp +++ b/src/frontend/qt_sdl/Platform.cpp @@ -52,6 +52,7 @@ #include "Platform.h" #include "Config.h" +#include "ROMManager.h" #include "LAN_Socket.h" #include "LAN_PCap.h" #include @@ -372,12 +373,13 @@ bool Mutex_TryLock(Mutex* mutex) } -void WriteNDSSave(const u8* savedata, u32 savelen) +void WriteNDSSave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen) { - // + if (ROMManager::NDSSave) + ROMManager::NDSSave->RequestFlush(savedata, savelen, writeoffset, writelen); } -void WriteGBASave(const u8* savedata, u32 savelen) +void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen) { // } diff --git a/src/frontend/qt_sdl/ROMLoader.cpp b/src/frontend/qt_sdl/ROMManager.cpp similarity index 96% rename from src/frontend/qt_sdl/ROMLoader.cpp rename to src/frontend/qt_sdl/ROMManager.cpp index aeaddbe2..650b87a5 100644 --- a/src/frontend/qt_sdl/ROMLoader.cpp +++ b/src/frontend/qt_sdl/ROMManager.cpp @@ -25,26 +25,27 @@ #ifdef ARCHIVE_SUPPORT_ENABLED #include "ArchiveUtil.h" #endif -#include "ROMLoader.h" +#include "ROMManager.h" #include "Config.h" #include "Platform.h" #include "NDS.h" #include "DSi.h" -#include "GBACart.h" #include "AREngine.h" -namespace ROMLoader +namespace ROMManager { -std::string FullROMPath; -std::string BaseROMDir; -std::string BaseROMName; -std::string BaseAssetName; +std::string FullROMPath = ""; +std::string BaseROMDir = ""; +std::string BaseROMName = ""; +std::string BaseAssetName = ""; -int GBACartType; +int GBACartType = -1; + +SaveManager* NDSSave = nullptr; int LastSep(std::string path) @@ -280,6 +281,9 @@ bool LoadBIOS() if (NDS::NeedsDirectBoot()) return false; + if (NDSSave) delete NDSSave; + NDSSave = nullptr; + FullROMPath = ""; BaseROMDir = ""; BaseROMName = ""; @@ -362,6 +366,9 @@ bool LoadROM(QStringList filepath, bool reset) else return false; + if (NDSSave) delete NDSSave; + NDSSave = nullptr; + FullROMPath = fullpath; BaseROMDir = basepath; BaseROMName = romname; @@ -398,6 +405,11 @@ bool LoadROM(QStringList filepath, bool reset) } } + if (res) + { + NDSSave = new SaveManager(savname); + } + delete[] savedata; delete[] filedata; return res; @@ -405,6 +417,9 @@ bool LoadROM(QStringList filepath, bool reset) void EjectCart() { + if (NDSSave) delete NDSSave; + NDSSave = nullptr; + NDS::EjectCart(); FullROMPath = ""; @@ -456,6 +471,8 @@ QString GBACartLabel() + + void ROMIcon(u8 (&data)[512], u16 (&palette)[16], u32* iconRef) { int index = 0; diff --git a/src/frontend/qt_sdl/ROMLoader.h b/src/frontend/qt_sdl/ROMManager.h similarity index 91% rename from src/frontend/qt_sdl/ROMLoader.h rename to src/frontend/qt_sdl/ROMManager.h index 723ce815..c6e7837a 100644 --- a/src/frontend/qt_sdl/ROMLoader.h +++ b/src/frontend/qt_sdl/ROMManager.h @@ -16,17 +16,20 @@ with melonDS. If not, see http://www.gnu.org/licenses/. */ -#ifndef ROMLOADER_H -#define ROMLOADER_H +#ifndef ROMMANAGER_H +#define ROMMANAGER_H #include "types.h" +#include "SaveManager.h" #include #include -namespace ROMLoader +namespace ROMManager { +extern SaveManager* NDSSave; + QString VerifySetup(); void Reset(); bool LoadBIOS(); @@ -81,4 +84,4 @@ enum } -#endif // ROMLOADER_H +#endif // ROMMANAGER_H diff --git a/src/frontend/qt_sdl/SaveManager.cpp b/src/frontend/qt_sdl/SaveManager.cpp index 968797c8..05200f88 100644 --- a/src/frontend/qt_sdl/SaveManager.cpp +++ b/src/frontend/qt_sdl/SaveManager.cpp @@ -23,12 +23,29 @@ #include "Platform.h" -SaveManager::SaveManager() +SaveManager::SaveManager(std::string path) : QThread() { SecondaryBuffer = nullptr; + SecondaryBufferLength = 0; SecondaryBufferLock = new QMutex(); Running = false; + + Path = path; + + Buffer = nullptr; + Length = 0; + FlushRequested = false; + + FlushVersion = 0; + PreviousFlushVersion = 0; + TimeAtLastFlushRequest = 0; + + if (!path.empty()) + { + Running = true; + start(); + } } SaveManager::~SaveManager() @@ -43,49 +60,59 @@ SaveManager::~SaveManager() if (SecondaryBuffer) delete[] SecondaryBuffer; delete SecondaryBufferLock; + + if (Buffer) delete[] Buffer; } -void SaveManager::Setup(std::string path, u8* buffer, u32 length) +void SaveManager::RequestFlush(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen) { - // Flush SRAM in case there is unflushed data from previous state. - FlushSecondaryBuffer(); - - SecondaryBufferLock->lock(); - - Path = path; - - Buffer = buffer; - Length = length; - - if(SecondaryBuffer) delete[] SecondaryBuffer; // Delete secondary buffer, there might be previous state. - - SecondaryBuffer = new u8[length]; - SecondaryBufferLength = length; - - FlushVersion = 0; - PreviousFlushVersion = 0; - TimeAtLastFlushRequest = 0; - - SecondaryBufferLock->unlock(); - - if ((!path.empty()) && (!Running)) + if (Length != savelen) { - Running = true; - start(); + if (Buffer) delete[] Buffer; + + Length = savelen; + Buffer = new u8[Length]; + + memcpy(Buffer, savedata, Length); } - else if (path.empty() && Running) + else { - Running = false; - wait(); + if ((writeoffset+writelen) > savelen) + { + u32 len = savelen - writeoffset; + memcpy(&Buffer[writeoffset], &savedata[writeoffset], len); + len = writelen - len; + if (len > savelen) len = savelen; + memcpy(&Buffer[0], &savedata[0], len); + } + else + { + memcpy(&Buffer[writeoffset], &savedata[writeoffset], writelen); + } } + + FlushRequested = true; } -void SaveManager::RequestFlush() +void SaveManager::CheckFlush() { + if (!FlushRequested) return; + SecondaryBufferLock->lock(); printf("SaveManager: Flush requested\n"); + + if (SecondaryBufferLength != Length) + { + if (SecondaryBuffer) delete[] SecondaryBuffer; + + SecondaryBufferLength = Length; + SecondaryBuffer = new u8[SecondaryBufferLength]; + } + memcpy(SecondaryBuffer, Buffer, Length); + + FlushRequested = false; FlushVersion++; TimeAtLastFlushRequest = time(nullptr); @@ -112,6 +139,8 @@ void SaveManager::run() void SaveManager::FlushSecondaryBuffer(u8* dst, u32 dstLength) { + if (!SecondaryBuffer) return; + // When flushing to a file, there's no point in re-writing the exact same data. if (!dst && !NeedsFlush()) return; // When flushing to memory, we don't know if dst already has any data so we only check that we CAN flush. @@ -141,16 +170,3 @@ bool SaveManager::NeedsFlush() { return FlushVersion != PreviousFlushVersion; } - -void SaveManager::UpdateBuffer(u8* src, u32 srcLength) -{ - if (!src || srcLength != Length) return; - - // should we create a lock for the primary buffer? this method is not intended to be called from a secondary thread in the way Flush is - memcpy(Buffer, src, srcLength); - SecondaryBufferLock->lock(); - memcpy(SecondaryBuffer, src, srcLength); - SecondaryBufferLock->unlock(); - - PreviousFlushVersion = FlushVersion; -} diff --git a/src/frontend/qt_sdl/SaveManager.h b/src/frontend/qt_sdl/SaveManager.h index 2e8b1d79..5f8d36c5 100644 --- a/src/frontend/qt_sdl/SaveManager.h +++ b/src/frontend/qt_sdl/SaveManager.h @@ -34,15 +34,14 @@ class SaveManager : public QThread void run() override; public: - SaveManager(); + SaveManager(std::string path); ~SaveManager(); - void Setup(std::string path, u8* buffer, u32 length); - void RequestFlush(); + void RequestFlush(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen); + void CheckFlush(); bool NeedsFlush(); void FlushSecondaryBuffer(u8* dst = nullptr, u32 dstLength = 0); - void UpdateBuffer(u8* src, u32 srcLength); private: std::string Path; @@ -51,6 +50,7 @@ private: u8* Buffer; u32 Length; + bool FlushRequested; QMutex* SecondaryBufferLock; u8* SecondaryBuffer; diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 6836a73d..5f340522 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -81,7 +81,7 @@ #include "main_shaders.h" -#include "ROMLoader.h" +#include "ROMManager.h" #include "ArchiveUtil.h" // TODO: uniform variable spelling @@ -543,6 +543,9 @@ void EmuThread::run() // emulate u32 nlines = NDS::RunFrame(); + if (ROMManager::NDSSave) + ROMManager::NDSSave->CheckFlush(); + FrontBufferLock.lock(); FrontBuffer = GPU::FrontBuffer; #ifdef OGLRENDERER_ENABLED @@ -1308,7 +1311,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) menu->addSeparator(); - actCurrentCart = menu->addAction("DS slot: " + ROMLoader::CartLabel()); + actCurrentCart = menu->addAction("DS slot: " + ROMManager::CartLabel()); actCurrentCart->setEnabled(false); actInsertCart = menu->addAction("Insert cart..."); @@ -1319,7 +1322,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) menu->addSeparator(); - actCurrentGBACart = menu->addAction("GBA slot: " + ROMLoader::GBACartLabel()); + actCurrentGBACart = menu->addAction("GBA slot: " + ROMManager::GBACartLabel()); actCurrentGBACart->setEnabled(false); actInsertGBACart = menu->addAction("Insert ROM cart..."); @@ -2019,7 +2022,7 @@ void MainWindow::loadROM(QString filename) bool MainWindow::verifySetup() { - QString res = ROMLoader::VerifySetup(); + QString res = ROMManager::VerifySetup(); if (!res.isEmpty()) { QMessageBox::critical(this, "melonDS", res); @@ -2145,7 +2148,7 @@ void MainWindow::onOpenFile() // TODO: add to recent ROM list - if (!ROMLoader::LoadROM(file, true)) + if (!ROMManager::LoadROM(file, true)) { // TODO: better error reporting? QMessageBox::critical(this, "melonDS", "Failed to load the ROM."); @@ -2156,7 +2159,7 @@ void MainWindow::onOpenFile() NDS::Start(); emuThread->emuRun(); - actCurrentCart->setText("DS slot: " + ROMLoader::CartLabel()); + actCurrentCart->setText("DS slot: " + ROMManager::CartLabel()); actEjectCart->setEnabled(true); } @@ -2308,7 +2311,7 @@ void MainWindow::onBootFirmware() return; } - if (!ROMLoader::LoadBIOS()) + if (!ROMManager::LoadBIOS()) { // TODO: better error reporting? QMessageBox::critical(this, "melonDS", "This firmware is not bootable."); @@ -2333,7 +2336,7 @@ void MainWindow::onInsertCart() // TODO: add to recent ROM list?? - if (!ROMLoader::LoadROM(file, false)) + if (!ROMManager::LoadROM(file, false)) { // TODO: better error reporting? QMessageBox::critical(this, "melonDS", "Failed to load the ROM."); @@ -2343,7 +2346,7 @@ void MainWindow::onInsertCart() emuThread->emuUnpause(); - actCurrentCart->setText("DS slot: " + ROMLoader::CartLabel()); + actCurrentCart->setText("DS slot: " + ROMManager::CartLabel()); actEjectCart->setEnabled(true); } @@ -2351,11 +2354,11 @@ void MainWindow::onEjectCart() { emuThread->emuPause(); - ROMLoader::EjectCart(); + ROMManager::EjectCart(); emuThread->emuUnpause(); - actCurrentCart->setText("DS slot: " + ROMLoader::CartLabel()); + actCurrentCart->setText("DS slot: " + ROMManager::CartLabel()); actEjectCart->setEnabled(false); } @@ -2368,11 +2371,11 @@ void MainWindow::onInsertGBAAddon() emuThread->emuPause(); - ROMLoader::LoadGBAAddon(type); + ROMManager::LoadGBAAddon(type); emuThread->emuUnpause(); - actCurrentGBACart->setText("GBA slot: " + ROMLoader::GBACartLabel()); + actCurrentGBACart->setText("GBA slot: " + ROMManager::GBACartLabel()); actEjectGBACart->setEnabled(true); } @@ -2554,7 +2557,7 @@ void MainWindow::onReset() actUndoStateLoad->setEnabled(false); - ROMLoader::Reset(); + ROMManager::Reset(); OSD::AddMessage(0, "Reset"); emuThread->emuRun();