aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ARCodeFile.cpp13
-rw-r--r--src/ARCodeFile.h9
-rw-r--r--src/AREngine.cpp7
-rw-r--r--src/AREngine.h1
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/CRC32.cpp4
-rw-r--r--src/CRC32.h2
-rw-r--r--src/DSi.cpp233
-rw-r--r--src/DSi.h6
-rw-r--r--src/DSi_AES.cpp37
-rw-r--r--src/DSi_AES.h2
-rw-r--r--src/DSi_Camera.cpp39
-rw-r--r--src/DSi_Camera.h4
-rw-r--r--src/DSi_DSP.cpp2
-rw-r--r--src/DSi_DSP.h4
-rw-r--r--src/DSi_I2C.cpp20
-rw-r--r--src/DSi_I2C.h2
-rw-r--r--src/DSi_NDMA.cpp26
-rw-r--r--src/DSi_NWifi.cpp39
-rw-r--r--src/DSi_NWifi.h2
-rw-r--r--src/DSi_SD.cpp86
-rw-r--r--src/DSi_SD.h7
-rw-r--r--src/DSi_SPI_TSC.cpp9
-rw-r--r--src/GBACart.cpp370
-rw-r--r--src/GBACart.h62
-rw-r--r--src/NDS.cpp172
-rw-r--r--src/NDS.h31
-rw-r--r--src/NDSCart.cpp460
-rw-r--r--src/NDSCart.h49
-rw-r--r--src/NDSCart_SRAMManager.cpp184
-rw-r--r--src/NDSCart_SRAMManager.h39
-rw-r--r--src/Platform.h7
-rw-r--r--src/SPI.cpp1
-rw-r--r--src/SPI.h1
-rw-r--r--src/Savestate.cpp9
-rw-r--r--src/Savestate.h3
-rw-r--r--src/frontend/FrontendUtil.h90
-rw-r--r--src/frontend/SharedConfig.h42
-rw-r--r--src/frontend/Util_ROM.cpp845
-rw-r--r--src/frontend/qt_sdl/ArchiveUtil.cpp94
-rw-r--r--src/frontend/qt_sdl/ArchiveUtil.h9
-rw-r--r--src/frontend/qt_sdl/AudioSettingsDialog.cpp4
-rw-r--r--src/frontend/qt_sdl/CMakeLists.txt5
-rw-r--r--src/frontend/qt_sdl/CheatsDialog.cpp29
-rw-r--r--src/frontend/qt_sdl/Config.cpp445
-rw-r--r--src/frontend/qt_sdl/Config.h113
-rw-r--r--src/frontend/qt_sdl/EmuSettingsDialog.cpp117
-rw-r--r--src/frontend/qt_sdl/FirmwareSettingsDialog.cpp24
-rw-r--r--src/frontend/qt_sdl/FirmwareSettingsDialog.h2
-rw-r--r--src/frontend/qt_sdl/LAN_PCap.cpp2
-rw-r--r--src/frontend/qt_sdl/PathSettingsDialog.cpp119
-rw-r--r--src/frontend/qt_sdl/PathSettingsDialog.h67
-rw-r--r--src/frontend/qt_sdl/PathSettingsDialog.ui149
-rw-r--r--src/frontend/qt_sdl/Platform.cpp16
-rw-r--r--src/frontend/qt_sdl/ROMInfoDialog.cpp6
-rw-r--r--src/frontend/qt_sdl/ROMInfoDialog.h4
-rw-r--r--src/frontend/qt_sdl/ROMManager.cpp843
-rw-r--r--src/frontend/qt_sdl/ROMManager.h66
-rw-r--r--src/frontend/qt_sdl/SaveManager.cpp194
-rw-r--r--src/frontend/qt_sdl/SaveManager.h70
-rw-r--r--src/frontend/qt_sdl/TitleManagerDialog.cpp4
-rw-r--r--src/frontend/qt_sdl/WifiSettingsDialog.cpp18
-rw-r--r--src/frontend/qt_sdl/main.cpp855
-rw-r--r--src/frontend/qt_sdl/main.h31
64 files changed, 3575 insertions, 2631 deletions
diff --git a/src/ARCodeFile.cpp b/src/ARCodeFile.cpp
index d79cd39..4e44f06 100644
--- a/src/ARCodeFile.cpp
+++ b/src/ARCodeFile.cpp
@@ -26,10 +26,9 @@
// TODO: more user-friendly error reporting
-ARCodeFile::ARCodeFile(const char* filename)
+ARCodeFile::ARCodeFile(std::string filename)
{
- memset(Filename, 0, sizeof(Filename));
- strncpy(Filename, filename, 1023);
+ Filename = filename;
Error = false;
@@ -91,7 +90,7 @@ bool ARCodeFile::Load()
if (isincat) Categories.push_back(curcat);
isincat = true;
- memcpy(curcat.Name, catname, 128);
+ curcat.Name = catname;
curcat.Codes.clear();
}
else if (!strncasecmp(start, "CODE", 4))
@@ -118,7 +117,7 @@ bool ARCodeFile::Load()
if (isincode) curcat.Codes.push_back(curcode);
isincode = true;
- memcpy(curcode.Name, codename, 128);
+ curcode.Name = codename;
curcode.Enabled = enable!=0;
curcode.CodeLen = 0;
}
@@ -172,12 +171,12 @@ bool ARCodeFile::Save()
ARCodeCat& cat = *it;
if (it != Categories.begin()) fprintf(f, "\r\n");
- fprintf(f, "CAT %s\r\n\r\n", cat.Name);
+ fprintf(f, "CAT %s\r\n\r\n", cat.Name.c_str());
for (ARCodeList::iterator jt = cat.Codes.begin(); jt != cat.Codes.end(); jt++)
{
ARCode& code = *jt;
- fprintf(f, "CODE %d %s\r\n", code.Enabled, code.Name);
+ fprintf(f, "CODE %d %s\r\n", code.Enabled, code.Name.c_str());
for (u32 i = 0; i < code.CodeLen; i+=2)
{
diff --git a/src/ARCodeFile.h b/src/ARCodeFile.h
index a3c36e4..1614908 100644
--- a/src/ARCodeFile.h
+++ b/src/ARCodeFile.h
@@ -19,13 +19,14 @@
#ifndef ARCODEFILE_H
#define ARCODEFILE_H
+#include <string>
#include <list>
#include "types.h"
struct ARCode
{
- char Name[128];
+ std::string Name;
bool Enabled;
u32 CodeLen;
u32 Code[2*64];
@@ -35,7 +36,7 @@ typedef std::list<ARCode> ARCodeList;
struct ARCodeCat
{
- char Name[128];
+ std::string Name;
ARCodeList Codes;
};
@@ -45,7 +46,7 @@ typedef std::list<ARCodeCat> ARCodeCatList;
class ARCodeFile
{
public:
- ARCodeFile(const char* filename);
+ ARCodeFile(std::string filename);
~ARCodeFile();
bool Error;
@@ -56,7 +57,7 @@ public:
ARCodeCatList Categories;
private:
- char Filename[1024];
+ std::string Filename;
};
#endif // ARCODEFILE_H
diff --git a/src/AREngine.cpp b/src/AREngine.cpp
index ec3b70e..eb5ab34 100644
--- a/src/AREngine.cpp
+++ b/src/AREngine.cpp
@@ -50,8 +50,6 @@ void DeInit()
void Reset()
{
- CodeFile = nullptr;
-
if (NDS::ConsoleType == 1)
{
BusRead8 = DSi::ARM7Read8;
@@ -73,6 +71,11 @@ void Reset()
}
+ARCodeFile* GetCodeFile()
+{
+ return CodeFile;
+}
+
void SetCodeFile(ARCodeFile* file)
{
CodeFile = file;
diff --git a/src/AREngine.h b/src/AREngine.h
index c142711..362b320 100644
--- a/src/AREngine.h
+++ b/src/AREngine.h
@@ -28,6 +28,7 @@ bool Init();
void DeInit();
void Reset();
+ARCodeFile* GetCodeFile();
void SetCodeFile(ARCodeFile* file);
void RunCheats();
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d1f47dc..7288b54 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -36,7 +36,6 @@ add_library(core STATIC
melonDLDI.h
NDS.cpp
NDSCart.cpp
- NDSCart_SRAMManager.cpp
Platform.h
ROMList.h
FreeBIOS.h
diff --git a/src/CRC32.cpp b/src/CRC32.cpp
index b51b171..eabdf33 100644
--- a/src/CRC32.cpp
+++ b/src/CRC32.cpp
@@ -52,7 +52,7 @@ void _inittable()
}
}
-u32 CRC32(u8 *data, int len)
+u32 CRC32(u8 *data, int len, u32 start)
{
if (!tableinited)
{
@@ -60,7 +60,7 @@ u32 CRC32(u8 *data, int len)
tableinited = true;
}
- u32 crc = 0xFFFFFFFF;
+ u32 crc = start ^ 0xFFFFFFFF;
while (len--)
crc = (crc >> 8) ^ crctable[(crc & 0xFF) ^ *data++];
diff --git a/src/CRC32.h b/src/CRC32.h
index 2107533..5600a63 100644
--- a/src/CRC32.h
+++ b/src/CRC32.h
@@ -21,6 +21,6 @@
#include "types.h"
-u32 CRC32(u8* data, int len);
+u32 CRC32(u8* data, int len, u32 start=0);
#endif // CRC32_H
diff --git a/src/DSi.cpp b/src/DSi.cpp
index 9267f14..2ac1032 100644
--- a/src/DSi.cpp
+++ b/src/DSi.cpp
@@ -47,8 +47,6 @@
namespace DSi
{
-u32 BootAddr[2];
-
u16 SCFG_BIOS;
u16 SCFG_Clock9;
u16 SCFG_Clock7;
@@ -79,16 +77,12 @@ DSi_NDMA* NDMAs[8];
DSi_SDHost* SDMMC;
DSi_SDHost* SDIO;
-FILE* SDMMCFile = nullptr;
-
u64 ConsoleID;
u8 eMMC_CID[16];
-u8 ITCMInit[0x8000];
-u8 ARM7Init[0x3C00];
-
void Set_SCFG_Clock9(u16 val);
+void Set_SCFG_MC(u32 val);
bool Init()
@@ -134,8 +128,6 @@ void DeInit()
delete SDMMC;
delete SDIO;
-
- CloseDSiNAND();
}
void Reset()
@@ -144,21 +136,24 @@ void Reset()
//NDS::ARM9->CP15Write(0x911, 0x00000020);
//NDS::ARM9->CP15Write(0x100, NDS::ARM9->CP15Read(0x100) | 0x00050000);
- NDS::ARM9->JumpTo(BootAddr[0]);
- NDS::ARM7->JumpTo(BootAddr[1]);
+ NDS::MapSharedWRAM(3);
NDMACnt[0] = 0; NDMACnt[1] = 0;
for (int i = 0; i < 8; i++) NDMAs[i]->Reset();
- memcpy(NDS::ARM9->ITCM, ITCMInit, 0x8000);
-
DSi_I2C::Reset();
- DSi_AES::Reset();
DSi_DSP::Reset();
+ SDMMC->CloseHandles();
+ SDIO->CloseHandles();
+
+ LoadNAND();
+
SDMMC->Reset();
SDIO->Reset();
+ DSi_AES::Reset();
+
SCFG_BIOS = 0x0101; // TODO: should be zero when booting from BIOS
SCFG_Clock9 = 0x0187; // CHECKME
SCFG_Clock7 = 0x0187;
@@ -172,22 +167,85 @@ void Reset()
// LCD init flag
GPU::DispStat[0] |= (1<<6);
GPU::DispStat[1] |= (1<<6);
+}
- NDS::MapSharedWRAM(3);
+void DoSavestate(Savestate* file)
+{
+ file->Section("DSIG");
- for (u32 i = 0; i < 0x3C00; i+=4)
- ARM7Write32(0x03FFC400+i, *(u32*)&ARM7Init[i]);
+ file->Var16(&SCFG_BIOS);
+ file->Var16(&SCFG_Clock9);
+ file->Var16(&SCFG_Clock7);
+ file->VarArray(&SCFG_EXT[0], sizeof(u32)*2);
+ file->Var32(&SCFG_MC);
+ file->Var16(&SCFG_RST);
- u32 eaddr = 0x03FFE6E4;
- ARM7Write32(eaddr+0x00, *(u32*)&eMMC_CID[0]);
- ARM7Write32(eaddr+0x04, *(u32*)&eMMC_CID[4]);
- ARM7Write32(eaddr+0x08, *(u32*)&eMMC_CID[8]);
- ARM7Write32(eaddr+0x0C, *(u32*)&eMMC_CID[12]);
- ARM7Write16(eaddr+0x2C, 0x0001);
- ARM7Write16(eaddr+0x2E, 0x0001);
- ARM7Write16(eaddr+0x3C, 0x0100);
- ARM7Write16(eaddr+0x3E, 0x40E0);
- ARM7Write16(eaddr+0x42, 0x0001);
+ //file->VarArray(ARM9iBIOS, 0x10000);
+ //file->VarArray(ARM7iBIOS, 0x10000);
+
+ if (file->Saving)
+ {
+ file->VarArray(&MBK[0][0], sizeof(u32)*8);
+ file->VarArray(&MBK[1][5], sizeof(u32)*3);
+ file->Var32(&MBK[0][8]);
+ }
+ else
+ {
+ Set_SCFG_Clock9(SCFG_Clock9);
+ Set_SCFG_MC(SCFG_MC);
+ DSi_DSP::SetRstLine(SCFG_RST & 0x0001);
+
+ MBK[0][8] = 0;
+ MBK[1][8] = 0;
+
+ u32 mbk[12];
+ file->VarArray(&mbk, sizeof(u32)*12);
+
+ MapNWRAM_A(0, mbk[0] & 0xFF);
+ MapNWRAM_A(1, (mbk[0] >> 8) & 0xFF);
+ MapNWRAM_A(2, (mbk[0] >> 16) & 0xFF);
+ MapNWRAM_A(3, mbk[0] >> 24);
+
+ MapNWRAM_B(0, mbk[1] & 0xFF);
+ MapNWRAM_B(1, (mbk[1] >> 8) & 0xFF);
+ MapNWRAM_B(2, (mbk[1] >> 16) & 0xFF);
+ MapNWRAM_B(3, mbk[1] >> 24);
+ MapNWRAM_B(4, mbk[2] & 0xFF);
+ MapNWRAM_B(5, (mbk[2] >> 8) & 0xFF);
+ MapNWRAM_B(6, (mbk[2] >> 16) & 0xFF);
+ MapNWRAM_B(7, mbk[2] >> 24);
+
+ MapNWRAM_C(0, mbk[3] & 0xFF);
+ MapNWRAM_C(1, (mbk[3] >> 8) & 0xFF);
+ MapNWRAM_C(2, (mbk[3] >> 16) & 0xFF);
+ MapNWRAM_C(3, mbk[3] >> 24);
+ MapNWRAM_C(4, mbk[4] & 0xFF);
+ MapNWRAM_C(5, (mbk[4] >> 8) & 0xFF);
+ MapNWRAM_C(6, (mbk[4] >> 16) & 0xFF);
+ MapNWRAM_C(7, mbk[4] >> 24);
+
+ MapNWRAMRange(0, 0, mbk[5]);
+ MapNWRAMRange(0, 1, mbk[6]);
+ MapNWRAMRange(0, 2, mbk[7]);
+
+ MapNWRAMRange(1, 0, mbk[8]);
+ MapNWRAMRange(1, 1, mbk[9]);
+ MapNWRAMRange(1, 2, mbk[10]);
+
+ mbk[11] &= 0x00FFFF0F;
+ MBK[0][8] = mbk[11];
+ MBK[1][8] = mbk[11];
+ }
+
+ for (int i = 0; i < 8; i++)
+ NDMAs[i]->DoSavestate(file);
+
+ DSi_AES::DoSavestate(file);
+ DSi_Camera::DoSavestate(file);
+ DSi_DSP::DoSavestate(file);
+ DSi_I2C::DoSavestate(file);
+ SDMMC->DoSavestate(file);
+ SDIO->DoSavestate(file);
}
void DecryptModcryptArea(u32 offset, u32 size, u8* iv)
@@ -445,24 +503,30 @@ void SetupDirectBoot()
ARM9Write32(0x02FFE000+i, tmp);
}
- if (DSi_NAND::Init(SDMMCFile, &DSi::ARM7iBIOS[0x8308]))
+ FILE* nand = Platform::OpenLocalFile(Platform::GetConfigString(Platform::DSi_NANDPath), "r+b");
+ if (nand)
{
- u8 userdata[0x1B0];
- DSi_NAND::ReadUserData(userdata);
- for (u32 i = 0; i < 0x128; i+=4)
- ARM9Write32(0x02000400+i, *(u32*)&userdata[0x88+i]);
+ if (DSi_NAND::Init(nand, &DSi::ARM7iBIOS[0x8308]))
+ {
+ u8 userdata[0x1B0];
+ DSi_NAND::ReadUserData(userdata);
+ for (u32 i = 0; i < 0x128; i+=4)
+ ARM9Write32(0x02000400+i, *(u32*)&userdata[0x88+i]);
+
+ u8 hwinfoS[0xA4];
+ u8 hwinfoN[0x9C];
+ DSi_NAND::ReadHardwareInfo(hwinfoS, hwinfoN);
- u8 hwinfoS[0xA4];
- u8 hwinfoN[0x9C];
- DSi_NAND::ReadHardwareInfo(hwinfoS, hwinfoN);
+ for (u32 i = 0; i < 0x14; i+=4)
+ ARM9Write32(0x02000600+i, *(u32*)&hwinfoN[0x88+i]);
- for (u32 i = 0; i < 0x14; i+=4)
- ARM9Write32(0x02000600+i, *(u32*)&hwinfoN[0x88+i]);
+ for (u32 i = 0; i < 0x18; i+=4)
+ ARM9Write32(0x02FFFD68+i, *(u32*)&hwinfoS[0x88+i]);
- for (u32 i = 0; i < 0x18; i+=4)
- ARM9Write32(0x02FFFD68+i, *(u32*)&hwinfoS[0x88+i]);
+ DSi_NAND::DeInit();
+ }
- DSi_NAND::DeInit();
+ fclose(nand);
}
u8 nwifiver = SPI_Firmware::GetNWifiVersion();
@@ -544,21 +608,22 @@ void SoftReset()
NDS::ARM9->CP15Reset();
- memcpy(NDS::ARM9->ITCM, ITCMInit, 0x8000);
+ NDS::MapSharedWRAM(3);
- DSi_AES::Reset();
// TODO: does the DSP get reset? NWRAM doesn't, so I'm assuming no
// *HOWEVER*, the bootrom (which does get rerun) does remap NWRAM, and thus
// the DSP most likely gets reset
DSi_DSP::Reset();
+ SDMMC->CloseHandles();
+ SDIO->CloseHandles();
+
LoadNAND();
SDMMC->Reset();
SDIO->Reset();
- NDS::ARM9->JumpTo(BootAddr[0]);
- NDS::ARM7->JumpTo(BootAddr[1]);
+ DSi_AES::Reset();
SCFG_BIOS = 0x0101; // TODO: should be zero when booting from BIOS
SCFG_Clock9 = 0x0187; // CHECKME
@@ -574,22 +639,6 @@ void SoftReset()
// LCD init flag
GPU::DispStat[0] |= (1<<6);
GPU::DispStat[1] |= (1<<6);
-
- NDS::MapSharedWRAM(3);
-
- for (u32 i = 0; i < 0x3C00; i+=4)
- ARM7Write32(0x03FFC400+i, *(u32*)&ARM7Init[i]);
-
- u32 eaddr = 0x03FFE6E4;
- ARM7Write32(eaddr+0x00, *(u32*)&eMMC_CID[0]);
- ARM7Write32(eaddr+0x04, *(u32*)&eMMC_CID[4]);
- ARM7Write32(eaddr+0x08, *(u32*)&eMMC_CID[8]);
- ARM7Write32(eaddr+0x0C, *(u32*)&eMMC_CID[12]);
- ARM7Write16(eaddr+0x2C, 0x0001);
- ARM7Write16(eaddr+0x2E, 0x0001);
- ARM7Write16(eaddr+0x3C, 0x0100);
- ARM7Write16(eaddr+0x3E, 0x40E0);
- ARM7Write16(eaddr+0x42, 0x0001);
}
bool LoadBIOS()
@@ -650,7 +699,14 @@ bool LoadNAND()
{
printf("Loading DSi NAND\n");
- if (!DSi_NAND::Init(SDMMCFile, &DSi::ARM7iBIOS[0x8308]))
+ FILE* nand = Platform::OpenLocalFile(Platform::GetConfigString(Platform::DSi_NANDPath), "r+b");
+ if (!nand)
+ {
+ printf("Failed to open DSi NAND\n");
+ return false;
+ }
+
+ if (!DSi_NAND::Init(nand, &DSi::ARM7iBIOS[0x8308]))
{
printf("Failed to load DSi NAND\n");
return false;
@@ -676,8 +732,8 @@ bool LoadNAND()
memset(NWRAMMask, 0, sizeof(NWRAMMask));
u32 bootparams[8];
- fseek(SDMMCFile, 0x220, SEEK_SET);
- fread(bootparams, 4, 8, SDMMCFile);
+ fseek(nand, 0x220, SEEK_SET);
+ fread(bootparams, 4, 8, nand);
printf("ARM9: offset=%08X size=%08X RAM=%08X size_aligned=%08X\n",
bootparams[0], bootparams[1], bootparams[2], bootparams[3]);
@@ -690,8 +746,8 @@ bool LoadNAND()
MBK[1][8] = 0;
u32 mbk[12];
- fseek(SDMMCFile, 0x380, SEEK_SET);
- fread(mbk, 4, 12, SDMMCFile);
+ fseek(nand, 0x380, SEEK_SET);
+ fread(mbk, 4, 12, nand);
MapNWRAM_A(0, mbk[0] & 0xFF);
MapNWRAM_A(1, (mbk[0] >> 8) & 0xFF);
@@ -745,12 +801,12 @@ bool LoadNAND()
AES_init_ctx_iv(&ctx, boot2key, boot2iv);
- fseek(SDMMCFile, bootparams[0], SEEK_SET);
+ fseek(nand, bootparams[0], SEEK_SET);
dstaddr = bootparams[2];
for (u32 i = 0; i < bootparams[3]; i += 16)
{
u8 data[16];
- fread(data, 16, 1, SDMMCFile);
+ fread(data, 16, 1, nand);
for (int j = 0; j < 16; j++) tmp[j] = data[15-j];
AES_CTR_xcrypt_buffer(&ctx, tmp, 16);
@@ -770,12 +826,12 @@ bool LoadNAND()
AES_init_ctx_iv(&ctx, boot2key, boot2iv);
- fseek(SDMMCFile, bootparams[4], SEEK_SET);
+ fseek(nand, bootparams[4], SEEK_SET);
dstaddr = bootparams[6];
for (u32 i = 0; i < bootparams[7]; i += 16)
{
u8 data[16];
- fread(data, 16, 1, SDMMCFile);
+ fread(data, 16, 1, nand);
for (int j = 0; j < 16; j++) tmp[j] = data[15-j];
AES_CTR_xcrypt_buffer(&ctx, tmp, 16);
@@ -787,11 +843,6 @@ bool LoadNAND()
ARM7Write32(dstaddr, *(u32*)&data[12]); dstaddr += 4;
}
- // repoint the CPUs to the boot2 binaries
-
- BootAddr[0] = bootparams[2];
- BootAddr[1] = bootparams[6];
-
#define printhex(str, size) { for (int z = 0; z < (size); z++) printf("%02X", (str)[z]); printf("\n"); }
#define printhex_rev(str, size) { for (int z = (size)-1; z >= 0; z--) printf("%02X", (str)[z]); printf("\n"); }
@@ -800,18 +851,36 @@ bool LoadNAND()
printf("eMMC CID: "); printhex(eMMC_CID, 16);
printf("Console ID: %" PRIx64 "\n", ConsoleID);
- memset(ITCMInit, 0, 0x8000);
- memcpy(&ITCMInit[0x4400], &ARM9iBIOS[0x87F4], 0x400);
- memcpy(&ITCMInit[0x4800], &ARM9iBIOS[0x9920], 0x80);
- memcpy(&ITCMInit[0x4894], &ARM9iBIOS[0x99A0], 0x1048);
- memcpy(&ITCMInit[0x58DC], &ARM9iBIOS[0xA9E8], 0x1048);
+ u32 eaddr = 0x03FFE6E4;
+ ARM7Write32(eaddr+0x00, *(u32*)&eMMC_CID[0]);
+ ARM7Write32(eaddr+0x04, *(u32*)&eMMC_CID[4]);
+ ARM7Write32(eaddr+0x08, *(u32*)&eMMC_CID[8]);
+ ARM7Write32(eaddr+0x0C, *(u32*)&eMMC_CID[12]);
+ ARM7Write16(eaddr+0x2C, 0x0001);
+ ARM7Write16(eaddr+0x2E, 0x0001);
+ ARM7Write16(eaddr+0x3C, 0x0100);
+ ARM7Write16(eaddr+0x3E, 0x40E0);
+ ARM7Write16(eaddr+0x42, 0x0001);
+
+ memcpy(&NDS::ARM9->ITCM[0x4400], &ARM9iBIOS[0x87F4], 0x400);
+ memcpy(&NDS::ARM9->ITCM[0x4800], &ARM9iBIOS[0x9920], 0x80);
+ memcpy(&NDS::ARM9->ITCM[0x4894], &ARM9iBIOS[0x99A0], 0x1048);
+ memcpy(&NDS::ARM9->ITCM[0x58DC], &ARM9iBIOS[0xA9E8], 0x1048);
+ u8 ARM7Init[0x3C00];
memset(ARM7Init, 0, 0x3C00);
memcpy(&ARM7Init[0x0000], &ARM7iBIOS[0x8188], 0x200);
memcpy(&ARM7Init[0x0200], &ARM7iBIOS[0xB5D8], 0x40);
memcpy(&ARM7Init[0x0254], &ARM7iBIOS[0xC6D0], 0x1048);
memcpy(&ARM7Init[0x129C], &ARM7iBIOS[0xD718], 0x1048);
+ for (u32 i = 0; i < 0x3C00; i+=4)
+ ARM7Write32(0x03FFC400+i, *(u32*)&ARM7Init[i]);
+
+ // repoint the CPUs to the boot2 binaries
+ NDS::ARM9->JumpTo(bootparams[2]);
+ NDS::ARM7->JumpTo(bootparams[6]);
+
DSi_NAND::PatchUserData();
DSi_NAND::DeInit();
@@ -819,12 +888,6 @@ bool LoadNAND()
return true;
}
-void CloseDSiNAND()
-{
- if (DSi::SDMMCFile)
- fclose(DSi::SDMMCFile);
- DSi::SDMMCFile = nullptr;
-}
void RunNDMAs(u32 cpu)
{
diff --git a/src/DSi.h b/src/DSi.h
index 1236527..93f46eb 100644
--- a/src/DSi.h
+++ b/src/DSi.h
@@ -39,8 +39,6 @@ extern u64 ConsoleID;
extern DSi_SDHost* SDMMC;
extern DSi_SDHost* SDIO;
-extern FILE* SDMMCFile;
-
const u32 NWRAMSize = 0x40000;
extern u8* NWRAM_A;
@@ -59,14 +57,14 @@ bool Init();
void DeInit();
void Reset();
+void DoSavestate(Savestate* file);
+
void SetupDirectBoot();
void SoftReset();
bool LoadBIOS();
bool LoadNAND();
-void CloseDSiNAND();
-
void RunNDMAs(u32 cpu);
void StallNDMAs();
bool NDMAsInMode(u32 cpu, u32 mode);
diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp
index 02e4f1c..ec7b0e6 100644
--- a/src/DSi_AES.cpp
+++ b/src/DSi_AES.cpp
@@ -155,6 +155,43 @@ void Reset()
*(u32*)&KeyY[3][8] = 0x202DDD1D;
}
+void DoSavestate(Savestate* file)
+{
+ file->Section("AESi");
+
+ file->Var32(&Cnt);
+
+ file->Var32(&BlkCnt);
+ file->Var32(&RemExtra);
+ file->Var32(&RemBlocks);
+
+ file->Bool32(&OutputFlush);
+
+ file->Var32(&InputDMASize);
+ file->Var32(&OutputDMASize);
+ file->Var32(&AESMode);
+
+ InputFIFO.DoSavestate(file);
+ OutputFIFO.DoSavestate(file);
+
+ file->VarArray(IV, 16);
+
+ file->VarArray(MAC, 16);
+
+ file->VarArray(KeyNormal, 4*16);
+ file->VarArray(KeyX, 4*16);
+ file->VarArray(KeyY, 4*16);
+
+ file->VarArray(CurKey, 16);
+ file->VarArray(CurMAC, 16);
+
+ file->VarArray(OutputMAC, 16);
+ file->Bool32(&OutputMACDue);
+
+ file->VarArray(Ctx.RoundKey, AES_keyExpSize);
+ file->VarArray(Ctx.Iv, AES_BLOCKLEN);
+}
+
void ProcessBlock_CCM_Extra()
{
diff --git a/src/DSi_AES.h b/src/DSi_AES.h
index 27f8e64..021879e 100644
--- a/src/DSi_AES.h
+++ b/src/DSi_AES.h
@@ -30,6 +30,8 @@ bool Init();
void DeInit();
void Reset();
+void DoSavestate(Savestate* file);
+
u32 ReadCnt();
void WriteCnt(u32 val);
void WriteBlkCnt(u32 val);
diff --git a/src/DSi_Camera.cpp b/src/DSi_Camera.cpp
index d8cc335..10acdca 100644
--- a/src/DSi_Camera.cpp
+++ b/src/DSi_Camera.cpp
@@ -70,6 +70,21 @@ void DSi_Camera::Reset()
NDS::ScheduleEvent(NDS::Event_DSi_CamIRQ, true, kIRQInterval, IRQ, 0);
}
+void DSi_Camera::DoSavestate(Savestate* file)
+{
+ file->Section("CAMi");
+
+ file->Var16(&ModuleCnt);
+ file->Var16(&Cnt);
+
+ file->VarArray(FrameBuffer, sizeof(FrameBuffer));
+ file->Var32(&TransferPos);
+ file->Var32(&FrameLength);
+
+ DSi_Camera0->DoCamSavestate(file);
+ DSi_Camera1->DoCamSavestate(file);
+}
+
void DSi_Camera::IRQ(u32 param)
{
@@ -150,7 +165,29 @@ DSi_Camera::DSi_Camera(u32 num)
DSi_Camera::~DSi_Camera()
{
- //
+}
+
+void DSi_Camera::DoCamSavestate(Savestate* file)
+{
+ char magic[5] = "CAMx";
+ magic[3] = '0' + Num;
+ file->Section(magic);
+
+ file->Var32(&DataPos);
+ file->Var32(&RegAddr);
+ file->Var16(&RegData);
+
+ file->Var16(&PLLDiv);
+ file->Var16(&PLLPDiv);
+ file->Var16(&PLLCnt);
+ file->Var16(&ClocksCnt);
+ file->Var16(&StandbyCnt);
+ file->Var16(&MiscCnt);
+
+ file->Var16(&MCUAddr);
+ // TODO: MCUData??
+
+ file->VarArray(MCURegs, 0x8000);
}
void DSi_Camera::ResetCam()
diff --git a/src/DSi_Camera.h b/src/DSi_Camera.h
index 3f39e3a..5dc037d 100644
--- a/src/DSi_Camera.h
+++ b/src/DSi_Camera.h
@@ -28,6 +28,8 @@ public:
static void DeInit();
static void Reset();
+ static void DoSavestate(Savestate* file);
+
static void IRQ(u32 param);
static void RequestFrame(u32 cam);
@@ -36,6 +38,8 @@ public:
DSi_Camera(u32 num);
~DSi_Camera();
+ void DoCamSavestate(Savestate* file);
+
void ResetCam();
bool IsActivated();
diff --git a/src/DSi_DSP.cpp b/src/DSi_DSP.cpp
index 328f01d..c889aff 100644
--- a/src/DSi_DSP.cpp
+++ b/src/DSi_DSP.cpp
@@ -587,6 +587,8 @@ void DoSavestate(Savestate* file)
file->Var16(&DSP_REP[1]);
file->Var16(&DSP_REP[2]);
file->Var8((u8*)&SCFG_RST);
+
+ // TODO: save the Teakra state!!!
}
}
diff --git a/src/DSi_DSP.h b/src/DSi_DSP.h
index f5264b4..ade88ba 100644
--- a/src/DSi_DSP.h
+++ b/src/DSi_DSP.h
@@ -41,10 +41,10 @@ bool Init();
void DeInit();
void Reset();
-// TODO: needs to be called!
-// however, no DSi savestate stuff seems to be actually implemented?!
void DoSavestate(Savestate* file);
+void DSPCatchUpU32(u32 _);
+
// SCFG_RST bit0
bool IsRstReleased();
void SetRstLine(bool release);
diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp
index 6f5f2e5..9e865b1 100644
--- a/src/DSi_I2C.cpp
+++ b/src/DSi_I2C.cpp
@@ -72,6 +72,14 @@ void Reset()
Registers[0x81] = 0x64;
}
+void DoSavestate(Savestate* file)
+{
+ file->Section("I2BP");
+
+ file->VarArray(Registers, 0x100);
+ file->Var32(&CurPos);
+}
+
u8 GetBootFlag() { return Registers[0x70]; }
void Start()
@@ -169,6 +177,18 @@ void Reset()
DSi_Camera::Reset();
}
+void DoSavestate(Savestate* file)
+{
+ file->Section("I2Ci");
+
+ file->Var8(&Cnt);
+ file->Var8(&Data);
+ file->Var32(&Device);
+
+ DSi_BPTWL::DoSavestate(file);
+ // cameras are savestated from the DSi_Camera module
+}
+
void WriteCnt(u8 val)
{
//printf("I2C: write CNT %02X, %08X\n", val, NDS::GetPC(1));
diff --git a/src/DSi_I2C.h b/src/DSi_I2C.h
index c064366..5531399 100644
--- a/src/DSi_I2C.h
+++ b/src/DSi_I2C.h
@@ -34,7 +34,7 @@ extern u8 Cnt;
bool Init();
void DeInit();
void Reset();
-//void DoSavestate(Savestate* file);
+void DoSavestate(Savestate* file);
void WriteCnt(u8 val);
diff --git a/src/DSi_NDMA.cpp b/src/DSi_NDMA.cpp
index 37d5018..1c3b94a 100644
--- a/src/DSi_NDMA.cpp
+++ b/src/DSi_NDMA.cpp
@@ -63,7 +63,31 @@ void DSi_NDMA::Reset()
void DSi_NDMA::DoSavestate(Savestate* file)
{
- // TODO!
+ char magic[5] = "NDMx";
+ magic[3] = '0' + Num + (CPU*4);
+ file->Section(magic);
+
+ file->Var32(&SrcAddr);
+ file->Var32(&DstAddr);
+ file->Var32(&TotalLength);
+ file->Var32(&BlockLength);
+ file->Var32(&SubblockTimer);
+ file->Var32(&FillData);
+ file->Var32(&Cnt);
+
+ file->Var32(&StartMode);
+ file->Var32(&CurSrcAddr);
+ file->Var32(&CurDstAddr);
+ file->Var32(&SubblockLength);
+ file->Var32(&RemCount);
+ file->Var32(&IterCount);
+ file->Var32(&TotalRemCount);
+ file->Var32(&SrcAddrInc);
+ file->Var32(&DstAddrInc);
+
+ file->Var32(&Running);
+ file->Bool32(&InProgress);
+ file->Bool32(&IsGXFIFODMA);
}
void DSi_NDMA::WriteCnt(u32 val)
diff --git a/src/DSi_NWifi.cpp b/src/DSi_NWifi.cpp
index 57bd93c..fde48ec 100644
--- a/src/DSi_NWifi.cpp
+++ b/src/DSi_NWifi.cpp
@@ -223,6 +223,45 @@ void DSi_NWifi::Reset()
NDS::CancelEvent(NDS::Event_DSi_NWifi);
}
+void DSi_NWifi::DoSavestate(Savestate* file)
+{
+ file->Section("NWFi");
+
+ for (int i = 0; i < 9; i++)
+ Mailbox[i].DoSavestate(file);
+
+ file->Var8(&F0_IRQEnable);
+ file->Var8(&F0_IRQStatus);
+
+ file->Var8(&F1_IRQEnable);
+ file->Var8(&F1_IRQEnable_CPU);
+ file->Var8(&F1_IRQEnable_Error);
+ file->Var8(&F1_IRQEnable_Counter);
+ file->Var8(&F1_IRQStatus);
+ file->Var8(&F1_IRQStatus_CPU);
+ file->Var8(&F1_IRQStatus_Error);
+ file->Var8(&F1_IRQStatus_Counter);
+
+ file->Var32(&WindowData);
+ file->Var32(&WindowReadAddr);
+ file->Var32(&WindowWriteAddr);
+
+ file->Var32(&ROMID);
+ file->Var32(&ChipID);
+ file->Var32(&HostIntAddr);
+
+ file->VarArray(EEPROM, 0x400);
+ file->Var32(&EEPROMReady);
+
+ file->Var32(&BootPhase);
+
+ file->Var32(&ErrorMask);
+ file->Var32(&ScanTimer);
+
+ file->Var64(&BeaconTimer);
+ file->Var32(&ConnectionStatus);
+}
+
// CHECKME
// can IRQ status bits be set when the corresponding IRQs are disabled in the enable register?
diff --git a/src/DSi_NWifi.h b/src/DSi_NWifi.h
index da6597d..ef337fc 100644
--- a/src/DSi_NWifi.h
+++ b/src/DSi_NWifi.h
@@ -30,6 +30,8 @@ public:
void Reset();
+ void DoSavestate(Savestate* file);
+
void SendCMD(u8 cmd, u32 param);
void SendACMD(u8 cmd, u32 param);
diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp
index 4c2b085..6c5979b 100644
--- a/src/DSi_SD.cpp
+++ b/src/DSi_SD.cpp
@@ -51,8 +51,8 @@ DSi_SDHost::DSi_SDHost(u32 num)
{
Num = num;
- Ports[0] = NULL;
- Ports[1] = NULL;
+ Ports[0] = nullptr;
+ Ports[1] = nullptr;
}
DSi_SDHost::~DSi_SDHost()
@@ -61,6 +61,14 @@ DSi_SDHost::~DSi_SDHost()
if (Ports[1]) delete Ports[1];
}
+void DSi_SDHost::CloseHandles()
+{
+ if (Ports[0]) delete Ports[0];
+ if (Ports[1]) delete Ports[1];
+ Ports[0] = nullptr;
+ Ports[1] = nullptr;
+}
+
void DSi_SDHost::Reset()
{
if (Num == 0)
@@ -101,10 +109,7 @@ void DSi_SDHost::Reset()
TXReq = false;
- if (Ports[0]) delete Ports[0];
- if (Ports[1]) delete Ports[1];
- Ports[0] = nullptr;
- Ports[1] = nullptr;
+ CloseHandles();
if (Num == 0)
{
@@ -131,7 +136,7 @@ void DSi_SDHost::Reset()
else
sd = nullptr;
- mmc = new DSi_MMCStorage(this, true, DSi::SDMMCFile);
+ mmc = new DSi_MMCStorage(this, true, Platform::GetConfigString(Platform::DSi_NANDPath));
mmc->SetCID(DSi::eMMC_CID);
Ports[0] = sd;
@@ -150,7 +155,41 @@ void DSi_SDHost::Reset()
void DSi_SDHost::DoSavestate(Savestate* file)
{
- // TODO!
+ file->Section(Num ? "SDIO" : "SDMM");
+
+ file->Var16(&PortSelect);
+ file->Var16(&SoftReset);
+ file->Var16(&SDClock);
+ file->Var16(&SDOption);
+
+ file->Var32(&IRQStatus);
+ file->Var32(&IRQMask);
+
+ file->Var16(&CardIRQStatus);
+ file->Var16(&CardIRQMask);
+ file->Var16(&CardIRQCtl);
+
+ file->Var16(&DataCtl);
+ file->Var16(&Data32IRQ);
+ file->Var32(&DataMode);
+ file->Var16(&BlockCount16);
+ file->Var16(&BlockCount32);
+ file->Var16(&BlockCountInternal);
+ file->Var16(&BlockLen16);
+ file->Var16(&BlockLen32);
+ file->Var16(&StopAction);
+
+ file->Var16(&Command);
+ file->Var32(&Param);
+ file->VarArray(ResponseBuffer, 8);
+
+ file->Var32(&CurFIFO);
+ DataFIFO[0].DoSavestate(file);
+ DataFIFO[1].DoSavestate(file);
+ DataFIFO32.DoSavestate(file);
+
+ if (Ports[0]) Ports[0]->DoSavestate(file);
+ if (Ports[1]) Ports[1]->DoSavestate(file);
}
@@ -727,12 +766,15 @@ void DSi_SDHost::CheckSwapFIFO()
#define MMC_DESC (Internal?"NAND":"SDcard")
-DSi_MMCStorage::DSi_MMCStorage(DSi_SDHost* host, bool internal, FILE* file)
+DSi_MMCStorage::DSi_MMCStorage(DSi_SDHost* host, bool internal, std::string filename)
: DSi_SDDevice(host)
{
Internal = internal;
- File = file;
+ File = Platform::OpenLocalFile(filename, "r+b");
+
SD = nullptr;
+
+ ReadOnly = false;
}
DSi_MMCStorage::DSi_MMCStorage(DSi_SDHost* host, bool internal, std::string filename, u64 size, bool readonly, std::string sourcedir)
@@ -754,6 +796,10 @@ DSi_MMCStorage::~DSi_MMCStorage()
SD->Close();
delete SD;
}
+ if (File)
+ {
+ fclose(File);
+ }
}
void DSi_MMCStorage::Reset()
@@ -781,6 +827,26 @@ void DSi_MMCStorage::Reset()
RWCommand = 0;
}
+void DSi_MMCStorage::DoSavestate(Savestate* file)
+{
+ file->Section(Internal ? "NAND" : "SDCR");
+
+ file->VarArray(CID, 16);
+ file->VarArray(CSD, 16);
+
+ file->Var32(&CSR);
+ file->Var32(&OCR);
+ file->Var32(&RCA);
+ file->VarArray(SCR, 8);
+ file->VarArray(SSR, 64);
+
+ file->Var32(&BlockSize);
+ file->Var64(&RWAddress);
+ file->Var32(&RWCommand);
+
+ // TODO: what about the file contents?
+}
+
void DSi_MMCStorage::SendCMD(u8 cmd, u32 param)
{
if (CSR & (1<<5))
diff --git a/src/DSi_SD.h b/src/DSi_SD.h
index 1c0f7ce..2e63a63 100644
--- a/src/DSi_SD.h
+++ b/src/DSi_SD.h
@@ -33,6 +33,7 @@ public:
DSi_SDHost(u32 num);
~DSi_SDHost();
+ void CloseHandles();
void Reset();
void DoSavestate(Savestate* file);
@@ -108,6 +109,8 @@ public:
virtual void Reset() = 0;
+ virtual void DoSavestate(Savestate* file) = 0;
+
virtual void SendCMD(u8 cmd, u32 param) = 0;
virtual void ContinueTransfer() = 0;
@@ -122,12 +125,14 @@ protected:
class DSi_MMCStorage : public DSi_SDDevice
{
public:
- DSi_MMCStorage(DSi_SDHost* host, bool internal, FILE* file);
+ DSi_MMCStorage(DSi_SDHost* host, bool internal, std::string filename);
DSi_MMCStorage(DSi_SDHost* host, bool internal, std::string filename, u64 size, bool readonly, std::string sourcedir);
~DSi_MMCStorage();
void Reset();
+ void DoSavestate(Savestate* file);
+
void SetCID(u8* cid) { memcpy(CID, cid, 16); }
void SendCMD(u8 cmd, u32 param);
diff --git a/src/DSi_SPI_TSC.cpp b/src/DSi_SPI_TSC.cpp
index 061feb1..134d9de 100644
--- a/src/DSi_SPI_TSC.cpp
+++ b/src/DSi_SPI_TSC.cpp
@@ -71,14 +71,15 @@ void Reset()
void DoSavestate(Savestate* file)
{
- /*file->Section("SPTi");
+ file->Section("SPTi");
file->Var32(&DataPos);
- file->Var8(&ControlByte);
+ file->Var8(&Index);
+ file->Var8(&Bank);
file->Var8(&Data);
- file->Var16(&ConvResult);*/
- // TODO!!
+ file->VarArray(Bank3Regs, 0x80);
+ file->Var8(&TSCMode);
}
void SetMode(u8 mode)
diff --git a/src/GBACart.cpp b/src/GBACart.cpp
index e5b6e4f..ca092f4 100644
--- a/src/GBACart.cpp
+++ b/src/GBACart.cpp
@@ -18,6 +18,7 @@
#include <stdio.h>
#include <string.h>
+#include "NDS.h"
#include "GBACart.h"
#include "CRC32.h"
#include "Platform.h"
@@ -42,7 +43,6 @@ const char SOLAR_SENSOR_GAMECODES[10][5] =
bool CartInserted;
u8* CartROM;
u32 CartROMSize;
-u32 CartCRC;
u32 CartID;
CartCommon* Cart;
@@ -58,16 +58,20 @@ CartCommon::~CartCommon()
{
}
+void CartCommon::Reset()
+{
+}
+
void CartCommon::DoSavestate(Savestate* file)
{
file->Section("GBCS");
}
-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)
{
}
@@ -99,22 +103,32 @@ CartGame::CartGame(u8* rom, u32 len) : CartCommon()
{
ROM = rom;
ROMLength = len;
+}
+
+CartGame::~CartGame()
+{
+ if (SRAM) delete[] SRAM;
+}
+
+u32 CartGame::Checksum()
+{
+ u32 crc = CRC32(ROM, 0xC0, 0);
+ // TODO: hash more contents?
+
+ return crc;
+}
+
+void CartGame::Reset()
+{
memset(&GPIO, 0, sizeof(GPIO));
SRAM = nullptr;
- SRAMFile = nullptr;
SRAMLength = 0;
SRAMType = S_NULL;
SRAMFlashState = {};
}
-CartGame::~CartGame()
-{
- if (SRAMFile) fclose(SRAMFile);
- if (SRAM) delete[] SRAM;
-}
-
void CartGame::DoSavestate(Savestate* file)
{
CartCommon::DoSavestate(file);
@@ -123,8 +137,6 @@ void CartGame::DoSavestate(Savestate* file)
file->Var16(&GPIO.data);
file->Var16(&GPIO.direction);
- // logic mostly copied from NDSCart_SRAM
-
u32 oldlen = SRAMLength;
file->Var32(&SRAMLength);
@@ -133,6 +145,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 +157,7 @@ void CartGame::DoSavestate(Savestate* file)
{
// no save data, clear the current state
SRAMType = SaveType::S_NULL;
- if (SRAMFile) fclose(SRAMFile);
SRAM = nullptr;
- SRAMFile = nullptr;
return;
}
@@ -158,27 +169,24 @@ void CartGame::DoSavestate(Savestate* file)
file->Var8(&SRAMFlashState.state);
file->Var8((u8*)&SRAMType);
+
+ if ((!file->Saving) && SRAM)
+ Platform::WriteGBASave(SRAM, SRAMLength, 0, SRAMLength);
}
-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,26 +227,13 @@ 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 (!write)
- {
- LoadSave(path, 0); // lazy
- return;
- }
-
- strncpy(SRAMPath, path, 1023);
- SRAMPath[1023] = '\0';
+ if (!SRAM) return;
- FILE *f = Platform::OpenFile(path, "r+b");
- if (!f)
- {
- printf("GBACart_SRAM::RelocateSave: failed to create new file. fuck\n");
- return;
- }
-
- SRAMFile = f;
- fwrite(SRAM, SRAMLength, 1, SRAMFile);
+ u32 len = std::min(savelen, SRAMLength);
+ memcpy(SRAM, savedata, len);
+ Platform::WriteGBASave(savedata, len, 0, len);
}
u16 CartGame::ROMRead(u32 addr)
@@ -469,11 +464,7 @@ void CartGame::SRAMWrite_FLASH(u32 addr, u8 val)
u32 start_addr = addr + 0x10000 * SRAMFlashState.bank;
memset((u8*)&SRAM[start_addr], 0xFF, 0x1000);
- if (SRAMFile)
- {
- fseek(SRAMFile, start_addr, SEEK_SET);
- fwrite((u8*)&SRAM[start_addr], 1, 0x1000, SRAMFile);
- }
+ Platform::WriteGBASave(SRAM, SRAMLength, start_addr, 0x1000);
}
SRAMFlashState.state = 0;
SRAMFlashState.cmd = 0;
@@ -531,11 +522,8 @@ void CartGame::SRAMWrite_SRAM(u32 addr, u8 val)
{
*(u8*)&SRAM[addr] = val;
- if (SRAMFile)
- {
- fseek(SRAMFile, addr, SEEK_SET);
- fwrite((u8*)&SRAM[addr], 1, 1, SRAMFile);
- }
+ // TODO: optimize this!!
+ Platform::WriteGBASave(SRAM, SRAMLength, addr, 1);
}
}
@@ -544,16 +532,20 @@ const int CartGameSolarSensor::kLuxLevels[11] = {0, 5, 11, 18, 27, 42, 62, 84, 1
CartGameSolarSensor::CartGameSolarSensor(u8* rom, u32 len) : CartGame(rom, len)
{
- LightEdge = false;
- LightCounter = 0;
- LightSample = 0xFF;
- LightLevel = 0;
}
CartGameSolarSensor::~CartGameSolarSensor()
{
}
+void CartGameSolarSensor::Reset()
+{
+ LightEdge = false;
+ LightCounter = 0;
+ LightSample = 0xFF;
+ LightLevel = 0;
+}
+
void CartGameSolarSensor::DoSavestate(Savestate* file)
{
CartGame::DoSavestate(file);
@@ -608,104 +600,163 @@ void CartGameSolarSensor::ProcessGPIO()
}
-bool Init()
+CartRAMExpansion::CartRAMExpansion() : CartCommon()
{
- CartROM = nullptr;
+}
- Cart = nullptr;
+CartRAMExpansion::~CartRAMExpansion()
+{
+}
- return true;
+void CartRAMExpansion::Reset()
+{
+ memset(RAM, 0xFF, sizeof(RAM));
+ RAMEnable = 1;
}
-void DeInit()
+void CartRAMExpansion::DoSavestate(Savestate* file)
{
- if (CartROM) delete[] CartROM;
+ CartCommon::DoSavestate(file);
- if (Cart) delete Cart;
+ file->VarArray(RAM, sizeof(RAM));
+ file->Var16(&RAMEnable);
}
-void Reset()
+u16 CartRAMExpansion::ROMRead(u32 addr)
{
- // Do not reset cartridge ROM.
- // Prefer keeping the inserted cartridge on reset.
- // This allows resetting a DS game without losing GBA state,
- // and resetting to firmware without the slot being emptied.
- // The Stop function will clear the cartridge state via Eject().
+ addr &= 0x01FFFFFF;
+
+ if (addr < 0x01000000)
+ {
+ switch (addr)
+ {
+ case 0xB0: return 0xFFFF;
+ case 0xB2: return 0x0000;
+ case 0xB4: return 0x2400;
+ case 0xB6: return 0x2424;
+ case 0xB8: return 0xFFFF;
+ case 0xBA: return 0xFFFF;
+ case 0xBC: return 0xFFFF;
+ case 0xBE: return 0x7FFF;
+
+ case 0x1FFFC: return 0xFFFF;
+ case 0x1FFFE: return 0x7FFF;
+
+ case 0x240000: return RAMEnable;
+ case 0x240002: return 0x0000;
+ }
+
+ return 0xFFFF;
+ }
+ else if (addr < 0x01800000)
+ {
+ if (!RAMEnable) return 0xFFFF;
+
+ return *(u16*)&RAM[addr & 0x7FFFFF];
+ }
- // OpenBusDecay doesn't need to be reset, either, as it will be set
- // through NDS::SetGBASlotTimings().
+ return 0xFFFF;
}
-void Eject()
+void CartRAMExpansion::ROMWrite(u32 addr, u16 val)
{
- if (CartROM) delete[] CartROM;
+ addr &= 0x01FFFFFF;
- CartInserted = false;
- CartROM = NULL;
- CartROMSize = 0;
- CartCRC = 0;
- CartID = 0;
+ if (addr < 0x01000000)
+ {
+ switch (addr)
+ {
+ case 0x240000:
+ RAMEnable = val & 0x0001;
+ return;
+ }
+ }
+ else if (addr < 0x01800000)
+ {
+ if (!RAMEnable) return;
+
+ *(u16*)&RAM[addr & 0x7FFFFF] = val;
+ }
+}
+
+
+bool Init()
+{
+ CartROM = nullptr;
- if (Cart) delete Cart;
Cart = nullptr;
- Reset();
+ return true;
+}
+
+void DeInit()
+{
+ if (CartROM) delete[] CartROM;
+
+ if (Cart) delete Cart;
+}
+
+void Reset()
+{
+ if (Cart) Cart->Reset();
}
void DoSavestate(Savestate* file)
{
file->Section("GBAC"); // Game Boy Advance Cartridge
- // logic mostly copied from NDSCart
-
- // first we need to reload the cart itself,
- // since unlike with DS, it's not loaded in advance
+ // little state here
+ // no need to save OpenBusDecay, it will be set later
- file->Var32(&CartROMSize);
- if (!CartROMSize) // no GBA cartridge state? nothing to do here
+ u32 carttype = 0;
+ u32 cartchk = 0;
+ if (Cart)
{
- // do eject the cartridge if something is inserted
- Eject();
- return;
+ carttype = Cart->Type();
+ cartchk = Cart->Checksum();
}
- u32 oldCRC = CartCRC;
- file->Var32(&CartCRC);
-
- if (CartCRC != oldCRC)
+ if (file->Saving)
{
- // delete and reallocate ROM so that it is zero-padded to its full length
- if (CartROM) delete[] CartROM;
- CartROM = new u8[CartROMSize];
+ file->Var32(&carttype);
+ file->Var32(&cartchk);
}
+ else
+ {
+ u32 savetype;
+ file->Var32(&savetype);
+ if (savetype != carttype) return;
- // only save/load the cartridge header
- //
- // GBA connectivity on DS mainly involves identifying the title currently
- // inserted, reading save data, and issuing commands intercepted here
- // (e.g. solar sensor signals). we don't know of any case where GBA ROM is
- // read directly from DS software. therefore, it is more practical, both
- // from the development and user experience perspectives, to avoid dealing
- // with file dependencies, and store a small portion of ROM data that should
- // satisfy the needs of all known software that reads from the GBA slot.
- //
- // note: in case of a state load, only the cartridge header is restored, but
- // the rest of the ROM data is only cleared (zero-initialized) if the CRC
- // differs. Therefore, loading the GBA cartridge associated with the save state
- // in advance will maintain access to the full ROM contents.
- file->VarArray(CartROM, 192);
-
- CartInserted = true; // known, because CartROMSize > 0
- file->Var32(&CartCRC);
- file->Var32(&CartID);
-
- // now do the rest
+ u32 savechk;
+ file->Var32(&savechk);
+ if (savechk != cartchk) return;
+ }
if (Cart) Cart->DoSavestate(file);
}
-void LoadROMCommon(const char *sram)
+bool LoadROM(const u8* romdata, u32 romlen)
{
+ if (CartInserted)
+ EjectCart();
+
+ 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);
@@ -722,9 +773,6 @@ void LoadROMCommon(const char *sram)
printf("GBA solar sensor support detected!\n");
}
- CartCRC = CRC32(CartROM, CartROMSize);
- printf("GBA ROM CRC32: %08X\n", CartCRC);
-
CartInserted = true;
if (solarsensor)
@@ -732,61 +780,61 @@ void LoadROMCommon(const char *sram)
else
Cart = new CartGame(CartROM, CartROMSize);
+ if (Cart)
+ Cart->Reset();
+
// 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)
{
- FILE* f = Platform::OpenFile(path, "rb");
- if (!f)
+ if (Cart)
{
- return false;
- }
+ // gross hack
+ Cart->SetupSave(savelen);
- if (CartInserted)
- {
- Reset();
+ Cart->LoadSave(savedata, savelen);
}
-
- fseek(f, 0, SEEK_END);
- u32 len = (u32)ftell(f);
-
- CartROMSize = 0x200;
- while (CartROMSize < len)
- CartROMSize <<= 1;
-
- CartROM = new u8[CartROMSize];
- memset(CartROM, 0, CartROMSize);
- fseek(f, 0, SEEK_SET);
- fread(CartROM, 1, len, f);
- fclose(f);
-
- LoadROMCommon(sram);
-
- return true;
}
-bool LoadROM(const u8* romdata, u32 filelength, const char *sram)
+void LoadAddon(int type)
{
- CartROMSize = 0x200;
- while (CartROMSize < filelength)
- CartROMSize <<= 1;
+ CartROMSize = 0;
+ CartROM = nullptr;
- CartROM = new u8[CartROMSize];
- memcpy(CartROM, romdata, filelength);
+ switch (type)
+ {
+ case NDS::GBAAddon_RAMExpansion:
+ Cart = new CartRAMExpansion();
+ break;
- LoadROMCommon(sram);
+ default:
+ printf("GBACart: !! invalid addon type %d\n", type);
+ return;
+ }
- return true;
+ CartInserted = true;
}
-void RelocateSave(const char* path, bool write)
+void EjectCart()
{
- if (Cart) Cart->RelocateSave(path, write);
+ if (Cart) delete Cart;
+ Cart = nullptr;
+
+ if (CartROM) delete[] CartROM;
+
+ CartInserted = false;
+ CartROM = nullptr;
+ CartROMSize = 0;
+ CartID = 0;
}
diff --git a/src/GBACart.h b/src/GBACart.h
index 8698e25..13c6100 100644
--- a/src/GBACart.h
+++ b/src/GBACart.h
@@ -32,10 +32,15 @@ public:
CartCommon();
virtual ~CartCommon();
+ virtual u32 Type() { return 0x001; }
+ virtual u32 Checksum() { return 0; }
+
+ virtual void Reset();
+
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 int SetInput(int num, bool pressed);
@@ -53,10 +58,15 @@ public:
CartGame(u8* rom, u32 len);
virtual ~CartGame() override;
+ virtual u32 Type() override { return 0x101; }
+ virtual u32 Checksum() override;
+
+ virtual void Reset() override;
+
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 u16 ROMRead(u32 addr) override;
virtual void ROMWrite(u32 addr, u16 val) override;
@@ -107,11 +117,8 @@ protected:
} SRAMFlashState;
u8* SRAM;
- FILE* SRAMFile;
u32 SRAMLength;
SaveType SRAMType;
-
- char SRAMPath[1024];
};
// CartGameSolarSensor -- Boktai game cart
@@ -121,6 +128,10 @@ public:
CartGameSolarSensor(u8* rom, u32 len);
virtual ~CartGameSolarSensor() override;
+ virtual u32 Type() override { return 0x102; }
+
+ virtual void Reset() override;
+
virtual void DoSavestate(Savestate* file) override;
virtual int SetInput(int num, bool pressed) override;
@@ -136,6 +147,27 @@ private:
u8 LightLevel;
};
+// CartRAMExpansion -- RAM expansion cart (DS browser, ...)
+class CartRAMExpansion : public CartCommon
+{
+public:
+ CartRAMExpansion();
+ ~CartRAMExpansion() override;
+
+ virtual u32 Type() override { return 0x201; }
+
+ void Reset() override;
+
+ void DoSavestate(Savestate* file) override;
+
+ u16 ROMRead(u32 addr) override;
+ void ROMWrite(u32 addr, u16 val) override;
+
+private:
+ u8 RAM[0x800000];
+ u16 RAMEnable;
+};
+
// possible inputs for GBA carts that might accept user input
enum
{
@@ -146,17 +178,23 @@ enum
extern bool CartInserted;
extern u8* CartROM;
extern u32 CartROMSize;
-extern u32 CartCRC;
bool Init();
void DeInit();
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);
+
+void LoadAddon(int type);
+
+void EjectCart();
+
+//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 e809313..b5c8ee9 100644
--- a/src/NDS.cpp
+++ b/src/NDS.cpp
@@ -32,7 +32,6 @@
#include "Wifi.h"
#include "AREngine.h"
#include "Platform.h"
-#include "NDSCart_SRAMManager.h"
#include "FreeBIOS.h"
#ifdef JIT_ENABLED
@@ -42,6 +41,9 @@
#include "DSi.h"
#include "DSi_SPI_TSC.h"
+#include "DSi_NWifi.h"
+#include "DSi_Camera.h"
+#include "DSi_DSP.h"
namespace NDS
@@ -200,7 +202,6 @@ bool Init()
DMAs[6] = new DMA(1, 2);
DMAs[7] = new DMA(1, 3);
- if (!NDSCart_SRAMManager::Init()) return false;
if (!NDSCart::Init()) return false;
if (!GBACart::Init()) return false;
if (!GPU::Init()) return false;
@@ -228,7 +229,6 @@ void DeInit()
for (int i = 0; i < 8; i++)
delete DMAs[i];
- NDSCart_SRAMManager::DeInit();
NDSCart::DeInit();
GBACart::DeInit();
GPU::DeInit();
@@ -353,7 +353,28 @@ void InitTimings()
// handled later: GBA slot, wifi
}
-void SetupDirectBoot()
+bool NeedsDirectBoot()
+{
+ if (ConsoleType == 1)
+ {
+ // for now, DSi mode requires original BIOS/NAND
+ return false;
+ }
+ else
+ {
+ // internal BIOS does not support direct boot
+ if (!Platform::GetConfigBool(Platform::ExternalBIOSEnable))
+ return true;
+
+ // DSi/3DS firmwares aren't bootable
+ if (SPI_Firmware::GetFirmwareLength() == 0x20000)
+ return true;
+
+ return false;
+ }
+}
+
+void SetupDirectBoot(std::string romname)
{
if (ConsoleType == 1)
{
@@ -444,6 +465,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;
@@ -542,7 +565,6 @@ void Reset()
if (ConsoleType == 1)
{
DSi::LoadBIOS();
- DSi::LoadNAND();
ARM9ClockShift = 2;
MainRAMMask = 0xFFFFFF;
@@ -658,6 +680,11 @@ void Reset()
AREngine::Reset();
}
+void Start()
+{
+ Running = true;
+}
+
void Stop()
{
printf("Stopping: shutdown\n");
@@ -692,7 +719,14 @@ bool DoSavestate_Scheduler(Savestate* file)
DivDone,
SqrtDone,
- NULL
+ DSi_SDHost::FinishRX,
+ DSi_SDHost::FinishTX,
+ DSi_NWifi::MSTimer,
+ DSi_Camera::IRQ,
+ DSi_Camera::Transfer,
+ DSi_DSP::DSPCatchUpU32,
+
+ nullptr
};
int len = Event_MAX;
@@ -702,7 +736,7 @@ bool DoSavestate_Scheduler(Savestate* file)
{
SchedEvent* evt = &SchedList[i];
- u32 funcid = -1;
+ u32 funcid = 0xFFFFFFFF;
if (evt->Func)
{
for (int j = 0; eventfuncs[j]; j++)
@@ -749,7 +783,7 @@ bool DoSavestate_Scheduler(Savestate* file)
evt->Func = eventfuncs[funcid];
}
else
- evt->Func = NULL;
+ evt->Func = nullptr;
file->Var64(&evt->Timestamp);
file->Var32(&evt->Param);
@@ -763,15 +797,26 @@ bool DoSavestate(Savestate* file)
{
file->Section("NDSG");
- // TODO:
- // * do something for bool's (sizeof=1)
- // * do something for 'loading DSi-mode savestate in DS mode' and vice-versa
- // * add IE2/IF2 there
+ if (file->Saving)
+ {
+ u32 console = ConsoleType;
+ file->Var32(&console);
+ }
+ else
+ {
+ u32 console;
+ file->Var32(&console);
+ if (console != ConsoleType)
+ return false;
+ }
- file->VarArray(MainRAM, 0x400000);
- file->VarArray(SharedWRAM, 0x8000);
+ file->VarArray(MainRAM, MainRAMMaxSize);
+ file->VarArray(SharedWRAM, SharedWRAMSize);
file->VarArray(ARM7WRAM, ARM7WRAMSize);
+ //file->VarArray(ARM9BIOS, 0x1000);
+ //file->VarArray(ARM7BIOS, 0x4000);
+
file->VarArray(ExMemCnt, 2*sizeof(u16));
file->VarArray(ROMSeed0, 2*8);
file->VarArray(ROMSeed1, 2*8);
@@ -781,6 +826,8 @@ bool DoSavestate(Savestate* file)
file->VarArray(IME, 2*sizeof(u32));
file->VarArray(IE, 2*sizeof(u32));
file->VarArray(IF, 2*sizeof(u32));
+ file->Var32(&IE2);
+ file->Var32(&IF2);
file->Var8(&PostFlag9);
file->Var8(&PostFlag7);
@@ -825,11 +872,8 @@ bool DoSavestate(Savestate* file)
file->Var64(&LastSysClockCycles);
file->Var64(&FrameStartTimestamp);
file->Var32(&NumFrames);
- if (file->IsAtleastVersion(7, 1))
- {
- file->Var32(&NumLagFrames);
- file->Bool32(&LagFrameFlag);
- }
+ file->Var32(&NumLagFrames);
+ file->Bool32(&LagFrameFlag);
// TODO: save KeyInput????
file->Var16(&KeyCnt);
@@ -860,13 +904,17 @@ bool DoSavestate(Savestate* file)
ARM7->DoSavestate(file);
NDSCart::DoSavestate(file);
- GBACart::DoSavestate(file);
+ if (ConsoleType == 0)
+ GBACart::DoSavestate(file);
GPU::DoSavestate(file);
SPU::DoSavestate(file);
SPI::DoSavestate(file);
RTC::DoSavestate(file);
Wifi::DoSavestate(file);
+ if (ConsoleType == 1)
+ DSi::DoSavestate(file);
+
if (!file->Saving)
{
GPU::SetPowerCnt(PowerControl9);
@@ -888,72 +936,58 @@ 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, filelength, sram, direct))
- {
- Running = true;
- return true;
- }
- else
- {
- printf("Failed to load ROM from archive\n");
+ if (!NDSCart::LoadROM(romdata, romlen))
return false;
- }
+
+ if (savedata && savelen)
+ NDSCart::LoadSave(savedata, savelen);
+
+ return true;
}
-bool LoadROM(const char* path, const char* sram, bool direct)
+void LoadSave(const u8* savedata, u32 savelen)
{
- if (NDSCart::LoadROM(path, sram, direct))
- {
- Running = true;
- return true;
- }
- else
- {
- printf("Failed to load ROM %s\n", path);
- return false;
- }
+ if (savedata && savelen)
+ NDSCart::LoadSave(savedata, savelen);
}
-bool LoadGBAROM(const char* path, const char* sram)
+void EjectCart()
{
- if (GBACart::LoadROM(path, sram))
- {
- return true;
- }
- else
- {
- printf("Failed to load ROM %s\n", path);
- return false;
- }
+ NDSCart::EjectCart();
}
-bool LoadGBAROM(const u8* romdata, u32 filelength, const char *filename, const char *sram)
+bool CartInserted()
{
- if (GBACart::LoadROM(romdata, filelength, sram))
- {
- return true;
- }
- else
- {
- printf("Failed to load ROM %s from archive\n", filename);
+ return NDSCart::CartInserted;
+}
+
+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);
+
+ return true;
}
-void LoadBIOS()
+void LoadGBAAddon(int type)
{
- Reset();
- Running = true;
+ GBACart::LoadAddon(type);
}
-void RelocateSave(const char* path, bool write)
+void EjectGBACart()
{
- printf("SRAM: relocating to %s (write=%s)\n", path, write?"true":"false");
- NDSCart::RelocateSave(path, write);
+ GBACart::EjectCart();
}
+void LoadBIOS()
+{
+ Reset();
+}
u64 NextTarget()
@@ -1094,8 +1128,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,
@@ -1234,10 +1266,10 @@ void MicInputFrame(s16* data, int samples)
return SPI_TSC::MicInputFrame(data, samples);
}
-int ImportSRAM(u8* data, u32 length)
+/*int ImportSRAM(u8* data, u32 length)
{
return NDSCart::ImportSRAM(data, length);
-}
+}*/
void Halt()
diff --git a/src/NDS.h b/src/NDS.h
index 29fc4ef..c3764d1 100644
--- a/src/NDS.h
+++ b/src/NDS.h
@@ -19,6 +19,8 @@
#ifndef NDS_H
#define NDS_H
+#include <string>
+
#include "Savestate.h"
#include "types.h"
@@ -48,8 +50,6 @@ enum
Event_DSi_NWifi,
Event_DSi_CamIRQ,
Event_DSi_CamTransfer,
-
- Event_DSi_RAMSizeChange,
Event_DSi_DSP,
Event_MAX
@@ -162,6 +162,12 @@ struct MemRegion
u32 Mask;
};
+// supported GBA slot addon types
+enum
+{
+ GBAAddon_RAMExpansion = 1,
+};
+
#ifdef JIT_ENABLED
extern bool EnableJIT;
#endif
@@ -219,6 +225,7 @@ extern u8* ARM7WRAM;
bool Init();
void DeInit();
void Reset();
+void Start();
void Stop();
bool DoSavestate(Savestate* file);
@@ -229,13 +236,19 @@ 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 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);
void LoadBIOS();
-void SetupDirectBoot();
-void RelocateSave(const char* path, bool write);
+
+bool LoadCart(const u8* romdata, u32 romlen, const u8* savedata, u32 savelen);
+void LoadSave(const u8* savedata, u32 savelen);
+void EjectCart();
+bool CartInserted();
+
+bool NeedsDirectBoot();
+void SetupDirectBoot(std::string romname);
+
+bool LoadGBACart(const u8* romdata, u32 romlen, const u8* savedata, u32 savelen);
+void LoadGBAAddon(int type);
+void EjectGBACart();
u32 RunFrame();
@@ -249,8 +262,6 @@ void SetLidClosed(bool closed);
void MicInputFrame(s16* data, int samples);
-int ImportSRAM(u8* data, u32 length);
-
void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 param);
void CancelEvent(u32 id);
diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp
index 3d231ac..940827f 100644
--- a/src/NDSCart.cpp
+++ b/src/NDSCart.cpp
@@ -22,11 +22,11 @@
#include "DSi.h"
#include "NDSCart.h"
#include "ARM.h"
+#include "CRC32.h"
#include "DSi_AES.h"
#include "Platform.h"
#include "ROMList.h"
#include "melonDLDI.h"
-#include "NDSCart_SRAMManager.h"
namespace NDSCart
@@ -51,12 +51,9 @@ u32 TransferDir;
u8 TransferCmd[8];
bool CartInserted;
-char CartName[256];
u8* CartROM;
u32 CartROMSize;
u32 CartID;
-bool CartIsHomebrew;
-bool CartIsDSi;
NDSHeader Header;
NDSBanner Banner;
@@ -135,13 +132,24 @@ void Key1_ApplyKeycode(u32* keycode, u32 mod)
}
}
+void Key1_LoadKeyBuf(bool dsi)
+{
+ // it is possible that this gets called before the BIOSes are loaded
+ // so we will read from the BIOS files directly
+
+ std::string path = Platform::GetConfigString(dsi ? Platform::DSi_BIOS7Path : Platform::BIOS7Path);
+ FILE* f = Platform::OpenLocalFile(path, "rb");
+ if (f)
+ {
+ fseek(f, dsi ? 0xC6D0 : 0x0030, SEEK_SET);
+ fread(Key1_KeyBuf, 0x1048, 1, f);
+ fclose(f);
+ }
+}
+
void Key1_InitKeycode(bool dsi, u32 idcode, u32 level, u32 mod)
{
- // TODO: source the key data from different possible places
- if (dsi && NDS::ConsoleType==1)
- memcpy(Key1_KeyBuf, &DSi::ARM7iBIOS[0xC6D0], 0x1048); // hax
- else
- memcpy(Key1_KeyBuf, &NDS::ARM7BIOS[0x30], 0x1048); // hax
+ Key1_LoadKeyBuf(dsi);
u32 keycode[3] = {idcode, idcode>>1, idcode<<1};
if (level >= 1) Key1_ApplyKeycode(keycode, mod);
@@ -191,6 +199,22 @@ CartCommon::~CartCommon()
{
}
+u32 CartCommon::Checksum()
+{
+ u32 crc = CRC32(ROM, 0x40);
+
+ crc = CRC32(&ROM[Header.ARM9ROMOffset], Header.ARM9Size, crc);
+ crc = CRC32(&ROM[Header.ARM7ROMOffset], Header.ARM7Size, crc);
+
+ if (IsDSi)
+ {
+ crc = CRC32(&ROM[Header.DSiARM9iROMOffset], Header.DSiARM9iSize, crc);
+ crc = CRC32(&ROM[Header.DSiARM7iROMOffset], Header.DSiARM7iSize, crc);
+ }
+
+ return crc;
+}
+
void CartCommon::Reset()
{
CmdEncMode = 0;
@@ -198,11 +222,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,20 +238,11 @@ 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)
-{
-}
-
-int CartCommon::ImportSRAM(const u8* data, u32 length)
-{
- return 0;
-}
-
-void CartCommon::FlushSRAMFile()
+void CartCommon::LoadSave(const u8* savedata, u32 savelen)
{
}
@@ -392,11 +407,7 @@ void CartRetail::DoSavestate(Savestate* file)
CartCommon::DoSavestate(file);
// we reload the SRAM contents.
- // it should be the same file (as it should be the same ROM, duh)
- // but the contents may change
-
- //if (!file->Saving && SRAMLength)
- // delete[] SRAM;
+ // it should be the same file, but the contents may change
u32 oldlen = SRAMLength;
@@ -407,13 +418,11 @@ 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)
{
- //if (!file->Saving)
- // SRAM = new u8[SRAMLength];
-
file->VarArray(SRAM, SRAMLength);
}
@@ -423,20 +432,14 @@ void CartRetail::DoSavestate(Savestate* file)
file->Var32(&SRAMAddr);
file->Var8(&SRAMStatus);
- // SRAMManager might now have an old buffer (or one from the future or alternate timeline!)
- if (!file->Saving)
- {
- SRAMFileDirty = false;
- NDSCart_SRAMManager::RequestFlush();
- }
+ if ((!file->Saving) && SRAM)
+ Platform::WriteNDSSave(SRAM, SRAMLength, 0, SRAMLength);
}
-void CartRetail::LoadSave(const char* path, u32 type)
+void CartRetail::SetupSave(u32 type)
{
if (SRAM) delete[] SRAM;
-
- strncpy(SRAMPath, path, 1023);
- SRAMPath[1023] = '\0';
+ SRAM = nullptr;
if (type > 10) type = 0;
int sramlen[] =
@@ -455,18 +458,6 @@ void CartRetail::LoadSave(const char* path, u32 type)
memset(SRAM, 0xFF, SRAMLength);
}
- FILE* f = Platform::OpenFile(path, "rb");
- if (f)
- {
- fseek(f, 0, SEEK_SET);
- fread(SRAM, 1, SRAMLength, f);
-
- fclose(f);
- }
-
- SRAMFileDirty = false;
- NDSCart_SRAMManager::Setup(path, SRAM, SRAMLength);
-
switch (type)
{
case 1: SRAMType = 1; break; // EEPROM, small
@@ -483,47 +474,13 @@ void CartRetail::LoadSave(const char* path, u32 type)
}
}
-void CartRetail::RelocateSave(const char* path, bool write)
+void CartRetail::LoadSave(const u8* savedata, u32 savelen)
{
- if (!write)
- {
- LoadSave(path, 0); // lazy
- return;
- }
-
- strncpy(SRAMPath, path, 1023);
- SRAMPath[1023] = '\0';
-
- FILE* f = Platform::OpenFile(path, "wb");
- if (!f)
- {
- printf("NDSCart_SRAM::RelocateSave: failed to create new file. fuck\n");
- return;
- }
+ if (!SRAM) return;
- fwrite(SRAM, SRAMLength, 1, f);
- fclose(f);
-}
-
-int CartRetail::ImportSRAM(const u8* data, u32 length)
-{
- memcpy(SRAM, data, std::min(length, SRAMLength));
- FILE* f = Platform::OpenFile(SRAMPath, "wb");
- if (f)
- {
- fwrite(SRAM, SRAMLength, 1, f);
- fclose(f);
- }
-
- return length - SRAMLength;
-}
-
-void CartRetail::FlushSRAMFile()
-{
- if (!SRAMFileDirty) return;
-
- SRAMFileDirty = false;
- NDSCart_SRAMManager::RequestFlush();
+ u32 len = std::min(savelen, SRAMLength);
+ memcpy(SRAM, savedata, len);
+ Platform::WriteNDSSave(savedata, len, 0, len);
}
int CartRetail::ROMCommandStart(u8* cmd, u8* data, u32 len)
@@ -624,6 +581,7 @@ u8 CartRetail::SRAMWrite_EEPROMTiny(u8 val, u32 pos, bool last)
if (pos < 2)
{
SRAMAddr = val;
+ SRAMFirstAddr = SRAMAddr;
}
else
{
@@ -631,11 +589,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
@@ -683,6 +645,7 @@ u8 CartRetail::SRAMWrite_EEPROM(u8 val, u32 pos, bool last)
{
SRAMAddr <<= 8;
SRAMAddr |= val;
+ SRAMFirstAddr = SRAMAddr;
}
else
{
@@ -690,11 +653,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
@@ -735,6 +702,7 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
{
SRAMAddr <<= 8;
SRAMAddr |= val;
+ SRAMFirstAddr = SRAMAddr;
}
else
{
@@ -742,11 +710,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
@@ -768,17 +740,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
@@ -809,6 +786,7 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
{
SRAMAddr <<= 8;
SRAMAddr |= val;
+ SRAMFirstAddr = SRAMAddr;
}
if ((pos == 3) && (SRAMStatus & (1<<1)))
{
@@ -817,9 +795,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
@@ -827,6 +809,7 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
{
SRAMAddr <<= 8;
SRAMAddr |= val;
+ SRAMFirstAddr = SRAMAddr;
}
if ((pos == 3) && (SRAMStatus & (1<<1)))
{
@@ -835,9 +818,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:
@@ -884,19 +871,12 @@ void CartRetailNAND::DoSavestate(Savestate* file)
BuildSRAMID();
}
-void CartRetailNAND::LoadSave(const char* path, u32 type)
+void CartRetailNAND::LoadSave(const u8* savedata, u32 savelen)
{
- CartRetail::LoadSave(path, type);
+ CartRetail::LoadSave(savedata, savelen);
BuildSRAMID();
}
-int CartRetailNAND::ImportSRAM(const u8* data, u32 length)
-{
- int ret = CartRetail::ImportSRAM(data, length);
- BuildSRAMID();
- return ret;
-}
-
int CartRetailNAND::ROMCommandStart(u8* cmd, u8* data, u32 len)
{
if (CmdEncMode != 2) return CartCommon::ROMCommandStart(cmd, data, len);
@@ -926,7 +906,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;
@@ -1164,8 +1144,30 @@ u8 CartRetailBT::SPIWrite(u8 val, u32 pos, bool last)
CartHomebrew::CartHomebrew(u8* rom, u32 len, u32 chipid) : CartCommon(rom, len, chipid)
{
+ SD = nullptr;
+}
+
+CartHomebrew::~CartHomebrew()
+{
+ if (SD)
+ {
+ SD->Close();
+ delete SD;
+ }
+}
+
+void CartHomebrew::Reset()
+{
+ CartCommon::Reset();
+
ReadOnly = Platform::GetConfigBool(Platform::DLDI_ReadOnly);
+ if (SD)
+ {
+ SD->Close();
+ delete SD;
+ }
+
if (Platform::GetConfigBool(Platform::DLDI_Enable))
{
std::string folderpath;
@@ -1185,29 +1187,15 @@ CartHomebrew::CartHomebrew(u8* rom, u32 len, u32 chipid) : CartCommon(rom, len,
SD = nullptr;
}
-CartHomebrew::~CartHomebrew()
+void CartHomebrew::SetupDirectBoot(std::string romname)
{
- if (SD)
- {
- SD->Close();
- delete SD;
- }
-}
-
-void CartHomebrew::Reset()
-{
- CartCommon::Reset();
-}
-
-void CartHomebrew::SetupDirectBoot()
-{
- 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 +1204,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;
@@ -1441,6 +1429,7 @@ void CartHomebrew::ReadROM_B7(u32 addr, u32 len, u8* data, u32 offset)
bool Init()
{
+ CartInserted = false;
CartROM = nullptr;
Cart = nullptr;
@@ -1455,17 +1444,6 @@ void DeInit()
void Reset()
{
- CartInserted = false;
- if (CartROM) delete[] CartROM;
- CartROM = nullptr;
- CartROMSize = 0;
- CartID = 0;
- CartIsHomebrew = false;
- CartIsDSi = false;
-
- if (Cart) delete Cart;
- Cart = nullptr;
-
ResetCart();
}
@@ -1494,6 +1472,30 @@ void DoSavestate(Savestate* file)
// (TODO: system to verify that indeed the right ROM is loaded)
// (what to CRC? whole ROM? code binaries? latter would be more convenient for ie. romhaxing)
+ u32 carttype = 0;
+ u32 cartchk = 0;
+ if (Cart)
+ {
+ carttype = Cart->Type();
+ cartchk = Cart->Checksum();
+ }
+
+ if (file->Saving)
+ {
+ file->Var32(&carttype);
+ file->Var32(&cartchk);
+ }
+ else
+ {
+ u32 savetype;
+ file->Var32(&savetype);
+ if (savetype != carttype) return;
+
+ u32 savechk;
+ file->Var32(&savechk);
+ if (savechk != cartchk) return;
+ }
+
if (Cart) Cart->DoSavestate(file);
}
@@ -1542,11 +1544,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 +1573,28 @@ void DecryptSecureArea(u8* out)
}
}
-bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
+bool LoadROM(const u8* romdata, u32 romlen)
{
+ if (CartInserted)
+ EjectCart();
+
+ 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));
@@ -1589,7 +1606,10 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
(u32)Header.GameCode[0];
u8 unitcode = Header.UnitCode;
- CartIsDSi = (unitcode & 0x02) != 0;
+ bool dsi = (unitcode & 0x02) != 0;
+
+ u32 arm9base = Header.ARM9ROMOffset;
+ bool homebrew = (arm9base < 0x4000) || (gamecode == 0x23232323);
ROMListEntry romparams;
if (!ReadROMParams(gamecode, &romparams))
@@ -1599,7 +1619,7 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
romparams.GameCode = gamecode;
romparams.ROMSize = CartROMSize;
- if (*(u32*)&CartROM[0x20] < 0x4000)
+ if (homebrew)
romparams.SaveMemType = 0; // no saveRAM for homebrew
else
romparams.SaveMemType = 2; // assume EEPROM 64k (TODO FIXME)
@@ -1607,7 +1627,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
@@ -1622,7 +1643,7 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
if (romparams.SaveMemType >= 8 && romparams.SaveMemType <= 10)
CartID |= 0x08000000; // NAND flag
- if (CartIsDSi)
+ if (dsi)
CartID |= 0x40000000;
// cart ID for Jam with the Band
@@ -1633,34 +1654,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;
@@ -1672,7 +1683,7 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
irversion = 2; // Pokémon HG/SS, B/W, B2/W2
}
- if (CartIsHomebrew)
+ if (homebrew)
Cart = new CartHomebrew(CartROM, CartROMSize, CartID);
else if (CartID & 0x08000000)
Cart = new CartRetailNAND(CartROM, CartROMSize, CartID);
@@ -1684,99 +1695,44 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
Cart = new CartRetail(CartROM, CartROMSize, CartID);
if (Cart)
- {
Cart->Reset();
- if (direct)
- {
- NDS::SetupDirectBoot();
- Cart->SetupDirectBoot();
- }
- }
- // encryption
- Key1_InitKeycode(false, gamecode, 2, 2);
-
- // save
- 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)
{
- // TODO: streaming mode? for really big ROMs or systems with limited RAM
- // for now we're lazy
- // also TODO: validate what we're loading!!
-
- FILE* f = Platform::OpenFile(path, "rb");
- if (!f)
- {
- return false;
- }
-
- NDS::Reset();
-
- char* romname = strrchr((char*)path, '/');
- if (!romname)
- {
- romname = strrchr((char*)path, '\\');
- if (!romname)
- romname = (char*)&path[-1];
- }
- romname++;
- strncpy(CartName, romname, 255); CartName[255] = '\0';
-
- fseek(f, 0, SEEK_END);
- u32 len = (u32)ftell(f);
-
- CartROMSize = 0x200;
- while (CartROMSize < len)
- CartROMSize <<= 1;
-
- CartROM = new u8[CartROMSize];
- memset(CartROM, 0, CartROMSize);
- fseek(f, 0, SEEK_SET);
- fread(CartROM, 1, len, f);
-
- fclose(f);
-
- return LoadROMCommon(len, sram, direct);
+ if (Cart)
+ Cart->LoadSave(savedata, savelen);
}
-bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct)
+void SetupDirectBoot(std::string romname)
{
- NDS::Reset();
-
- // TODO: make it more meaningful?
- strncpy(CartName, "rom.nds", 256);
-
- u32 len = filelength;
- CartROMSize = 0x200;
- while (CartROMSize < len)
- CartROMSize <<= 1;
-
- CartROM = new u8[CartROMSize];
- memset(CartROM, 0, CartROMSize);
- memcpy(CartROM, romdata, filelength);
-
- return LoadROMCommon(filelength, sram, direct);
+ if (Cart)
+ Cart->SetupDirectBoot(romname);
}
-void RelocateSave(const char* path, bool write)
+void EjectCart()
{
- if (Cart) Cart->RelocateSave(path, write);
-}
+ if (!CartInserted) return;
-void FlushSRAMFile()
-{
- if (Cart) Cart->FlushSRAMFile();
-}
+ // ejecting the cart triggers the gamecard IRQ
+ NDS::SetIRQ(0, NDS::IRQ_CartIREQMC);
+ NDS::SetIRQ(1, NDS::IRQ_CartIREQMC);
-int ImportSRAM(const u8* data, u32 length)
-{
- if (Cart) return Cart->ImportSRAM(data, length);
- return 0;
+ if (Cart) delete Cart;
+ Cart = nullptr;
+
+ CartInserted = false;
+ if (CartROM) delete[] CartROM;
+ CartROM = nullptr;
+ CartROMSize = 0;
+ CartID = 0;
+
+ // CHECKME: does an eject imply anything for the ROM/SPI transfer registers?
}
void ResetCart()
@@ -1880,6 +1836,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 9f39988..b5b5c3f 100644
--- a/src/NDSCart.h
+++ b/src/NDSCart.h
@@ -19,6 +19,8 @@
#ifndef NDSCART_H
#define NDSCART_H
+#include <string>
+
#include "types.h"
#include "NDS_Header.h"
#include "FATStorage.h"
@@ -33,15 +35,16 @@ public:
CartCommon(u8* rom, u32 len, u32 chipid);
virtual ~CartCommon();
+ virtual u32 Type() { return 0x001; }
+ virtual u32 Checksum();
+
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 int ROMCommandStart(u8* cmd, u8* data, u32 len);
virtual void ROMCommandFinish(u8* cmd, u8* data, u32 len);
@@ -71,14 +74,14 @@ public:
CartRetail(u8* rom, u32 len, u32 chipid);
virtual ~CartRetail() override;
+ virtual u32 Type() override { return 0x101; }
+
virtual void Reset() override;
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 int ROMCommandStart(u8* cmd, u8* data, u32 len) override;
@@ -95,11 +98,9 @@ protected:
u32 SRAMLength;
u32 SRAMType;
- char SRAMPath[1024];
- bool SRAMFileDirty;
-
u8 SRAMCmd;
u32 SRAMAddr;
+ u32 SRAMFirstAddr;
u8 SRAMStatus;
};
@@ -110,12 +111,13 @@ public:
CartRetailNAND(u8* rom, u32 len, u32 chipid);
~CartRetailNAND() override;
+ virtual u32 Type() override { return 0x102; }
+
void Reset() override;
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 ROMCommandStart(u8* cmd, u8* data, u32 len) override;
void ROMCommandFinish(u8* cmd, u8* data, u32 len) override;
@@ -139,6 +141,8 @@ public:
CartRetailIR(u8* rom, u32 len, u32 chipid, u32 irversion);
~CartRetailIR() override;
+ virtual u32 Type() override { return 0x103; }
+
void Reset() override;
void DoSavestate(Savestate* file) override;
@@ -157,6 +161,8 @@ public:
CartRetailBT(u8* rom, u32 len, u32 chipid);
~CartRetailBT() override;
+ virtual u32 Type() override { return 0x104; }
+
void Reset() override;
void DoSavestate(Savestate* file) override;
@@ -171,8 +177,10 @@ public:
CartHomebrew(u8* rom, u32 len, u32 chipid);
~CartHomebrew() override;
+ virtual u32 Type() override { return 0x201; }
+
void Reset() override;
- void SetupDirectBoot() override;
+ void SetupDirectBoot(std::string romname) override;
void DoSavestate(Savestate* file) override;
@@ -192,6 +200,7 @@ extern u32 ROMCnt;
extern u8 ROMCommand[8];
+extern bool CartInserted;
extern u8* CartROM;
extern u32 CartROMSize;
@@ -207,14 +216,12 @@ 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);
-
-void FlushSRAMFile();
-void RelocateSave(const char* path, bool write);
+bool LoadROM(const u8* romdata, u32 romlen);
+void LoadSave(const u8* savedata, u32 savelen);
+void SetupDirectBoot(std::string romname);
-int ImportSRAM(const u8* data, u32 length);
+void EjectCart();
void ResetCart();
diff --git a/src/NDSCart_SRAMManager.cpp b/src/NDSCart_SRAMManager.cpp
deleted file mode 100644
index addd122..0000000
--- a/src/NDSCart_SRAMManager.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- 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 <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <time.h>
-#include <atomic>
-#include "NDSCart_SRAMManager.h"
-#include "Platform.h"
-
-namespace NDSCart_SRAMManager
-{
-
-Platform::Thread* FlushThread;
-std::atomic_bool FlushThreadRunning;
-Platform::Mutex* SecondaryBufferLock;
-
-char Path[1024];
-
-u8* Buffer;
-u32 Length;
-
-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;
-
-void FlushThreadFunc();
-
-bool Init()
-{
- SecondaryBufferLock = Platform::Mutex_Create();
-
- return true;
-}
-
-void DeInit()
-{
- if (FlushThreadRunning)
- {
- FlushThreadRunning = false;
- Platform::Thread_Wait(FlushThread);
- Platform::Thread_Free(FlushThread);
- FlushSecondaryBuffer();
- }
-
- if (SecondaryBuffer) delete[] SecondaryBuffer;
- SecondaryBuffer = NULL;
-
- Platform::Mutex_Free(SecondaryBufferLock);
-}
-
-void Setup(const char* path, u8* buffer, u32 length)
-{
- // Flush SRAM in case there is unflushed data from previous state.
- FlushSecondaryBuffer();
-
- Platform::Mutex_Lock(SecondaryBufferLock);
-
- strncpy(Path, path, 1023);
- Path[1023] = '\0';
-
- 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;
-
- Platform::Mutex_Unlock(SecondaryBufferLock);
-
- if (path[0] != '\0' && !FlushThreadRunning)
- {
- FlushThread = Platform::Thread_Create(FlushThreadFunc);
- FlushThreadRunning = true;
- }
- else if (path[0] == '\0' && FlushThreadRunning)
- {
- FlushThreadRunning = false;
- Platform::Thread_Wait(FlushThread);
- Platform::Thread_Free(FlushThread);
- }
-}
-
-void RequestFlush()
-{
- Platform::Mutex_Lock(SecondaryBufferLock);
- printf("NDS SRAM: Flush requested\n");
- memcpy(SecondaryBuffer, Buffer, Length);
- FlushVersion++;
- TimeAtLastFlushRequest = time(NULL);
- Platform::Mutex_Unlock(SecondaryBufferLock);
-}
-
-void FlushThreadFunc()
-{
- for (;;)
- {
- Platform::Sleep(100 * 1000); // 100ms
-
- if (!FlushThreadRunning) return;
-
- // We debounce for two seconds after last flush request to ensure that writing has finished.
- if (TimeAtLastFlushRequest == 0 || difftime(time(NULL), TimeAtLastFlushRequest) < 2)
- {
- continue;
- }
-
- FlushSecondaryBuffer();
- }
-}
-
-void FlushSecondaryBuffer(u8* dst, s32 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;
-
- Platform::Mutex_Lock(SecondaryBufferLock);
- if (dst)
- {
- memcpy(dst, SecondaryBuffer, SecondaryBufferLength);
- }
- else
- {
- FILE* f = Platform::OpenFile(Path, "wb");
- if (f)
- {
- printf("NDS SRAM: Written\n");
- fwrite(SecondaryBuffer, SecondaryBufferLength, 1, f);
- fclose(f);
- }
- }
- PreviousFlushVersion = FlushVersion;
- TimeAtLastFlushRequest = 0;
- Platform::Mutex_Unlock(SecondaryBufferLock);
-}
-
-bool NeedsFlush()
-{
- return FlushVersion != PreviousFlushVersion;
-}
-
-void UpdateBuffer(u8* src, s32 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);
- Platform::Mutex_Lock(SecondaryBufferLock);
- memcpy(SecondaryBuffer, src, srcLength);
- Platform::Mutex_Unlock(SecondaryBufferLock);
-
- PreviousFlushVersion = FlushVersion;
-}
-
-}
diff --git a/src/NDSCart_SRAMManager.h b/src/NDSCart_SRAMManager.h
deleted file mode 100644
index 89b65ce..0000000
--- a/src/NDSCart_SRAMManager.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- 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 NDSCART_SRAMMANAGER_H
-#define NDSCART_SRAMMANAGER_H
-
-#include "types.h"
-
-namespace NDSCart_SRAMManager
-{
- extern u32 SecondaryBufferLength;
-
- bool Init();
- void DeInit();
-
- void Setup(const char* path, u8* buffer, u32 length);
- void RequestFlush();
-
- bool NeedsFlush();
- void FlushSecondaryBuffer(u8* dst = NULL, s32 dstLength = 0);
- void UpdateBuffer(u8* src, s32 srcLength);
-}
-
-#endif // NDSCART_SRAMMANAGER_H \ No newline at end of file
diff --git a/src/Platform.h b/src/Platform.h
index bbdc245..aefbf4b 100644
--- a/src/Platform.h
+++ b/src/Platform.h
@@ -145,6 +145,13 @@ void Mutex_Unlock(Mutex* mutex);
bool Mutex_TryLock(Mutex* mutex);
+// 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
// packet type: DS-style TX header (12 bytes) + original 802.11 frame
bool MP_Init();
diff --git a/src/SPI.cpp b/src/SPI.cpp
index 80ef336..1641a26 100644
--- a/src/SPI.cpp
+++ b/src/SPI.cpp
@@ -463,6 +463,7 @@ void SetupDirectBoot(bool dsi)
}
}
+u32 GetFirmwareLength() { return FirmwareLength; }
u8 GetConsoleType() { return Firmware[0x1D]; }
u8 GetWifiVersion() { return Firmware[0x2F]; }
u8 GetNWifiVersion() { return Firmware[0x1FD]; } // for DSi; will return 0xFF on a DS
diff --git a/src/SPI.h b/src/SPI.h
index d82485b..d98d3c2 100644
--- a/src/SPI.h
+++ b/src/SPI.h
@@ -28,6 +28,7 @@ void SetupDirectBoot(bool dsi);
u32 FixFirmwareLength(u32 originalLength);
+u32 GetFirmwareLength();
u8 GetConsoleType();
u8 GetWifiVersion();
u8 GetNWifiVersion();
diff --git a/src/Savestate.cpp b/src/Savestate.cpp
index 1bfe937..81d42eb 100644
--- a/src/Savestate.cpp
+++ b/src/Savestate.cpp
@@ -43,7 +43,10 @@
* different minor means adjustments may have to be made
*/
-Savestate::Savestate(const char* filename, bool save)
+// TODO: buffering system! or something of that sort
+// repeated fread/fwrite is slow on Switch
+
+Savestate::Savestate(std::string filename, bool save)
{
const char* magic = "MELN";
@@ -55,7 +58,7 @@ Savestate::Savestate(const char* filename, bool save)
file = Platform::OpenLocalFile(filename, "wb");
if (!file)
{
- printf("savestate: file %s doesn't exist\n", filename);
+ printf("savestate: file %s doesn't exist\n", filename.c_str());
Error = true;
return;
}
@@ -74,7 +77,7 @@ Savestate::Savestate(const char* filename, bool save)
file = Platform::OpenFile(filename, "rb");
if (!file)
{
- printf("savestate: file %s doesn't exist\n", filename);
+ printf("savestate: file %s doesn't exist\n", filename.c_str());
Error = true;
return;
}
diff --git a/src/Savestate.h b/src/Savestate.h
index 60d34cc..5fe4ddc 100644
--- a/src/Savestate.h
+++ b/src/Savestate.h
@@ -19,6 +19,7 @@
#ifndef SAVESTATE_H
#define SAVESTATE_H
+#include <string>
#include <stdio.h>
#include "types.h"
@@ -28,7 +29,7 @@
class Savestate
{
public:
- Savestate(const char* filename, bool save);
+ Savestate(std::string filename, bool save);
~Savestate();
bool Error;
diff --git a/src/frontend/FrontendUtil.h b/src/frontend/FrontendUtil.h
index f52dced..a0085a8 100644
--- a/src/frontend/FrontendUtil.h
+++ b/src/frontend/FrontendUtil.h
@@ -21,100 +21,12 @@
#include "types.h"
+#include <string>
#include <vector>
namespace Frontend
{
-enum
-{
- ROMSlot_NDS = 0,
- ROMSlot_GBA,
-
- ROMSlot_MAX
-};
-
-enum
-{
- Load_OK = 0,
-
- Load_BIOS9Missing,
- Load_BIOS9Bad,
-
- Load_BIOS7Missing,
- Load_BIOS7Bad,
-
- Load_FirmwareMissing,
- Load_FirmwareBad,
- Load_FirmwareNotBootable,
-
- Load_DSiBIOS9Missing,
- Load_DSiBIOS9Bad,
-
- Load_DSiBIOS7Missing,
- Load_DSiBIOS7Bad,
-
- Load_DSiNANDMissing,
- Load_DSiNANDBad,
-
- // TODO: more precise errors for ROM loading
- Load_ROMLoadError,
-};
-
-extern char ROMPath [ROMSlot_MAX][1024];
-extern char SRAMPath[ROMSlot_MAX][1024];
-extern bool SavestateLoaded;
-
-// Stores type of nds rom i.e. nds/srl/dsi. Should be updated everytime an NDS rom is loaded from an archive
-extern char NDSROMExtension[4];
-
-// initialize the ROM handling utility
-void Init_ROM();
-
-// deinitialize the ROM handling utility
-void DeInit_ROM();
-
-// load the BIOS/firmware and boot from it
-int LoadBIOS();
-
-// load a ROM file to the specified cart slot
-// note: loading a ROM to the NDS slot resets emulation
-int LoadROM(const char* file, int slot);
-int LoadROM(const u8 *romdata, u32 romlength, const char *archivefilename, const char *romfilename, const char *sramfilename, int slot);
-
-// unload the ROM loaded in the specified cart slot
-// simulating ejection of the cartridge
-void UnloadROM(int slot);
-
-void ROMIcon(u8 (&data)[512], u16 (&palette)[16], u32* iconRef);
-void AnimatedROMIcon(u8 (&data)[8][512], u16 (&palette)[8][16], u16 (&sequence)[64], u32 (&animatedTexRef)[32 * 32 * 64], std::vector<int> &animatedSequenceRef);
-
-// reset execution of the current ROM
-int Reset();
-
-// get the filename associated with the given savestate slot (1-8)
-void GetSavestateName(int slot, char* filename, int len);
-
-// determine whether the given savestate slot does contain a savestate
-bool SavestateExists(int slot);
-
-// load the given savestate file
-// if successful, emulation will continue from the savestate's point
-bool LoadState(const char* filename);
-
-// save the current emulator state to the given file
-bool SaveState(const char* filename);
-
-// undo the latest savestate load
-void UndoStateLoad();
-
-// imports savedata from an external file. Returns the difference between the filesize and the SRAM size
-int ImportSRAM(const char* filename);
-
-// enable or disable cheats
-void EnableCheats(bool enable);
-
-
// setup the display layout based on the provided display size and parameters
// * screenWidth/screenHeight: size of the host display
// * screenLayout: how the DS screens are laid out
diff --git a/src/frontend/SharedConfig.h b/src/frontend/SharedConfig.h
deleted file mode 100644
index 3598e74..0000000
--- a/src/frontend/SharedConfig.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- 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 SHAREDCONFIG_H
-#define SHAREDCONFIG_H
-
-namespace Config
-{
-
-extern int ConsoleType;
-extern int DirectBoot;
-extern int SavestateRelocSRAM;
-
-extern int ExternalBIOSEnable;
-
-extern char BIOS9Path[1024];
-extern char BIOS7Path[1024];
-extern char FirmwarePath[1024];
-
-extern char DSiBIOS9Path[1024];
-extern char DSiBIOS7Path[1024];
-extern char DSiFirmwarePath[1024];
-extern char DSiNANDPath[1024];
-
-}
-
-#endif
diff --git a/src/frontend/Util_ROM.cpp b/src/frontend/Util_ROM.cpp
deleted file mode 100644
index 4d23c70..0000000
--- a/src/frontend/Util_ROM.cpp
+++ /dev/null
@@ -1,845 +0,0 @@
-/*
- 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 <stdio.h>
-#include <string.h>
-
-#include <utility>
-
-#ifdef ARCHIVE_SUPPORT_ENABLED
-#include "ArchiveUtil.h"
-#endif
-#include "FrontendUtil.h"
-#include "SharedConfig.h"
-#include "Platform.h"
-
-#include "NDS.h"
-#include "DSi.h"
-#include "GBACart.h"
-
-#include "AREngine.h"
-
-
-namespace Frontend
-{
-
-char ROMPath [ROMSlot_MAX][1024];
-char SRAMPath [ROMSlot_MAX][1024];
-char PrevSRAMPath[ROMSlot_MAX][1024]; // for savestate 'undo load'
-
-char NDSROMExtension[4];
-
-bool SavestateLoaded;
-
-ARCodeFile* CheatFile;
-bool CheatsOn;
-
-
-void Init_ROM()
-{
- SavestateLoaded = false;
-
- memset(ROMPath[ROMSlot_NDS], 0, 1024);
- memset(ROMPath[ROMSlot_GBA], 0, 1024);
- memset(SRAMPath[ROMSlot_NDS], 0, 1024);
- memset(SRAMPath[ROMSlot_GBA], 0, 1024);
- memset(PrevSRAMPath[ROMSlot_NDS], 0, 1024);
- memset(PrevSRAMPath[ROMSlot_GBA], 0, 1024);
-
- CheatFile = nullptr;
- CheatsOn = false;
-}
-
-void DeInit_ROM()
-{
- if (CheatFile)
- {
- delete CheatFile;
- CheatFile = nullptr;
- }
-}
-
-// TODO: currently, when failing to load a ROM for whatever reason, we attempt
-// to revert to the previous state and resume execution; this may not be a very
-// good thing, depending on what state the core was left in.
-// should we do a better state revert (via the savestate system)? completely stop?
-
-void SetupSRAMPath(int slot)
-{
- strncpy(SRAMPath[slot], ROMPath[slot], 1023);
- SRAMPath[slot][1023] = '\0';
- strncpy(SRAMPath[slot] + strlen(ROMPath[slot]) - 3, "sav", 3);
-}
-
-int VerifyDSBIOS()
-{
- FILE* f;
- long len;
-
- if (!Config::ExternalBIOSEnable) return Load_OK;
-
- f = Platform::OpenLocalFile(Config::BIOS9Path, "rb");
- if (!f) return Load_BIOS9Missing;
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- if (len != 0x1000)
- {
- fclose(f);
- return Load_BIOS9Bad;
- }
-
- fclose(f);
-
- f = Platform::OpenLocalFile(Config::BIOS7Path, "rb");
- if (!f) return Load_BIOS7Missing;
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- if (len != 0x4000)
- {
- fclose(f);
- return Load_BIOS7Bad;
- }
-
- fclose(f);
-
- return Load_OK;
-}
-
-int VerifyDSiBIOS()
-{
- FILE* f;
- long len;
-
- // TODO: check the first 32 bytes
-
- f = Platform::OpenLocalFile(Config::DSiBIOS9Path, "rb");
- if (!f) return Load_DSiBIOS9Missing;
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- if (len != 0x10000)
- {
- fclose(f);
- return Load_DSiBIOS9Bad;
- }
-
- fclose(f);
-
- f = Platform::OpenLocalFile(Config::DSiBIOS7Path, "rb");
- if (!f) return Load_DSiBIOS7Missing;
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- if (len != 0x10000)
- {
- fclose(f);
- return Load_DSiBIOS7Bad;
- }
-
- fclose(f);
-
- return Load_OK;
-}
-
-int VerifyDSFirmware()
-{
- FILE* f;
- long len;
-
- if (!Config::ExternalBIOSEnable) return Load_FirmwareNotBootable;
-
- f = Platform::OpenLocalFile(Config::FirmwarePath, "rb");
- if (!f) return Load_FirmwareNotBootable;
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- if (len == 0x20000)
- {
- // 128KB firmware, not bootable
- fclose(f);
- return Load_FirmwareNotBootable;
- }
- else if (len != 0x40000 && len != 0x80000)
- {
- fclose(f);
- return Load_FirmwareBad;
- }
-
- fclose(f);
-
- return Load_OK;
-}
-
-int VerifyDSiFirmware()
-{
- FILE* f;
- long len;
-
- f = Platform::OpenLocalFile(Config::DSiFirmwarePath, "rb");
- if (!f) return Load_FirmwareMissing;
-
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- if (len != 0x20000)
- {
- // not 128KB
- // TODO: check whether those work
- fclose(f);
- return Load_FirmwareBad;
- }
-
- fclose(f);
-
- return Load_OK;
-}
-
-int SetupDSiNAND()
-{
- FILE* f;
- long len;
-
- f = Platform::OpenLocalFile(Config::DSiNANDPath, "r+b");
- if (!f) return Load_DSiNANDMissing;
-
- // TODO: some basic checks
- // check that it has the nocash footer, and all
-
- DSi::SDMMCFile = f;
-
- return Load_OK;
-}
-
-void LoadCheats()
-{
- if (CheatFile)
- {
- delete CheatFile;
- CheatFile = nullptr;
- }
-
- char filename[1024];
- if (ROMPath[ROMSlot_NDS][0] != '\0')
- {
- strncpy(filename, ROMPath[ROMSlot_NDS], 1023);
- filename[1023] = '\0';
- strncpy(filename + strlen(ROMPath[ROMSlot_NDS]) - 3, "mch", 3);
- }
- else
- {
- strncpy(filename, "firmware.mch", 1023);
- }
-
- // TODO: check for error (malformed cheat file, ...)
- CheatFile = new ARCodeFile(filename);
-
- AREngine::SetCodeFile(CheatsOn ? CheatFile : nullptr);
-}
-
-int LoadBIOS()
-{
- DSi::CloseDSiNAND();
-
- int res;
-
- res = VerifyDSBIOS();
- if (res != Load_OK) return res;
-
- if (Config::ConsoleType == 1)
- {
- res = VerifyDSiBIOS();
- if (res != Load_OK) return res;
-
- res = VerifyDSiFirmware();
- if (res != Load_OK) return res;
-
- res = SetupDSiNAND();
- if (res != Load_OK) return res;
- }
- else
- {
- res = VerifyDSFirmware();
- if (res != Load_OK) return res;
- }
-
- // TODO:
- // original code in the libui frontend called NDS::LoadGBAROM() if needed
- // should this be carried over here?
- // is that behavior consistent with that of LoadROM() below?
-
- ROMPath[ROMSlot_NDS][0] = '\0';
- SRAMPath[ROMSlot_NDS][0] = '\0';
-
- NDS::SetConsoleType(Config::ConsoleType);
- NDS::LoadBIOS();
-
- SavestateLoaded = false;
-
- LoadCheats();
-
- return Load_OK;
-}
-
-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;
-
- if (Config::ConsoleType == 1 && slot == 1)
- {
- // cannot load a GBA ROM into a DSi
- return Load_ROMLoadError;
- }
-
- res = VerifyDSBIOS();
- if (res != Load_OK) return res;
-
- if (Config::ConsoleType == 1)
- {
- res = VerifyDSiBIOS();
- if (res != Load_OK) return res;
-
- res = VerifyDSiFirmware();
- if (res != Load_OK) return res;
-
- res = SetupDSiNAND();
- if (res != Load_OK) return res;
-
- GBACart::Eject();
- ROMPath[ROMSlot_GBA][0] = '\0';
- }
- else
- {
- res = VerifyDSFirmware();
- if (res != Load_OK)
- {
- if (res == Load_FirmwareNotBootable)
- directboot = true;
- else
- return res;
- }
- }
-
- char oldpath[1024];
- char oldsram[1024];
- strncpy(oldpath, ROMPath[slot], 1024);
- strncpy(oldsram, SRAMPath[slot], 1024);
-
- strncpy(SRAMPath[slot], sramfilename, 1024);
- strncpy(ROMPath[slot], archivefilename, 1024);
-
- NDS::SetConsoleType(Config::ConsoleType);
-
- if (slot == ROMSlot_NDS && NDS::LoadROM(romdata, romlength, SRAMPath[slot], directboot))
- {
- SavestateLoaded = false;
-
- LoadCheats();
-
- // Reload the inserted GBA cartridge (if any)
- // TODO: report failure there??
- //if (ROMPath[ROMSlot_GBA][0] != '\0') NDS::LoadGBAROM(ROMPath[ROMSlot_GBA], SRAMPath[ROMSlot_GBA]);
-
- strncpy(PrevSRAMPath[slot], SRAMPath[slot], 1024); // safety
- return Load_OK;
- }
- else if (slot == ROMSlot_GBA && NDS::LoadGBAROM(romdata, romlength, romfilename, SRAMPath[slot]))
- {
- SavestateLoaded = false; // checkme??
-
- strncpy(PrevSRAMPath[slot], SRAMPath[slot], 1024); // safety
- return Load_OK;
- }
- else
- {
- strncpy(ROMPath[slot], oldpath, 1024);
- strncpy(SRAMPath[slot], oldsram, 1024);
- return Load_ROMLoadError;
- }
-}
-
-int LoadROM(const char* file, int slot)
-{
- DSi::CloseDSiNAND();
-
- int res;
- bool directboot = Config::DirectBoot != 0;
-
- if (Config::ConsoleType == 1 && slot == 1)
- {
- // cannot load a GBA ROM into a DSi
- return Load_ROMLoadError;
- }
-
- res = VerifyDSBIOS();
- if (res != Load_OK) return res;
-
- if (Config::ConsoleType == 1)
- {
- res = VerifyDSiBIOS();
- if (res != Load_OK) return res;
-
- res = VerifyDSiFirmware();
- if (res != Load_OK) return res;
-
- res = SetupDSiNAND();
- if (res != Load_OK) return res;
-
- GBACart::Eject();
- ROMPath[ROMSlot_GBA][0] = '\0';
- }
- else
- {
- res = VerifyDSFirmware();
- if (res != Load_OK)
- {
- if (res == Load_FirmwareNotBootable)
- directboot = true;
- else
- return res;
- }
- }
-
- char oldpath[1024];
- char oldsram[1024];
- strncpy(oldpath, ROMPath[slot], 1024);
- strncpy(oldsram, SRAMPath[slot], 1024);
-
- strncpy(ROMPath[slot], file, 1023);
- ROMPath[slot][1023] = '\0';
-
- SetupSRAMPath(0);
- SetupSRAMPath(1);
-
- NDS::SetConsoleType(Config::ConsoleType);
-
- if (slot == ROMSlot_NDS && NDS::LoadROM(ROMPath[slot], SRAMPath[slot], directboot))
- {
- SavestateLoaded = false;
-
- LoadCheats();
-
- // Reload the inserted GBA cartridge (if any)
- // TODO: report failure there??
- if (ROMPath[ROMSlot_GBA][0] != '\0') NDS::LoadGBAROM(ROMPath[ROMSlot_GBA], SRAMPath[ROMSlot_GBA]);
-
- strncpy(PrevSRAMPath[slot], SRAMPath[slot], 1024); // safety
- return Load_OK;
- }
- else if (slot == ROMSlot_GBA && NDS::LoadGBAROM(ROMPath[slot], SRAMPath[slot]))
- {
- SavestateLoaded = false; // checkme??
-
- strncpy(PrevSRAMPath[slot], SRAMPath[slot], 1024); // safety
- return Load_OK;
- }
- else
- {
- strncpy(ROMPath[slot], oldpath, 1024);
- strncpy(SRAMPath[slot], oldsram, 1024);
- return Load_ROMLoadError;
- }
-}
-
-void ROMIcon(u8 (&data)[512], u16 (&palette)[16], u32* iconRef)
-{
- int index = 0;
- for (int i = 0; i < 4; i++)
- {
- for (int j = 0; j < 4; j++)
- {
- for (int k = 0; k < 8; k++)
- {
- for (int l = 0; l < 8; l++)
- {
- u8 pal_index = index % 2 ? data[index/2] >> 4 : data[index/2] & 0x0F;
- u8 r = ((palette[pal_index] >> 0) & 0x1F) * 255 / 31;
- u8 g = ((palette[pal_index] >> 5) & 0x1F) * 255 / 31;
- u8 b = ((palette[pal_index] >> 10) & 0x1F) * 255 / 31;
- u8 a = pal_index ? 255: 0;
- u32* row = &iconRef[256 * i + 32 * k + 8 * j];
- row[l] = (a << 24) | (r << 16) | (g << 8) | b;
- index++;
- }
- }
- }
- }
-}
-
-#define SEQ_FLIPV(i) ((i & 0b1000000000000000) >> 15)
-#define SEQ_FLIPH(i) ((i & 0b0100000000000000) >> 14)
-#define SEQ_PAL(i) ((i & 0b0011100000000000) >> 11)
-#define SEQ_BMP(i) ((i & 0b0000011100000000) >> 8)
-#define SEQ_DUR(i) ((i & 0b0000000011111111) >> 0)
-
-void AnimatedROMIcon(u8 (&data)[8][512], u16 (&palette)[8][16], u16 (&sequence)[64], u32 (&animatedTexRef)[32 * 32 * 64], std::vector<int> &animatedSequenceRef)
-{
- for (int i = 0; i < 64; i++)
- {
- if (!sequence[i])
- break;
- u32* frame = &animatedTexRef[32 * 32 * i];
- ROMIcon(data[SEQ_BMP(sequence[i])], palette[SEQ_PAL(sequence[i])], frame);
-
- if (SEQ_FLIPH(sequence[i]))
- {
- for (int x = 0; x < 32; x++)
- {
- for (int y = 0; y < 32/2; y++)
- {
- std::swap(frame[x * 32 + y], frame[x * 32 + (32 - 1 - y)]);
- }
- }
- }
- if (SEQ_FLIPV(sequence[i]))
- {
- for (int x = 0; x < 32/2; x++)
- {
- for (int y = 0; y < 32; y++)
- {
- std::swap(frame[x * 32 + y], frame[(32 - 1 - x) * 32 + y]);
- }
- }
- }
-
- for (int j = 0; j < SEQ_DUR(sequence[i]); j++)
- animatedSequenceRef.push_back(i);
- }
-}
-
-void UnloadROM(int slot)
-{
- if (slot == ROMSlot_NDS)
- {
- // TODO!
- }
- else if (slot == ROMSlot_GBA)
- {
- GBACart::Eject();
- }
-
- ROMPath[slot][0] = '\0';
-
- DSi::CloseDSiNAND();
-}
-
-int Reset()
-{
- DSi::CloseDSiNAND();
-
- int res;
- bool directboot = Config::DirectBoot != 0;
-
- res = VerifyDSBIOS();
- if (res != Load_OK) return res;
-
- if (Config::ConsoleType == 1)
- {
- res = VerifyDSiBIOS();
- if (res != Load_OK) return res;
-
- res = VerifyDSiFirmware();
- if (res != Load_OK) return res;
-
- res = SetupDSiNAND();
- if (res != Load_OK) return res;
-
- GBACart::Eject();
- ROMPath[ROMSlot_GBA][0] = '\0';
- }
- else
- {
- res = VerifyDSFirmware();
- if (res != Load_OK)
- {
- if (res == Load_FirmwareNotBootable)
- directboot = true;
- else
- return res;
- }
- }
-
- SavestateLoaded = false;
-
- NDS::SetConsoleType(Config::ConsoleType);
-
- if (ROMPath[ROMSlot_NDS][0] == '\0')
- {
- NDS::LoadBIOS();
- }
- else
- {
- char ext[5] = {0}; int _len = strlen(ROMPath[ROMSlot_NDS]);
- strncpy(ext, ROMPath[ROMSlot_NDS] + _len - 4, 4);
-
- if(!strncasecmp(ext, ".nds", 4) || !strncasecmp(ext, ".srl", 4) || !strncasecmp(ext, ".dsi", 4))
- {
- SetupSRAMPath(0);
- if (!NDS::LoadROM(ROMPath[ROMSlot_NDS], SRAMPath[ROMSlot_NDS], directboot))
- return Load_ROMLoadError;
- }
-#ifdef ARCHIVE_SUPPORT_ENABLED
- else
- {
- u8 *romdata = nullptr; u32 romlen;
- char romfilename[1024] = {0}, sramfilename[1024];
- strncpy(sramfilename, SRAMPath[ROMSlot_NDS], 1024); // Use existing SRAMPath
-
- int pos = strlen(sramfilename) - 1;
- while(pos > 0 && sramfilename[pos] != '/' && sramfilename[pos] != '\\')
- --pos;
-
- strncpy(romfilename, &sramfilename[pos + 1], 1024);
- strncpy(&romfilename[strlen(romfilename) - 3], NDSROMExtension, 3); // extension could be nds, srl or dsi
- printf("RESET loading from archive : %s\n", romfilename);
- romlen = Archive::ExtractFileFromArchive(ROMPath[ROMSlot_NDS], romfilename, &romdata);
- if(!romdata)
- return Load_ROMLoadError;
-
- bool ok = NDS::LoadROM(romdata, romlen, sramfilename, directboot);
- delete romdata;
- if(!ok)
- return Load_ROMLoadError;
- }
-#endif
- }
-
- if (ROMPath[ROMSlot_GBA][0] != '\0')
- {
- char ext[5] = {0}; int _len = strlen(ROMPath[ROMSlot_GBA]);
- strncpy(ext, ROMPath[ROMSlot_GBA] + _len - 4, 4);
-
- if(!strncasecmp(ext, ".gba", 4))
- {
- SetupSRAMPath(1);
- if (!NDS::LoadGBAROM(ROMPath[ROMSlot_GBA], SRAMPath[ROMSlot_GBA]))
- return Load_ROMLoadError;
- }
-#ifdef ARCHIVE_SUPPORT_ENABLED
- else
- {
- u8 *romdata = nullptr; u32 romlen;
- char romfilename[1024] = {0}, sramfilename[1024];
- strncpy(sramfilename, SRAMPath[ROMSlot_GBA], 1024); // Use existing SRAMPath
-
- int pos = strlen(sramfilename) - 1;
- while(pos > 0 && sramfilename[pos] != '/' && sramfilename[pos] != '\\')
- --pos;
-
- strncpy(romfilename, &sramfilename[pos + 1], 1024);
- strncpy(&romfilename[strlen(romfilename) - 3], "gba", 3);
- printf("RESET loading from archive : %s\n", romfilename);
- romlen = Archive::ExtractFileFromArchive(ROMPath[ROMSlot_GBA], romfilename, &romdata);
- if(!romdata)
- return Load_ROMLoadError;
-
- bool ok = NDS::LoadGBAROM(romdata, romlen, romfilename, SRAMPath[ROMSlot_GBA]);
- delete romdata;
- if(!ok)
- return Load_ROMLoadError;
- }
-#endif
- }
-
- LoadCheats();
-
- return Load_OK;
-}
-
-
-// SAVESTATE TODO
-// * configurable paths. not everyone wants their ROM directory to be polluted, I guess.
-
-void GetSavestateName(int slot, char* filename, int len)
-{
- int pos;
-
- if (ROMPath[ROMSlot_NDS][0] == '\0') // running firmware, no ROM
- {
- strcpy(filename, "firmware");
- pos = 8;
- }
- else
- {
- char *rompath;
- char ext[5] = {0}; int _len = strlen(ROMPath[ROMSlot_NDS]);
- strncpy(ext, ROMPath[ROMSlot_NDS] + _len - 4, 4);
-
- if(!strncasecmp(ext, ".nds", 4) || !strncasecmp(ext, ".srl", 4) || !strncasecmp(ext, ".dsi", 4))
- rompath = ROMPath[ROMSlot_NDS];
- else
- rompath = SRAMPath[ROMSlot_NDS]; // If archive, construct ssname from sram file
-
- int l = strlen(rompath);
- pos = l;
- while (rompath[pos] != '.' && pos > 0) pos--;
- if (pos == 0) pos = l;
-
- // avoid buffer overflow. shoddy
- if (pos > len-5) pos = len-5;
-
- strncpy(&filename[0], rompath, pos);
- }
- strcpy(&filename[pos], ".ml");
- filename[pos+3] = '0'+slot;
- filename[pos+4] = '\0';
-}
-
-bool SavestateExists(int slot)
-{
- char ssfile[1024];
- GetSavestateName(slot, ssfile, 1024);
- return Platform::FileExists(ssfile);
-}
-
-bool LoadState(const char* filename)
-{
- u32 oldGBACartCRC = GBACart::CartCRC;
-
- // backup
- Savestate* backup = new Savestate("timewarp.mln", true);
- NDS::DoSavestate(backup);
- delete backup;
-
- bool failed = false;
-
- Savestate* state = new Savestate(filename, false);
- if (state->Error)
- {
- delete state;
-
- //uiMsgBoxError(MainWindow, "Error", "Could not load savestate file.");
-
- // current state might be crapoed, so restore from sane backup
- state = new Savestate("timewarp.mln", false);
- failed = true;
- }
-
- NDS::DoSavestate(state);
- delete state;
-
- if (!failed)
- {
- if (Config::SavestateRelocSRAM && ROMPath[ROMSlot_NDS][0]!='\0')
- {
- strncpy(PrevSRAMPath[ROMSlot_NDS], SRAMPath[0], 1024);
-
- strncpy(SRAMPath[ROMSlot_NDS], filename, 1019);
- int len = strlen(SRAMPath[ROMSlot_NDS]);
- strcpy(&SRAMPath[ROMSlot_NDS][len], ".sav");
- SRAMPath[ROMSlot_NDS][len+4] = '\0';
-
- NDS::RelocateSave(SRAMPath[ROMSlot_NDS], false);
- }
-
- bool loadedPartialGBAROM = false;
-
- // in case we have a GBA cart inserted, and the GBA ROM changes
- // due to having loaded a save state, we do not want to reload
- // the previous cartridge on reset, or commit writes to any
- // loaded save file. therefore, their paths are "nulled".
- if (GBACart::CartInserted && GBACart::CartCRC != oldGBACartCRC)
- {
- ROMPath[ROMSlot_GBA][0] = '\0';
- SRAMPath[ROMSlot_GBA][0] = '\0';
- loadedPartialGBAROM = true;
- }
-
- // TODO forward this to user in a meaningful way!!
- /*char msg[64];
- if (slot > 0) sprintf(msg, "State loaded from slot %d%s",
- slot, loadedPartialGBAROM ? " (GBA ROM header only)" : "");
- else sprintf(msg, "State loaded from file%s",
- loadedPartialGBAROM ? " (GBA ROM header only)" : "");
- OSD::AddMessage(0, msg);*/
-
- SavestateLoaded = true;
- }
-
- return !failed;
-}
-
-bool SaveState(const char* filename)
-{
- Savestate* state = new Savestate(filename, true);
- if (state->Error)
- {
- delete state;
- return false;
- }
- else
- {
- NDS::DoSavestate(state);
- delete state;
-
- if (Config::SavestateRelocSRAM && ROMPath[ROMSlot_NDS][0]!='\0')
- {
- strncpy(SRAMPath[ROMSlot_NDS], filename, 1019);
- int len = strlen(SRAMPath[ROMSlot_NDS]);
- strcpy(&SRAMPath[ROMSlot_NDS][len], ".sav");
- SRAMPath[ROMSlot_NDS][len+4] = '\0';
-
- NDS::RelocateSave(SRAMPath[ROMSlot_NDS], true);
- }
- }
-
- return true;
-}
-
-void UndoStateLoad()
-{
- if (!SavestateLoaded) return;
-
- // pray that this works
- // what do we do if it doesn't???
- // but it should work.
- Savestate* backup = new Savestate("timewarp.mln", false);
- NDS::DoSavestate(backup);
- delete backup;
-
- if (ROMPath[ROMSlot_NDS][0]!='\0')
- {
- strncpy(SRAMPath[ROMSlot_NDS], PrevSRAMPath[ROMSlot_NDS], 1024);
- NDS::RelocateSave(SRAMPath[ROMSlot_NDS], false);
- }
-}
-
-int ImportSRAM(const char* filename)
-{
- FILE* file = fopen(filename, "rb");
- fseek(file, 0, SEEK_END);
- u32 size = ftell(file);
- u8* importData = new u8[size];
- rewind(file);
- fread(importData, size, 1, file);
- fclose(file);
-
- int diff = NDS::ImportSRAM(importData, size);
- delete[] importData;
- return diff;
-}
-
-void EnableCheats(bool enable)
-{
- CheatsOn = enable;
- if (CheatFile)
- AREngine::SetCodeFile(CheatsOn ? CheatFile : nullptr);
-}
-
-}
diff --git a/src/frontend/qt_sdl/ArchiveUtil.cpp b/src/frontend/qt_sdl/ArchiveUtil.cpp
index 6919d48..af8e4a9 100644
--- a/src/frontend/qt_sdl/ArchiveUtil.cpp
+++ b/src/frontend/qt_sdl/ArchiveUtil.cpp
@@ -17,43 +17,66 @@
*/
#include "ArchiveUtil.h"
+#include "Platform.h"
namespace Archive
{
-QVector<QString> ListArchive(const char* path)
+#ifdef __WIN32__
+#define melon_archive_open(a, f, b) archive_read_open_filename_w(a, (const wchar_t*)f.utf16(), b)
+#else
+#define melon_archive_open(a, f, b) archive_read_open_filename(a, f.toUtf8().constData(), b)
+#endif // __WIN32__
+
+bool compareCI(const QString& s1, const QString& s2)
+{
+ return s1.toLower() < s2.toLower();
+}
+
+QVector<QString> ListArchive(QString path)
{
struct archive *a;
struct archive_entry *entry;
int r;
- QVector<QString> fileList = {"OK"};
-
+ QVector<QString> fileList;
+
a = archive_read_new();
+
archive_read_support_filter_all(a);
archive_read_support_format_all(a);
- r = archive_read_open_filename(a, path, 10240);
+
+ //r = archive_read_open_filename(a, path, 10240);
+ r = melon_archive_open(a, path, 10240);
if (r != ARCHIVE_OK)
{
return QVector<QString> {"Err"};
}
-
- while (archive_read_next_header(a, &entry) == ARCHIVE_OK)
+
+ while (archive_read_next_header(a, &entry) == ARCHIVE_OK)
{
- fileList.push_back(archive_entry_pathname(entry));
- archive_read_data_skip(a);
+ if (archive_entry_filetype(entry) != AE_IFREG)
+ continue;
+
+ fileList.push_back(archive_entry_pathname_utf8(entry));
+ archive_read_data_skip(a);
}
+
archive_read_close(a);
- archive_read_free(a);
+ archive_read_free(a);
+
if (r != ARCHIVE_OK)
{
return QVector<QString> {"Err"};
}
-
+
+ std::stable_sort(fileList.begin(), fileList.end(), compareCI);
+ fileList.prepend("OK");
+
return fileList;
}
-QVector<QString> ExtractFileFromArchive(const char* path, const char* wantedFile, QByteArray *romBuffer)
+QVector<QString> ExtractFileFromArchive(QString path, QString wantedFile, QByteArray *romBuffer)
{
struct archive *a = archive_read_new();
struct archive_entry *entry;
@@ -61,8 +84,9 @@ QVector<QString> ExtractFileFromArchive(const char* path, const char* wantedFile
archive_read_support_format_all(a);
archive_read_support_filter_all(a);
-
- r = archive_read_open_filename(a, path, 10240);
+
+ //r = archive_read_open_filename(a, path, 10240);
+ r = melon_archive_open(a, path, 10240);
if (r != ARCHIVE_OK)
{
return QVector<QString> {"Err"};
@@ -70,7 +94,7 @@ QVector<QString> ExtractFileFromArchive(const char* path, const char* wantedFile
while (archive_read_next_header(a, &entry) == ARCHIVE_OK)
{
- if (strcmp(wantedFile, archive_entry_pathname(entry)) == 0)
+ if (strcmp(wantedFile.toUtf8().constData(), archive_entry_pathname_utf8(entry)) == 0)
{
break;
}
@@ -92,7 +116,45 @@ QVector<QString> ExtractFileFromArchive(const char* path, const char* wantedFile
}
-u32 ExtractFileFromArchive(const char* path, const char* wantedFile, u8 **romdata)
+u32 ExtractFileFromArchive(QString path, QString wantedFile, u8** filedata, u32* filesize)
+{
+ struct archive *a = archive_read_new();
+ struct archive_entry *entry;
+ int r;
+
+ if (!filedata) return -1;
+
+ archive_read_support_format_all(a);
+ archive_read_support_filter_all(a);
+
+ //r = archive_read_open_filename(a, path, 10240);
+ r = melon_archive_open(a, path, 10240);
+ if (r != ARCHIVE_OK)
+ {
+ return -1;
+ }
+
+ while (archive_read_next_header(a, &entry) == ARCHIVE_OK)
+ {
+ if (strcmp(wantedFile.toUtf8().constData(), archive_entry_pathname_utf8(entry)) == 0)
+ {
+ break;
+ }
+ }
+
+ size_t bytesToRead = archive_entry_size(entry);
+ if (filesize) *filesize = bytesToRead;
+ *filedata = new u8[bytesToRead];
+ ssize_t bytesRead = archive_read_data(a, *filedata, bytesToRead);
+
+ archive_read_close(a);
+ archive_read_free(a);
+
+ return (u32)bytesRead;
+
+}
+
+/*u32 ExtractFileFromArchive(const char* path, const char* wantedFile, u8 **romdata)
{
QByteArray romBuffer;
QVector<QString> extractResult = ExtractFileFromArchive(path, wantedFile, &romBuffer);
@@ -107,6 +169,6 @@ u32 ExtractFileFromArchive(const char* path, const char* wantedFile, u8 **romdat
memcpy(*romdata, romBuffer.data(), len);
return len;
-}
+}*/
}
diff --git a/src/frontend/qt_sdl/ArchiveUtil.h b/src/frontend/qt_sdl/ArchiveUtil.h
index a8a4a14..ce5e192 100644
--- a/src/frontend/qt_sdl/ArchiveUtil.h
+++ b/src/frontend/qt_sdl/ArchiveUtil.h
@@ -34,10 +34,11 @@
namespace Archive
{
-
-QVector<QString> ListArchive(const char* path);
-QVector<QString> ExtractFileFromArchive(const char* path, const char* wantedFile, QByteArray *romBuffer);
-u32 ExtractFileFromArchive(const char* path, const char* wantedFile, u8 **romdata);
+
+QVector<QString> ListArchive(QString path);
+u32 ExtractFileFromArchive(QString path, QString wantedFile, u8** filedata, u32* filesize);
+//QVector<QString> ExtractFileFromArchive(QString path, QString wantedFile, QByteArray *romBuffer);
+//u32 ExtractFileFromArchive(const char* path, const char* wantedFile, u8 **romdata);
}
diff --git a/src/frontend/qt_sdl/AudioSettingsDialog.cpp b/src/frontend/qt_sdl/AudioSettingsDialog.cpp
index d4ce678..dff3055 100644
--- a/src/frontend/qt_sdl/AudioSettingsDialog.cpp
+++ b/src/frontend/qt_sdl/AudioSettingsDialog.cpp
@@ -62,7 +62,7 @@ AudioSettingsDialog::AudioSettingsDialog(QWidget* parent) : QDialog(parent), ui(
connect(grpMicMode, SIGNAL(buttonClicked(int)), this, SLOT(onChangeMicMode(int)));
grpMicMode->button(Config::MicInputType)->setChecked(true);
- ui->txtMicWavPath->setText(Config::MicWavPath);
+ ui->txtMicWavPath->setText(QString::fromStdString(Config::MicWavPath));
bool iswav = (Config::MicInputType == 3);
ui->txtMicWavPath->setEnabled(iswav);
@@ -77,7 +77,7 @@ AudioSettingsDialog::~AudioSettingsDialog()
void AudioSettingsDialog::on_AudioSettingsDialog_accepted()
{
Config::MicInputType = grpMicMode->checkedId();
- strncpy(Config::MicWavPath, ui->txtMicWavPath->text().toStdString().c_str(), 1023); Config::MicWavPath[1023] = '\0';
+ Config::MicWavPath = ui->txtMicWavPath->text().toStdString();
Config::Save();
closeDlg();
diff --git a/src/frontend/qt_sdl/CMakeLists.txt b/src/frontend/qt_sdl/CMakeLists.txt
index ad38e37..b1dfd45 100644
--- a/src/frontend/qt_sdl/CMakeLists.txt
+++ b/src/frontend/qt_sdl/CMakeLists.txt
@@ -12,6 +12,7 @@ SET(SOURCES_QT_SDL
VideoSettingsDialog.cpp
AudioSettingsDialog.cpp
FirmwareSettingsDialog.cpp
+ PathSettingsDialog.cpp
WifiSettingsDialog.cpp
InterfaceSettingsDialog.cpp
ROMInfoDialog.cpp
@@ -24,16 +25,16 @@ SET(SOURCES_QT_SDL
font.h
Platform.cpp
QPathInput.h
+ ROMManager.cpp
+ SaveManager.cpp
ArchiveUtil.h
ArchiveUtil.cpp
- ../Util_ROM.cpp
../Util_Video.cpp
../Util_Audio.cpp
../FrontendUtil.h
../mic_blow.h
- ../SharedConfig.h
${CMAKE_SOURCE_DIR}/res/melon.qrc
)
diff --git a/src/frontend/qt_sdl/CheatsDialog.cpp b/src/frontend/qt_sdl/CheatsDialog.cpp
index afa0805..28211ad 100644
--- a/src/frontend/qt_sdl/CheatsDialog.cpp
+++ b/src/frontend/qt_sdl/CheatsDialog.cpp
@@ -24,6 +24,7 @@
#include "types.h"
#include "Platform.h"
#include "Config.h"
+#include "ROMManager.h"
#include "CheatsDialog.h"
#include "ui_CheatsDialog.h"
@@ -33,15 +34,13 @@ CheatsDialog* CheatsDialog::currentDlg = nullptr;
extern std::string EmuDirectory;
-namespace Frontend { extern ARCodeFile* CheatFile; }
-
CheatsDialog::CheatsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::CheatsDialog)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
- codeFile = Frontend::CheatFile;
+ codeFile = ROMManager::GetCheatFile();
QStandardItemModel* model = new QStandardItemModel();
ui->tvCodeList->setModel(model);
@@ -55,7 +54,7 @@ CheatsDialog::CheatsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::Cheats
{
ARCodeCat& cat = *i;
- QStandardItem* catitem = new QStandardItem(cat.Name);
+ QStandardItem* catitem = new QStandardItem(QString::fromStdString(cat.Name));
catitem->setEditable(true);
catitem->setData(QVariant::fromValue(i));
root->appendRow(catitem);
@@ -64,7 +63,7 @@ CheatsDialog::CheatsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::Cheats
{
ARCode& code = *j;
- QStandardItem* codeitem = new QStandardItem(code.Name);
+ QStandardItem* codeitem = new QStandardItem(QString::fromStdString(code.Name));
codeitem->setEditable(true);
codeitem->setCheckable(true);
codeitem->setCheckState(code.Enabled ? Qt::Checked : Qt::Unchecked);
@@ -113,13 +112,12 @@ void CheatsDialog::on_btnNewCat_clicked()
ARCodeCat cat;
cat.Codes.clear();
- memset(cat.Name, 0, 128);
- strncpy(cat.Name, "(new category)", 127);
+ cat.Name = "(new category)";
codeFile->Categories.push_back(cat);
ARCodeCatList::iterator id = codeFile->Categories.end(); id--;
- QStandardItem* catitem = new QStandardItem(cat.Name);
+ QStandardItem* catitem = new QStandardItem(QString::fromStdString(cat.Name));
catitem->setEditable(true);
catitem->setData(QVariant::fromValue(id));
root->appendRow(catitem);
@@ -160,8 +158,7 @@ void CheatsDialog::on_btnNewARCode_clicked()
ARCodeCat& cat = *it_cat;
ARCode code;
- memset(code.Name, 0, 128);
- strncpy(code.Name, "(new AR code)", 127);
+ code.Name = "(new AR code)";
code.Enabled = true;
code.CodeLen = 0;
memset(code.Code, 0, sizeof(code.Code));
@@ -169,7 +166,7 @@ void CheatsDialog::on_btnNewARCode_clicked()
cat.Codes.push_back(code);
ARCodeList::iterator id = cat.Codes.end(); id--;
- QStandardItem* codeitem = new QStandardItem(code.Name);
+ QStandardItem* codeitem = new QStandardItem(QString::fromStdString(code.Name));
codeitem->setEditable(true);
codeitem->setCheckable(true);
codeitem->setCheckState(code.Enabled ? Qt::Checked : Qt::Unchecked);
@@ -275,13 +272,12 @@ void CheatsDialog::onCheatEntryModified(QStandardItem* item)
if (item->text().isEmpty())
{
- QString oldname = QString(cat.Name);
+ QString oldname = QString::fromStdString(cat.Name);
item->setText(oldname.isEmpty() ? "(blank category name?)" : oldname);
}
else
{
- strncpy(cat.Name, item->text().toStdString().c_str(), 127);
- cat.Name[127] = '\0';
+ cat.Name = item->text().toStdString();
}
}
else if (data.canConvert<ARCodeList::iterator>())
@@ -290,13 +286,12 @@ void CheatsDialog::onCheatEntryModified(QStandardItem* item)
if (item->text().isEmpty())
{
- QString oldname = QString(code.Name);
+ QString oldname = QString::fromStdString(code.Name);
item->setText(oldname.isEmpty() ? "(blank code name?)" : oldname);
}
else
{
- strncpy(code.Name, item->text().toStdString().c_str(), 127);
- code.Name[127] = '\0';
+ code.Name = item->text().toStdString();
}
code.Enabled = (item->checkState() == Qt::Checked);
diff --git a/src/frontend/qt_sdl/Config.cpp b/src/frontend/qt_sdl/Config.cpp
index 30babaf..cf2e0d6 100644
--- a/src/frontend/qt_sdl/Config.cpp
+++ b/src/frontend/qt_sdl/Config.cpp
@@ -36,268 +36,276 @@ int JoystickID;
int WindowWidth;
int WindowHeight;
-int WindowMaximized;
+bool WindowMaximized;
int ScreenRotation;
int ScreenGap;
int ScreenLayout;
-int ScreenSwap;
+bool ScreenSwap;
int ScreenSizing;
-int IntegerScaling;
+bool IntegerScaling;
int ScreenAspectTop;
int ScreenAspectBot;
-int ScreenFilter;
+bool ScreenFilter;
-int ScreenUseGL;
-int ScreenVSync;
+bool ScreenUseGL;
+bool ScreenVSync;
int ScreenVSyncInterval;
int _3DRenderer;
-int Threaded3D;
+bool Threaded3D;
int GL_ScaleFactor;
-int GL_BetterPolygons;
+bool GL_BetterPolygons;
-int LimitFPS;
-int AudioSync;
-int ShowOSD;
+bool LimitFPS;
+bool AudioSync;
+bool ShowOSD;
int ConsoleType;
-int DirectBoot;
+bool DirectBoot;
#ifdef JIT_ENABLED
-int JIT_Enable = false;
+bool JIT_Enable = false;
int JIT_MaxBlockSize = 32;
-int JIT_BranchOptimisations = true;
-int JIT_LiteralOptimisations = true;
-int JIT_FastMemory = true;
+bool JIT_BranchOptimisations = true;
+bool JIT_LiteralOptimisations = true;
+bool JIT_FastMemory = true;
#endif
-int ExternalBIOSEnable;
+bool ExternalBIOSEnable;
-char BIOS9Path[1024];
-char BIOS7Path[1024];
-char FirmwarePath[1024];
+std::string BIOS9Path;
+std::string BIOS7Path;
+std::string FirmwarePath;
-char DSiBIOS9Path[1024];
-char DSiBIOS7Path[1024];
-char DSiFirmwarePath[1024];
-char DSiNANDPath[1024];
+std::string DSiBIOS9Path;
+std::string DSiBIOS7Path;
+std::string DSiFirmwarePath;
+std::string DSiNANDPath;
-int DLDIEnable;
-char DLDISDPath[1024];
+bool DLDIEnable;
+std::string DLDISDPath;
int DLDISize;
-int DLDIReadOnly;
-int DLDIFolderSync;
-char DLDIFolderPath[1024];
+bool DLDIReadOnly;
+bool DLDIFolderSync;
+std::string DLDIFolderPath;
-int DSiSDEnable;
-char DSiSDPath[1024];
+bool DSiSDEnable;
+std::string DSiSDPath;
int DSiSDSize;
-int DSiSDReadOnly;
-int DSiSDFolderSync;
-char DSiSDFolderPath[1024];
+bool DSiSDReadOnly;
+bool DSiSDFolderSync;
+std::string DSiSDFolderPath;
-int FirmwareOverrideSettings;
-char FirmwareUsername[64];
+bool FirmwareOverrideSettings;
+std::string FirmwareUsername;
int FirmwareLanguage;
int FirmwareBirthdayMonth;
int FirmwareBirthdayDay;
int FirmwareFavouriteColour;
-char FirmwareMessage[1024];
-char FirmwareMAC[18];
-int RandomizeMAC;
+std::string FirmwareMessage;
+std::string FirmwareMAC;
+bool RandomizeMAC;
-int SocketBindAnyAddr;
-char LANDevice[128];
-int DirectLAN;
+bool SocketBindAnyAddr;
+std::string LANDevice;
+bool DirectLAN;
-int SavestateRelocSRAM;
+bool SavestateRelocSRAM;
int AudioInterp;
int AudioBitrate;
int AudioVolume;
int MicInputType;
-char MicWavPath[1024];
+std::string MicWavPath;
-char LastROMFolder[1024];
+std::string LastROMFolder;
-char RecentROMList[10][1024];
+std::string RecentROMList[10];
-int EnableCheats;
+std::string SaveFilePath;
+std::string SavestatePath;
+std::string CheatFilePath;
-int MouseHide;
+bool EnableCheats;
+
+bool MouseHide;
int MouseHideSeconds;
-int PauseLostFocus;
+bool PauseLostFocus;
const char* kConfigFile = "melonDS.ini";
ConfigEntry ConfigFile[] =
{
- {"Key_A", 0, &KeyMapping[0], -1, NULL, 0},
- {"Key_B", 0, &KeyMapping[1], -1, NULL, 0},
- {"Key_Select", 0, &KeyMapping[2], -1, NULL, 0},
- {"Key_Start", 0, &KeyMapping[3], -1, NULL, 0},
- {"Key_Right", 0, &KeyMapping[4], -1, NULL, 0},
- {"Key_Left", 0, &KeyMapping[5], -1, NULL, 0},
- {"Key_Up", 0, &KeyMapping[6], -1, NULL, 0},
- {"Key_Down", 0, &KeyMapping[7], -1, NULL, 0},
- {"Key_R", 0, &KeyMapping[8], -1, NULL, 0},
- {"Key_L", 0, &KeyMapping[9], -1, NULL, 0},
- {"Key_X", 0, &KeyMapping[10], -1, NULL, 0},
- {"Key_Y", 0, &KeyMapping[11], -1, NULL, 0},
-
- {"Joy_A", 0, &JoyMapping[0], -1, NULL, 0},
- {"Joy_B", 0, &JoyMapping[1], -1, NULL, 0},
- {"Joy_Select", 0, &JoyMapping[2], -1, NULL, 0},
- {"Joy_Start", 0, &JoyMapping[3], -1, NULL, 0},
- {"Joy_Right", 0, &JoyMapping[4], -1, NULL, 0},
- {"Joy_Left", 0, &JoyMapping[5], -1, NULL, 0},
- {"Joy_Up", 0, &JoyMapping[6], -1, NULL, 0},
- {"Joy_Down", 0, &JoyMapping[7], -1, NULL, 0},
- {"Joy_R", 0, &JoyMapping[8], -1, NULL, 0},
- {"Joy_L", 0, &JoyMapping[9], -1, NULL, 0},
- {"Joy_X", 0, &JoyMapping[10], -1, NULL, 0},
- {"Joy_Y", 0, &JoyMapping[11], -1, NULL, 0},
-
- {"HKKey_Lid", 0, &HKKeyMapping[HK_Lid], -1, NULL, 0},
- {"HKKey_Mic", 0, &HKKeyMapping[HK_Mic], -1, NULL, 0},
- {"HKKey_Pause", 0, &HKKeyMapping[HK_Pause], -1, NULL, 0},
- {"HKKey_Reset", 0, &HKKeyMapping[HK_Reset], -1, NULL, 0},
- {"HKKey_FastForward", 0, &HKKeyMapping[HK_FastForward], -1, NULL, 0},
- {"HKKey_FastForwardToggle", 0, &HKKeyMapping[HK_FastForwardToggle], -1, NULL, 0},
- {"HKKey_FullscreenToggle", 0, &HKKeyMapping[HK_FullscreenToggle], -1, NULL, 0},
- {"HKKey_SwapScreens", 0, &HKKeyMapping[HK_SwapScreens], -1, NULL, 0},
- {"HKKey_SolarSensorDecrease", 0, &HKKeyMapping[HK_SolarSensorDecrease], -1, NULL, 0},
- {"HKKey_SolarSensorIncrease", 0, &HKKeyMapping[HK_SolarSensorIncrease], -1, NULL, 0},
- {"HKKey_FrameStep", 0, &HKKeyMapping[HK_FrameStep], -1, NULL, 0},
-
- {"HKJoy_Lid", 0, &HKJoyMapping[HK_Lid], -1, NULL, 0},
- {"HKJoy_Mic", 0, &HKJoyMapping[HK_Mic], -1, NULL, 0},
- {"HKJoy_Pause", 0, &HKJoyMapping[HK_Pause], -1, NULL, 0},
- {"HKJoy_Reset", 0, &HKJoyMapping[HK_Reset], -1, NULL, 0},
- {"HKJoy_FastForward", 0, &HKJoyMapping[HK_FastForward], -1, NULL, 0},
- {"HKJoy_FastForwardToggle", 0, &HKJoyMapping[HK_FastForwardToggle], -1, NULL, 0},
- {"HKJoy_FullscreenToggle", 0, &HKJoyMapping[HK_FullscreenToggle], -1, NULL, 0},
- {"HKJoy_SwapScreens", 0, &HKJoyMapping[HK_SwapScreens], -1, NULL, 0},
- {"HKJoy_SolarSensorDecrease", 0, &HKJoyMapping[HK_SolarSensorDecrease], -1, NULL, 0},
- {"HKJoy_SolarSensorIncrease", 0, &HKJoyMapping[HK_SolarSensorIncrease], -1, NULL, 0},
- {"HKJoy_FrameStep", 0, &HKJoyMapping[HK_FrameStep], -1, NULL, 0},
-
- {"JoystickID", 0, &JoystickID, 0, NULL, 0},
-
- {"WindowWidth", 0, &WindowWidth, 256, NULL, 0},
- {"WindowHeight", 0, &WindowHeight, 384, NULL, 0},
- {"WindowMax", 0, &WindowMaximized, 0, NULL, 0},
-
- {"ScreenRotation", 0, &ScreenRotation, 0, NULL, 0},
- {"ScreenGap", 0, &ScreenGap, 0, NULL, 0},
- {"ScreenLayout", 0, &ScreenLayout, 0, NULL, 0},
- {"ScreenSwap", 0, &ScreenSwap, 0, NULL, 0},
- {"ScreenSizing", 0, &ScreenSizing, 0, NULL, 0},
- {"IntegerScaling", 0, &IntegerScaling, 0, NULL, 0},
- {"ScreenAspectTop",0, &ScreenAspectTop,0, NULL, 0},
- {"ScreenAspectBot",0, &ScreenAspectBot,0, NULL, 0},
- {"ScreenFilter", 0, &ScreenFilter, 1, NULL, 0},
-
- {"ScreenUseGL", 0, &ScreenUseGL, 0, NULL, 0},
- {"ScreenVSync", 0, &ScreenVSync, 0, NULL, 0},
- {"ScreenVSyncInterval", 0, &ScreenVSyncInterval, 1, NULL, 0},
-
- {"3DRenderer", 0, &_3DRenderer, 0, NULL, 0},
- {"Threaded3D", 0, &Threaded3D, 1, NULL, 0},
-
- {"GL_ScaleFactor", 0, &GL_ScaleFactor, 1, NULL, 0},
- {"GL_BetterPolygons", 0, &GL_BetterPolygons, 0, NULL, 0},
-
- {"LimitFPS", 0, &LimitFPS, 1, NULL, 0},
- {"AudioSync", 0, &AudioSync, 0, NULL, 0},
- {"ShowOSD", 0, &ShowOSD, 1, NULL, 0},
-
- {"ConsoleType", 0, &ConsoleType, 0, NULL, 0},
- {"DirectBoot", 0, &DirectBoot, 1, NULL, 0},
+ {"Key_A", 0, &KeyMapping[0], -1},
+ {"Key_B", 0, &KeyMapping[1], -1},
+ {"Key_Select", 0, &KeyMapping[2], -1},
+ {"Key_Start", 0, &KeyMapping[3], -1},
+ {"Key_Right", 0, &KeyMapping[4], -1},
+ {"Key_Left", 0, &KeyMapping[5], -1},
+ {"Key_Up", 0, &KeyMapping[6], -1},
+ {"Key_Down", 0, &KeyMapping[7], -1},
+ {"Key_R", 0, &KeyMapping[8], -1},
+ {"Key_L", 0, &KeyMapping[9], -1},
+ {"Key_X", 0, &KeyMapping[10], -1},
+ {"Key_Y", 0, &KeyMapping[11], -1},
+
+ {"Joy_A", 0, &JoyMapping[0], -1},
+ {"Joy_B", 0, &JoyMapping[1], -1},
+ {"Joy_Select", 0, &JoyMapping[2], -1},
+ {"Joy_Start", 0, &JoyMapping[3], -1},
+ {"Joy_Right", 0, &JoyMapping[4], -1},
+ {"Joy_Left", 0, &JoyMapping[5], -1},
+ {"Joy_Up", 0, &JoyMapping[6], -1},
+ {"Joy_Down", 0, &JoyMapping[7], -1},
+ {"Joy_R", 0, &JoyMapping[8], -1},
+ {"Joy_L", 0, &JoyMapping[9], -1},
+ {"Joy_X", 0, &JoyMapping[10], -1},
+ {"Joy_Y", 0, &JoyMapping[11], -1},
+
+ {"HKKey_Lid", 0, &HKKeyMapping[HK_Lid], -1},
+ {"HKKey_Mic", 0, &HKKeyMapping[HK_Mic], -1},
+ {"HKKey_Pause", 0, &HKKeyMapping[HK_Pause], -1},
+ {"HKKey_Reset", 0, &HKKeyMapping[HK_Reset], -1},
+ {"HKKey_FastForward", 0, &HKKeyMapping[HK_FastForward], -1},
+ {"HKKey_FastForwardToggle", 0, &HKKeyMapping[HK_FastForwardToggle], -1},
+ {"HKKey_FullscreenToggle", 0, &HKKeyMapping[HK_FullscreenToggle], -1},
+ {"HKKey_SwapScreens", 0, &HKKeyMapping[HK_SwapScreens], -1},
+ {"HKKey_SolarSensorDecrease", 0, &HKKeyMapping[HK_SolarSensorDecrease], -1},
+ {"HKKey_SolarSensorIncrease", 0, &HKKeyMapping[HK_SolarSensorIncrease], -1},
+ {"HKKey_FrameStep", 0, &HKKeyMapping[HK_FrameStep], -1},
+
+ {"HKJoy_Lid", 0, &HKJoyMapping[HK_Lid], -1},
+ {"HKJoy_Mic", 0, &HKJoyMapping[HK_Mic], -1},
+ {"HKJoy_Pause", 0, &HKJoyMapping[HK_Pause], -1},
+ {"HKJoy_Reset", 0, &HKJoyMapping[HK_Reset], -1},
+ {"HKJoy_FastForward", 0, &HKJoyMapping[HK_FastForward], -1},
+ {"HKJoy_FastForwardToggle", 0, &HKJoyMapping[HK_FastForwardToggle], -1},
+ {"HKJoy_FullscreenToggle", 0, &HKJoyMapping[HK_FullscreenToggle], -1},
+ {"HKJoy_SwapScreens", 0, &HKJoyMapping[HK_SwapScreens], -1},
+ {"HKJoy_SolarSensorDecrease", 0, &HKJoyMapping[HK_SolarSensorDecrease], -1},
+ {"HKJoy_SolarSensorIncrease", 0, &HKJoyMapping[HK_SolarSensorIncrease], -1},
+ {"HKJoy_FrameStep", 0, &HKJoyMapping[HK_FrameStep], -1},
+
+ {"JoystickID", 0, &JoystickID, 0},
+
+ {"WindowWidth", 0, &WindowWidth, 256},
+ {"WindowHeight", 0, &WindowHeight, 384},
+ {"WindowMax", 1, &WindowMaximized, false},
+
+ {"ScreenRotation", 0, &ScreenRotation, 0},
+ {"ScreenGap", 0, &ScreenGap, 0},
+ {"ScreenLayout", 0, &ScreenLayout, 0},
+ {"ScreenSwap", 1, &ScreenSwap, false},
+ {"ScreenSizing", 0, &ScreenSizing, 0},
+ {"IntegerScaling", 1, &IntegerScaling, false},
+ {"ScreenAspectTop",0, &ScreenAspectTop,0},
+ {"ScreenAspectBot",0, &ScreenAspectBot,0},
+ {"ScreenFilter", 1, &ScreenFilter, true},
+
+ {"ScreenUseGL", 1, &ScreenUseGL, false},
+ {"ScreenVSync", 1, &ScreenVSync, false},
+ {"ScreenVSyncInterval", 0, &ScreenVSyncInterval, 1},
+
+ {"3DRenderer", 0, &_3DRenderer, 0},
+ {"Threaded3D", 1, &Threaded3D, true},
+
+ {"GL_ScaleFactor", 0, &GL_ScaleFactor, 1},
+ {"GL_BetterPolygons", 1, &GL_BetterPolygons, false},
+
+ {"LimitFPS", 1, &LimitFPS, true},
+ {"AudioSync", 1, &AudioSync, false},
+ {"ShowOSD", 1, &ShowOSD, true},
+
+ {"ConsoleType", 0, &ConsoleType, 0},
+ {"DirectBoot", 1, &DirectBoot, true},
#ifdef JIT_ENABLED
- {"JIT_Enable", 0, &JIT_Enable, 0, NULL, 0},
- {"JIT_MaxBlockSize", 0, &JIT_MaxBlockSize, 32, NULL, 0},
- {"JIT_BranchOptimisations", 0, &JIT_BranchOptimisations, 1, NULL, 0},
- {"JIT_LiteralOptimisations", 0, &JIT_LiteralOptimisations, 1, NULL, 0},
+ {"JIT_Enable", 1, &JIT_Enable, false},
+ {"JIT_MaxBlockSize", 0, &JIT_MaxBlockSize, 32},
+ {"JIT_BranchOptimisations", 1, &JIT_BranchOptimisations, true},
+ {"JIT_LiteralOptimisations", 1, &JIT_LiteralOptimisations, true},
#ifdef __APPLE__
- {"JIT_FastMemory", 0, &JIT_FastMemory, 0, NULL, 0},
+ {"JIT_FastMemory", 1, &JIT_FastMemory, false},
#else
- {"JIT_FastMemory", 0, &JIT_FastMemory, 1, NULL, 0},
+ {"JIT_FastMemory", 1, &JIT_FastMemory, true},
#endif
#endif
- {"ExternalBIOSEnable", 0, &ExternalBIOSEnable, 0, NULL, 0},
-
- {"BIOS9Path", 1, BIOS9Path, 0, "", 1023},
- {"BIOS7Path", 1, BIOS7Path, 0, "", 1023},
- {"FirmwarePath", 1, FirmwarePath, 0, "", 1023},
-
- {"DSiBIOS9Path", 1, DSiBIOS9Path, 0, "", 1023},
- {"DSiBIOS7Path", 1, DSiBIOS7Path, 0, "", 1023},
- {"DSiFirmwarePath", 1, DSiFirmwarePath, 0, "", 1023},
- {"DSiNANDPath", 1, DSiNANDPath, 0, "", 1023},
-
- {"DLDIEnable", 0, &DLDIEnable, 0, NULL, 0},
- {"DLDISDPath", 1, DLDISDPath, 0, "dldi.bin", 1023},
- {"DLDISize", 0, &DLDISize, 0, NULL, 0},
- {"DLDIReadOnly", 0, &DLDIReadOnly, 0, NULL, 0},
- {"DLDIFolderSync", 0, &DLDIFolderSync, 0, NULL, 0},
- {"DLDIFolderPath", 1, DLDIFolderPath, 0, "", 1023},
-
- {"DSiSDEnable", 0, &DSiSDEnable, 0, NULL, 0},
- {"DSiSDPath", 1, DSiSDPath, 0, "dsisd.bin", 1023},
- {"DSiSDSize", 0, &DSiSDSize, 0, NULL, 0},
- {"DSiSDReadOnly", 0, &DSiSDReadOnly, 0, NULL, 0},
- {"DSiSDFolderSync", 0, &DSiSDFolderSync, 0, NULL, 0},
- {"DSiSDFolderPath", 1, DSiSDFolderPath, 0, "", 1023},
-
- {"FirmwareOverrideSettings", 0, &FirmwareOverrideSettings, false, NULL, 0},
- {"FirmwareUsername", 1, FirmwareUsername, 0, "melonDS", 63},
- {"FirmwareLanguage", 0, &FirmwareLanguage, 1, NULL, 0},
- {"FirmwareBirthdayMonth", 0, &FirmwareBirthdayMonth, 0, NULL, 0},
- {"FirmwareBirthdayDay", 0, &FirmwareBirthdayDay, 0, NULL, 0},
- {"FirmwareFavouriteColour", 0, &FirmwareFavouriteColour, 0, NULL, 0},
- {"FirmwareMessage", 1, FirmwareMessage, 0, "", 1023},
- {"FirmwareMAC", 1, FirmwareMAC, 0, "", 17},
- {"RandomizeMAC", 0, &RandomizeMAC, 0, NULL, 0},
-
- {"SockBindAnyAddr", 0, &SocketBindAnyAddr, 0, NULL, 0},
- {"LANDevice", 1, LANDevice, 0, "", 127},
- {"DirectLAN", 0, &DirectLAN, 0, NULL, 0},
-
- {"SavStaRelocSRAM", 0, &SavestateRelocSRAM, 0, NULL, 0},
-
- {"AudioInterp", 0, &AudioInterp, 0, NULL, 0},
- {"AudioBitrate", 0, &AudioBitrate, 0, NULL, 0},
- {"AudioVolume", 0, &AudioVolume, 256, NULL, 0},
- {"MicInputType", 0, &MicInputType, 1, NULL, 0},
- {"MicWavPath", 1, MicWavPath, 0, "", 1023},
-
- {"LastROMFolder", 1, LastROMFolder, 0, "", 1023},
-
- {"RecentROM_0", 1, RecentROMList[0], 0, "", 1023},
- {"RecentROM_1", 1, RecentROMList[1], 0, "", 1023},
- {"RecentROM_2", 1, RecentROMList[2], 0, "", 1023},
- {"RecentROM_3", 1, RecentROMList[3], 0, "", 1023},
- {"RecentROM_4", 1, RecentROMList[4], 0, "", 1023},
- {"RecentROM_5", 1, RecentROMList[5], 0, "", 1023},
- {"RecentROM_6", 1, RecentROMList[6], 0, "", 1023},
- {"RecentROM_7", 1, RecentROMList[7], 0, "", 1023},
- {"RecentROM_8", 1, RecentROMList[8], 0, "", 1023},
- {"RecentROM_9", 1, RecentROMList[9], 0, "", 1023},
-
- {"EnableCheats", 0, &EnableCheats, 0, NULL, 0},
-
- {"MouseHide", 0, &MouseHide, 0, NULL, 0},
- {"MouseHideSeconds", 0, &MouseHideSeconds, 5, NULL, 0},
- {"PauseLostFocus", 0, &PauseLostFocus, 0, NULL, 0},
-
- {"", -1, NULL, 0, NULL, 0}
+ {"ExternalBIOSEnable", 1, &ExternalBIOSEnable, false},
+
+ {"BIOS9Path", 2, &BIOS9Path, ""},
+ {"BIOS7Path", 2, &BIOS7Path, ""},
+ {"FirmwarePath", 2, &FirmwarePath, ""},
+
+ {"DSiBIOS9Path", 2, &DSiBIOS9Path, ""},
+ {"DSiBIOS7Path", 2, &DSiBIOS7Path, ""},
+ {"DSiFirmwarePath", 2, &DSiFirmwarePath, ""},
+ {"DSiNANDPath", 2, &DSiNANDPath, ""},
+
+ {"DLDIEnable", 1, &DLDIEnable, false},
+ {"DLDISDPath", 2, &DLDISDPath, "dldi.bin"},
+ {"DLDISize", 0, &DLDISize, 0},
+ {"DLDIReadOnly", 1, &DLDIReadOnly, false},
+ {"DLDIFolderSync", 1, &DLDIFolderSync, false},
+ {"DLDIFolderPath", 2, &DLDIFolderPath, ""},
+
+ {"DSiSDEnable", 1, &DSiSDEnable, false},
+ {"DSiSDPath", 2, &DSiSDPath, "dsisd.bin"},
+ {"DSiSDSize", 0, &DSiSDSize, 0},
+ {"DSiSDReadOnly", 1, &DSiSDReadOnly, false},
+ {"DSiSDFolderSync", 1, &DSiSDFolderSync, false},
+ {"DSiSDFolderPath", 2, &DSiSDFolderPath, ""},
+
+ {"FirmwareOverrideSettings", 1, &FirmwareOverrideSettings, false},
+ {"FirmwareUsername", 2, &FirmwareUsername, "melonDS"},
+ {"FirmwareLanguage", 0, &FirmwareLanguage, 1},
+ {"FirmwareBirthdayMonth", 0, &FirmwareBirthdayMonth, 1},
+ {"FirmwareBirthdayDay", 0, &FirmwareBirthdayDay, 1},
+ {"FirmwareFavouriteColour", 0, &FirmwareFavouriteColour, 0},
+ {"FirmwareMessage", 2, &FirmwareMessage, ""},
+ {"FirmwareMAC", 2, &FirmwareMAC, ""},
+ {"RandomizeMAC", 1, &RandomizeMAC, false},
+
+ {"SockBindAnyAddr", 1, &SocketBindAnyAddr, false},
+ {"LANDevice", 2, &LANDevice, ""},
+ {"DirectLAN", 1, &DirectLAN, false},
+
+ {"SavStaRelocSRAM", 1, &SavestateRelocSRAM, false},
+
+ {"AudioInterp", 0, &AudioInterp, 0},
+ {"AudioBitrate", 0, &AudioBitrate, 0},
+ {"AudioVolume", 0, &AudioVolume, 256},
+ {"MicInputType", 0, &MicInputType, 1},
+ {"MicWavPath", 2, &MicWavPath, ""},
+
+ {"LastROMFolder", 2, &LastROMFolder, ""},
+
+ {"RecentROM_0", 2, &RecentROMList[0], ""},
+ {"RecentROM_1", 2, &RecentROMList[1], ""},
+ {"RecentROM_2", 2, &RecentROMList[2], ""},
+ {"RecentROM_3", 2, &RecentROMList[3], ""},
+ {"RecentROM_4", 2, &RecentROMList[4], ""},
+ {"RecentROM_5", 2, &RecentROMList[5], ""},
+ {"RecentROM_6", 2, &RecentROMList[6], ""},
+ {"RecentROM_7", 2, &RecentROMList[7], ""},
+ {"RecentROM_8", 2, &RecentROMList[8], ""},
+ {"RecentROM_9", 2, &RecentROMList[9], ""},
+
+ {"SaveFilePath", 2, &SaveFilePath, ""},
+ {"SavestatePath", 2, &SavestatePath, ""},
+ {"CheatFilePath", 2, &CheatFilePath, ""},
+
+ {"EnableCheats", 1, &EnableCheats, false},
+
+ {"MouseHide", 1, &MouseHide, false},
+ {"MouseHideSeconds", 0, &MouseHideSeconds, 5},
+ {"PauseLostFocus", 1, &PauseLostFocus, false},
+
+ {"", -1, nullptr, 0}
};
@@ -308,12 +316,11 @@ void Load()
{
if (!entry->Value) break;
- if (entry->Type == 0)
- *(int*)entry->Value = entry->DefaultInt;
- else
+ switch (entry->Type)
{
- strncpy((char*)entry->Value, entry->DefaultStr, entry->StrLength);
- ((char*)entry->Value)[entry->StrLength] = '\0';
+ case 0: *(int*)entry->Value = std::get<int>(entry->Default); break;
+ case 1: *(bool*)entry->Value = std::get<bool>(entry->Default); break;
+ case 2: *(std::string*)entry->Value = std::get<std::string>(entry->Default); break;
}
entry++;
@@ -341,10 +348,12 @@ void Load()
if (!strncmp(entry->Name, entryname, 32))
{
- if (entry->Type == 0)
- *(int*)entry->Value = strtol(entryval, NULL, 10);
- else
- strncpy((char*)entry->Value, entryval, entry->StrLength);
+ switch (entry->Type)
+ {
+ case 0: *(int*)entry->Value = strtol(entryval, NULL, 10); break;
+ case 1: *(bool*)entry->Value = strtol(entryval, NULL, 10) ? true:false; break;
+ case 2: *(std::string*)entry->Value = entryval; break;
+ }
break;
}
@@ -366,10 +375,12 @@ void Save()
{
if (!entry->Value) break;
- if (entry->Type == 0)
- fprintf(f, "%s=%d\r\n", entry->Name, *(int*)entry->Value);
- else
- fprintf(f, "%s=%s\r\n", entry->Name, (char*)entry->Value);
+ switch (entry->Type)
+ {
+ case 0: fprintf(f, "%s=%d\r\n", entry->Name, *(int*)entry->Value); break;
+ case 1: fprintf(f, "%s=%d\r\n", entry->Name, *(bool*)entry->Value ? 1:0); break;
+ case 2: fprintf(f, "%s=%s\r\n", entry->Name, (*(std::string*)entry->Value).c_str()); break;
+ }
entry++;
}
diff --git a/src/frontend/qt_sdl/Config.h b/src/frontend/qt_sdl/Config.h
index ad9b4c6..902ec6d 100644
--- a/src/frontend/qt_sdl/Config.h
+++ b/src/frontend/qt_sdl/Config.h
@@ -19,6 +19,9 @@
#ifndef PLATFORMCONFIG_H
#define PLATFORMCONFIG_H
+#include <variant>
+#include <string>
+
enum
{
HK_Lid = 0,
@@ -41,11 +44,9 @@ namespace Config
struct ConfigEntry
{
char Name[32];
- int Type;
- void* Value;
- int DefaultInt;
- const char* DefaultStr;
- int StrLength; // should be set to actual array length minus one
+ int Type; // 0=int 1=bool 2=string
+ void* Value; // pointer to the value variable
+ std::variant<int, bool, std::string> Default;
};
@@ -59,99 +60,103 @@ extern int JoystickID;
extern int WindowWidth;
extern int WindowHeight;
-extern int WindowMaximized;
+extern bool WindowMaximized;
extern int ScreenRotation;
extern int ScreenGap;
extern int ScreenLayout;
-extern int ScreenSwap;
+extern bool ScreenSwap;
extern int ScreenSizing;
extern int ScreenAspectTop;
extern int ScreenAspectBot;
-extern int IntegerScaling;
-extern int ScreenFilter;
+extern bool IntegerScaling;
+extern bool ScreenFilter;
-extern int ScreenUseGL;
-extern int ScreenVSync;
+extern bool ScreenUseGL;
+extern bool ScreenVSync;
extern int ScreenVSyncInterval;
extern int _3DRenderer;
-extern int Threaded3D;
+extern bool Threaded3D;
extern int GL_ScaleFactor;
-extern int GL_BetterPolygons;
+extern bool GL_BetterPolygons;
-extern int LimitFPS;
-extern int AudioSync;
-extern int ShowOSD;
+extern bool LimitFPS;
+extern bool AudioSync;
+extern bool ShowOSD;
extern int ConsoleType;
-extern int DirectBoot;
+extern bool DirectBoot;
#ifdef JIT_ENABLED
-extern int JIT_Enable;
+extern bool JIT_Enable;
extern int JIT_MaxBlockSize;
-extern int JIT_BranchOptimisations;
-extern int JIT_LiteralOptimisations;
-extern int JIT_FastMemory;
+extern bool JIT_BranchOptimisations;
+extern bool JIT_LiteralOptimisations;
+extern bool JIT_FastMemory;
#endif
-extern int ExternalBIOSEnable;
+extern bool ExternalBIOSEnable;
-extern char BIOS9Path[1024];
-extern char BIOS7Path[1024];
-extern char FirmwarePath[1024];
+extern std::string BIOS9Path;
+extern std::string BIOS7Path;
+extern std::string FirmwarePath;
-extern char DSiBIOS9Path[1024];
-extern char DSiBIOS7Path[1024];
-extern char DSiFirmwarePath[1024];
-extern char DSiNANDPath[1024];
+extern std::string DSiBIOS9Path;
+extern std::string DSiBIOS7Path;
+extern std::string DSiFirmwarePath;
+extern std::string DSiNANDPath;
-extern int DLDIEnable;
-extern char DLDISDPath[1024];
+extern bool DLDIEnable;
+extern std::string DLDISDPath;
extern int DLDISize;
-extern int DLDIReadOnly;
-extern int DLDIFolderSync;
-extern char DLDIFolderPath[1024];
+extern bool DLDIReadOnly;
+extern bool DLDIFolderSync;
+extern std::string DLDIFolderPath;
-extern int DSiSDEnable;
-extern char DSiSDPath[1024];
+extern bool DSiSDEnable;
+extern std::string DSiSDPath;
extern int DSiSDSize;
-extern int DSiSDReadOnly;
-extern int DSiSDFolderSync;
-extern char DSiSDFolderPath[1024];
+extern bool DSiSDReadOnly;
+extern bool DSiSDFolderSync;
+extern std::string DSiSDFolderPath;
-extern int FirmwareOverrideSettings;
-extern char FirmwareUsername[64];
+extern bool FirmwareOverrideSettings;
+extern std::string FirmwareUsername;
extern int FirmwareLanguage;
extern int FirmwareBirthdayMonth;
extern int FirmwareBirthdayDay;
extern int FirmwareFavouriteColour;
-extern char FirmwareMessage[1024];
-extern char FirmwareMAC[18];
-extern int RandomizeMAC;
+extern std::string FirmwareMessage;
+extern std::string FirmwareMAC;
+extern bool RandomizeMAC;
-extern int SocketBindAnyAddr;
-extern char LANDevice[128];
-extern int DirectLAN;
+extern bool SocketBindAnyAddr;
+extern std::string LANDevice;
+extern bool DirectLAN;
-extern int SavestateRelocSRAM;
+extern bool SavestateRelocSRAM;
extern int AudioInterp;
extern int AudioBitrate;
extern int AudioVolume;
extern int MicInputType;
-extern char MicWavPath[1024];
+extern std::string MicWavPath;
+
+extern std::string LastROMFolder;
-extern char LastROMFolder[1024];
+extern std::string RecentROMList[10];
-extern char RecentROMList[10][1024];
+extern std::string SaveFilePath;
+extern std::string SavestatePath;
+extern std::string CheatFilePath;
-extern int EnableCheats;
+extern bool EnableCheats;
-extern int MouseHide;
+extern bool MouseHide;
extern int MouseHideSeconds;
-extern int PauseLostFocus;
+extern bool PauseLostFocus;
void Load();
diff --git a/src/frontend/qt_sdl/EmuSettingsDialog.cpp b/src/frontend/qt_sdl/EmuSettingsDialog.cpp
index fd2ca85..7511881 100644
--- a/src/frontend/qt_sdl/EmuSettingsDialog.cpp
+++ b/src/frontend/qt_sdl/EmuSettingsDialog.cpp
@@ -42,27 +42,27 @@ EmuSettingsDialog::EmuSettingsDialog(QWidget* parent) : QDialog(parent), ui(new
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
- ui->chkExternalBIOS->setChecked(Config::ExternalBIOSEnable != 0);
- ui->txtBIOS9Path->setText(Config::BIOS9Path);
- ui->txtBIOS7Path->setText(Config::BIOS7Path);
- ui->txtFirmwarePath->setText(Config::FirmwarePath);
+ ui->chkExternalBIOS->setChecked(Config::ExternalBIOSEnable);
+ ui->txtBIOS9Path->setText(QString::fromStdString(Config::BIOS9Path));
+ ui->txtBIOS7Path->setText(QString::fromStdString(Config::BIOS7Path));
+ ui->txtFirmwarePath->setText(QString::fromStdString(Config::FirmwarePath));
- ui->txtDSiBIOS9Path->setText(Config::DSiBIOS9Path);
- ui->txtDSiBIOS7Path->setText(Config::DSiBIOS7Path);
- ui->txtDSiFirmwarePath->setText(Config::DSiFirmwarePath);
- ui->txtDSiNANDPath->setText(Config::DSiNANDPath);
+ ui->txtDSiBIOS9Path->setText(QString::fromStdString(Config::DSiBIOS9Path));
+ ui->txtDSiBIOS7Path->setText(QString::fromStdString(Config::DSiBIOS7Path));
+ ui->txtDSiFirmwarePath->setText(QString::fromStdString(Config::DSiFirmwarePath));
+ ui->txtDSiNANDPath->setText(QString::fromStdString(Config::DSiNANDPath));
ui->cbxConsoleType->addItem("DS");
ui->cbxConsoleType->addItem("DSi (experimental)");
ui->cbxConsoleType->setCurrentIndex(Config::ConsoleType);
- ui->chkDirectBoot->setChecked(Config::DirectBoot != 0);
+ ui->chkDirectBoot->setChecked(Config::DirectBoot);
#ifdef JIT_ENABLED
- ui->chkEnableJIT->setChecked(Config::JIT_Enable != 0);
- ui->chkJITBranchOptimisations->setChecked(Config::JIT_BranchOptimisations != 0);
- ui->chkJITLiteralOptimisations->setChecked(Config::JIT_LiteralOptimisations != 0);
- ui->chkJITFastMemory->setChecked(Config::JIT_FastMemory != 0);
+ ui->chkEnableJIT->setChecked(Config::JIT_Enable);
+ ui->chkJITBranchOptimisations->setChecked(Config::JIT_BranchOptimisations);
+ ui->chkJITLiteralOptimisations->setChecked(Config::JIT_LiteralOptimisations);
+ ui->chkJITFastMemory->setChecked(Config::JIT_FastMemory);
#ifdef __APPLE__
ui->chkJITFastMemory->setDisabled(true);
#endif
@@ -101,20 +101,20 @@ EmuSettingsDialog::EmuSettingsDialog(QWidget* parent) : QDialog(parent), ui(new
ui->cbxDSiSDSize->addItem(sizelbl);
}
- ui->cbDLDIEnable->setChecked(Config::DLDIEnable != 0);
- ui->txtDLDISDPath->setText(Config::DLDISDPath);
+ ui->cbDLDIEnable->setChecked(Config::DLDIEnable);
+ ui->txtDLDISDPath->setText(QString::fromStdString(Config::DLDISDPath));
ui->cbxDLDISize->setCurrentIndex(Config::DLDISize);
- ui->cbDLDIReadOnly->setChecked(Config::DLDIReadOnly != 0);
- ui->cbDLDIFolder->setChecked(Config::DLDIFolderSync != 0);
- ui->txtDLDIFolder->setText(Config::DLDIFolderPath);
+ ui->cbDLDIReadOnly->setChecked(Config::DLDIReadOnly);
+ ui->cbDLDIFolder->setChecked(Config::DLDIFolderSync);
+ ui->txtDLDIFolder->setText(QString::fromStdString(Config::DLDIFolderPath));
on_cbDLDIEnable_toggled();
- ui->cbDSiSDEnable->setChecked(Config::DSiSDEnable != 0);
- ui->txtDSiSDPath->setText(Config::DSiSDPath);
+ ui->cbDSiSDEnable->setChecked(Config::DSiSDEnable);
+ ui->txtDSiSDPath->setText(QString::fromStdString(Config::DSiSDPath));
ui->cbxDSiSDSize->setCurrentIndex(Config::DSiSDSize);
- ui->cbDSiSDReadOnly->setChecked(Config::DSiSDReadOnly != 0);
- ui->cbDSiSDFolder->setChecked(Config::DSiSDFolderSync != 0);
- ui->txtDSiSDFolder->setText(Config::DSiSDFolderPath);
+ ui->cbDSiSDReadOnly->setChecked(Config::DSiSDReadOnly);
+ ui->cbDSiSDFolder->setChecked(Config::DSiSDFolderSync);
+ ui->txtDSiSDFolder->setText(QString::fromStdString(Config::DSiSDFolderPath));
on_cbDSiSDEnable_toggled();
}
@@ -140,8 +140,7 @@ void EmuSettingsDialog::verifyFirmware()
// looked at has 0x180 bytes from the header repeated at 0x3FC80, but
// bytes 0x0C-0x14 are different.
- char filename[1024];
- strncpy(filename, ui->txtFirmwarePath->text().toStdString().c_str(), 1023); filename[1023] = '\0';
+ std::string filename = ui->txtFirmwarePath->text().toStdString();
FILE* f = Platform::OpenLocalFile(filename, "rb");
if (!f) return;
u8 chk1[0x180], chk2[0x180];
@@ -175,24 +174,24 @@ void EmuSettingsDialog::done(int r)
verifyFirmware();
int consoleType = ui->cbxConsoleType->currentIndex();
- int directBoot = ui->chkDirectBoot->isChecked() ? 1:0;
+ bool directBoot = ui->chkDirectBoot->isChecked();
- int jitEnable = ui->chkEnableJIT->isChecked() ? 1:0;
+ bool jitEnable = ui->chkEnableJIT->isChecked();
int jitMaxBlockSize = ui->spnJITMaximumBlockSize->value();
- int jitBranchOptimisations = ui->chkJITBranchOptimisations->isChecked() ? 1:0;
- int jitLiteralOptimisations = ui->chkJITLiteralOptimisations->isChecked() ? 1:0;
- int jitFastMemory = ui->chkJITFastMemory->isChecked() ? 1:0;
+ bool jitBranchOptimisations = ui->chkJITBranchOptimisations->isChecked();
+ bool jitLiteralOptimisations = ui->chkJITLiteralOptimisations->isChecked();
+ bool jitFastMemory = ui->chkJITFastMemory->isChecked();
- int externalBiosEnable = ui->chkExternalBIOS->isChecked() ? 1:0;
+ bool externalBiosEnable = ui->chkExternalBIOS->isChecked();
std::string bios9Path = ui->txtBIOS9Path->text().toStdString();
std::string bios7Path = ui->txtBIOS7Path->text().toStdString();
std::string firmwarePath = ui->txtFirmwarePath->text().toStdString();
- int dldiEnable = ui->cbDLDIEnable->isChecked() ? 1:0;
+ bool dldiEnable = ui->cbDLDIEnable->isChecked();
std::string dldiSDPath = ui->txtDLDISDPath->text().toStdString();
int dldiSize = ui->cbxDLDISize->currentIndex();
- int dldiReadOnly = ui->cbDLDIReadOnly->isChecked() ? 1:0;
- int dldiFolderSync = ui->cbDLDIFolder->isChecked() ? 1:0;
+ bool dldiReadOnly = ui->cbDLDIReadOnly->isChecked();
+ bool dldiFolderSync = ui->cbDLDIFolder->isChecked();
std::string dldiFolderPath = ui->txtDLDIFolder->text().toStdString();
std::string dsiBios9Path = ui->txtDSiBIOS9Path->text().toStdString();
@@ -200,11 +199,11 @@ void EmuSettingsDialog::done(int r)
std::string dsiFirmwarePath = ui->txtDSiFirmwarePath->text().toStdString();
std::string dsiNANDPath = ui->txtDSiNANDPath->text().toStdString();
- int dsiSDEnable = ui->cbDSiSDEnable->isChecked() ? 1:0;
+ bool dsiSDEnable = ui->cbDSiSDEnable->isChecked();
std::string dsiSDPath = ui->txtDSiSDPath->text().toStdString();
int dsiSDSize = ui->cbxDSiSDSize->currentIndex();
- int dsiSDReadOnly = ui->cbDSiSDReadOnly->isChecked() ? 1:0;
- int dsiSDFolderSync = ui->cbDSiSDFolder->isChecked() ? 1:0;
+ bool dsiSDReadOnly = ui->cbDSiSDReadOnly->isChecked();
+ bool dsiSDFolderSync = ui->cbDSiSDFolder->isChecked();
std::string dsiSDFolderPath = ui->txtDSiSDFolder->text().toStdString();
if (consoleType != Config::ConsoleType
@@ -217,25 +216,25 @@ void EmuSettingsDialog::done(int r)
|| jitFastMemory != Config::JIT_FastMemory
#endif
|| externalBiosEnable != Config::ExternalBIOSEnable
- || strcmp(Config::BIOS9Path, bios9Path.c_str()) != 0
- || strcmp(Config::BIOS7Path, bios7Path.c_str()) != 0
- || strcmp(Config::FirmwarePath, firmwarePath.c_str()) != 0
+ || bios9Path != Config::BIOS9Path
+ || bios7Path != Config::BIOS7Path
+ || firmwarePath != Config::FirmwarePath
|| dldiEnable != Config::DLDIEnable
- || strcmp(Config::DLDISDPath, dldiSDPath.c_str()) != 0
+ || dldiSDPath != Config::DLDISDPath
|| dldiSize != Config::DLDISize
|| dldiReadOnly != Config::DLDIReadOnly
|| dldiFolderSync != Config::DLDIFolderSync
- || strcmp(Config::DLDIFolderPath, dldiFolderPath.c_str()) != 0
- || strcmp(Config::DSiBIOS9Path, dsiBios9Path.c_str()) != 0
- || strcmp(Config::DSiBIOS7Path, dsiBios7Path.c_str()) != 0
- || strcmp(Config::DSiFirmwarePath, dsiFirmwarePath.c_str()) != 0
- || strcmp(Config::DSiNANDPath, dsiNANDPath.c_str()) != 0
+ || dldiFolderPath != Config::DLDIFolderPath
+ || dsiBios9Path != Config::DSiBIOS9Path
+ || dsiBios7Path != Config::DSiBIOS7Path
+ || dsiFirmwarePath != Config::DSiFirmwarePath
+ || dsiNANDPath != Config::DSiNANDPath
|| dsiSDEnable != Config::DSiSDEnable
- || strcmp(Config::DSiSDPath, dsiSDPath.c_str()) != 0
+ || dsiSDPath != Config::DSiSDPath
|| dsiSDSize != Config::DSiSDSize
|| dsiSDReadOnly != Config::DSiSDReadOnly
|| dsiSDFolderSync != Config::DSiSDFolderSync
- || strcmp(Config::DSiSDFolderPath, dsiSDFolderPath.c_str()) != 0)
+ || dsiSDFolderPath != Config::DSiSDFolderPath)
{
if (RunningSomething
&& QMessageBox::warning(this, "Reset necessary to apply changes",
@@ -244,28 +243,28 @@ void EmuSettingsDialog::done(int r)
return;
Config::ExternalBIOSEnable = externalBiosEnable;
- strncpy(Config::BIOS9Path, bios9Path.c_str(), 1023); Config::BIOS9Path[1023] = '\0';
- strncpy(Config::BIOS7Path, bios7Path.c_str(), 1023); Config::BIOS7Path[1023] = '\0';
- strncpy(Config::FirmwarePath, firmwarePath.c_str(), 1023); Config::FirmwarePath[1023] = '\0';
+ Config::BIOS9Path = bios9Path;
+ Config::BIOS7Path = bios7Path;
+ Config::FirmwarePath = firmwarePath;
Config::DLDIEnable = dldiEnable;
- strncpy(Config::DLDISDPath, dldiSDPath.c_str(), 1023); Config::DLDISDPath[1023] = '\0';
+ Config::DLDISDPath = dldiSDPath;
Config::DLDISize = dldiSize;
Config::DLDIReadOnly = dldiReadOnly;
Config::DLDIFolderSync = dldiFolderSync;
- strncpy(Config::DLDIFolderPath, dldiFolderPath.c_str(), 1023); Config::DLDIFolderPath[1023] = '\0';
+ Config::DLDIFolderPath = dldiFolderPath;
- strncpy(Config::DSiBIOS9Path, dsiBios9Path.c_str(), 1023); Config::DSiBIOS9Path[1023] = '\0';
- strncpy(Config::DSiBIOS7Path, dsiBios7Path.c_str(), 1023); Config::DSiBIOS7Path[1023] = '\0';
- strncpy(Config::DSiFirmwarePath, dsiFirmwarePath.c_str(), 1023); Config::DSiFirmwarePath[1023] = '\0';
- strncpy(Config::DSiNANDPath, dsiNANDPath.c_str(), 1023); Config::DSiNANDPath[1023] = '\0';
+ Config::DSiBIOS9Path = dsiBios9Path;
+ Config::DSiBIOS7Path = dsiBios7Path;
+ Config::DSiFirmwarePath = dsiFirmwarePath;
+ Config::DSiNANDPath = dsiNANDPath;
Config::DSiSDEnable = dsiSDEnable;
- strncpy(Config::DSiSDPath, dsiSDPath.c_str(), 1023); Config::DSiSDPath[1023] = '\0';
+ Config::DSiSDPath = dsiSDPath;
Config::DSiSDSize = dsiSDSize;
Config::DSiSDReadOnly = dsiSDReadOnly;
Config::DSiSDFolderSync = dsiSDFolderSync;
- strncpy(Config::DSiSDFolderPath, dsiSDFolderPath.c_str(), 1023); Config::DSiSDFolderPath[1023] = '\0';
+ Config::DSiSDFolderPath = dsiSDFolderPath;
#ifdef JIT_ENABLED
Config::JIT_Enable = jitEnable;
diff --git a/src/frontend/qt_sdl/FirmwareSettingsDialog.cpp b/src/frontend/qt_sdl/FirmwareSettingsDialog.cpp
index 0b2cad6..976934f 100644
--- a/src/frontend/qt_sdl/FirmwareSettingsDialog.cpp
+++ b/src/frontend/qt_sdl/FirmwareSettingsDialog.cpp
@@ -35,7 +35,7 @@ FirmwareSettingsDialog::FirmwareSettingsDialog(QWidget* parent) : QDialog(parent
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
- ui->usernameEdit->setText(Config::FirmwareUsername);
+ ui->usernameEdit->setText(QString::fromStdString(Config::FirmwareUsername));
ui->languageBox->addItems(languages);
ui->languageBox->setCurrentIndex(Config::FirmwareLanguage);
@@ -59,12 +59,12 @@ FirmwareSettingsDialog::FirmwareSettingsDialog(QWidget* parent) : QDialog(parent
}
ui->colorsEdit->setCurrentIndex(Config::FirmwareFavouriteColour);
- ui->messageEdit->setText(Config::FirmwareMessage);
+ ui->messageEdit->setText(QString::fromStdString(Config::FirmwareMessage));
ui->overrideFirmwareBox->setChecked(Config::FirmwareOverrideSettings);
- ui->txtMAC->setText(Config::FirmwareMAC);
- ui->cbRandomizeMAC->setChecked(Config::RandomizeMAC != 0);
+ ui->txtMAC->setText(QString::fromStdString(Config::FirmwareMAC));
+ ui->cbRandomizeMAC->setChecked(Config::RandomizeMAC);
on_cbRandomizeMAC_toggled();
}
@@ -123,7 +123,7 @@ void FirmwareSettingsDialog::done(int r)
return;
}
- int newOverride = ui->overrideFirmwareBox->isChecked();
+ bool newOverride = ui->overrideFirmwareBox->isChecked();
std::string newName = ui->usernameEdit->text().toStdString();
int newLanguage = ui->languageBox->currentIndex();
@@ -133,16 +133,16 @@ void FirmwareSettingsDialog::done(int r)
std::string newMessage = ui->messageEdit->text().toStdString();
std::string newMAC = ui->txtMAC->text().toStdString();
- int newRandomizeMAC = ui->cbRandomizeMAC->isChecked() ? 1:0;
+ bool newRandomizeMAC = ui->cbRandomizeMAC->isChecked();
if ( newOverride != Config::FirmwareOverrideSettings
- || strcmp(newName.c_str(), Config::FirmwareUsername) != 0
+ || newName != Config::FirmwareUsername
|| newLanguage != Config::FirmwareLanguage
|| newFavColor != Config::FirmwareFavouriteColour
|| newBirthdayDay != Config::FirmwareBirthdayDay
|| newBirthdayMonth != Config::FirmwareBirthdayMonth
- || strcmp(newMessage.c_str(), Config::FirmwareMessage) != 0
- || strcmp(newMAC.c_str(), Config::FirmwareMAC) != 0
+ || newMessage != Config::FirmwareMessage
+ || newMAC != Config::FirmwareMAC
|| newRandomizeMAC != Config::RandomizeMAC)
{
if (RunningSomething
@@ -153,14 +153,14 @@ void FirmwareSettingsDialog::done(int r)
Config::FirmwareOverrideSettings = newOverride;
- strncpy(Config::FirmwareUsername, newName.c_str(), 63); Config::FirmwareUsername[63] = '\0';
+ Config::FirmwareUsername = newName;
Config::FirmwareLanguage = newLanguage;
Config::FirmwareFavouriteColour = newFavColor;
Config::FirmwareBirthdayDay = newBirthdayDay;
Config::FirmwareBirthdayMonth = newBirthdayMonth;
- strncpy(Config::FirmwareMessage, newMessage.c_str(), 1023); Config::FirmwareMessage[1023] = '\0';
+ Config::FirmwareMessage = newMessage;
- strncpy(Config::FirmwareMAC, newMAC.c_str(), 17); Config::FirmwareMAC[17] = '\0';
+ Config::FirmwareMAC = newMAC;
Config::RandomizeMAC = newRandomizeMAC;
Config::Save();
diff --git a/src/frontend/qt_sdl/FirmwareSettingsDialog.h b/src/frontend/qt_sdl/FirmwareSettingsDialog.h
index 1ae409f..7ed8b0b 100644
--- a/src/frontend/qt_sdl/FirmwareSettingsDialog.h
+++ b/src/frontend/qt_sdl/FirmwareSettingsDialog.h
@@ -109,7 +109,7 @@ public:
}
currentDlg = new FirmwareSettingsDialog(parent);
- currentDlg->show();
+ currentDlg->open();
return currentDlg;
}
static void closeDlg()
diff --git a/src/frontend/qt_sdl/LAN_PCap.cpp b/src/frontend/qt_sdl/LAN_PCap.cpp
index ed3eee9..dcc2310 100644
--- a/src/frontend/qt_sdl/LAN_PCap.cpp
+++ b/src/frontend/qt_sdl/LAN_PCap.cpp
@@ -318,7 +318,7 @@ bool Init(bool open_adapter)
PCapAdapterData = &Adapters[0];
for (int i = 0; i < NumAdapters; i++)
{
- if (!strncmp(Adapters[i].DeviceName, Config::LANDevice, 128))
+ if (!strncmp(Adapters[i].DeviceName, Config::LANDevice.c_str(), 128))
PCapAdapterData = &Adapters[i];
}
diff --git a/src/frontend/qt_sdl/PathSettingsDialog.cpp b/src/frontend/qt_sdl/PathSettingsDialog.cpp
new file mode 100644
index 0000000..5a2fa1a
--- /dev/null
+++ b/src/frontend/qt_sdl/PathSettingsDialog.cpp
@@ -0,0 +1,119 @@
+/*
+ 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 <stdio.h>
+#include <QFileDialog>
+#include <QMessageBox>
+
+#include "types.h"
+#include "Config.h"
+
+#include "PathSettingsDialog.h"
+#include "ui_PathSettingsDialog.h"
+
+
+PathSettingsDialog* PathSettingsDialog::currentDlg = nullptr;
+
+extern std::string EmuDirectory;
+extern bool RunningSomething;
+
+bool PathSettingsDialog::needsReset = false;
+
+
+PathSettingsDialog::PathSettingsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::PathSettingsDialog)
+{
+ ui->setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose);
+
+ ui->txtSaveFilePath->setText(QString::fromStdString(Config::SaveFilePath));
+ ui->txtSavestatePath->setText(QString::fromStdString(Config::SavestatePath));
+ ui->txtCheatFilePath->setText(QString::fromStdString(Config::CheatFilePath));
+}
+
+PathSettingsDialog::~PathSettingsDialog()
+{
+ delete ui;
+}
+
+void PathSettingsDialog::done(int r)
+{
+ needsReset = false;
+
+ if (r == QDialog::Accepted)
+ {
+ std::string saveFilePath = ui->txtSaveFilePath->text().toStdString();
+ std::string savestatePath = ui->txtSavestatePath->text().toStdString();
+ std::string cheatFilePath = ui->txtCheatFilePath->text().toStdString();
+
+ if ( saveFilePath != Config::SaveFilePath
+ || savestatePath != Config::SavestatePath
+ || cheatFilePath != Config::CheatFilePath)
+ {
+ if (RunningSomething
+ && QMessageBox::warning(this, "Reset necessary to apply changes",
+ "The emulation will be reset for the changes to take place.",
+ QMessageBox::Ok, QMessageBox::Cancel) != QMessageBox::Ok)
+ return;
+
+ Config::SaveFilePath = saveFilePath;
+ Config::SavestatePath = savestatePath;
+ Config::CheatFilePath = cheatFilePath;
+
+ Config::Save();
+
+ needsReset = true;
+ }
+ }
+
+ QDialog::done(r);
+
+ closeDlg();
+}
+
+void PathSettingsDialog::on_btnSaveFileBrowse_clicked()
+{
+ QString dir = QFileDialog::getExistingDirectory(this,
+ "Select save files path...",
+ QString::fromStdString(EmuDirectory));
+
+ if (dir.isEmpty()) return;
+
+ ui->txtSaveFilePath->setText(dir);
+}
+
+void PathSettingsDialog::on_btnSavestateBrowse_clicked()
+{
+ QString dir = QFileDialog::getExistingDirectory(this,
+ "Select savestates path...",
+ QString::fromStdString(EmuDirectory));
+
+ if (dir.isEmpty()) return;
+
+ ui->txtSavestatePath->setText(dir);
+}
+
+void PathSettingsDialog::on_btnCheatFileBrowse_clicked()
+{
+ QString dir = QFileDialog::getExistingDirectory(this,
+ "Select cheat files path...",
+ QString::fromStdString(EmuDirectory));
+
+ if (dir.isEmpty()) return;
+
+ ui->txtCheatFilePath->setText(dir);
+}
diff --git a/src/frontend/qt_sdl/PathSettingsDialog.h b/src/frontend/qt_sdl/PathSettingsDialog.h
new file mode 100644
index 0000000..6a0fea2
--- /dev/null
+++ b/src/frontend/qt_sdl/PathSettingsDialog.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 PATHSETTINGSDIALOG_H
+#define PATHSETTINGSDIALOG_H
+
+#include <QDialog>
+
+namespace Ui { class PathSettingsDialog; }
+class PathSettingsDialog;
+
+class PathSettingsDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit PathSettingsDialog(QWidget* parent);
+ ~PathSettingsDialog();
+
+ static PathSettingsDialog* currentDlg;
+ static PathSettingsDialog* openDlg(QWidget* parent)
+ {
+ if (currentDlg)
+ {
+ currentDlg->activateWindow();
+ return currentDlg;
+ }
+
+ currentDlg = new PathSettingsDialog(parent);
+ currentDlg->open();
+ return currentDlg;
+ }
+ static void closeDlg()
+ {
+ currentDlg = nullptr;
+ }
+
+ static bool needsReset;
+
+private slots:
+ void done(int r);
+
+ void on_btnSaveFileBrowse_clicked();
+ void on_btnSavestateBrowse_clicked();
+ void on_btnCheatFileBrowse_clicked();
+
+private:
+ Ui::PathSettingsDialog* ui;
+};
+
+#endif // PATHSETTINGSDIALOG_H
diff --git a/src/frontend/qt_sdl/PathSettingsDialog.ui b/src/frontend/qt_sdl/PathSettingsDialog.ui
new file mode 100644
index 0000000..95f5acc
--- /dev/null
+++ b/src/frontend/qt_sdl/PathSettingsDialog.ui
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PathSettingsDialog</class>
+ <widget class="QDialog" name="PathSettingsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>439</width>
+ <height>166</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Path settings - melonDS</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="txtSaveFilePath">
+ <property name="clearButtonEnabled">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QPushButton" name="btnCheatFileBrowse">
+ <property name="text">
+ <string>Browse...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Savestates path:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="txtCheatFilePath">
+ <property name="clearButtonEnabled">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="3">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Leave a path blank to use the current ROM's path.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" colspan="3">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Cheat files path:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="btnSaveFileBrowse">
+ <property name="text">
+ <string>Browse...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="btnSavestateBrowse">
+ <property name="text">
+ <string>Browse...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="txtSavestatePath">
+ <property name="clearButtonEnabled">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Save files path:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" colspan="3">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>txtSaveFilePath</tabstop>
+ <tabstop>btnSaveFileBrowse</tabstop>
+ <tabstop>txtSavestatePath</tabstop>
+ <tabstop>btnSavestateBrowse</tabstop>
+ <tabstop>txtCheatFilePath</tabstop>
+ <tabstop>btnCheatFileBrowse</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>PathSettingsDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>PathSettingsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/frontend/qt_sdl/Platform.cpp b/src/frontend/qt_sdl/Platform.cpp
index 812c953..0197264 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 <string>
@@ -207,7 +208,7 @@ bool GetConfigArray(ConfigEntry entry, void* data)
{
case Firm_MAC:
{
- char* mac_in = Config::FirmwareMAC;
+ std::string& mac_in = Config::FirmwareMAC;
u8* mac_out = (u8*)data;
int o = 0;
@@ -372,6 +373,19 @@ bool Mutex_TryLock(Mutex* mutex)
}
+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, u32 writeoffset, u32 writelen)
+{
+ if (ROMManager::GBASave)
+ ROMManager::GBASave->RequestFlush(savedata, savelen, writeoffset, writelen);
+}
+
+
bool MP_Init()
{
int opt_true = 1;
diff --git a/src/frontend/qt_sdl/ROMInfoDialog.cpp b/src/frontend/qt_sdl/ROMInfoDialog.cpp
index 9166efe..5fbca0f 100644
--- a/src/frontend/qt_sdl/ROMInfoDialog.cpp
+++ b/src/frontend/qt_sdl/ROMInfoDialog.cpp
@@ -45,14 +45,14 @@ ROMInfoDialog::ROMInfoDialog(QWidget* parent) : QDialog(parent), ui(new Ui::ROMI
u32 iconData[32 * 32];
- Frontend::ROMIcon(NDSCart::Banner.Icon, NDSCart::Banner.Palette, iconData);
+ ROMManager::ROMIcon(NDSCart::Banner.Icon, NDSCart::Banner.Palette, iconData);
iconImage = QImage(reinterpret_cast<unsigned char*>(iconData), 32, 32, QImage::Format_ARGB32).copy();
ui->iconImage->setPixmap(QPixmap::fromImage(iconImage));
if (NDSCart::Banner.Version == 0x103)
{
u32 animatedIconData[32 * 32 * 64] = {0};
- Frontend::AnimatedROMIcon(NDSCart::Banner.DSiIcon, NDSCart::Banner.DSiPalette, NDSCart::Banner.DSiSequence, animatedIconData, animatedSequence);
+ ROMManager::AnimatedROMIcon(NDSCart::Banner.DSiIcon, NDSCart::Banner.DSiPalette, NDSCart::Banner.DSiSequence, animatedIconData, animatedSequence);
for (int i = 0; i < 64; i++)
{
@@ -130,7 +130,7 @@ void ROMInfoDialog::on_saveIconButton_clicked()
{
QString filename = QFileDialog::getSaveFileName(this,
"Save Icon",
- Config::LastROMFolder,
+ QString::fromStdString(Config::LastROMFolder),
"PNG Images (*.png)");
if (filename.isEmpty())
return;
diff --git a/src/frontend/qt_sdl/ROMInfoDialog.h b/src/frontend/qt_sdl/ROMInfoDialog.h
index 5193554..8fdab74 100644
--- a/src/frontend/qt_sdl/ROMInfoDialog.h
+++ b/src/frontend/qt_sdl/ROMInfoDialog.h
@@ -25,7 +25,7 @@
#include <QImage>
#include "types.h"
-#include "FrontendUtil.h"
+#include "ROMManager.h"
namespace Ui { class ROMInfoDialog; }
class ROMInfoDialog;
@@ -58,7 +58,7 @@ public:
private slots:
void done(int r);
-
+
void on_saveIconButton_clicked();
void iconSetFrame(int frame);
diff --git a/src/frontend/qt_sdl/ROMManager.cpp b/src/frontend/qt_sdl/ROMManager.cpp
new file mode 100644
index 0000000..2b9bbd3
--- /dev/null
+++ b/src/frontend/qt_sdl/ROMManager.cpp
@@ -0,0 +1,843 @@
+/*
+ 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 <stdio.h>
+#include <string.h>
+
+#include <string>
+#include <utility>
+
+#ifdef ARCHIVE_SUPPORT_ENABLED
+#include "ArchiveUtil.h"
+#endif
+#include "ROMManager.h"
+#include "Config.h"
+#include "Platform.h"
+
+#include "NDS.h"
+#include "DSi.h"
+
+
+namespace ROMManager
+{
+
+int CartType = -1;
+std::string BaseROMDir = "";
+std::string BaseROMName = "";
+std::string BaseAssetName = "";
+
+int GBACartType = -1;
+std::string BaseGBAROMDir = "";
+std::string BaseGBAROMName = "";
+std::string BaseGBAAssetName = "";
+
+SaveManager* NDSSave = nullptr;
+SaveManager* GBASave = nullptr;
+
+bool SavestateLoaded = false;
+std::string PreviousSaveFile = "";
+
+ARCodeFile* CheatFile = nullptr;
+bool CheatsOn = false;
+
+
+int LastSep(std::string path)
+{
+ int i = path.length() - 1;
+ while (i >= 0)
+ {
+ if (path[i] == '/' || path[i] == '\\')
+ return i;
+
+ i--;
+ }
+
+ return -1;
+}
+
+std::string GetAssetPath(bool gba, std::string configpath, std::string ext, std::string file="")
+{
+ if (configpath.empty())
+ configpath = gba ? BaseGBAROMDir : BaseROMDir;
+
+ if (file.empty())
+ {
+ file = gba ? BaseGBAAssetName : BaseAssetName;
+ if (file.empty())
+ file = "firmware";
+ }
+
+ for (;;)
+ {
+ int i = configpath.length() - 1;
+ if (configpath[i] == '/' || configpath[i] == '\\')
+ configpath = configpath.substr(0, i);
+ else
+ break;
+ }
+
+ if (!configpath.empty())
+ configpath += "/";
+
+ return configpath + file + ext;
+}
+
+
+QString VerifyDSBIOS()
+{
+ FILE* f;
+ long len;
+
+ f = Platform::OpenLocalFile(Config::BIOS9Path, "rb");
+ if (!f) return "DS ARM9 BIOS was not found or could not be accessed. Check your emu settings.";
+
+ fseek(f, 0, SEEK_END);
+ len = ftell(f);
+ if (len != 0x1000)
+ {
+ fclose(f);
+ return "DS ARM9 BIOS is not a valid BIOS dump.";
+ }
+
+ fclose(f);
+
+ f = Platform::OpenLocalFile(Config::BIOS7Path, "rb");
+ if (!f) return "DS ARM7 BIOS was not found or could not be accessed. Check your emu settings.";
+
+ fseek(f, 0, SEEK_END);
+ len = ftell(f);
+ if (len != 0x4000)
+ {
+ fclose(f);
+ return "DS ARM7 BIOS is not a valid BIOS dump.";
+ }
+
+ fclose(f);
+
+ return "";
+}
+
+QString VerifyDSiBIOS()
+{
+ FILE* f;
+ long len;
+
+ // TODO: check the first 32 bytes
+
+ f = Platform::OpenLocalFile(Config::DSiBIOS9Path, "rb");
+ if (!f) return "DSi ARM9 BIOS was not found or could not be accessed. Check your emu settings.";
+
+ fseek(f, 0, SEEK_END);
+ len = ftell(f);
+ if (len != 0x10000)
+ {
+ fclose(f);
+ return "DSi ARM9 BIOS is not a valid BIOS dump.";
+ }
+
+ fclose(f);
+
+ f = Platform::OpenLocalFile(Config::DSiBIOS7Path, "rb");
+ if (!f) return "DSi ARM7 BIOS was not found or could not be accessed. Check your emu settings.";
+
+ fseek(f, 0, SEEK_END);
+ len = ftell(f);
+ if (len != 0x10000)
+ {
+ fclose(f);
+ return "DSi ARM7 BIOS is not a valid BIOS dump.";
+ }
+
+ fclose(f);
+
+ return "";
+}
+
+QString VerifyDSFirmware()
+{
+ FILE* f;
+ long len;
+
+ f = Platform::OpenLocalFile(Config::FirmwarePath, "rb");
+ if (!f) return "DS firmware was not found or could not be accessed. Check your emu settings.";
+
+ fseek(f, 0, SEEK_END);
+ len = ftell(f);
+ if (len == 0x20000)
+ {
+ // 128KB firmware, not bootable
+ fclose(f);
+ // TODO report it somehow? detect in core?
+ return "";
+ }
+ else if (len != 0x40000 && len != 0x80000)
+ {
+ fclose(f);
+ return "DS firmware is not a valid firmware dump.";
+ }
+
+ fclose(f);
+
+ return "";
+}
+
+QString VerifyDSiFirmware()
+{
+ FILE* f;
+ long len;
+
+ f = Platform::OpenLocalFile(Config::DSiFirmwarePath, "rb");
+ if (!f) return "DSi firmware was not found or could not be accessed. Check your emu settings.";
+
+ fseek(f, 0, SEEK_END);
+ len = ftell(f);
+ if (len != 0x20000)
+ {
+ // not 128KB
+ // TODO: check whether those work
+ fclose(f);
+ return "DSi firmware is not a valid firmware dump.";
+ }
+
+ fclose(f);
+
+ return "";
+}
+
+QString VerifyDSiNAND()
+{
+ FILE* f;
+ long len;
+
+ f = Platform::OpenLocalFile(Config::DSiNANDPath, "r+b");
+ if (!f) return "DSi NAND was not found or could not be accessed. Check your emu settings.";
+
+ // TODO: some basic checks
+ // check that it has the nocash footer, and all
+
+ fclose(f);
+
+ return "";
+}
+
+QString VerifySetup()
+{
+ QString res;
+
+ if (Config::ExternalBIOSEnable)
+ {
+ res = VerifyDSBIOS();
+ if (!res.isEmpty()) return res;
+ }
+
+ if (Config::ConsoleType == 1)
+ {
+ res = VerifyDSiBIOS();
+ if (!res.isEmpty()) return res;
+
+ if (Config::ExternalBIOSEnable)
+ {
+ res = VerifyDSiFirmware();
+ if (!res.isEmpty()) return res;
+ }
+
+ res = VerifyDSiNAND();
+ if (!res.isEmpty()) return res;
+ }
+ else
+ {
+ if (Config::ExternalBIOSEnable)
+ {
+ res = VerifyDSFirmware();
+ if (!res.isEmpty()) return res;
+ }
+ }
+
+ return "";
+}
+
+
+std::string GetSavestateName(int slot)
+{
+ std::string ext = ".ml";
+ ext += (char)('0'+slot);
+ return GetAssetPath(false, Config::SavestatePath, ext);
+}
+
+bool SavestateExists(int slot)
+{
+ std::string ssfile = GetSavestateName(slot);
+ return Platform::FileExists(ssfile);
+}
+
+bool LoadState(std::string filename)
+{
+ // backup
+ Savestate* backup = new Savestate("timewarp.mln", true);
+ NDS::DoSavestate(backup);
+ delete backup;
+
+ bool failed = false;
+
+ Savestate* state = new Savestate(filename, false);
+ if (state->Error)
+ {
+ delete state;
+
+ // current state might be crapoed, so restore from sane backup
+ state = new Savestate("timewarp.mln", false);
+ failed = true;
+ }
+
+ bool res = NDS::DoSavestate(state);
+ delete state;
+
+ if (!res)
+ {
+ failed = true;
+ state = new Savestate("timewarp.mln", false);
+ NDS::DoSavestate(state);
+ delete state;
+ }
+
+ if (failed) return false;
+
+ if (Config::SavestateRelocSRAM && NDSSave)
+ {
+ PreviousSaveFile = NDSSave->GetPath();
+
+ std::string savefile = filename.substr(LastSep(filename)+1);
+ savefile = GetAssetPath(false, Config::SaveFilePath, ".sav", savefile);
+ NDSSave->SetPath(savefile, true);
+ }
+
+ SavestateLoaded = true;
+
+ return true;
+}
+
+bool SaveState(std::string filename)
+{
+ Savestate* state = new Savestate(filename, true);
+ if (state->Error)
+ {
+ delete state;
+ return false;
+ }
+
+ NDS::DoSavestate(state);
+ delete state;
+
+ if (Config::SavestateRelocSRAM && NDSSave)
+ {
+ std::string savefile = filename.substr(LastSep(filename)+1);
+ savefile = GetAssetPath(false, Config::SaveFilePath, ".sav", savefile);
+ NDSSave->SetPath(savefile, false);
+ }
+
+ return true;
+}
+
+void UndoStateLoad()
+{
+ if (!SavestateLoaded) return;
+
+ // pray that this works
+ // what do we do if it doesn't???
+ // but it should work.
+ Savestate* backup = new Savestate("timewarp.mln", false);
+ NDS::DoSavestate(backup);
+ delete backup;
+
+ if (NDSSave && (!PreviousSaveFile.empty()))
+ {
+ NDSSave->SetPath(PreviousSaveFile, true);
+ }
+}
+
+
+void UnloadCheats()
+{
+ if (CheatFile)
+ {
+ delete CheatFile;
+ CheatFile = nullptr;
+ }
+}
+
+void LoadCheats()
+{
+ UnloadCheats();
+
+ std::string filename = GetAssetPath(false, Config::CheatFilePath, ".mch");
+
+ // TODO: check for error (malformed cheat file, ...)
+ CheatFile = new ARCodeFile(filename);
+
+ AREngine::SetCodeFile(CheatsOn ? CheatFile : nullptr);
+}
+
+void EnableCheats(bool enable)
+{
+ CheatsOn = enable;
+ if (CheatFile)
+ AREngine::SetCodeFile(CheatsOn ? CheatFile : nullptr);
+}
+
+ARCodeFile* GetCheatFile()
+{
+ return CheatFile;
+}
+
+
+void Reset()
+{
+ NDS::SetConsoleType(Config::ConsoleType);
+ if (Config::ConsoleType == 1) EjectGBACart();
+ NDS::Reset();
+
+ if ((CartType != -1) && NDSSave)
+ {
+ std::string oldsave = NDSSave->GetPath();
+ std::string newsave = GetAssetPath(false, Config::SaveFilePath, ".sav");
+ if (oldsave != newsave)
+ NDSSave->SetPath(newsave, false);
+ }
+
+ if ((GBACartType != -1) && GBASave)
+ {
+ std::string oldsave = GBASave->GetPath();
+ std::string newsave = GetAssetPath(true, Config::SaveFilePath, ".sav");
+ if (oldsave != newsave)
+ GBASave->SetPath(newsave, false);
+ }
+
+ if (!BaseROMName.empty())
+ {
+ if (Config::DirectBoot || NDS::NeedsDirectBoot())
+ {
+ NDS::SetupDirectBoot(BaseROMName);
+ }
+ }
+}
+
+
+bool LoadBIOS()
+{
+ NDS::SetConsoleType(Config::ConsoleType);
+
+ if (NDS::NeedsDirectBoot())
+ return false;
+
+ /*if (NDSSave) delete NDSSave;
+ NDSSave = nullptr;
+
+ CartType = -1;
+ BaseROMDir = "";
+ BaseROMName = "";
+ BaseAssetName = "";*/
+
+ NDS::Reset();
+ return true;
+}
+
+
+bool LoadROM(QStringList filepath, bool reset)
+{
+ if (filepath.empty()) return false;
+
+ u8* filedata;
+ u32 filelen;
+
+ std::string basepath;
+ std::string romname;
+
+ int num = filepath.count();
+ if (num == 1)
+ {
+ // regular file
+
+ std::string filename = filepath.at(0).toStdString();
+ FILE* f = Platform::OpenFile(filename, "rb", true);
+ if (!f) return false;
+
+ fseek(f, 0, SEEK_END);
+ long len = ftell(f);
+ if (len > 0x40000000)
+ {
+ fclose(f);
+ return false;
+ }
+
+ fseek(f, 0, SEEK_SET);
+ filedata = new u8[len];
+ size_t nread = fread(filedata, (size_t)len, 1, f);
+ if (nread != 1)
+ {
+ fclose(f);
+ delete[] filedata;
+ return false;
+ }
+
+ fclose(f);
+ filelen = (u32)len;
+
+ int pos = LastSep(filename);
+ basepath = filename.substr(0, pos);
+ romname = filename.substr(pos+1);
+ }
+#ifdef ARCHIVE_SUPPORT_ENABLED
+ else if (num == 2)
+ {
+ // file inside archive
+
+ u32 lenread = Archive::ExtractFileFromArchive(filepath.at(0), filepath.at(1), &filedata, &filelen);
+ if (lenread < 0) return false;
+ if (!filedata) return false;
+ if (lenread != filelen)
+ {
+ delete[] filedata;
+ return false;
+ }
+
+ std::string std_archivepath = filepath.at(0).toStdString();
+ basepath = std_archivepath.substr(0, LastSep(std_archivepath));
+
+ std::string std_romname = filepath.at(1).toStdString();
+ romname = std_romname.substr(LastSep(std_romname)+1);
+ }
+#endif
+ else
+ return false;
+
+ if (NDSSave) delete NDSSave;
+ NDSSave = nullptr;
+
+ BaseROMDir = basepath;
+ BaseROMName = romname;
+ BaseAssetName = romname.substr(0, romname.rfind('.'));
+
+ if (reset)
+ {
+ NDS::SetConsoleType(Config::ConsoleType);
+ NDS::Reset();
+ }
+
+ u32 savelen = 0;
+ u8* savedata = nullptr;
+
+ std::string savname = GetAssetPath(false, Config::SaveFilePath, ".sav");
+ FILE* sav = Platform::OpenFile(savname, "rb", true);
+ if (sav)
+ {
+ fseek(sav, 0, SEEK_END);
+ savelen = (u32)ftell(sav);
+
+ fseek(sav, 0, SEEK_SET);
+ savedata = new u8[savelen];
+ fread(savedata, savelen, 1, sav);
+ fclose(sav);
+ }
+
+ bool res = NDS::LoadCart(filedata, filelen, savedata, savelen);
+ if (res && reset)
+ {
+ if (Config::DirectBoot || NDS::NeedsDirectBoot())
+ {
+ NDS::SetupDirectBoot(romname);
+ }
+ }
+
+ if (res)
+ {
+ CartType = 0;
+ NDSSave = new SaveManager(savname);
+
+ LoadCheats();
+ }
+
+ if (savedata) delete[] savedata;
+ delete[] filedata;
+ return res;
+}
+
+void EjectCart()
+{
+ if (NDSSave) delete NDSSave;
+ NDSSave = nullptr;
+
+ UnloadCheats();
+
+ NDS::EjectCart();
+
+ CartType = -1;
+ BaseROMDir = "";
+ BaseROMName = "";
+ BaseAssetName = "";
+}
+
+bool CartInserted()
+{
+ return CartType != -1;
+}
+
+QString CartLabel()
+{
+ if (CartType == -1)
+ return "(none)";
+
+ QString ret = QString::fromStdString(BaseROMName);
+
+ int maxlen = 32;
+ if (ret.length() > maxlen)
+ ret = ret.left(maxlen-6) + "..." + ret.right(3);
+
+ return ret;
+}
+
+
+bool LoadGBAROM(QStringList filepath)
+{
+ if (Config::ConsoleType == 1) return false;
+ if (filepath.empty()) return false;
+
+ u8* filedata;
+ u32 filelen;
+
+ std::string basepath;
+ std::string romname;
+
+ int num = filepath.count();
+ if (num == 1)
+ {
+ // regular file
+
+ std::string filename = filepath.at(0).toStdString();
+ FILE* f = Platform::OpenFile(filename, "rb", true);
+ if (!f) return false;
+
+ fseek(f, 0, SEEK_END);
+ long len = ftell(f);
+ if (len > 0x40000000)
+ {
+ fclose(f);
+ return false;
+ }
+
+ fseek(f, 0, SEEK_SET);
+ filedata = new u8[len];
+ size_t nread = fread(filedata, (size_t)len, 1, f);
+ if (nread != 1)
+ {
+ fclose(f);
+ delete[] filedata;
+ return false;
+ }
+
+ fclose(f);
+ filelen = (u32)len;
+
+ int pos = LastSep(filename);
+ basepath = filename.substr(0, pos);
+ romname = filename.substr(pos+1);
+ }
+#ifdef ARCHIVE_SUPPORT_ENABLED
+ else if (num == 2)
+ {
+ // file inside archive
+
+ u32 lenread = Archive::ExtractFileFromArchive(filepath.at(0), filepath.at(1), &filedata, &filelen);
+ if (lenread < 0) return false;
+ if (!filedata) return false;
+ if (lenread != filelen)
+ {
+ delete[] filedata;
+ return false;
+ }
+
+ std::string std_archivepath = filepath.at(0).toStdString();
+ basepath = std_archivepath.substr(0, LastSep(std_archivepath));
+
+ std::string std_romname = filepath.at(1).toStdString();
+ romname = std_romname.substr(LastSep(std_romname)+1);
+ }
+#endif
+ else
+ return false;
+
+ if (GBASave) delete GBASave;
+ GBASave = nullptr;
+
+ BaseGBAROMDir = basepath;
+ BaseGBAROMName = romname;
+ BaseGBAAssetName = romname.substr(0, romname.rfind('.'));
+
+ u32 savelen = 0;
+ u8* savedata = nullptr;
+
+ std::string savname = GetAssetPath(true, Config::SaveFilePath, ".sav");
+ FILE* sav = Platform::OpenFile(savname, "rb", true);
+ if (sav)
+ {
+ fseek(sav, 0, SEEK_END);
+ savelen = (u32)ftell(sav);
+
+ fseek(sav, 0, SEEK_SET);
+ savedata = new u8[savelen];
+ fread(savedata, savelen, 1, sav);
+ fclose(sav);
+ }
+
+ bool res = NDS::LoadGBACart(filedata, filelen, savedata, savelen);
+
+ if (res)
+ {
+ GBACartType = 0;
+ GBASave = new SaveManager(savname);
+ }
+
+ if (savedata) delete[] savedata;
+ delete[] filedata;
+ return res;
+}
+
+void LoadGBAAddon(int type)
+{
+ if (Config::ConsoleType == 1) return;
+
+ if (GBASave) delete GBASave;
+ GBASave = nullptr;
+
+ NDS::LoadGBAAddon(type);
+
+ GBACartType = type;
+ BaseGBAROMDir = "";
+ BaseGBAROMName = "";
+ BaseGBAAssetName = "";
+}
+
+void EjectGBACart()
+{
+ if (GBASave) delete GBASave;
+ GBASave = nullptr;
+
+ NDS::EjectGBACart();
+
+ GBACartType = -1;
+ BaseGBAROMDir = "";
+ BaseGBAROMName = "";
+ BaseGBAAssetName = "";
+}
+
+bool GBACartInserted()
+{
+ return GBACartType != -1;
+}
+
+QString GBACartLabel()
+{
+ if (Config::ConsoleType == 1) return "none (DSi)";
+
+ switch (GBACartType)
+ {
+ case 0:
+ {
+ QString ret = QString::fromStdString(BaseGBAROMName);
+
+ int maxlen = 32;
+ if (ret.length() > maxlen)
+ ret = ret.left(maxlen-6) + "..." + ret.right(3);
+
+ return ret;
+ }
+
+ case NDS::GBAAddon_RAMExpansion:
+ return "Memory expansion";
+ }
+
+ return "(none)";
+}
+
+
+void ROMIcon(u8 (&data)[512], u16 (&palette)[16], u32* iconRef)
+{
+ int index = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ for (int j = 0; j < 4; j++)
+ {
+ for (int k = 0; k < 8; k++)
+ {
+ for (int l = 0; l < 8; l++)
+ {
+ u8 pal_index = index % 2 ? data[index/2] >> 4 : data[index/2] & 0x0F;
+ u8 r = ((palette[pal_index] >> 0) & 0x1F) * 255 / 31;
+ u8 g = ((palette[pal_index] >> 5) & 0x1F) * 255 / 31;
+ u8 b = ((palette[pal_index] >> 10) & 0x1F) * 255 / 31;
+ u8 a = pal_index ? 255: 0;
+ u32* row = &iconRef[256 * i + 32 * k + 8 * j];
+ row[l] = (a << 24) | (r << 16) | (g << 8) | b;
+ index++;
+ }
+ }
+ }
+ }
+}
+
+#define SEQ_FLIPV(i) ((i & 0b1000000000000000) >> 15)
+#define SEQ_FLIPH(i) ((i & 0b0100000000000000) >> 14)
+#define SEQ_PAL(i) ((i & 0b0011100000000000) >> 11)
+#define SEQ_BMP(i) ((i & 0b0000011100000000) >> 8)
+#define SEQ_DUR(i) ((i & 0b0000000011111111) >> 0)
+
+void AnimatedROMIcon(u8 (&data)[8][512], u16 (&palette)[8][16], u16 (&sequence)[64], u32 (&animatedTexRef)[32 * 32 * 64], std::vector<int> &animatedSequenceRef)
+{
+ for (int i = 0; i < 64; i++)
+ {
+ if (!sequence[i])
+ break;
+ u32* frame = &animatedTexRef[32 * 32 * i];
+ ROMIcon(data[SEQ_BMP(sequence[i])], palette[SEQ_PAL(sequence[i])], frame);
+
+ if (SEQ_FLIPH(sequence[i]))
+ {
+ for (int x = 0; x < 32; x++)
+ {
+ for (int y = 0; y < 32/2; y++)
+ {
+ std::swap(frame[x * 32 + y], frame[x * 32 + (32 - 1 - y)]);
+ }
+ }
+ }
+ if (SEQ_FLIPV(sequence[i]))
+ {
+ for (int x = 0; x < 32/2; x++)
+ {
+ for (int y = 0; y < 32; y++)
+ {
+ std::swap(frame[x * 32 + y], frame[(32 - 1 - x) * 32 + y]);
+ }
+ }
+ }
+
+ for (int j = 0; j < SEQ_DUR(sequence[i]); j++)
+ animatedSequenceRef.push_back(i);
+ }
+}
+
+}
diff --git a/src/frontend/qt_sdl/ROMManager.h b/src/frontend/qt_sdl/ROMManager.h
new file mode 100644
index 0000000..8c97965
--- /dev/null
+++ b/src/frontend/qt_sdl/ROMManager.h
@@ -0,0 +1,66 @@
+/*
+ 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 ROMMANAGER_H
+#define ROMMANAGER_H
+
+#include "types.h"
+#include "SaveManager.h"
+#include "AREngine.h"
+
+#include <string>
+#include <vector>
+
+namespace ROMManager
+{
+
+extern SaveManager* NDSSave;
+extern SaveManager* GBASave;
+
+QString VerifySetup();
+void Reset();
+bool LoadBIOS();
+
+bool LoadROM(QStringList filepath, bool reset);
+void EjectCart();
+bool CartInserted();
+QString CartLabel();
+
+bool LoadGBAROM(QStringList filepath);
+void LoadGBAAddon(int type);
+void EjectGBACart();
+bool GBACartInserted();
+QString GBACartLabel();
+
+std::string GetSavestateName(int slot);
+bool SavestateExists(int slot);
+bool LoadState(std::string filename);
+bool SaveState(std::string filename);
+void UndoStateLoad();
+
+void EnableCheats(bool enable);
+ARCodeFile* GetCheatFile();
+
+void ROMIcon(u8 (&data)[512], u16 (&palette)[16], u32* iconRef);
+void AnimatedROMIcon(u8 (&data)[8][512], u16 (&palette)[8][16],
+ u16 (&sequence)[64], u32 (&animatedTexRef)[32 * 32 * 64],
+ std::vector<int> &animatedSequenceRef);
+
+}
+
+#endif // ROMMANAGER_H
diff --git a/src/frontend/qt_sdl/SaveManager.cpp b/src/frontend/qt_sdl/SaveManager.cpp
new file mode 100644
index 0000000..20ac543
--- /dev/null
+++ b/src/frontend/qt_sdl/SaveManager.cpp
@@ -0,0 +1,194 @@
+/*
+ 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 <stdio.h>
+#include <string.h>
+
+#include "SaveManager.h"
+#include "Platform.h"
+
+
+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()
+{
+ if (Running)
+ {
+ Running = false;
+ wait();
+ FlushSecondaryBuffer();
+ }
+
+ if (SecondaryBuffer) delete[] SecondaryBuffer;
+
+ delete SecondaryBufferLock;
+
+ if (Buffer) delete[] Buffer;
+}
+
+std::string SaveManager::GetPath()
+{
+ return Path;
+}
+
+void SaveManager::SetPath(std::string path, bool reload)
+{
+ Path = path;
+
+ if (reload)
+ {
+ FILE* f = Platform::OpenFile(Path, "rb", true);
+ if (f)
+ {
+ fread(Buffer, 1, Length, f);
+ fclose(f);
+ }
+ }
+ else
+ FlushRequested = true;
+}
+
+void SaveManager::RequestFlush(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen)
+{
+ if (Length != savelen)
+ {
+ if (Buffer) delete[] Buffer;
+
+ Length = savelen;
+ Buffer = new u8[Length];
+
+ memcpy(Buffer, savedata, Length);
+ }
+ else
+ {
+ 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::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);
+
+ 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)
+{
+ 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.
+ 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;
+}
diff --git a/src/frontend/qt_sdl/SaveManager.h b/src/frontend/qt_sdl/SaveManager.h
new file mode 100644
index 0000000..9ccb0e3
--- /dev/null
+++ b/src/frontend/qt_sdl/SaveManager.h
@@ -0,0 +1,70 @@
+/*
+ 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 <string>
+#include <unistd.h>
+#include <time.h>
+#include <atomic>
+#include <QThread>
+#include <QMutex>
+
+#include "types.h"
+
+class SaveManager : public QThread
+{
+ Q_OBJECT
+ void run() override;
+
+public:
+ SaveManager(std::string path);
+ ~SaveManager();
+
+ std::string GetPath();
+ void SetPath(std::string path, bool reload);
+
+ void RequestFlush(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen);
+ void CheckFlush();
+
+ bool NeedsFlush();
+ void FlushSecondaryBuffer(u8* dst = nullptr, u32 dstLength = 0);
+
+private:
+ std::string Path;
+
+ std::atomic_bool Running;
+
+ u8* Buffer;
+ u32 Length;
+ bool FlushRequested;
+
+ 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/TitleManagerDialog.cpp b/src/frontend/qt_sdl/TitleManagerDialog.cpp
index 0a5e65d..5af3636 100644
--- a/src/frontend/qt_sdl/TitleManagerDialog.cpp
+++ b/src/frontend/qt_sdl/TitleManagerDialog.cpp
@@ -23,7 +23,7 @@
#include "types.h"
#include "Platform.h"
#include "Config.h"
-#include "FrontendUtil.h"
+#include "ROMManager.h"
#include "DSi_NAND.h"
#include "TitleManagerDialog.h"
@@ -111,7 +111,7 @@ void TitleManagerDialog::createTitleItem(u32 category, u32 titleid)
DSi_NAND::GetTitleInfo(category, titleid, version, &header, &banner);
u32 icondata[32*32];
- Frontend::ROMIcon(banner.Icon, banner.Palette, icondata);
+ ROMManager::ROMIcon(banner.Icon, banner.Palette, icondata);
QImage iconimg((const uchar*)icondata, 32, 32, QImage::Format_ARGB32);
QIcon icon(QPixmap::fromImage(iconimg.copy()));
diff --git a/src/frontend/qt_sdl/WifiSettingsDialog.cpp b/src/frontend/qt_sdl/WifiSettingsDialog.cpp
index d438179..e584b6a 100644
--- a/src/frontend/qt_sdl/WifiSettingsDialog.cpp
+++ b/src/frontend/qt_sdl/WifiSettingsDialog.cpp
@@ -55,7 +55,7 @@ WifiSettingsDialog::WifiSettingsDialog(QWidget* parent) : QDialog(parent), ui(ne
ui->rbDirectMode->setText("Direct mode (requires " PCAP_NAME " and ethernet connection)");
- ui->cbBindAnyAddr->setChecked(Config::SocketBindAnyAddr != 0);
+ ui->cbBindAnyAddr->setChecked(Config::SocketBindAnyAddr);
int sel = 0;
for (int i = 0; i < LAN_PCap::NumAdapters; i++)
@@ -64,13 +64,14 @@ WifiSettingsDialog::WifiSettingsDialog(QWidget* parent) : QDialog(parent), ui(ne
ui->cbxDirectAdapter->addItem(QString(adapter->FriendlyName));
- if (!strncmp(adapter->DeviceName, Config::LANDevice, 128))
+ if (!strncmp(adapter->DeviceName, Config::LANDevice.c_str(), 128))
sel = i;
}
ui->cbxDirectAdapter->setCurrentIndex(sel);
- ui->rbDirectMode->setChecked(Config::DirectLAN != 0);
- ui->rbIndirectMode->setChecked(Config::DirectLAN == 0);
+ // errrr???
+ ui->rbDirectMode->setChecked(Config::DirectLAN);
+ ui->rbIndirectMode->setChecked(!Config::DirectLAN);
if (!haspcap) ui->rbDirectMode->setEnabled(false);
updateAdapterControls();
@@ -87,19 +88,18 @@ void WifiSettingsDialog::done(int r)
if (r == QDialog::Accepted)
{
- Config::SocketBindAnyAddr = ui->cbBindAnyAddr->isChecked() ? 1:0;
- Config::DirectLAN = ui->rbDirectMode->isChecked() ? 1:0;
+ Config::SocketBindAnyAddr = ui->cbBindAnyAddr->isChecked();
+ Config::DirectLAN = ui->rbDirectMode->isChecked();
int sel = ui->cbxDirectAdapter->currentIndex();
if (sel < 0 || sel >= LAN_PCap::NumAdapters) sel = 0;
if (LAN_PCap::NumAdapters < 1)
{
- Config::LANDevice[0] = '\0';
+ Config::LANDevice = "";
}
else
{
- strncpy(Config::LANDevice, LAN_PCap::Adapters[sel].DeviceName, 127);
- Config::LANDevice[127] = '\0';
+ Config::LANDevice = LAN_PCap::Adapters[sel].DeviceName;
}
Config::Save();
diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp
index bf7c261..5711a05 100644
--- a/src/frontend/qt_sdl/main.cpp
+++ b/src/frontend/qt_sdl/main.cpp
@@ -56,6 +56,7 @@
#include "VideoSettingsDialog.h"
#include "AudioSettingsDialog.h"
#include "FirmwareSettingsDialog.h"
+#include "PathSettingsDialog.h"
#include "WifiSettingsDialog.h"
#include "InterfaceSettingsDialog.h"
#include "ROMInfoDialog.h"
@@ -80,6 +81,7 @@
#include "main_shaders.h"
+#include "ROMManager.h"
#include "ArchiveUtil.h"
// TODO: uniform variable spelling
@@ -180,7 +182,7 @@ void micClose()
micDevice = 0;
}
-void micLoadWav(const char* name)
+void micLoadWav(std::string name)
{
SDL_AudioSpec format;
memset(&format, 0, sizeof(SDL_AudioSpec));
@@ -191,7 +193,7 @@ void micLoadWav(const char* name)
u8* buf;
u32 len;
- if (!SDL_LoadWAV(name, &format, &buf, &len))
+ if (!SDL_LoadWAV(name.c_str(), &format, &buf, &len))
return;
const u64 dstfreq = 44100;
@@ -541,6 +543,12 @@ void EmuThread::run()
// emulate
u32 nlines = NDS::RunFrame();
+ if (ROMManager::NDSSave)
+ ROMManager::NDSSave->CheckFlush();
+
+ if (ROMManager::GBASave)
+ ROMManager::GBASave->CheckFlush();
+
FrontBufferLock.lock();
FrontBuffer = GPU::FrontBuffer;
#ifdef OGLRENDERER_ENABLED
@@ -1281,7 +1289,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
oldW = Config::WindowWidth;
oldH = Config::WindowHeight;
- oldMax = Config::WindowMaximized!=0;
+ oldMax = Config::WindowMaximized;
setWindowTitle("melonDS " MELONDS_VERSION);
setAttribute(Qt::WA_DeleteOnClose);
@@ -1295,16 +1303,16 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
connect(actOpenROM, &QAction::triggered, this, &MainWindow::onOpenFile);
actOpenROM->setShortcut(QKeySequence(QKeySequence::StandardKey::Open));
- actOpenROMArchive = menu->addAction("Open ROM inside archive...");
+ /*actOpenROMArchive = menu->addAction("Open ROM inside archive...");
connect(actOpenROMArchive, &QAction::triggered, this, &MainWindow::onOpenFileArchive);
- actOpenROMArchive->setShortcut(QKeySequence(Qt::Key_O | Qt::CTRL | Qt::SHIFT));
+ actOpenROMArchive->setShortcut(QKeySequence(Qt::Key_O | Qt::CTRL | Qt::SHIFT));*/
recentMenu = menu->addMenu("Open recent");
for (int i = 0; i < 10; ++i)
{
- char* item = Config::RecentROMList[i];
- if (strlen(item) > 0)
- recentFileList.push_back(item);
+ std::string item = Config::RecentROMList[i];
+ if (!item.empty())
+ recentFileList.push_back(QString::fromStdString(item));
}
updateRecentFilesMenu();
@@ -1314,6 +1322,41 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
menu->addSeparator();
+ actCurrentCart = menu->addAction("DS slot: " + ROMManager::CartLabel());
+ actCurrentCart->setEnabled(false);
+
+ actInsertCart = menu->addAction("Insert cart...");
+ connect(actInsertCart, &QAction::triggered, this, &MainWindow::onInsertCart);
+
+ actEjectCart = menu->addAction("Eject cart");
+ connect(actEjectCart, &QAction::triggered, this, &MainWindow::onEjectCart);
+
+ menu->addSeparator();
+
+ actCurrentGBACart = menu->addAction("GBA slot: " + ROMManager::GBACartLabel());
+ actCurrentGBACart->setEnabled(false);
+
+ actInsertGBACart = menu->addAction("Insert ROM cart...");
+ connect(actInsertGBACart, &QAction::triggered, this, &MainWindow::onInsertGBACart);
+
+ {
+ QMenu* submenu = menu->addMenu("Insert add-on cart");
+
+ actInsertGBAAddon[0] = submenu->addAction("Memory expansion");
+ actInsertGBAAddon[0]->setData(QVariant(NDS::GBAAddon_RAMExpansion));
+ connect(actInsertGBAAddon[0], &QAction::triggered, this, &MainWindow::onInsertGBAAddon);
+ }
+
+ actEjectGBACart = menu->addAction("Eject cart");
+ connect(actEjectGBACart, &QAction::triggered, this, &MainWindow::onEjectGBACart);
+
+ menu->addSeparator();
+
+ actImportSavefile = menu->addAction("Import savefile");
+ connect(actImportSavefile, &QAction::triggered, this, &MainWindow::onImportSavefile);
+
+ menu->addSeparator();
+
{
QMenu* submenu = menu->addMenu("Save state");
@@ -1351,9 +1394,6 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
actUndoStateLoad->setShortcut(QKeySequence(Qt::Key_F12));
connect(actUndoStateLoad, &QAction::triggered, this, &MainWindow::onUndoStateLoad);
- actImportSavefile = menu->addAction("Import savefile");
- connect(actImportSavefile, &QAction::triggered, this, &MainWindow::onImportSavefile);
-
menu->addSeparator();
actQuit = menu->addAction("Quit");
@@ -1422,6 +1462,9 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
actFirmwareSettings = menu->addAction("Firmware settings");
connect(actFirmwareSettings, &QAction::triggered, this, &MainWindow::onOpenFirmwareSettings);
+ actPathSettings = menu->addAction("Path settings");
+ connect(actPathSettings, &QAction::triggered, this, &MainWindow::onOpenPathSettings);
+
{
QMenu* submenu = menu->addMenu("Savestate settings");
@@ -1588,6 +1631,16 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
createScreenPanel();
+ actEjectCart->setEnabled(false);
+ actEjectGBACart->setEnabled(false);
+
+ if (Config::ConsoleType == 1)
+ {
+ actInsertGBACart->setEnabled(false);
+ for (int i = 0; i < 1; i++)
+ actInsertGBAAddon[i]->setEnabled(false);
+ }
+
for (int i = 0; i < 9; i++)
{
actSaveState[i]->setEnabled(false);
@@ -1602,13 +1655,13 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
actFrameStep->setEnabled(false);
actSetupCheats->setEnabled(false);
- actTitleManager->setEnabled(strlen(Config::DSiNANDPath) > 0);
+ actTitleManager->setEnabled(!Config::DSiNANDPath.empty());
- actEnableCheats->setChecked(Config::EnableCheats != 0);
+ actEnableCheats->setChecked(Config::EnableCheats);
actROMInfo->setEnabled(false);
- actSavestateSRAMReloc->setChecked(Config::SavestateRelocSRAM != 0);
+ actSavestateSRAMReloc->setChecked(Config::SavestateRelocSRAM);
actScreenRotation[Config::ScreenRotation]->setChecked(true);
@@ -1623,18 +1676,18 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
actScreenLayout[Config::ScreenLayout]->setChecked(true);
actScreenSizing[Config::ScreenSizing]->setChecked(true);
- actIntegerScaling->setChecked(Config::IntegerScaling != 0);
+ actIntegerScaling->setChecked(Config::IntegerScaling);
- actScreenSwap->setChecked(Config::ScreenSwap != 0);
+ actScreenSwap->setChecked(Config::ScreenSwap);
actScreenAspectTop[Config::ScreenAspectTop]->setChecked(true);
actScreenAspectBot[Config::ScreenAspectBot]->setChecked(true);
- actScreenFiltering->setChecked(Config::ScreenFilter != 0);
- actShowOSD->setChecked(Config::ShowOSD != 0);
+ actScreenFiltering->setChecked(Config::ScreenFilter);
+ actShowOSD->setChecked(Config::ShowOSD);
- actLimitFramerate->setChecked(Config::LimitFPS != 0);
- actAudioSync->setChecked(Config::AudioSync != 0);
+ actLimitFramerate->setChecked(Config::LimitFPS);
+ actAudioSync->setChecked(Config::AudioSync);
}
MainWindow::~MainWindow()
@@ -1755,9 +1808,9 @@ void MainWindow::dragEnterEvent(QDragEnterEvent* event)
QStringList acceptedExts{".nds", ".srl", ".dsi", ".gba", ".rar",
".zip", ".7z", ".tar", ".tar.gz", ".tar.xz", ".tar.bz2"};
- for(const QString &ext : acceptedExts)
+ for (const QString &ext : acceptedExts)
{
- if(filename.endsWith(ext, Qt::CaseInsensitive))
+ if (filename.endsWith(ext, Qt::CaseInsensitive))
event->acceptProposedAction();
}
}
@@ -1769,66 +1822,66 @@ void MainWindow::dropEvent(QDropEvent* event)
QList<QUrl> urls = event->mimeData()->urls();
if (urls.count() > 1) return; // not handling more than one file at once
- emuThread->emuPause();
-
QString filename = urls.at(0).toLocalFile();
- QString ext = filename.right(3).toLower();
+ QStringList arcexts{".zip", ".7z", ".rar", ".tar", ".tar.gz", ".tar.xz", ".tar.bz2"};
- recentFileList.removeAll(filename);
- recentFileList.prepend(filename);
- updateRecentFilesMenu();
-
- char _filename[1024];
- strncpy(_filename, filename.toStdString().c_str(), 1023); _filename[1023] = '\0';
+ emuThread->emuPause();
- int slot; int res;
- if (ext == "gba")
- {
- slot = 1;
- res = Frontend::LoadROM(_filename, Frontend::ROMSlot_GBA);
- }
- else if(ext == "nds" || ext == "srl" || ext == "dsi")
+ if (!verifySetup())
{
- slot = 0;
- res = Frontend::LoadROM(_filename, Frontend::ROMSlot_NDS);
+ emuThread->emuUnpause();
+ return;
}
- else
+
+ for (const QString &ext : arcexts)
{
- QByteArray romBuffer;
- QString romFileName = pickAndExtractFileFromArchive(_filename, &romBuffer);
- if(romFileName.isEmpty())
+ if (filename.endsWith(ext, Qt::CaseInsensitive))
{
- res = Frontend::Load_ROMLoadError;
- }
- else
- {
- slot = (romFileName.endsWith(".gba", Qt::CaseInsensitive) ? 1 : 0);
- QString sramFileName = QFileInfo(_filename).absolutePath() + QDir::separator() + QFileInfo(romFileName).completeBaseName() + ".sav";
-
- if(slot == 0)
- strncpy(Frontend::NDSROMExtension, QFileInfo(romFileName).suffix().toStdString().c_str(), 4);
+ QString arcfile = pickFileFromArchive(filename);
+ if (arcfile.isEmpty())
+ {
+ emuThread->emuUnpause();
+ return;
+ }
- res = Frontend::LoadROM((const u8*)romBuffer.constData(), romBuffer.size(),
- _filename, romFileName.toStdString().c_str(), sramFileName.toStdString().c_str(),
- slot);
+ filename += "|" + arcfile;
}
}
- if (res != Frontend::Load_OK)
- {
- QMessageBox::critical(this,
- "melonDS",
- loadErrorStr(res));
- emuThread->emuUnpause();
- }
- else if (slot == 1)
+ QStringList file = filename.split('|');
+
+ if (filename.endsWith(".gba", Qt::CaseInsensitive))
{
- // checkme
+ if (!ROMManager::LoadGBAROM(file))
+ {
+ // TODO: better error reporting?
+ QMessageBox::critical(this, "melonDS", "Failed to load the ROM.");
+ emuThread->emuUnpause();
+ return;
+ }
+
emuThread->emuUnpause();
+
+ updateCartInserted(true);
}
else
{
+ if (!ROMManager::LoadROM(file, true))
+ {
+ // TODO: better error reporting?
+ QMessageBox::critical(this, "melonDS", "Failed to load the ROM.");
+ emuThread->emuUnpause();
+ return;
+ }
+
+ recentFileList.removeAll(filename);
+ recentFileList.prepend(filename);
+ updateRecentFilesMenu();
+
+ NDS::Start();
emuThread->emuRun();
+
+ updateCartInserted(false);
}
}
@@ -1846,145 +1899,178 @@ void MainWindow::onAppStateChanged(Qt::ApplicationState state)
}
}
-QString MainWindow::loadErrorStr(int error)
+bool MainWindow::verifySetup()
{
- switch (error)
+ QString res = ROMManager::VerifySetup();
+ if (!res.isEmpty())
{
- case Frontend::Load_BIOS9Missing:
- return "DS ARM9 BIOS was not found or could not be accessed. Check your emu settings.";
- case Frontend::Load_BIOS9Bad:
- return "DS ARM9 BIOS is not a valid BIOS dump.";
+ QMessageBox::critical(this, "melonDS", res);
+ return false;
+ }
- case Frontend::Load_BIOS7Missing:
- return "DS ARM7 BIOS was not found or could not be accessed. Check your emu settings.";
- case Frontend::Load_BIOS7Bad:
- return "DS ARM7 BIOS is not a valid BIOS dump.";
+ return true;
+}
- case Frontend::Load_FirmwareMissing:
- return "DS firmware was not found or could not be accessed. Check your emu settings.";
- case Frontend::Load_FirmwareBad:
- return "DS firmware is not a valid firmware dump.";
- case Frontend::Load_FirmwareNotBootable:
- return "DS firmware is not bootable.";
+bool MainWindow::preloadROMs(QString filename, QString gbafilename)
+{
+ if (!verifySetup())
+ {
+ return false;
+ }
- case Frontend::Load_DSiBIOS9Missing:
- return "DSi ARM9 BIOS was not found or could not be accessed. Check your emu settings.";
- case Frontend::Load_DSiBIOS9Bad:
- return "DSi ARM9 BIOS is not a valid BIOS dump.";
+ bool gbaloaded = false;
+ if (!gbafilename.isEmpty())
+ {
+ QStringList gbafile = gbafilename.split('|');
+ if (!ROMManager::LoadGBAROM(gbafile))
+ {
+ // TODO: better error reporting?
+ QMessageBox::critical(this, "melonDS", "Failed to load the GBA ROM.");
+ return false;
+ }
- case Frontend::Load_DSiBIOS7Missing:
- return "DSi ARM7 BIOS was not found or could not be accessed. Check your emu settings.";
- case Frontend::Load_DSiBIOS7Bad:
- return "DSi ARM7 BIOS is not a valid BIOS dump.";
+ gbaloaded = true;
+ }
- case Frontend::Load_DSiNANDMissing:
- return "DSi NAND was not found or could not be accessed. Check your emu settings.";
- case Frontend::Load_DSiNANDBad:
- return "DSi NAND is not a valid NAND dump.";
+ QStringList file = filename.split('|');
+ if (!ROMManager::LoadROM(file, true))
+ {
+ // TODO: better error reporting?
+ QMessageBox::critical(this, "melonDS", "Failed to load the ROM.");
+ return false;
+ }
+
+ recentFileList.removeAll(filename);
+ recentFileList.prepend(filename);
+ updateRecentFilesMenu();
+
+ NDS::Start();
+ emuThread->emuRun();
- case Frontend::Load_ROMLoadError:
- return "Failed to load the ROM. Make sure the file is accessible and isn't used by another application.";
+ updateCartInserted(false);
- default: return "Unknown error during launch; smack Arisotura.";
+ if (gbaloaded)
+ {
+ updateCartInserted(true);
}
+
+ return true;
}
-void MainWindow::loadROM(QByteArray *romData, QString archiveFileName, QString romFileName)
+QString MainWindow::pickFileFromArchive(QString archiveFileName)
{
- recentFileList.removeAll(archiveFileName);
- recentFileList.prepend(archiveFileName);
- updateRecentFilesMenu();
+ QVector<QString> archiveROMList = Archive::ListArchive(archiveFileName);
- // Strip entire archive name and get folder path
- strncpy(Config::LastROMFolder, QFileInfo(archiveFileName).absolutePath().toStdString().c_str(), 1024);
+ QString romFileName = ""; // file name inside archive
- QString sramFileName = QFileInfo(archiveFileName).absolutePath() + QDir::separator() + QFileInfo(romFileName).completeBaseName() + ".sav";
+ if (archiveROMList.size() > 2)
+ {
+ archiveROMList.removeFirst();
- int slot; int res;
- if (romFileName.endsWith("gba"))
+ bool ok;
+ QString toLoad = QInputDialog::getItem(this, "melonDS",
+ "This archive contains multiple files. Select which ROM you want to load.", archiveROMList.toList(), 0, false, &ok);
+ if (!ok) // User clicked on cancel
+ return QString();
+
+ romFileName = toLoad;
+ }
+ else if (archiveROMList.size() == 2)
{
- slot = 1;
- res = Frontend::LoadROM((const u8*)romData->constData(), romData->size(),
- archiveFileName.toStdString().c_str(),
- romFileName.toStdString().c_str(), sramFileName.toStdString().c_str(),
- Frontend::ROMSlot_GBA);
+ romFileName = archiveROMList.at(1);
}
- else
+ else if ((archiveROMList.size() == 1) && (archiveROMList[0] == QString("OK")))
{
- strncpy(Frontend::NDSROMExtension, QFileInfo(romFileName).suffix().toStdString().c_str(), 4);
- slot = 0;
- res = Frontend::LoadROM((const u8*)romData->constData(), romData->size(),
- archiveFileName.toStdString().c_str(),
- romFileName.toStdString().c_str(), sramFileName.toStdString().c_str(),
- Frontend::ROMSlot_NDS);
+ QMessageBox::warning(this, "melonDS", "This archive is empty.");
}
-
- if (res != Frontend::Load_OK)
+ else
{
- QMessageBox::critical(this,
- "melonDS",
- loadErrorStr(res));
- emuThread->emuUnpause();
+ QMessageBox::critical(this, "melonDS", "This archive could not be read. It may be corrupt or you don't have the permissions.");
}
- else if (slot == 1)
+
+ return romFileName;
+}
+
+QStringList MainWindow::pickROM(bool gba)
+{
+ QString console;
+ QStringList romexts;
+ QStringList arcexts{"*.zip", "*.7z", "*.rar", "*.tar", "*.tar.gz", "*.tar.xz", "*.tar.bz2"};
+ QStringList ret;
+
+ if (gba)
{
- // checkme
- emuThread->emuUnpause();
+ console = "GBA";
+ romexts.append("*.gba");
}
else
{
- emuThread->emuRun();
+ console = "DS";
+ romexts.append({"*.nds", "*.dsi", "*.ids", "*.srl"});
}
-}
-void MainWindow::loadROM(QString filename)
-{
- recentFileList.removeAll(filename);
- recentFileList.prepend(filename);
- updateRecentFilesMenu();
+ QString filter = romexts.join(' ') + " " + arcexts.join(' ');
+ filter = console + " ROMs (" + filter + ");;Any file (*.*)";
- // TODO: validate the input file!!
- // * check that it is a proper ROM
- // * ensure the binary offsets are sane
- // * etc
+ QString filename = QFileDialog::getOpenFileName(this,
+ "Open "+console+" ROM",
+ QString::fromStdString(Config::LastROMFolder),
+ filter);
+ if (filename.isEmpty())
+ return ret;
- // this shit is stupid
- char file[1024];
- strncpy(file, filename.toStdString().c_str(), 1023); file[1023] = '\0';
+ int pos = filename.length() - 1;
+ while (filename[pos] != '/' && filename[pos] != '\\' && pos > 0) pos--;
+ QString path_dir = filename.left(pos);
+ QString path_file = filename.mid(pos+1);
- int pos = strlen(file)-1;
- while (file[pos] != '/' && file[pos] != '\\' && pos > 0) pos--;
- strncpy(Config::LastROMFolder, file, pos);
- Config::LastROMFolder[pos] = '\0';
- char* ext = &file[strlen(file)-3];
+ Config::LastROMFolder = path_dir.toStdString();
- int slot; int res;
- if (!strcasecmp(ext, "gba"))
+ bool isarc = false;
+ for (const auto& ext : arcexts)
{
- slot = 1;
- res = Frontend::LoadROM(file, Frontend::ROMSlot_GBA);
+ int l = ext.length() - 1;
+ if (path_file.right(l).toLower() == ext.right(l))
+ {
+ isarc = true;
+ break;
+ }
+ }
+
+ if (isarc)
+ {
+ path_file = pickFileFromArchive(filename);
+ if (path_file.isEmpty())
+ return ret;
+
+ ret.append(filename);
+ ret.append(path_file);
}
else
{
- slot = 0;
- res = Frontend::LoadROM(file, Frontend::ROMSlot_NDS);
+ ret.append(filename);
}
- if (res != Frontend::Load_OK)
+ return ret;
+}
+
+void MainWindow::updateCartInserted(bool gba)
+{
+ bool inserted;
+ if (gba)
{
- QMessageBox::critical(this,
- "melonDS",
- loadErrorStr(res));
- emuThread->emuUnpause();
- }
- else if (slot == 1)
- {
- // checkme
- emuThread->emuUnpause();
+ inserted = ROMManager::GBACartInserted() && (Config::ConsoleType == 0);
+ actCurrentGBACart->setText("GBA slot: " + ROMManager::GBACartLabel());
+ actEjectGBACart->setEnabled(inserted);
}
else
{
- emuThread->emuRun();
+ inserted = ROMManager::CartInserted();
+ actCurrentCart->setText("DS slot: " + ROMManager::CartLabel());
+ actEjectCart->setEnabled(inserted);
+ actImportSavefile->setEnabled(inserted);
+ actSetupCheats->setEnabled(inserted);
+ actROMInfo->setEnabled(inserted);
}
}
@@ -1992,99 +2078,43 @@ void MainWindow::onOpenFile()
{
emuThread->emuPause();
- QString filename = QFileDialog::getOpenFileName(this,
- "Open ROM",
- Config::LastROMFolder,
- "DS ROMs (*.nds *.dsi *.srl);;GBA ROMs (*.gba *.zip);;Any file (*.*)");
- if (filename.isEmpty())
+ if (!verifySetup())
{
emuThread->emuUnpause();
return;
}
- loadROM(filename);
-}
-
-void MainWindow::onOpenFileArchive()
-{
- emuThread->emuPause();
-
- QString archiveFileName = QFileDialog::getOpenFileName(this,
- "Open ROM Archive",
- Config::LastROMFolder,
- "Archived ROMs (*.zip *.7z *.rar *.tar *.tar.gz *.tar.xz *.tar.bz2);;Any file (*.*)");
- if (archiveFileName.isEmpty())
+ QStringList file = pickROM(false);
+ if (file.isEmpty())
{
emuThread->emuUnpause();
return;
}
- QByteArray romBuffer;
- QString romFileName = pickAndExtractFileFromArchive(archiveFileName, &romBuffer);
- if(!romFileName.isEmpty())
+ if (!ROMManager::LoadROM(file, true))
{
- loadROM(&romBuffer, archiveFileName, romFileName);
+ // TODO: better error reporting?
+ QMessageBox::critical(this, "melonDS", "Failed to load the ROM.");
+ emuThread->emuUnpause();
+ return;
}
-}
-
-QString MainWindow::pickAndExtractFileFromArchive(QString archiveFileName, QByteArray *romBuffer)
-{
- printf("Finding list of ROMs...\n");
- QVector<QString> archiveROMList = Archive::ListArchive(archiveFileName.toUtf8().constData());
-
-
- QString romFileName; // file name inside archive
- if (archiveROMList.size() > 2)
- {
- archiveROMList.removeFirst();
+ QString filename = file.join('|');
+ recentFileList.removeAll(filename);
+ recentFileList.prepend(filename);
+ updateRecentFilesMenu();
- bool ok;
- QString toLoad = QInputDialog::getItem(this, "melonDS",
- "The archive was found to have multiple files. Select which ROM you want to load.", archiveROMList.toList(), 0, false, &ok);
- if(!ok) // User clicked on cancel
- return QString();
+ NDS::Start();
+ emuThread->emuRun();
- printf("Extracting '%s'\n", toLoad.toUtf8().constData());
- QVector<QString> extractResult = Archive::ExtractFileFromArchive(archiveFileName.toUtf8().constData(), toLoad.toUtf8().constData(), romBuffer);
- if (extractResult[0] != QString("Err"))
- {
- romFileName = extractResult[0];
- }
- else
- {
- QMessageBox::critical(this, "melonDS", QString("There was an error while trying to extract the ROM from the archive: ") + extractResult[1]);
- }
- }
- else if (archiveROMList.size() == 2)
- {
- printf("Extracting the only ROM in archive\n");
- QVector<QString> extractResult = Archive::ExtractFileFromArchive(archiveFileName.toUtf8().constData(), archiveROMList.at(1).toUtf8().constData(), romBuffer);
- if (extractResult[0] != QString("Err"))
- {
- romFileName = extractResult[0];
- }
- else
- {
- QMessageBox::critical(this, "melonDS", QString("There was an error while trying to extract the ROM from the archive: ") + extractResult[1]);
- }
- }
- else if ((archiveROMList.size() == 1) && (archiveROMList[0] == QString("OK")))
- {
- QMessageBox::warning(this, "melonDS", "The archive is intact, but there are no files inside.");
- }
- else
- {
- QMessageBox::critical(this, "melonDS", "The archive could not be read. It may be corrupt or you don't have the permissions.");
- }
-
- return romFileName;
+ updateCartInserted(false);
}
void MainWindow::onClearRecentFiles()
{
recentFileList.clear();
- memset(Config::RecentROMList, 0, 10 * 1024);
+ for (int i = 0; i < 10; i++)
+ Config::RecentROMList[i] = "";
updateRecentFilesMenu();
}
@@ -2092,8 +2122,10 @@ void MainWindow::updateRecentFilesMenu()
{
recentMenu->clear();
- for(int i = 0; i < recentFileList.size(); ++i)
+ for (int i = 0; i < recentFileList.size(); ++i)
{
+ if (i >= 10) break;
+
QString item_full = recentFileList.at(i);
QString item_display = item_full;
int itemlen = item_full.length();
@@ -2120,16 +2152,18 @@ void MainWindow::updateRecentFilesMenu()
actRecentFile_i->setData(item_full);
connect(actRecentFile_i, &QAction::triggered, this, &MainWindow::onClickRecentFile);
- if(i < 10)
- strncpy(Config::RecentROMList[i], recentFileList.at(i).toStdString().c_str(), 1024);
+ Config::RecentROMList[i] = recentFileList.at(i).toStdString();
}
+ while (recentFileList.size() > 10)
+ recentFileList.removeLast();
+
recentMenu->addSeparator();
QAction *actClearRecentList = recentMenu->addAction("Clear");
connect(actClearRecentList, &QAction::triggered, this, &MainWindow::onClearRecentFiles);
- if(recentFileList.empty())
+ if (recentFileList.empty())
actClearRecentList->setEnabled(false);
Config::Save();
@@ -2138,48 +2172,139 @@ void MainWindow::updateRecentFilesMenu()
void MainWindow::onClickRecentFile()
{
QAction *act = (QAction *)sender();
- QString fileName = act->data().toString();
+ QString filename = act->data().toString();
+ QStringList file = filename.split('|');
+
+ emuThread->emuPause();
- if (fileName.endsWith(".gba", Qt::CaseInsensitive) ||
- fileName.endsWith(".nds", Qt::CaseInsensitive) ||
- fileName.endsWith(".srl", Qt::CaseInsensitive) ||
- fileName.endsWith(".dsi", Qt::CaseInsensitive))
+ if (!verifySetup())
{
- emuThread->emuPause();
- loadROM(fileName);
+ emuThread->emuUnpause();
+ return;
}
- else
+
+ if (!ROMManager::LoadROM(file, true))
{
- // Archives
- QString archiveFileName = fileName;
- QByteArray romBuffer;
- QString romFileName = MainWindow::pickAndExtractFileFromArchive(archiveFileName, &romBuffer);
- if(!romFileName.isEmpty())
- {
- emuThread->emuPause();
- loadROM(&romBuffer, archiveFileName, romFileName);
- }
+ // TODO: better error reporting?
+ QMessageBox::critical(this, "melonDS", "Failed to load the ROM.");
+ emuThread->emuUnpause();
+ return;
}
+
+ recentFileList.removeAll(filename);
+ recentFileList.prepend(filename);
+ updateRecentFilesMenu();
+
+ NDS::Start();
+ emuThread->emuRun();
+
+ updateCartInserted(false);
}
void MainWindow::onBootFirmware()
{
- // TODO: check the whole GBA cart shito
+ emuThread->emuPause();
+ if (!verifySetup())
+ {
+ emuThread->emuUnpause();
+ return;
+ }
+
+ if (!ROMManager::LoadBIOS())
+ {
+ // TODO: better error reporting?
+ QMessageBox::critical(this, "melonDS", "This firmware is not bootable.");
+ emuThread->emuUnpause();
+ return;
+ }
+
+ NDS::Start();
+ emuThread->emuRun();
+}
+
+void MainWindow::onInsertCart()
+{
emuThread->emuPause();
- int res = Frontend::LoadBIOS();
- if (res != Frontend::Load_OK)
+ QStringList file = pickROM(false);
+ if (file.isEmpty())
{
- QMessageBox::critical(this,
- "melonDS",
- loadErrorStr(res));
emuThread->emuUnpause();
+ return;
}
- else
+
+ if (!ROMManager::LoadROM(file, false))
{
- emuThread->emuRun();
+ // TODO: better error reporting?
+ QMessageBox::critical(this, "melonDS", "Failed to load the ROM.");
+ emuThread->emuUnpause();
+ return;
+ }
+
+ emuThread->emuUnpause();
+
+ updateCartInserted(false);
+}
+
+void MainWindow::onEjectCart()
+{
+ emuThread->emuPause();
+
+ ROMManager::EjectCart();
+
+ emuThread->emuUnpause();
+
+ updateCartInserted(false);
+}
+
+void MainWindow::onInsertGBACart()
+{
+ emuThread->emuPause();
+
+ QStringList file = pickROM(true);
+ if (file.isEmpty())
+ {
+ emuThread->emuUnpause();
+ return;
+ }
+
+ if (!ROMManager::LoadGBAROM(file))
+ {
+ // TODO: better error reporting?
+ QMessageBox::critical(this, "melonDS", "Failed to load the ROM.");
+ emuThread->emuUnpause();
+ return;
}
+
+ emuThread->emuUnpause();
+
+ updateCartInserted(true);
+}
+
+void MainWindow::onInsertGBAAddon()
+{
+ QAction* act = (QAction*)sender();
+ int type = act->data().toInt();
+
+ emuThread->emuPause();
+
+ ROMManager::LoadGBAAddon(type);
+
+ emuThread->emuUnpause();
+
+ updateCartInserted(true);
+}
+
+void MainWindow::onEjectGBACart()
+{
+ emuThread->emuPause();
+
+ ROMManager::EjectGBACart();
+
+ emuThread->emuUnpause();
+
+ updateCartInserted(true);
}
void MainWindow::onSaveState()
@@ -2188,17 +2313,17 @@ void MainWindow::onSaveState()
emuThread->emuPause();
- char filename[1024];
+ std::string filename;
if (slot > 0)
{
- Frontend::GetSavestateName(slot, filename, 1024);
+ filename = ROMManager::GetSavestateName(slot);
}
else
{
// TODO: specific 'last directory' for savestate files?
QString qfilename = QFileDialog::getSaveFileName(this,
"Save state",
- Config::LastROMFolder,
+ QString::fromStdString(Config::LastROMFolder),
"melonDS savestates (*.mln);;Any file (*.*)");
if (qfilename.isEmpty())
{
@@ -2206,10 +2331,10 @@ void MainWindow::onSaveState()
return;
}
- strncpy(filename, qfilename.toStdString().c_str(), 1023); filename[1023] = '\0';
+ filename = qfilename.toStdString();
}
- if (Frontend::SaveState(filename))
+ if (ROMManager::SaveState(filename))
{
char msg[64];
if (slot > 0) sprintf(msg, "State saved to slot %d", slot);
@@ -2232,17 +2357,17 @@ void MainWindow::onLoadState()
emuThread->emuPause();
- char filename[1024];
+ std::string filename;
if (slot > 0)
{
- Frontend::GetSavestateName(slot, filename, 1024);
+ filename = ROMManager::GetSavestateName(slot);
}
else
{
// TODO: specific 'last directory' for savestate files?
QString qfilename = QFileDialog::getOpenFileName(this,
"Load state",
- Config::LastROMFolder,
+ QString::fromStdString(Config::LastROMFolder),
"melonDS savestates (*.ml*);;Any file (*.*)");
if (qfilename.isEmpty())
{
@@ -2250,7 +2375,7 @@ void MainWindow::onLoadState()
return;
}
- strncpy(filename, qfilename.toStdString().c_str(), 1023); filename[1023] = '\0';
+ filename = qfilename.toStdString();
}
if (!Platform::FileExists(filename))
@@ -2264,7 +2389,7 @@ void MainWindow::onLoadState()
return;
}
- if (Frontend::LoadState(filename))
+ if (ROMManager::LoadState(filename))
{
char msg[64];
if (slot > 0) sprintf(msg, "State loaded from slot %d", slot);
@@ -2284,7 +2409,7 @@ void MainWindow::onLoadState()
void MainWindow::onUndoStateLoad()
{
emuThread->emuPause();
- Frontend::UndoStateLoad();
+ ROMManager::UndoStateLoad();
emuThread->emuUnpause();
OSD::AddMessage(0, "State load undone");
@@ -2292,36 +2417,52 @@ void MainWindow::onUndoStateLoad()
void MainWindow::onImportSavefile()
{
- if (!RunningSomething) return;
-
emuThread->emuPause();
QString path = QFileDialog::getOpenFileName(this,
"Select savefile",
- Config::LastROMFolder,
+ QString::fromStdString(Config::LastROMFolder),
"Savefiles (*.sav *.bin *.dsv);;Any file (*.*)");
- if (!path.isEmpty())
+ if (path.isEmpty())
+ {
+ emuThread->emuUnpause();
+ return;
+ }
+
+ FILE* f = Platform::OpenFile(path.toStdString(), "rb", true);
+ if (!f)
+ {
+ QMessageBox::critical(this, "melonDS", "Could not open the given savefile.");
+ emuThread->emuUnpause();
+ return;
+ }
+
+ if (RunningSomething)
{
if (QMessageBox::warning(this,
- "Emulation will be reset and data overwritten",
+ "melonDS",
"The emulation will be reset and the current savefile overwritten.",
- QMessageBox::Ok, QMessageBox::Cancel) == QMessageBox::Ok)
+ QMessageBox::Ok, QMessageBox::Cancel) != QMessageBox::Ok)
{
- int res = Frontend::Reset();
- if (res != Frontend::Load_OK)
- {
- QMessageBox::critical(this, "melonDS", "Reset failed\n" + loadErrorStr(res));
- }
- else
- {
- int diff = Frontend::ImportSRAM(path.toStdString().c_str());
- if (diff > 0)
- OSD::AddMessage(0, "Trimmed savefile");
- else if (diff < 0)
- OSD::AddMessage(0, "Savefile shorter than SRAM");
- }
+ emuThread->emuUnpause();
+ return;
}
+
+ ROMManager::Reset();
}
+
+ u32 len;
+ fseek(f, 0, SEEK_END);
+ len = (u32)ftell(f);
+
+ u8* data = new u8[len];
+ fseek(f, 0, SEEK_SET);
+ fread(data, len, 1, f);
+
+ NDS::LoadSave(data, len);
+ delete[] data;
+
+ fclose(f);
emuThread->emuUnpause();
}
@@ -2360,19 +2501,10 @@ void MainWindow::onReset()
actUndoStateLoad->setEnabled(false);
- int res = Frontend::Reset();
- if (res != Frontend::Load_OK)
- {
- QMessageBox::critical(this,
- "melonDS",
- loadErrorStr(res));
- emuThread->emuUnpause();
- }
- else
- {
- OSD::AddMessage(0, "Reset");
- emuThread->emuRun();
- }
+ ROMManager::Reset();
+
+ OSD::AddMessage(0, "Reset");
+ emuThread->emuRun();
}
void MainWindow::onStop()
@@ -2393,7 +2525,7 @@ void MainWindow::onFrameStep()
void MainWindow::onEnableCheats(bool checked)
{
Config::EnableCheats = checked?1:0;
- Frontend::EnableCheats(Config::EnableCheats != 0);
+ ROMManager::EnableCheats(Config::EnableCheats != 0);
}
void MainWindow::onSetupCheats()
@@ -2431,11 +2563,28 @@ void MainWindow::onEmuSettingsDialogFinished(int res)
{
emuThread->emuUnpause();
+ if (Config::ConsoleType == 1)
+ {
+ actInsertGBACart->setEnabled(false);
+ for (int i = 0; i < 1; i++)
+ actInsertGBAAddon[i]->setEnabled(false);
+ actEjectGBACart->setEnabled(false);
+ }
+ else
+ {
+ actInsertGBACart->setEnabled(true);
+ for (int i = 0; i < 1; i++)
+ actInsertGBAAddon[i]->setEnabled(true);
+ actEjectGBACart->setEnabled(ROMManager::GBACartInserted());
+ }
+
if (EmuSettingsDialog::needsReset)
onReset();
+ actCurrentGBACart->setText("GBA slot: " + ROMManager::GBACartLabel());
+
if (!RunningSomething)
- actTitleManager->setEnabled(strlen(Config::DSiNANDPath) > 0);
+ actTitleManager->setEnabled(!Config::DSiNANDPath.empty());
}
void MainWindow::onOpenInputConfig()
@@ -2480,6 +2629,22 @@ void MainWindow::onFirmwareSettingsFinished(int res)
emuThread->emuUnpause();
}
+void MainWindow::onOpenPathSettings()
+{
+ emuThread->emuPause();
+
+ PathSettingsDialog* dlg = PathSettingsDialog::openDlg(this);
+ connect(dlg, &PathSettingsDialog::finished, this, &MainWindow::onPathSettingsFinished);
+}
+
+void MainWindow::onPathSettingsFinished(int res)
+{
+ if (PathSettingsDialog::needsReset)
+ onReset();
+
+ emuThread->emuUnpause();
+}
+
void MainWindow::onUpdateAudioSettings()
{
SPU::SetInterpolation(Config::AudioInterp);
@@ -2678,39 +2843,22 @@ void MainWindow::onFullscreenToggled()
void MainWindow::onEmuStart()
{
- // TODO: make savestates work in DSi mode!!
- if (Config::ConsoleType == 1)
- {
- for (int i = 0; i < 9; i++)
- {
- actSaveState[i]->setEnabled(false);
- actLoadState[i]->setEnabled(false);
- }
- actUndoStateLoad->setEnabled(false);
- }
- else
+ for (int i = 1; i < 9; i++)
{
- for (int i = 1; i < 9; i++)
- {
- actSaveState[i]->setEnabled(true);
- actLoadState[i]->setEnabled(Frontend::SavestateExists(i));
- }
- actSaveState[0]->setEnabled(true);
- actLoadState[0]->setEnabled(true);
- actUndoStateLoad->setEnabled(false);
+ actSaveState[i]->setEnabled(true);
+ actLoadState[i]->setEnabled(ROMManager::SavestateExists(i));
}
+ actSaveState[0]->setEnabled(true);
+ actLoadState[0]->setEnabled(true);
+ actUndoStateLoad->setEnabled(false);
actPause->setEnabled(true);
actPause->setChecked(false);
actReset->setEnabled(true);
actStop->setEnabled(true);
actFrameStep->setEnabled(true);
- actImportSavefile->setEnabled(true);
- actSetupCheats->setEnabled(true);
actTitleManager->setEnabled(false);
-
- actROMInfo->setEnabled(true);
}
void MainWindow::onEmuStop()
@@ -2723,17 +2871,13 @@ void MainWindow::onEmuStop()
actLoadState[i]->setEnabled(false);
}
actUndoStateLoad->setEnabled(false);
- actImportSavefile->setEnabled(false);
actPause->setEnabled(false);
actReset->setEnabled(false);
actStop->setEnabled(false);
actFrameStep->setEnabled(false);
- actSetupCheats->setEnabled(false);
- actTitleManager->setEnabled(strlen(Config::DSiNANDPath) > 0);
-
- actROMInfo->setEnabled(false);
+ actTitleManager->setEnabled(!Config::DSiNANDPath.empty());
}
void MainWindow::onUpdateVideoSettings(bool glchange)
@@ -2767,9 +2911,6 @@ void emuStop()
{
RunningSomething = false;
- Frontend::UnloadROM(Frontend::ROMSlot_NDS);
- Frontend::UnloadROM(Frontend::ROMSlot_GBA);
-
emit emuThread->windowEmuStop();
OSD::AddMessage(0xFFC040, "Shutdown");
@@ -2788,7 +2929,8 @@ bool MelonApplication::event(QEvent *event)
QFileOpenEvent *openEvent = static_cast<QFileOpenEvent*>(event);
emuThread->emuPause();
- mainWindow->loadROM(openEvent->file());
+ if (!mainWindow->preloadROMs(openEvent->file(), ""))
+ emuThread->emuUnpause();
}
return QApplication::event(event);
@@ -2886,8 +3028,7 @@ int main(int argc, char** argv)
micExtBufferWritePos = 0;
micWavBuffer = nullptr;
- Frontend::Init_ROM();
- Frontend::EnableCheats(Config::EnableCheats != 0);
+ ROMManager::EnableCheats(Config::EnableCheats != 0);
Frontend::Init_Audio(audioFreq);
@@ -2914,29 +3055,11 @@ int main(int argc, char** argv)
if (argc > 1)
{
- char* file = argv[1];
- char* ext = &file[strlen(file)-3];
-
- if (!strcasecmp(ext, "nds") || !strcasecmp(ext, "srl") || !strcasecmp(ext, "dsi"))
- {
- int res = Frontend::LoadROM(file, Frontend::ROMSlot_NDS);
+ QString file = argv[1];
+ QString gbafile = "";
+ if (argc > 2) gbafile = argv[2];
- if (res == Frontend::Load_OK)
- {
- if (argc > 2)
- {
- file = argv[2];
- ext = &file[strlen(file)-3];
-
- if (!strcasecmp(ext, "gba"))
- {
- Frontend::LoadROM(file, Frontend::ROMSlot_GBA);
- }
- }
-
- emuThread->emuRun();
- }
- }
+ mainWindow->preloadROMs(file, gbafile);
}
int ret = melon.exec();
@@ -2947,8 +3070,6 @@ int main(int argc, char** argv)
Input::CloseJoystick();
- Frontend::DeInit_ROM();
-
if (audioDevice) SDL_CloseAudioDevice(audioDevice);
micClose();
diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h
index 0b5e917..a0ee9c5 100644
--- a/src/frontend/qt_sdl/main.h
+++ b/src/frontend/qt_sdl/main.h
@@ -211,8 +211,7 @@ public:
bool hasOGL;
QOpenGLContext* getOGLContext();
- void loadROM(QString filename);
- void loadROM(QByteArray *romData, QString archiveFileName, QString romFileName);
+ bool preloadROMs(QString filename, QString gbafilename);
void onAppStateChanged(Qt::ApplicationState state);
@@ -231,10 +230,14 @@ signals:
private slots:
void onOpenFile();
- void onOpenFileArchive();
void onClickRecentFile();
void onClearRecentFiles();
void onBootFirmware();
+ void onInsertCart();
+ void onEjectCart();
+ void onInsertGBACart();
+ void onInsertGBAAddon();
+ void onEjectGBACart();
void onSaveState();
void onLoadState();
void onUndoStateLoad();
@@ -258,11 +261,13 @@ private slots:
void onOpenVideoSettings();
void onOpenAudioSettings();
void onOpenFirmwareSettings();
+ void onOpenPathSettings();
void onUpdateAudioSettings();
void onAudioSettingsFinished(int res);
void onOpenWifiSettings();
void onWifiSettingsFinished(int res);
void onFirmwareSettingsFinished(int res);
+ void onPathSettingsFinished(int res);
void onOpenInterfaceSettings();
void onInterfaceSettingsFinished(int res);
void onUpdateMouseTimer();
@@ -291,16 +296,19 @@ private slots:
void onFullscreenToggled();
private:
+ QStringList currentROM;
+ QStringList currentGBAROM;
QList<QString> recentFileList;
QMenu *recentMenu;
void updateRecentFilesMenu();
- QString pickAndExtractFileFromArchive(QString archiveFileName, QByteArray *romBuffer);
+ bool verifySetup();
+ QString pickFileFromArchive(QString archiveFileName);
+ QStringList pickROM(bool gba);
+ void updateCartInserted(bool gba);
void createScreenPanel();
- QString loadErrorStr(int error);
-
bool pausedManually = false;
int oldW, oldH;
@@ -312,12 +320,18 @@ public:
ScreenPanelNative* panelNative;
QAction* actOpenROM;
- QAction* actOpenROMArchive;
QAction* actBootFirmware;
+ QAction* actCurrentCart;
+ QAction* actInsertCart;
+ QAction* actEjectCart;
+ QAction* actCurrentGBACart;
+ QAction* actInsertGBACart;
+ QAction* actInsertGBAAddon[1];
+ QAction* actEjectGBACart;
+ QAction* actImportSavefile;
QAction* actSaveState[9];
QAction* actLoadState[9];
QAction* actUndoStateLoad;
- QAction* actImportSavefile;
QAction* actQuit;
QAction* actPause;
@@ -335,6 +349,7 @@ public:
QAction* actAudioSettings;
QAction* actWifiSettings;
QAction* actFirmwareSettings;
+ QAction* actPathSettings;
QAction* actInterfaceSettings;
QAction* actSavestateSRAMReloc;
QAction* actScreenSize[4];