From 3383c396cdae6204d8c9b6c7f9a80fdb0009338e Mon Sep 17 00:00:00 2001 From: Arisotura Date: Thu, 23 Dec 2021 13:20:26 +0100 Subject: [PATCH] committing WIP. won't build or anything. --- src/GBACart.cpp | 95 +++++++++++---- src/GBACart.h | 26 ++-- src/NDS.cpp | 55 +++++++-- src/NDS.h | 18 ++- src/NDSCart.cpp | 179 ++++++++++++++++++++-------- src/NDSCart.h | 42 ++++--- src/Platform.h | 4 + src/frontend/Util_ROM.cpp | 5 +- src/frontend/qt_sdl/CMakeLists.txt | 1 + src/frontend/qt_sdl/Platform.cpp | 11 ++ src/frontend/qt_sdl/SaveManager.cpp | 156 ++++++++++++++++++++++++ src/frontend/qt_sdl/SaveManager.h | 67 +++++++++++ src/frontend/qt_sdl/main.cpp | 4 +- 13 files changed, 545 insertions(+), 118 deletions(-) create mode 100644 src/frontend/qt_sdl/SaveManager.cpp create mode 100644 src/frontend/qt_sdl/SaveManager.h diff --git a/src/GBACart.cpp b/src/GBACart.cpp index e5b6e4fc..7ba07d1a 100644 --- a/src/GBACart.cpp +++ b/src/GBACart.cpp @@ -63,13 +63,21 @@ void CartCommon::DoSavestate(Savestate* file) file->Section("GBCS"); } -void CartCommon::LoadSave(const char* path, u32 type) +void CartCommon::SetupSave(u32 type) +{ +} + +void CartCommon::LoadSave(const u8* savedata, u32 savelen) +{ +} + +/*void CartCommon::LoadSave(const char* path, u32 type) { } void CartCommon::RelocateSave(const char* path, bool write) { -} +}*/ int CartCommon::SetInput(int num, bool pressed) { @@ -103,7 +111,7 @@ CartGame::CartGame(u8* rom, u32 len) : CartCommon() memset(&GPIO, 0, sizeof(GPIO)); SRAM = nullptr; - SRAMFile = nullptr; + //SRAMFile = nullptr; SRAMLength = 0; SRAMType = S_NULL; SRAMFlashState = {}; @@ -111,7 +119,7 @@ CartGame::CartGame(u8* rom, u32 len) : CartCommon() CartGame::~CartGame() { - if (SRAMFile) fclose(SRAMFile); + //if (SRAMFile) fclose(SRAMFile); if (SRAM) delete[] SRAM; } @@ -133,6 +141,7 @@ void CartGame::DoSavestate(Savestate* file) { // reallocate save memory if (oldlen) delete[] SRAM; + SRAM = nullptr; if (SRAMLength) SRAM = new u8[SRAMLength]; } if (SRAMLength) @@ -144,9 +153,9 @@ void CartGame::DoSavestate(Savestate* file) { // no save data, clear the current state SRAMType = SaveType::S_NULL; - if (SRAMFile) fclose(SRAMFile); + //if (SRAMFile) fclose(SRAMFile); SRAM = nullptr; - SRAMFile = nullptr; + //SRAMFile = nullptr; return; } @@ -160,25 +169,19 @@ void CartGame::DoSavestate(Savestate* file) file->Var8((u8*)&SRAMType); } -void CartGame::LoadSave(const char* path, u32 type) +void CartGame::SetupSave(u32 type) { if (SRAM) delete[] SRAM; + SRAM = nullptr; - strncpy(SRAMPath, path, 1023); - SRAMPath[1023] = '\0'; - SRAMLength = 0; + // TODO: have type be determined from some list, like in NDSCart + // and not this gross hack!! + SRAMLength = type; - FILE* f = Platform::OpenFile(SRAMPath, "r+b"); - if (f) + if (SRAMLength) { - fseek(f, 0, SEEK_END); - SRAMLength = (u32)ftell(f); SRAM = new u8[SRAMLength]; - - fseek(f, 0, SEEK_SET); - fread(SRAM, SRAMLength, 1, f); - - SRAMFile = f; + memset(SRAM, 0xFF, SRAMLength); } switch (SRAMLength) @@ -219,7 +222,14 @@ void CartGame::LoadSave(const char* path, u32 type) } } -void CartGame::RelocateSave(const char* path, bool write) +void CartGame::LoadSave(const u8* savedata, u32 savelen) +{ + if (!SRAM) return; + + memcpy(SRAM, savedata, std::min(savelen, SRAMLength)); +} + +/*void CartGame::RelocateSave(const char* path, bool write) { if (!write) { @@ -239,7 +249,7 @@ void CartGame::RelocateSave(const char* path, bool write) SRAMFile = f; fwrite(SRAM, SRAMLength, 1, SRAMFile); -} +}*/ u16 CartGame::ROMRead(u32 addr) { @@ -704,8 +714,26 @@ void DoSavestate(Savestate* file) if (Cart) Cart->DoSavestate(file); } -void LoadROMCommon(const char *sram) +//void LoadROMCommon(const char *sram) +bool LoadROM(const u8* romdata, u32 romlen) { + CartROMSize = 0x200; + while (CartROMSize < romlen) + CartROMSize <<= 1; + + try + { + CartROM = new u8[CartROMSize]; + } + catch (const std::bad_alloc& e) + { + printf("GBACart: failed to allocate memory for ROM (%d bytes)\n", CartROMSize); + return false; + } + + memset(CartROM, 0, CartROMSize); + memcpy(CartROM, romdata, romlen); + char gamecode[5] = { '\0' }; memcpy(&gamecode, CartROM + 0xAC, 4); printf("GBA game code: %s\n", gamecode); @@ -733,13 +761,28 @@ void LoadROMCommon(const char *sram) Cart = new CartGame(CartROM, CartROMSize); // save - printf("GBA save file: %s\n", sram); + //printf("GBA save file: %s\n", sram); // TODO: have a list of sorts like in NDSCart? to determine the savemem type - if (Cart) Cart->LoadSave(sram, 0); + //if (Cart) Cart->LoadSave(sram, 0); + + // TODO: setup cart save here! from a list or something + + return true; } -bool LoadROM(const char* path, const char* sram) +void LoadSave(const u8* savedata, u32 savelen) +{ + if (Cart) + { + // gross hack + Cart->SetupSave(savelen); + + Cart->LoadSave(savedata, savelen); + } +} + +/*bool LoadROM(const char* path, const char* sram) { FILE* f = Platform::OpenFile(path, "rb"); if (!f) @@ -787,7 +830,7 @@ bool LoadROM(const u8* romdata, u32 filelength, const char *sram) void RelocateSave(const char* path, bool write) { if (Cart) Cart->RelocateSave(path, write); -} +}*/ int SetInput(int num, bool pressed) diff --git a/src/GBACart.h b/src/GBACart.h index 8698e257..0f2bf5c1 100644 --- a/src/GBACart.h +++ b/src/GBACart.h @@ -34,8 +34,10 @@ public: virtual void DoSavestate(Savestate* file); - virtual void LoadSave(const char* path, u32 type); - virtual void RelocateSave(const char* path, bool write); + virtual void SetupSave(u32 type); + virtual void LoadSave(const u8* savedata, u32 savelen); + //virtual void LoadSave(const char* path, u32 type); + //virtual void RelocateSave(const char* path, bool write); virtual int SetInput(int num, bool pressed); @@ -55,8 +57,10 @@ public: virtual void DoSavestate(Savestate* file) override; - virtual void LoadSave(const char* path, u32 type) override; - virtual void RelocateSave(const char* path, bool write) override; + virtual void SetupSave(u32 type) override; + virtual void LoadSave(const u8* savedata, u32 savelen) override; + //virtual void LoadSave(const char* path, u32 type) override; + //virtual void RelocateSave(const char* path, bool write) override; virtual u16 ROMRead(u32 addr) override; virtual void ROMWrite(u32 addr, u16 val) override; @@ -107,11 +111,11 @@ protected: } SRAMFlashState; u8* SRAM; - FILE* SRAMFile; + //FILE* SRAMFile; u32 SRAMLength; SaveType SRAMType; - char SRAMPath[1024]; + //char SRAMPath[1024]; }; // CartGameSolarSensor -- Boktai game cart @@ -154,9 +158,13 @@ void Reset(); void Eject(); void DoSavestate(Savestate* file); -bool LoadROM(const char* path, const char* sram); -bool LoadROM(const u8* romdata, u32 filelength, const char *sram); -void RelocateSave(const char* path, bool write); + +bool LoadROM(const u8* romdata, u32 romlen); +void LoadSave(const u8* savedata, u32 savelen); + +//bool LoadROM(const char* path, const char* sram); +//bool LoadROM(const u8* romdata, u32 filelength, const char *sram); +//void RelocateSave(const char* path, bool write); // TODO: make more flexible, support nonbinary inputs int SetInput(int num, bool pressed); diff --git a/src/NDS.cpp b/src/NDS.cpp index e8093137..e12f6ba6 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -200,7 +200,7 @@ bool Init() DMAs[6] = new DMA(1, 2); DMAs[7] = new DMA(1, 3); - if (!NDSCart_SRAMManager::Init()) return false; + //if (!NDSCart_SRAMManager::Init()) return false; if (!NDSCart::Init()) return false; if (!GBACart::Init()) return false; if (!GPU::Init()) return false; @@ -228,7 +228,7 @@ void DeInit() for (int i = 0; i < 8; i++) delete DMAs[i]; - NDSCart_SRAMManager::DeInit(); + //NDSCart_SRAMManager::DeInit(); NDSCart::DeInit(); GBACart::DeInit(); GPU::DeInit(); @@ -353,7 +353,7 @@ void InitTimings() // handled later: GBA slot, wifi } -void SetupDirectBoot() +void SetupDirectBoot(std::string romname) { if (ConsoleType == 1) { @@ -444,6 +444,8 @@ void SetupDirectBoot() ARM9->CP15Write(0x911, 0x00000020); } + NDSCart::SetupDirectBoot(romname); + ARM9->R[12] = NDSCart::Header.ARM9EntryAddress; ARM9->R[13] = 0x03002F7C; ARM9->R[14] = NDSCart::Header.ARM9EntryAddress; @@ -658,6 +660,11 @@ void Reset() AREngine::Reset(); } +void Start() +{ + Running = true; +} + void Stop() { printf("Stopping: shutdown\n"); @@ -888,7 +895,39 @@ void SetConsoleType(int type) ConsoleType = type; } -bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct) +bool LoadCart(const u8* romdata, u32 romlen, const u8* savedata, u32 savelen) +{ + if (!NDSCart::LoadROM(romdata, romlen)) + return false; + + if (savedata && savelen) + NDSCart::LoadSave(savedata, savelen); + + //Running = true; +} + +void EjectCart() +{ + printf("TODO!!!!\n"); +} + +bool LoadGBACart(const u8* romdata, u32 romlen, const u8* savedata, u32 savelen) +{ + if (!GBACart::LoadROM(romdata, romlen)) + return false; + + if (savedata && savelen) + GBACart::LoadSave(savedata, savelen); + + //Running = true; +} + +void EjectGBACart() +{ + printf("TODO!!!!\n"); +} + +/*bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct) { if (NDSCart::LoadROM(romdata, filelength, sram, direct)) { @@ -940,19 +979,19 @@ bool LoadGBAROM(const u8* romdata, u32 filelength, const char *filename, const c printf("Failed to load ROM %s from archive\n", filename); return false; } -} +}*/ void LoadBIOS() { Reset(); - Running = true; + //Running = true; } -void RelocateSave(const char* path, bool write) +/*void RelocateSave(const char* path, bool write) { printf("SRAM: relocating to %s (write=%s)\n", path, write?"true":"false"); NDSCart::RelocateSave(path, write); -} +}*/ diff --git a/src/NDS.h b/src/NDS.h index 29fc4ef5..2ea26d4d 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -19,6 +19,8 @@ #ifndef NDS_H #define NDS_H +#include + #include "Savestate.h" #include "types.h" @@ -219,6 +221,7 @@ extern u8* ARM7WRAM; bool Init(); void DeInit(); void Reset(); +void Start(); void Stop(); bool DoSavestate(Savestate* file); @@ -229,13 +232,20 @@ void SetARM7RegionTimings(u32 addrstart, u32 addrend, u32 region, int buswidth, // 0=DS 1=DSi void SetConsoleType(int type); -bool LoadROM(const char* path, const char* sram, bool direct); +/*bool LoadROM(const char* path, const char* sram, bool direct); bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct); bool LoadGBAROM(const char* path, const char* sram); -bool LoadGBAROM(const u8* romdata, u32 filelength, const char *filename, const char *sram); +bool LoadGBAROM(const u8* romdata, u32 filelength, const char *filename, const char *sram);*/ void LoadBIOS(); -void SetupDirectBoot(); -void RelocateSave(const char* path, bool write); + +bool LoadCart(const u8* romdata, u32 romlen, const u8* savedata, u32 savelen); +void EjectCart(); +void SetupDirectBoot(std::string romname); + +bool LoadGBACart(const u8* romdata, u32 romlen, const u8* savedata, u32 savelen); +void EjectGBACart(); + +//void RelocateSave(const char* path, bool write); u32 RunFrame(); diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp index 3d231acc..09c260f6 100644 --- a/src/NDSCart.cpp +++ b/src/NDSCart.cpp @@ -51,7 +51,7 @@ u32 TransferDir; u8 TransferCmd[8]; bool CartInserted; -char CartName[256]; +//char CartName[256]; u8* CartROM; u32 CartROMSize; u32 CartID; @@ -198,11 +198,11 @@ void CartCommon::Reset() DSiMode = false; } -void CartCommon::SetupDirectBoot() +void CartCommon::SetupDirectBoot(std::string romname) { CmdEncMode = 2; DataEncMode = 2; - DSiMode = IsDSi && NDS::ConsoleType==1; + DSiMode = IsDSi && (NDS::ConsoleType==1); } void CartCommon::DoSavestate(Savestate* file) @@ -214,11 +214,15 @@ void CartCommon::DoSavestate(Savestate* file) file->Bool32(&DSiMode); } -void CartCommon::LoadSave(const char* path, u32 type) +void CartCommon::SetupSave(u32 type) { } -void CartCommon::RelocateSave(const char* path, bool write) +void CartCommon::LoadSave(const u8* savedata, u32 savelen) +{ +} + +/*void CartCommon::RelocateSave(const char* path, bool write) { } @@ -229,7 +233,7 @@ int CartCommon::ImportSRAM(const u8* data, u32 length) void CartCommon::FlushSRAMFile() { -} +}*/ int CartCommon::ROMCommandStart(u8* cmd, u8* data, u32 len) { @@ -407,6 +411,7 @@ void CartRetail::DoSavestate(Savestate* file) printf("oh well. loading it anyway. adsfgdsf\n"); if (oldlen) delete[] SRAM; + SRAM = nullptr; if (SRAMLength) SRAM = new u8[SRAMLength]; } if (SRAMLength) @@ -424,14 +429,59 @@ void CartRetail::DoSavestate(Savestate* file) file->Var8(&SRAMStatus); // SRAMManager might now have an old buffer (or one from the future or alternate timeline!) - if (!file->Saving) + /*if (!file->Saving) { SRAMFileDirty = false; NDSCart_SRAMManager::RequestFlush(); + }*/ +} + +void CartRetail::SetupSave(u32 type) +{ + if (SRAM) delete[] SRAM; + SRAM = nullptr; + + if (type > 10) type = 0; + int sramlen[] = + { + 0, + 512, + 8192, 65536, 128*1024, + 256*1024, 512*1024, 1024*1024, + 8192*1024, 16384*1024, 65536*1024 + }; + SRAMLength = sramlen[type]; + + if (SRAMLength) + { + SRAM = new u8[SRAMLength]; + memset(SRAM, 0xFF, SRAMLength); + } + + switch (type) + { + case 1: SRAMType = 1; break; // EEPROM, small + case 2: + case 3: + case 4: SRAMType = 2; break; // EEPROM, regular + case 5: + case 6: + case 7: SRAMType = 3; break; // FLASH + case 8: + case 9: + case 10: SRAMType = 4; break; // NAND + default: SRAMType = 0; break; // ...whatever else } } -void CartRetail::LoadSave(const char* path, u32 type) +void CartRetail::LoadSave(const u8* savedata, u32 savelen) +{ + if (!SRAM) return; + + memcpy(SRAM, savedata, std::min(savelen, SRAMLength)); +} + +/*void CartRetail::LoadSave(const char* path, u32 type) { if (SRAM) delete[] SRAM; @@ -481,9 +531,9 @@ void CartRetail::LoadSave(const char* path, u32 type) case 10: SRAMType = 4; break; // NAND default: SRAMType = 0; break; // ...whatever else } -} +}*/ -void CartRetail::RelocateSave(const char* path, bool write) +/*void CartRetail::RelocateSave(const char* path, bool write) { if (!write) { @@ -524,7 +574,7 @@ void CartRetail::FlushSRAMFile() SRAMFileDirty = false; NDSCart_SRAMManager::RequestFlush(); -} +}*/ int CartRetail::ROMCommandStart(u8* cmd, u8* data, u32 len) { @@ -1199,15 +1249,15 @@ void CartHomebrew::Reset() CartCommon::Reset(); } -void CartHomebrew::SetupDirectBoot() +void CartHomebrew::SetupDirectBoot(std::string romname) { - CartCommon::SetupDirectBoot(); + CartCommon::SetupDirectBoot(romname); if (SD) { // add the ROM to the SD volume - if (!SD->InjectFile(CartName, CartROM, CartROMSize)) + if (!SD->InjectFile(romname, CartROM, CartROMSize)) return; // setup argv command line @@ -1216,7 +1266,7 @@ void CartHomebrew::SetupDirectBoot() int argvlen; strncpy(argv, "fat:/", 511); - strncat(argv, CartName, 511); + strncat(argv, romname.c_str(), 511); argvlen = strlen(argv); void (*writefn)(u32,u32) = (NDS::ConsoleType==1) ? DSi::ARM9Write32 : NDS::ARM9Write32; @@ -1542,11 +1592,6 @@ bool ReadROMParams(u32 gamecode, ROMListEntry* params) void DecryptSecureArea(u8* out) { - // TODO: source decryption data from different possible sources - // * original DS-mode ARM7 BIOS has the key data at 0x30 - // * .srl ROMs (VC dumps) have encrypted secure areas but have precomputed - // decryption data at 0x1000 (and at the beginning of the DSi region if any) - u32 gamecode = (u32)Header.GameCode[3] << 24 | (u32)Header.GameCode[2] << 16 | (u32)Header.GameCode[1] << 8 | @@ -1576,8 +1621,28 @@ void DecryptSecureArea(u8* out) } } -bool LoadROMCommon(u32 filelength, const char *sram, bool direct) +//bool LoadROMCommon(u32 filelength, const char *sram, bool direct) +bool LoadROM(const u8* romdata, u32 romlen) { + //NDS::Reset(); + + CartROMSize = 0x200; + while (CartROMSize < romlen) + CartROMSize <<= 1; + + try + { + CartROM = new u8[CartROMSize]; + } + catch (const std::bad_alloc& e) + { + printf("NDSCart: failed to allocate memory for ROM (%d bytes)\n", CartROMSize); + return false; + } + + memset(CartROM, 0, CartROMSize); + memcpy(CartROM, romdata, romlen); + memcpy(&Header, CartROM, sizeof(Header)); memcpy(&Banner, CartROM + Header.BannerOffset, sizeof(Banner)); @@ -1591,6 +1656,9 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct) u8 unitcode = Header.UnitCode; CartIsDSi = (unitcode & 0x02) != 0; + u32 arm9base = Header.ARM9ROMOffset; + CartIsHomebrew = (arm9base < 0x4000) || (gamecode == 0x23232323); + ROMListEntry romparams; if (!ReadROMParams(gamecode, &romparams)) { @@ -1599,7 +1667,7 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct) romparams.GameCode = gamecode; romparams.ROMSize = CartROMSize; - if (*(u32*)&CartROM[0x20] < 0x4000) + if (CartIsHomebrew) romparams.SaveMemType = 0; // no saveRAM for homebrew else romparams.SaveMemType = 2; // assume EEPROM 64k (TODO FIXME) @@ -1607,7 +1675,8 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct) else printf("ROM entry: %08X %08X\n", romparams.ROMSize, romparams.SaveMemType); - if (romparams.ROMSize != filelength) printf("!! bad ROM size %d (expected %d) rounded to %d\n", filelength, romparams.ROMSize, CartROMSize); + if (romparams.ROMSize != romlen) + printf("!! bad ROM size %d (expected %d) rounded to %d\n", romlen, romparams.ROMSize, CartROMSize); // generate a ROM ID // note: most games don't check the actual value @@ -1633,34 +1702,24 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct) printf("Cart ID: %08X\n", CartID); - u32 arm9base = *(u32*)&CartROM[0x20]; - - if (arm9base < 0x8000) + if (arm9base >= 0x4000 && arm9base < 0x8000) { - if (arm9base >= 0x4000) + // reencrypt secure area if needed + if (*(u32*)&CartROM[arm9base] == 0xE7FFDEFF && *(u32*)&CartROM[arm9base+0x10] != 0xE7FFDEFF) { - // reencrypt secure area if needed - if (*(u32*)&CartROM[arm9base] == 0xE7FFDEFF && *(u32*)&CartROM[arm9base+0x10] != 0xE7FFDEFF) - { - printf("Re-encrypting cart secure area\n"); + printf("Re-encrypting cart secure area\n"); - strncpy((char*)&CartROM[arm9base], "encryObj", 8); + strncpy((char*)&CartROM[arm9base], "encryObj", 8); - Key1_InitKeycode(false, gamecode, 3, 2); - for (u32 i = 0; i < 0x800; i += 8) - Key1_Encrypt((u32*)&CartROM[arm9base + i]); + Key1_InitKeycode(false, gamecode, 3, 2); + for (u32 i = 0; i < 0x800; i += 8) + Key1_Encrypt((u32*)&CartROM[arm9base + i]); - Key1_InitKeycode(false, gamecode, 2, 2); - Key1_Encrypt((u32*)&CartROM[arm9base]); - } + Key1_InitKeycode(false, gamecode, 2, 2); + Key1_Encrypt((u32*)&CartROM[arm9base]); } } - if ((arm9base < 0x4000) || (gamecode == 0x23232323)) - { - CartIsHomebrew = true; - } - CartInserted = true; u32 irversion = 0; @@ -1684,26 +1743,36 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct) Cart = new CartRetail(CartROM, CartROMSize, CartID); if (Cart) - { + Cart->Reset(); + /*{ Cart->Reset(); if (direct) { NDS::SetupDirectBoot(); Cart->SetupDirectBoot(); } - } + }*/ // encryption - Key1_InitKeycode(false, gamecode, 2, 2); + // needed???? + //Key1_InitKeycode(false, gamecode, 2, 2); // save - printf("Save file: %s\n", sram); - if (Cart) Cart->LoadSave(sram, romparams.SaveMemType); + //printf("Save file: %s\n", sram); + //if (Cart) Cart->LoadSave(sram, romparams.SaveMemType); + if (Cart && romparams.SaveMemType > 0) + Cart->SetupSave(romparams.SaveMemType); return true; } -bool LoadROM(const char* path, const char* sram, bool direct) +void LoadSave(const u8* savedata, u32 savelen) +{ + if (Cart) + Cart->LoadSave(savedata, savelen); +} + +/*bool LoadROM(const char* path, const char* sram, bool direct) { // TODO: streaming mode? for really big ROMs or systems with limited RAM // for now we're lazy @@ -1761,9 +1830,15 @@ bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct) memcpy(CartROM, romdata, filelength); return LoadROMCommon(filelength, sram, direct); +}*/ + +void SetupDirectBoot(std::string romname) +{ + if (Cart) + Cart->SetupDirectBoot(romname); } -void RelocateSave(const char* path, bool write) +/*void RelocateSave(const char* path, bool write) { if (Cart) Cart->RelocateSave(path, write); } @@ -1777,7 +1852,7 @@ int ImportSRAM(const u8* data, u32 length) { if (Cart) return Cart->ImportSRAM(data, length); return 0; -} +}*/ void ResetCart() { @@ -1880,6 +1955,8 @@ void WriteROMCnt(u32 val) *(u32*)&TransferCmd[0] = *(u32*)&ROMCommand[0]; *(u32*)&TransferCmd[4] = *(u32*)&ROMCommand[4]; + memset(TransferData, 0xFF, TransferLen); + /*printf("ROM COMMAND %04X %08X %02X%02X%02X%02X%02X%02X%02X%02X SIZE %04X\n", SPICnt, ROMCnt, TransferCmd[0], TransferCmd[1], TransferCmd[2], TransferCmd[3], diff --git a/src/NDSCart.h b/src/NDSCart.h index 9f399889..208e564b 100644 --- a/src/NDSCart.h +++ b/src/NDSCart.h @@ -19,6 +19,8 @@ #ifndef NDSCART_H #define NDSCART_H +#include + #include "types.h" #include "NDS_Header.h" #include "FATStorage.h" @@ -34,14 +36,15 @@ public: virtual ~CartCommon(); virtual void Reset(); - virtual void SetupDirectBoot(); + virtual void SetupDirectBoot(std::string romname); virtual void DoSavestate(Savestate* file); - virtual void LoadSave(const char* path, u32 type); - virtual void RelocateSave(const char* path, bool write); - virtual int ImportSRAM(const u8* data, u32 length); - virtual void FlushSRAMFile(); + virtual void SetupSave(u32 type); + virtual void LoadSave(const u8* savedata, u32 savelen); + //virtual void RelocateSave(const char* path, bool write); + //virtual int ImportSRAM(const u8* data, u32 length); + //virtual void FlushSRAMFile(); virtual int ROMCommandStart(u8* cmd, u8* data, u32 len); virtual void ROMCommandFinish(u8* cmd, u8* data, u32 len); @@ -75,10 +78,11 @@ public: virtual void DoSavestate(Savestate* file) override; - virtual void LoadSave(const char* path, u32 type) override; - virtual void RelocateSave(const char* path, bool write) override; - virtual int ImportSRAM(const u8* data, u32 length) override; - virtual void FlushSRAMFile() override; + virtual void SetupSave(u32 type) override; + virtual void LoadSave(const u8* savedata, u32 savelen) override; + //virtual void RelocateSave(const char* path, bool write) override; + //virtual int ImportSRAM(const u8* data, u32 length) override; + //virtual void FlushSRAMFile() override; virtual int ROMCommandStart(u8* cmd, u8* data, u32 len) override; @@ -114,8 +118,8 @@ public: void DoSavestate(Savestate* file) override; - void LoadSave(const char* path, u32 type) override; - int ImportSRAM(const u8* data, u32 length) override; + void LoadSave(const u8* savedata, u32 savelen) override; + //int ImportSRAM(const u8* data, u32 length) override; int ROMCommandStart(u8* cmd, u8* data, u32 len) override; void ROMCommandFinish(u8* cmd, u8* data, u32 len) override; @@ -172,7 +176,7 @@ public: ~CartHomebrew() override; void Reset() override; - void SetupDirectBoot() override; + void SetupDirectBoot(std::string romname) override; void DoSavestate(Savestate* file) override; @@ -207,14 +211,18 @@ void Reset(); void DoSavestate(Savestate* file); void DecryptSecureArea(u8* out); -bool LoadROM(const char* path, const char* sram, bool direct); -bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct); +//bool LoadROM(const char* path, const char* sram, bool direct); +//bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct); -void FlushSRAMFile(); +bool LoadROM(const u8* romdata, u32 romlen); +void LoadSave(const u8* savedata, u32 savelen); +void SetupDirectBoot(std::string romname); -void RelocateSave(const char* path, bool write); +//void FlushSRAMFile(); -int ImportSRAM(const u8* data, u32 length); +//void RelocateSave(const char* path, bool write); + +//int ImportSRAM(const u8* data, u32 length); void ResetCart(); diff --git a/src/Platform.h b/src/Platform.h index bbdc245c..ec3e0022 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -145,6 +145,10 @@ void Mutex_Unlock(Mutex* mutex); bool Mutex_TryLock(Mutex* mutex); +void WriteNDSSave(const u8* savedata, u32 savelen); +void WriteGBASave(const u8* savedata, u32 savelen); + + // local multiplayer comm interface // packet type: DS-style TX header (12 bytes) + original 802.11 frame bool MP_Init(); diff --git a/src/frontend/Util_ROM.cpp b/src/frontend/Util_ROM.cpp index 00bb9ade..f50f4869 100644 --- a/src/frontend/Util_ROM.cpp +++ b/src/frontend/Util_ROM.cpp @@ -298,7 +298,7 @@ int LoadBIOS() int LoadROM(const u8 *romdata, u32 romlength, const char *archivefilename, const char *romfilename, const char *sramfilename, int slot) { int res; - bool directboot = Config::DirectBoot != 0; + bool directboot = Config::DirectBoot; if (Config::ConsoleType == 1 && slot == 1) { @@ -580,6 +580,7 @@ int Reset() else { std::string ext = ROMPath[ROMSlot_NDS].substr(ROMPath[ROMSlot_NDS].length() - 4); + std::transform(ext.begin(), ext.end(), ext.begin(), tolower); if (ext == ".nds" || ext == ".srl" || ext == ".dsi") { @@ -619,6 +620,7 @@ int Reset() if (!ROMPath[ROMSlot_GBA].empty()) { std::string ext = ROMPath[ROMSlot_GBA].substr(ROMPath[ROMSlot_GBA].length() - 4); + std::transform(ext.begin(), ext.end(), ext.begin(), tolower); if (ext == ".gba") { @@ -675,6 +677,7 @@ std::string GetSavestateName(int slot) { std::string rompath; std::string ext = ROMPath[ROMSlot_NDS].substr(ROMPath[ROMSlot_NDS].length() - 4); + std::transform(ext.begin(), ext.end(), ext.begin(), tolower); // TODO!!! MORE SHIT THAT IS GONNA ASPLODE if (ext == ".nds" || ext == ".srl" || ext == ".dsi") diff --git a/src/frontend/qt_sdl/CMakeLists.txt b/src/frontend/qt_sdl/CMakeLists.txt index f637fdc8..7fb0aa7a 100644 --- a/src/frontend/qt_sdl/CMakeLists.txt +++ b/src/frontend/qt_sdl/CMakeLists.txt @@ -25,6 +25,7 @@ SET(SOURCES_QT_SDL font.h Platform.cpp QPathInput.h + SaveManager.cpp ArchiveUtil.h ArchiveUtil.cpp diff --git a/src/frontend/qt_sdl/Platform.cpp b/src/frontend/qt_sdl/Platform.cpp index de292d7f..843a228b 100644 --- a/src/frontend/qt_sdl/Platform.cpp +++ b/src/frontend/qt_sdl/Platform.cpp @@ -372,6 +372,17 @@ bool Mutex_TryLock(Mutex* mutex) } +void WriteNDSSave(const u8* savedata, u32 savelen) +{ + // +} + +void WriteGBASave(const u8* savedata, u32 savelen) +{ + // +} + + bool MP_Init() { int opt_true = 1; diff --git a/src/frontend/qt_sdl/SaveManager.cpp b/src/frontend/qt_sdl/SaveManager.cpp new file mode 100644 index 00000000..c78c801e --- /dev/null +++ b/src/frontend/qt_sdl/SaveManager.cpp @@ -0,0 +1,156 @@ +/* + Copyright 2016-2021 Arisotura + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#include +#include + +#include "SaveManager.h" +#include "Platform.h" + + +SaveManager() +{ + SecondaryBuffer = nullptr; + SecondaryBufferLock = new QMutex(); + + Running = false; +} + +~SaveManager() +{ + if (Running) + { + Running = false; + wait(); + FlushSecondaryBuffer(); + } + + if (SecondaryBuffer) delete[] SecondaryBuffer; + + delete SecondaryBufferLock; +} + +void SaveManager::Setup(std::string path, u8* buffer, u32 length) +{ + // 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)) + { + Running = true; + start(); + } + else if (path.empty && Running) + { + Running = false; + wait(); + } +} + +void SaveManager::RequestFlush() +{ + SecondaryBufferLock->lock(); + + printf("SaveManager: Flush requested\n"); + memcpy(SecondaryBuffer, Buffer, Length); + FlushVersion++; + TimeAtLastFlushRequest = time(nullptr); + + SecondaryBufferLock->unlock(); +} + +void SaveManager::run() +{ + for (;;) + { + QThread::msleep(100); + + if (!Running) return; + + // We debounce for two seconds after last flush request to ensure that writing has finished. + if (TimeAtLastFlushRequest == 0 || difftime(time(nullptr), TimeAtLastFlushRequest) < 2) + { + continue; + } + + FlushSecondaryBuffer(); + } +} + +void SaveManager::FlushSecondaryBuffer(u8* dst, u32 dstLength) +{ + // 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. + if (dst && dstLength < SecondaryBufferLength) return; + + SecondaryBufferLock->lock(); + if (dst) + { + memcpy(dst, SecondaryBuffer, SecondaryBufferLength); + } + else + { + FILE* f = Platform::OpenFile(Path, "wb"); + if (f) + { + printf("SaveManager: Written\n"); + fwrite(SecondaryBuffer, SecondaryBufferLength, 1, f); + fclose(f); + } + } + PreviousFlushVersion = FlushVersion; + TimeAtLastFlushRequest = 0; + SecondaryBufferLock->unlock(); +} + +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 new file mode 100644 index 00000000..2e8b1d79 --- /dev/null +++ b/src/frontend/qt_sdl/SaveManager.h @@ -0,0 +1,67 @@ +/* + Copyright 2016-2021 Arisotura + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef SAVEMANAGER_H +#define SAVEMANAGER_H + +#include +#include +#include +#include +#include +#include + +#include "types.h" + +class SaveManager : public QThread +{ + Q_OBJECT + void run() override; + +public: + SaveManager(); + ~SaveManager(); + + void Setup(std::string path, u8* buffer, u32 length); + void RequestFlush(); + + bool NeedsFlush(); + void FlushSecondaryBuffer(u8* dst = nullptr, u32 dstLength = 0); + void UpdateBuffer(u8* src, u32 srcLength); + +private: + std::string Path; + + std::atomic_bool Running; + + u8* Buffer; + u32 Length; + + QMutex* SecondaryBufferLock; + u8* SecondaryBuffer; + u32 SecondaryBufferLength; + + time_t TimeAtLastFlushRequest; + + // We keep versions in case the user closes the application before + // a flush cycle is finished. + u32 PreviousFlushVersion; + u32 FlushVersion; +}; + +#endif // SAVEMANAGER_H diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 6e0355ab..f3b79978 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -2477,8 +2477,8 @@ void MainWindow::onOpenPathSettings() void MainWindow::onPathSettingsFinished(int res) { - //if (FirmwareSettingsDialog::needsReset) - // onReset(); + if (PathSettingsDialog::needsReset) + onReset(); emuThread->emuUnpause(); }