Custom path support (#1333)
also including: * getting rid of shitty strings * all new, cleaner ROM handling code * base for DSi savestates * GBA slot addons (for now, memory cart)
This commit is contained in:
parent
c4cd9da674
commit
e665e25bd3
|
@ -26,10 +26,9 @@
|
||||||
// TODO: more user-friendly error reporting
|
// TODO: more user-friendly error reporting
|
||||||
|
|
||||||
|
|
||||||
ARCodeFile::ARCodeFile(const char* filename)
|
ARCodeFile::ARCodeFile(std::string filename)
|
||||||
{
|
{
|
||||||
memset(Filename, 0, sizeof(Filename));
|
Filename = filename;
|
||||||
strncpy(Filename, filename, 1023);
|
|
||||||
|
|
||||||
Error = false;
|
Error = false;
|
||||||
|
|
||||||
|
@ -91,7 +90,7 @@ bool ARCodeFile::Load()
|
||||||
if (isincat) Categories.push_back(curcat);
|
if (isincat) Categories.push_back(curcat);
|
||||||
isincat = true;
|
isincat = true;
|
||||||
|
|
||||||
memcpy(curcat.Name, catname, 128);
|
curcat.Name = catname;
|
||||||
curcat.Codes.clear();
|
curcat.Codes.clear();
|
||||||
}
|
}
|
||||||
else if (!strncasecmp(start, "CODE", 4))
|
else if (!strncasecmp(start, "CODE", 4))
|
||||||
|
@ -118,7 +117,7 @@ bool ARCodeFile::Load()
|
||||||
if (isincode) curcat.Codes.push_back(curcode);
|
if (isincode) curcat.Codes.push_back(curcode);
|
||||||
isincode = true;
|
isincode = true;
|
||||||
|
|
||||||
memcpy(curcode.Name, codename, 128);
|
curcode.Name = codename;
|
||||||
curcode.Enabled = enable!=0;
|
curcode.Enabled = enable!=0;
|
||||||
curcode.CodeLen = 0;
|
curcode.CodeLen = 0;
|
||||||
}
|
}
|
||||||
|
@ -172,12 +171,12 @@ bool ARCodeFile::Save()
|
||||||
ARCodeCat& cat = *it;
|
ARCodeCat& cat = *it;
|
||||||
|
|
||||||
if (it != Categories.begin()) fprintf(f, "\r\n");
|
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++)
|
for (ARCodeList::iterator jt = cat.Codes.begin(); jt != cat.Codes.end(); jt++)
|
||||||
{
|
{
|
||||||
ARCode& code = *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)
|
for (u32 i = 0; i < code.CodeLen; i+=2)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,13 +19,14 @@
|
||||||
#ifndef ARCODEFILE_H
|
#ifndef ARCODEFILE_H
|
||||||
#define ARCODEFILE_H
|
#define ARCODEFILE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
struct ARCode
|
struct ARCode
|
||||||
{
|
{
|
||||||
char Name[128];
|
std::string Name;
|
||||||
bool Enabled;
|
bool Enabled;
|
||||||
u32 CodeLen;
|
u32 CodeLen;
|
||||||
u32 Code[2*64];
|
u32 Code[2*64];
|
||||||
|
@ -35,7 +36,7 @@ typedef std::list<ARCode> ARCodeList;
|
||||||
|
|
||||||
struct ARCodeCat
|
struct ARCodeCat
|
||||||
{
|
{
|
||||||
char Name[128];
|
std::string Name;
|
||||||
ARCodeList Codes;
|
ARCodeList Codes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,7 +46,7 @@ typedef std::list<ARCodeCat> ARCodeCatList;
|
||||||
class ARCodeFile
|
class ARCodeFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ARCodeFile(const char* filename);
|
ARCodeFile(std::string filename);
|
||||||
~ARCodeFile();
|
~ARCodeFile();
|
||||||
|
|
||||||
bool Error;
|
bool Error;
|
||||||
|
@ -56,7 +57,7 @@ public:
|
||||||
ARCodeCatList Categories;
|
ARCodeCatList Categories;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char Filename[1024];
|
std::string Filename;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ARCODEFILE_H
|
#endif // ARCODEFILE_H
|
||||||
|
|
|
@ -50,8 +50,6 @@ void DeInit()
|
||||||
|
|
||||||
void Reset()
|
void Reset()
|
||||||
{
|
{
|
||||||
CodeFile = nullptr;
|
|
||||||
|
|
||||||
if (NDS::ConsoleType == 1)
|
if (NDS::ConsoleType == 1)
|
||||||
{
|
{
|
||||||
BusRead8 = DSi::ARM7Read8;
|
BusRead8 = DSi::ARM7Read8;
|
||||||
|
@ -73,6 +71,11 @@ void Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ARCodeFile* GetCodeFile()
|
||||||
|
{
|
||||||
|
return CodeFile;
|
||||||
|
}
|
||||||
|
|
||||||
void SetCodeFile(ARCodeFile* file)
|
void SetCodeFile(ARCodeFile* file)
|
||||||
{
|
{
|
||||||
CodeFile = file;
|
CodeFile = file;
|
||||||
|
|
|
@ -28,6 +28,7 @@ bool Init();
|
||||||
void DeInit();
|
void DeInit();
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
|
ARCodeFile* GetCodeFile();
|
||||||
void SetCodeFile(ARCodeFile* file);
|
void SetCodeFile(ARCodeFile* file);
|
||||||
|
|
||||||
void RunCheats();
|
void RunCheats();
|
||||||
|
|
|
@ -36,7 +36,6 @@ add_library(core STATIC
|
||||||
melonDLDI.h
|
melonDLDI.h
|
||||||
NDS.cpp
|
NDS.cpp
|
||||||
NDSCart.cpp
|
NDSCart.cpp
|
||||||
NDSCart_SRAMManager.cpp
|
|
||||||
Platform.h
|
Platform.h
|
||||||
ROMList.h
|
ROMList.h
|
||||||
FreeBIOS.h
|
FreeBIOS.h
|
||||||
|
|
|
@ -52,7 +52,7 @@ void _inittable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 CRC32(u8 *data, int len)
|
u32 CRC32(u8 *data, int len, u32 start)
|
||||||
{
|
{
|
||||||
if (!tableinited)
|
if (!tableinited)
|
||||||
{
|
{
|
||||||
|
@ -60,7 +60,7 @@ u32 CRC32(u8 *data, int len)
|
||||||
tableinited = true;
|
tableinited = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 crc = 0xFFFFFFFF;
|
u32 crc = start ^ 0xFFFFFFFF;
|
||||||
|
|
||||||
while (len--)
|
while (len--)
|
||||||
crc = (crc >> 8) ^ crctable[(crc & 0xFF) ^ *data++];
|
crc = (crc >> 8) ^ crctable[(crc & 0xFF) ^ *data++];
|
||||||
|
|
|
@ -21,6 +21,6 @@
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
u32 CRC32(u8* data, int len);
|
u32 CRC32(u8* data, int len, u32 start=0);
|
||||||
|
|
||||||
#endif // CRC32_H
|
#endif // CRC32_H
|
||||||
|
|
233
src/DSi.cpp
233
src/DSi.cpp
|
@ -47,8 +47,6 @@
|
||||||
namespace DSi
|
namespace DSi
|
||||||
{
|
{
|
||||||
|
|
||||||
u32 BootAddr[2];
|
|
||||||
|
|
||||||
u16 SCFG_BIOS;
|
u16 SCFG_BIOS;
|
||||||
u16 SCFG_Clock9;
|
u16 SCFG_Clock9;
|
||||||
u16 SCFG_Clock7;
|
u16 SCFG_Clock7;
|
||||||
|
@ -79,16 +77,12 @@ DSi_NDMA* NDMAs[8];
|
||||||
DSi_SDHost* SDMMC;
|
DSi_SDHost* SDMMC;
|
||||||
DSi_SDHost* SDIO;
|
DSi_SDHost* SDIO;
|
||||||
|
|
||||||
FILE* SDMMCFile = nullptr;
|
|
||||||
|
|
||||||
u64 ConsoleID;
|
u64 ConsoleID;
|
||||||
u8 eMMC_CID[16];
|
u8 eMMC_CID[16];
|
||||||
|
|
||||||
u8 ITCMInit[0x8000];
|
|
||||||
u8 ARM7Init[0x3C00];
|
|
||||||
|
|
||||||
|
|
||||||
void Set_SCFG_Clock9(u16 val);
|
void Set_SCFG_Clock9(u16 val);
|
||||||
|
void Set_SCFG_MC(u32 val);
|
||||||
|
|
||||||
|
|
||||||
bool Init()
|
bool Init()
|
||||||
|
@ -134,8 +128,6 @@ void DeInit()
|
||||||
|
|
||||||
delete SDMMC;
|
delete SDMMC;
|
||||||
delete SDIO;
|
delete SDIO;
|
||||||
|
|
||||||
CloseDSiNAND();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset()
|
void Reset()
|
||||||
|
@ -144,21 +136,24 @@ void Reset()
|
||||||
//NDS::ARM9->CP15Write(0x911, 0x00000020);
|
//NDS::ARM9->CP15Write(0x911, 0x00000020);
|
||||||
//NDS::ARM9->CP15Write(0x100, NDS::ARM9->CP15Read(0x100) | 0x00050000);
|
//NDS::ARM9->CP15Write(0x100, NDS::ARM9->CP15Read(0x100) | 0x00050000);
|
||||||
|
|
||||||
NDS::ARM9->JumpTo(BootAddr[0]);
|
NDS::MapSharedWRAM(3);
|
||||||
NDS::ARM7->JumpTo(BootAddr[1]);
|
|
||||||
|
|
||||||
NDMACnt[0] = 0; NDMACnt[1] = 0;
|
NDMACnt[0] = 0; NDMACnt[1] = 0;
|
||||||
for (int i = 0; i < 8; i++) NDMAs[i]->Reset();
|
for (int i = 0; i < 8; i++) NDMAs[i]->Reset();
|
||||||
|
|
||||||
memcpy(NDS::ARM9->ITCM, ITCMInit, 0x8000);
|
|
||||||
|
|
||||||
DSi_I2C::Reset();
|
DSi_I2C::Reset();
|
||||||
DSi_AES::Reset();
|
|
||||||
DSi_DSP::Reset();
|
DSi_DSP::Reset();
|
||||||
|
|
||||||
|
SDMMC->CloseHandles();
|
||||||
|
SDIO->CloseHandles();
|
||||||
|
|
||||||
|
LoadNAND();
|
||||||
|
|
||||||
SDMMC->Reset();
|
SDMMC->Reset();
|
||||||
SDIO->Reset();
|
SDIO->Reset();
|
||||||
|
|
||||||
|
DSi_AES::Reset();
|
||||||
|
|
||||||
SCFG_BIOS = 0x0101; // TODO: should be zero when booting from BIOS
|
SCFG_BIOS = 0x0101; // TODO: should be zero when booting from BIOS
|
||||||
SCFG_Clock9 = 0x0187; // CHECKME
|
SCFG_Clock9 = 0x0187; // CHECKME
|
||||||
SCFG_Clock7 = 0x0187;
|
SCFG_Clock7 = 0x0187;
|
||||||
|
@ -172,22 +167,85 @@ void Reset()
|
||||||
// LCD init flag
|
// LCD init flag
|
||||||
GPU::DispStat[0] |= (1<<6);
|
GPU::DispStat[0] |= (1<<6);
|
||||||
GPU::DispStat[1] |= (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)
|
file->Var16(&SCFG_BIOS);
|
||||||
ARM7Write32(0x03FFC400+i, *(u32*)&ARM7Init[i]);
|
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;
|
//file->VarArray(ARM9iBIOS, 0x10000);
|
||||||
ARM7Write32(eaddr+0x00, *(u32*)&eMMC_CID[0]);
|
//file->VarArray(ARM7iBIOS, 0x10000);
|
||||||
ARM7Write32(eaddr+0x04, *(u32*)&eMMC_CID[4]);
|
|
||||||
ARM7Write32(eaddr+0x08, *(u32*)&eMMC_CID[8]);
|
if (file->Saving)
|
||||||
ARM7Write32(eaddr+0x0C, *(u32*)&eMMC_CID[12]);
|
{
|
||||||
ARM7Write16(eaddr+0x2C, 0x0001);
|
file->VarArray(&MBK[0][0], sizeof(u32)*8);
|
||||||
ARM7Write16(eaddr+0x2E, 0x0001);
|
file->VarArray(&MBK[1][5], sizeof(u32)*3);
|
||||||
ARM7Write16(eaddr+0x3C, 0x0100);
|
file->Var32(&MBK[0][8]);
|
||||||
ARM7Write16(eaddr+0x3E, 0x40E0);
|
}
|
||||||
ARM7Write16(eaddr+0x42, 0x0001);
|
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)
|
void DecryptModcryptArea(u32 offset, u32 size, u8* iv)
|
||||||
|
@ -445,24 +503,30 @@ void SetupDirectBoot()
|
||||||
ARM9Write32(0x02FFE000+i, tmp);
|
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];
|
if (DSi_NAND::Init(nand, &DSi::ARM7iBIOS[0x8308]))
|
||||||
DSi_NAND::ReadUserData(userdata);
|
{
|
||||||
for (u32 i = 0; i < 0x128; i+=4)
|
u8 userdata[0x1B0];
|
||||||
ARM9Write32(0x02000400+i, *(u32*)&userdata[0x88+i]);
|
DSi_NAND::ReadUserData(userdata);
|
||||||
|
for (u32 i = 0; i < 0x128; i+=4)
|
||||||
|
ARM9Write32(0x02000400+i, *(u32*)&userdata[0x88+i]);
|
||||||
|
|
||||||
u8 hwinfoS[0xA4];
|
u8 hwinfoS[0xA4];
|
||||||
u8 hwinfoN[0x9C];
|
u8 hwinfoN[0x9C];
|
||||||
DSi_NAND::ReadHardwareInfo(hwinfoS, hwinfoN);
|
DSi_NAND::ReadHardwareInfo(hwinfoS, hwinfoN);
|
||||||
|
|
||||||
for (u32 i = 0; i < 0x14; i+=4)
|
for (u32 i = 0; i < 0x14; i+=4)
|
||||||
ARM9Write32(0x02000600+i, *(u32*)&hwinfoN[0x88+i]);
|
ARM9Write32(0x02000600+i, *(u32*)&hwinfoN[0x88+i]);
|
||||||
|
|
||||||
for (u32 i = 0; i < 0x18; i+=4)
|
for (u32 i = 0; i < 0x18; i+=4)
|
||||||
ARM9Write32(0x02FFFD68+i, *(u32*)&hwinfoS[0x88+i]);
|
ARM9Write32(0x02FFFD68+i, *(u32*)&hwinfoS[0x88+i]);
|
||||||
|
|
||||||
DSi_NAND::DeInit();
|
DSi_NAND::DeInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(nand);
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 nwifiver = SPI_Firmware::GetNWifiVersion();
|
u8 nwifiver = SPI_Firmware::GetNWifiVersion();
|
||||||
|
@ -544,21 +608,22 @@ void SoftReset()
|
||||||
|
|
||||||
NDS::ARM9->CP15Reset();
|
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
|
// 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
|
// *HOWEVER*, the bootrom (which does get rerun) does remap NWRAM, and thus
|
||||||
// the DSP most likely gets reset
|
// the DSP most likely gets reset
|
||||||
DSi_DSP::Reset();
|
DSi_DSP::Reset();
|
||||||
|
|
||||||
|
SDMMC->CloseHandles();
|
||||||
|
SDIO->CloseHandles();
|
||||||
|
|
||||||
LoadNAND();
|
LoadNAND();
|
||||||
|
|
||||||
SDMMC->Reset();
|
SDMMC->Reset();
|
||||||
SDIO->Reset();
|
SDIO->Reset();
|
||||||
|
|
||||||
NDS::ARM9->JumpTo(BootAddr[0]);
|
DSi_AES::Reset();
|
||||||
NDS::ARM7->JumpTo(BootAddr[1]);
|
|
||||||
|
|
||||||
SCFG_BIOS = 0x0101; // TODO: should be zero when booting from BIOS
|
SCFG_BIOS = 0x0101; // TODO: should be zero when booting from BIOS
|
||||||
SCFG_Clock9 = 0x0187; // CHECKME
|
SCFG_Clock9 = 0x0187; // CHECKME
|
||||||
|
@ -574,22 +639,6 @@ void SoftReset()
|
||||||
// LCD init flag
|
// LCD init flag
|
||||||
GPU::DispStat[0] |= (1<<6);
|
GPU::DispStat[0] |= (1<<6);
|
||||||
GPU::DispStat[1] |= (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()
|
bool LoadBIOS()
|
||||||
|
@ -650,7 +699,14 @@ bool LoadNAND()
|
||||||
{
|
{
|
||||||
printf("Loading DSi NAND\n");
|
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");
|
printf("Failed to load DSi NAND\n");
|
||||||
return false;
|
return false;
|
||||||
|
@ -676,8 +732,8 @@ bool LoadNAND()
|
||||||
memset(NWRAMMask, 0, sizeof(NWRAMMask));
|
memset(NWRAMMask, 0, sizeof(NWRAMMask));
|
||||||
|
|
||||||
u32 bootparams[8];
|
u32 bootparams[8];
|
||||||
fseek(SDMMCFile, 0x220, SEEK_SET);
|
fseek(nand, 0x220, SEEK_SET);
|
||||||
fread(bootparams, 4, 8, SDMMCFile);
|
fread(bootparams, 4, 8, nand);
|
||||||
|
|
||||||
printf("ARM9: offset=%08X size=%08X RAM=%08X size_aligned=%08X\n",
|
printf("ARM9: offset=%08X size=%08X RAM=%08X size_aligned=%08X\n",
|
||||||
bootparams[0], bootparams[1], bootparams[2], bootparams[3]);
|
bootparams[0], bootparams[1], bootparams[2], bootparams[3]);
|
||||||
|
@ -690,8 +746,8 @@ bool LoadNAND()
|
||||||
MBK[1][8] = 0;
|
MBK[1][8] = 0;
|
||||||
|
|
||||||
u32 mbk[12];
|
u32 mbk[12];
|
||||||
fseek(SDMMCFile, 0x380, SEEK_SET);
|
fseek(nand, 0x380, SEEK_SET);
|
||||||
fread(mbk, 4, 12, SDMMCFile);
|
fread(mbk, 4, 12, nand);
|
||||||
|
|
||||||
MapNWRAM_A(0, mbk[0] & 0xFF);
|
MapNWRAM_A(0, mbk[0] & 0xFF);
|
||||||
MapNWRAM_A(1, (mbk[0] >> 8) & 0xFF);
|
MapNWRAM_A(1, (mbk[0] >> 8) & 0xFF);
|
||||||
|
@ -745,12 +801,12 @@ bool LoadNAND()
|
||||||
|
|
||||||
AES_init_ctx_iv(&ctx, boot2key, boot2iv);
|
AES_init_ctx_iv(&ctx, boot2key, boot2iv);
|
||||||
|
|
||||||
fseek(SDMMCFile, bootparams[0], SEEK_SET);
|
fseek(nand, bootparams[0], SEEK_SET);
|
||||||
dstaddr = bootparams[2];
|
dstaddr = bootparams[2];
|
||||||
for (u32 i = 0; i < bootparams[3]; i += 16)
|
for (u32 i = 0; i < bootparams[3]; i += 16)
|
||||||
{
|
{
|
||||||
u8 data[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];
|
for (int j = 0; j < 16; j++) tmp[j] = data[15-j];
|
||||||
AES_CTR_xcrypt_buffer(&ctx, tmp, 16);
|
AES_CTR_xcrypt_buffer(&ctx, tmp, 16);
|
||||||
|
@ -770,12 +826,12 @@ bool LoadNAND()
|
||||||
|
|
||||||
AES_init_ctx_iv(&ctx, boot2key, boot2iv);
|
AES_init_ctx_iv(&ctx, boot2key, boot2iv);
|
||||||
|
|
||||||
fseek(SDMMCFile, bootparams[4], SEEK_SET);
|
fseek(nand, bootparams[4], SEEK_SET);
|
||||||
dstaddr = bootparams[6];
|
dstaddr = bootparams[6];
|
||||||
for (u32 i = 0; i < bootparams[7]; i += 16)
|
for (u32 i = 0; i < bootparams[7]; i += 16)
|
||||||
{
|
{
|
||||||
u8 data[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];
|
for (int j = 0; j < 16; j++) tmp[j] = data[15-j];
|
||||||
AES_CTR_xcrypt_buffer(&ctx, tmp, 16);
|
AES_CTR_xcrypt_buffer(&ctx, tmp, 16);
|
||||||
|
@ -787,11 +843,6 @@ bool LoadNAND()
|
||||||
ARM7Write32(dstaddr, *(u32*)&data[12]); dstaddr += 4;
|
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(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"); }
|
#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("eMMC CID: "); printhex(eMMC_CID, 16);
|
||||||
printf("Console ID: %" PRIx64 "\n", ConsoleID);
|
printf("Console ID: %" PRIx64 "\n", ConsoleID);
|
||||||
|
|
||||||
memset(ITCMInit, 0, 0x8000);
|
u32 eaddr = 0x03FFE6E4;
|
||||||
memcpy(&ITCMInit[0x4400], &ARM9iBIOS[0x87F4], 0x400);
|
ARM7Write32(eaddr+0x00, *(u32*)&eMMC_CID[0]);
|
||||||
memcpy(&ITCMInit[0x4800], &ARM9iBIOS[0x9920], 0x80);
|
ARM7Write32(eaddr+0x04, *(u32*)&eMMC_CID[4]);
|
||||||
memcpy(&ITCMInit[0x4894], &ARM9iBIOS[0x99A0], 0x1048);
|
ARM7Write32(eaddr+0x08, *(u32*)&eMMC_CID[8]);
|
||||||
memcpy(&ITCMInit[0x58DC], &ARM9iBIOS[0xA9E8], 0x1048);
|
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);
|
memset(ARM7Init, 0, 0x3C00);
|
||||||
memcpy(&ARM7Init[0x0000], &ARM7iBIOS[0x8188], 0x200);
|
memcpy(&ARM7Init[0x0000], &ARM7iBIOS[0x8188], 0x200);
|
||||||
memcpy(&ARM7Init[0x0200], &ARM7iBIOS[0xB5D8], 0x40);
|
memcpy(&ARM7Init[0x0200], &ARM7iBIOS[0xB5D8], 0x40);
|
||||||
memcpy(&ARM7Init[0x0254], &ARM7iBIOS[0xC6D0], 0x1048);
|
memcpy(&ARM7Init[0x0254], &ARM7iBIOS[0xC6D0], 0x1048);
|
||||||
memcpy(&ARM7Init[0x129C], &ARM7iBIOS[0xD718], 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::PatchUserData();
|
||||||
|
|
||||||
DSi_NAND::DeInit();
|
DSi_NAND::DeInit();
|
||||||
|
@ -819,12 +888,6 @@ bool LoadNAND()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CloseDSiNAND()
|
|
||||||
{
|
|
||||||
if (DSi::SDMMCFile)
|
|
||||||
fclose(DSi::SDMMCFile);
|
|
||||||
DSi::SDMMCFile = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunNDMAs(u32 cpu)
|
void RunNDMAs(u32 cpu)
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,8 +39,6 @@ extern u64 ConsoleID;
|
||||||
extern DSi_SDHost* SDMMC;
|
extern DSi_SDHost* SDMMC;
|
||||||
extern DSi_SDHost* SDIO;
|
extern DSi_SDHost* SDIO;
|
||||||
|
|
||||||
extern FILE* SDMMCFile;
|
|
||||||
|
|
||||||
const u32 NWRAMSize = 0x40000;
|
const u32 NWRAMSize = 0x40000;
|
||||||
|
|
||||||
extern u8* NWRAM_A;
|
extern u8* NWRAM_A;
|
||||||
|
@ -59,14 +57,14 @@ bool Init();
|
||||||
void DeInit();
|
void DeInit();
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
|
void DoSavestate(Savestate* file);
|
||||||
|
|
||||||
void SetupDirectBoot();
|
void SetupDirectBoot();
|
||||||
void SoftReset();
|
void SoftReset();
|
||||||
|
|
||||||
bool LoadBIOS();
|
bool LoadBIOS();
|
||||||
bool LoadNAND();
|
bool LoadNAND();
|
||||||
|
|
||||||
void CloseDSiNAND();
|
|
||||||
|
|
||||||
void RunNDMAs(u32 cpu);
|
void RunNDMAs(u32 cpu);
|
||||||
void StallNDMAs();
|
void StallNDMAs();
|
||||||
bool NDMAsInMode(u32 cpu, u32 mode);
|
bool NDMAsInMode(u32 cpu, u32 mode);
|
||||||
|
|
|
@ -155,6 +155,43 @@ void Reset()
|
||||||
*(u32*)&KeyY[3][8] = 0x202DDD1D;
|
*(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()
|
void ProcessBlock_CCM_Extra()
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,6 +30,8 @@ bool Init();
|
||||||
void DeInit();
|
void DeInit();
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
|
void DoSavestate(Savestate* file);
|
||||||
|
|
||||||
u32 ReadCnt();
|
u32 ReadCnt();
|
||||||
void WriteCnt(u32 val);
|
void WriteCnt(u32 val);
|
||||||
void WriteBlkCnt(u32 val);
|
void WriteBlkCnt(u32 val);
|
||||||
|
|
|
@ -70,6 +70,21 @@ void DSi_Camera::Reset()
|
||||||
NDS::ScheduleEvent(NDS::Event_DSi_CamIRQ, true, kIRQInterval, IRQ, 0);
|
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)
|
void DSi_Camera::IRQ(u32 param)
|
||||||
{
|
{
|
||||||
|
@ -150,7 +165,29 @@ DSi_Camera::DSi_Camera(u32 num)
|
||||||
|
|
||||||
DSi_Camera::~DSi_Camera()
|
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()
|
void DSi_Camera::ResetCam()
|
||||||
|
|
|
@ -28,6 +28,8 @@ public:
|
||||||
static void DeInit();
|
static void DeInit();
|
||||||
static void Reset();
|
static void Reset();
|
||||||
|
|
||||||
|
static void DoSavestate(Savestate* file);
|
||||||
|
|
||||||
static void IRQ(u32 param);
|
static void IRQ(u32 param);
|
||||||
static void RequestFrame(u32 cam);
|
static void RequestFrame(u32 cam);
|
||||||
|
|
||||||
|
@ -36,6 +38,8 @@ public:
|
||||||
DSi_Camera(u32 num);
|
DSi_Camera(u32 num);
|
||||||
~DSi_Camera();
|
~DSi_Camera();
|
||||||
|
|
||||||
|
void DoCamSavestate(Savestate* file);
|
||||||
|
|
||||||
void ResetCam();
|
void ResetCam();
|
||||||
bool IsActivated();
|
bool IsActivated();
|
||||||
|
|
||||||
|
|
|
@ -587,6 +587,8 @@ void DoSavestate(Savestate* file)
|
||||||
file->Var16(&DSP_REP[1]);
|
file->Var16(&DSP_REP[1]);
|
||||||
file->Var16(&DSP_REP[2]);
|
file->Var16(&DSP_REP[2]);
|
||||||
file->Var8((u8*)&SCFG_RST);
|
file->Var8((u8*)&SCFG_RST);
|
||||||
|
|
||||||
|
// TODO: save the Teakra state!!!
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,10 +41,10 @@ bool Init();
|
||||||
void DeInit();
|
void DeInit();
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
// TODO: needs to be called!
|
|
||||||
// however, no DSi savestate stuff seems to be actually implemented?!
|
|
||||||
void DoSavestate(Savestate* file);
|
void DoSavestate(Savestate* file);
|
||||||
|
|
||||||
|
void DSPCatchUpU32(u32 _);
|
||||||
|
|
||||||
// SCFG_RST bit0
|
// SCFG_RST bit0
|
||||||
bool IsRstReleased();
|
bool IsRstReleased();
|
||||||
void SetRstLine(bool release);
|
void SetRstLine(bool release);
|
||||||
|
|
|
@ -72,6 +72,14 @@ void Reset()
|
||||||
Registers[0x81] = 0x64;
|
Registers[0x81] = 0x64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DoSavestate(Savestate* file)
|
||||||
|
{
|
||||||
|
file->Section("I2BP");
|
||||||
|
|
||||||
|
file->VarArray(Registers, 0x100);
|
||||||
|
file->Var32(&CurPos);
|
||||||
|
}
|
||||||
|
|
||||||
u8 GetBootFlag() { return Registers[0x70]; }
|
u8 GetBootFlag() { return Registers[0x70]; }
|
||||||
|
|
||||||
void Start()
|
void Start()
|
||||||
|
@ -169,6 +177,18 @@ void Reset()
|
||||||
DSi_Camera::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)
|
void WriteCnt(u8 val)
|
||||||
{
|
{
|
||||||
//printf("I2C: write CNT %02X, %08X\n", val, NDS::GetPC(1));
|
//printf("I2C: write CNT %02X, %08X\n", val, NDS::GetPC(1));
|
||||||
|
|
|
@ -34,7 +34,7 @@ extern u8 Cnt;
|
||||||
bool Init();
|
bool Init();
|
||||||
void DeInit();
|
void DeInit();
|
||||||
void Reset();
|
void Reset();
|
||||||
//void DoSavestate(Savestate* file);
|
void DoSavestate(Savestate* file);
|
||||||
|
|
||||||
void WriteCnt(u8 val);
|
void WriteCnt(u8 val);
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,31 @@ void DSi_NDMA::Reset()
|
||||||
|
|
||||||
void DSi_NDMA::DoSavestate(Savestate* file)
|
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)
|
void DSi_NDMA::WriteCnt(u32 val)
|
||||||
|
|
|
@ -223,6 +223,45 @@ void DSi_NWifi::Reset()
|
||||||
NDS::CancelEvent(NDS::Event_DSi_NWifi);
|
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
|
// CHECKME
|
||||||
// can IRQ status bits be set when the corresponding IRQs are disabled in the enable register?
|
// can IRQ status bits be set when the corresponding IRQs are disabled in the enable register?
|
||||||
|
|
|
@ -30,6 +30,8 @@ public:
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
|
void DoSavestate(Savestate* file);
|
||||||
|
|
||||||
void SendCMD(u8 cmd, u32 param);
|
void SendCMD(u8 cmd, u32 param);
|
||||||
void SendACMD(u8 cmd, u32 param);
|
void SendACMD(u8 cmd, u32 param);
|
||||||
|
|
||||||
|
|
|
@ -51,8 +51,8 @@ DSi_SDHost::DSi_SDHost(u32 num)
|
||||||
{
|
{
|
||||||
Num = num;
|
Num = num;
|
||||||
|
|
||||||
Ports[0] = NULL;
|
Ports[0] = nullptr;
|
||||||
Ports[1] = NULL;
|
Ports[1] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
DSi_SDHost::~DSi_SDHost()
|
DSi_SDHost::~DSi_SDHost()
|
||||||
|
@ -61,6 +61,14 @@ DSi_SDHost::~DSi_SDHost()
|
||||||
if (Ports[1]) delete Ports[1];
|
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()
|
void DSi_SDHost::Reset()
|
||||||
{
|
{
|
||||||
if (Num == 0)
|
if (Num == 0)
|
||||||
|
@ -101,10 +109,7 @@ void DSi_SDHost::Reset()
|
||||||
|
|
||||||
TXReq = false;
|
TXReq = false;
|
||||||
|
|
||||||
if (Ports[0]) delete Ports[0];
|
CloseHandles();
|
||||||
if (Ports[1]) delete Ports[1];
|
|
||||||
Ports[0] = nullptr;
|
|
||||||
Ports[1] = nullptr;
|
|
||||||
|
|
||||||
if (Num == 0)
|
if (Num == 0)
|
||||||
{
|
{
|
||||||
|
@ -131,7 +136,7 @@ void DSi_SDHost::Reset()
|
||||||
else
|
else
|
||||||
sd = nullptr;
|
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);
|
mmc->SetCID(DSi::eMMC_CID);
|
||||||
|
|
||||||
Ports[0] = sd;
|
Ports[0] = sd;
|
||||||
|
@ -150,7 +155,41 @@ void DSi_SDHost::Reset()
|
||||||
|
|
||||||
void DSi_SDHost::DoSavestate(Savestate* file)
|
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")
|
#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)
|
: DSi_SDDevice(host)
|
||||||
{
|
{
|
||||||
Internal = internal;
|
Internal = internal;
|
||||||
File = file;
|
File = Platform::OpenLocalFile(filename, "r+b");
|
||||||
|
|
||||||
SD = nullptr;
|
SD = nullptr;
|
||||||
|
|
||||||
|
ReadOnly = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DSi_MMCStorage::DSi_MMCStorage(DSi_SDHost* host, bool internal, std::string filename, u64 size, bool readonly, std::string sourcedir)
|
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();
|
SD->Close();
|
||||||
delete SD;
|
delete SD;
|
||||||
}
|
}
|
||||||
|
if (File)
|
||||||
|
{
|
||||||
|
fclose(File);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DSi_MMCStorage::Reset()
|
void DSi_MMCStorage::Reset()
|
||||||
|
@ -781,6 +827,26 @@ void DSi_MMCStorage::Reset()
|
||||||
RWCommand = 0;
|
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)
|
void DSi_MMCStorage::SendCMD(u8 cmd, u32 param)
|
||||||
{
|
{
|
||||||
if (CSR & (1<<5))
|
if (CSR & (1<<5))
|
||||||
|
|
|
@ -33,6 +33,7 @@ public:
|
||||||
DSi_SDHost(u32 num);
|
DSi_SDHost(u32 num);
|
||||||
~DSi_SDHost();
|
~DSi_SDHost();
|
||||||
|
|
||||||
|
void CloseHandles();
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
void DoSavestate(Savestate* file);
|
void DoSavestate(Savestate* file);
|
||||||
|
@ -108,6 +109,8 @@ public:
|
||||||
|
|
||||||
virtual void Reset() = 0;
|
virtual void Reset() = 0;
|
||||||
|
|
||||||
|
virtual void DoSavestate(Savestate* file) = 0;
|
||||||
|
|
||||||
virtual void SendCMD(u8 cmd, u32 param) = 0;
|
virtual void SendCMD(u8 cmd, u32 param) = 0;
|
||||||
virtual void ContinueTransfer() = 0;
|
virtual void ContinueTransfer() = 0;
|
||||||
|
|
||||||
|
@ -122,12 +125,14 @@ protected:
|
||||||
class DSi_MMCStorage : public DSi_SDDevice
|
class DSi_MMCStorage : public DSi_SDDevice
|
||||||
{
|
{
|
||||||
public:
|
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(DSi_SDHost* host, bool internal, std::string filename, u64 size, bool readonly, std::string sourcedir);
|
||||||
~DSi_MMCStorage();
|
~DSi_MMCStorage();
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
|
void DoSavestate(Savestate* file);
|
||||||
|
|
||||||
void SetCID(u8* cid) { memcpy(CID, cid, 16); }
|
void SetCID(u8* cid) { memcpy(CID, cid, 16); }
|
||||||
|
|
||||||
void SendCMD(u8 cmd, u32 param);
|
void SendCMD(u8 cmd, u32 param);
|
||||||
|
|
|
@ -71,14 +71,15 @@ void Reset()
|
||||||
|
|
||||||
void DoSavestate(Savestate* file)
|
void DoSavestate(Savestate* file)
|
||||||
{
|
{
|
||||||
/*file->Section("SPTi");
|
file->Section("SPTi");
|
||||||
|
|
||||||
file->Var32(&DataPos);
|
file->Var32(&DataPos);
|
||||||
file->Var8(&ControlByte);
|
file->Var8(&Index);
|
||||||
|
file->Var8(&Bank);
|
||||||
file->Var8(&Data);
|
file->Var8(&Data);
|
||||||
|
|
||||||
file->Var16(&ConvResult);*/
|
file->VarArray(Bank3Regs, 0x80);
|
||||||
// TODO!!
|
file->Var8(&TSCMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetMode(u8 mode)
|
void SetMode(u8 mode)
|
||||||
|
|
384
src/GBACart.cpp
384
src/GBACart.cpp
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "NDS.h"
|
||||||
#include "GBACart.h"
|
#include "GBACart.h"
|
||||||
#include "CRC32.h"
|
#include "CRC32.h"
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
|
@ -42,7 +43,6 @@ const char SOLAR_SENSOR_GAMECODES[10][5] =
|
||||||
bool CartInserted;
|
bool CartInserted;
|
||||||
u8* CartROM;
|
u8* CartROM;
|
||||||
u32 CartROMSize;
|
u32 CartROMSize;
|
||||||
u32 CartCRC;
|
|
||||||
u32 CartID;
|
u32 CartID;
|
||||||
|
|
||||||
CartCommon* Cart;
|
CartCommon* Cart;
|
||||||
|
@ -58,16 +58,20 @@ CartCommon::~CartCommon()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CartCommon::Reset()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void CartCommon::DoSavestate(Savestate* file)
|
void CartCommon::DoSavestate(Savestate* file)
|
||||||
{
|
{
|
||||||
file->Section("GBCS");
|
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;
|
ROM = rom;
|
||||||
ROMLength = len;
|
ROMLength = len;
|
||||||
|
|
||||||
memset(&GPIO, 0, sizeof(GPIO));
|
|
||||||
|
|
||||||
SRAM = nullptr;
|
|
||||||
SRAMFile = nullptr;
|
|
||||||
SRAMLength = 0;
|
|
||||||
SRAMType = S_NULL;
|
|
||||||
SRAMFlashState = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CartGame::~CartGame()
|
CartGame::~CartGame()
|
||||||
{
|
{
|
||||||
if (SRAMFile) fclose(SRAMFile);
|
|
||||||
if (SRAM) delete[] SRAM;
|
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;
|
||||||
|
SRAMLength = 0;
|
||||||
|
SRAMType = S_NULL;
|
||||||
|
SRAMFlashState = {};
|
||||||
|
}
|
||||||
|
|
||||||
void CartGame::DoSavestate(Savestate* file)
|
void CartGame::DoSavestate(Savestate* file)
|
||||||
{
|
{
|
||||||
CartCommon::DoSavestate(file);
|
CartCommon::DoSavestate(file);
|
||||||
|
@ -123,8 +137,6 @@ void CartGame::DoSavestate(Savestate* file)
|
||||||
file->Var16(&GPIO.data);
|
file->Var16(&GPIO.data);
|
||||||
file->Var16(&GPIO.direction);
|
file->Var16(&GPIO.direction);
|
||||||
|
|
||||||
// logic mostly copied from NDSCart_SRAM
|
|
||||||
|
|
||||||
u32 oldlen = SRAMLength;
|
u32 oldlen = SRAMLength;
|
||||||
|
|
||||||
file->Var32(&SRAMLength);
|
file->Var32(&SRAMLength);
|
||||||
|
@ -133,6 +145,7 @@ void CartGame::DoSavestate(Savestate* file)
|
||||||
{
|
{
|
||||||
// reallocate save memory
|
// reallocate save memory
|
||||||
if (oldlen) delete[] SRAM;
|
if (oldlen) delete[] SRAM;
|
||||||
|
SRAM = nullptr;
|
||||||
if (SRAMLength) SRAM = new u8[SRAMLength];
|
if (SRAMLength) SRAM = new u8[SRAMLength];
|
||||||
}
|
}
|
||||||
if (SRAMLength)
|
if (SRAMLength)
|
||||||
|
@ -144,9 +157,7 @@ void CartGame::DoSavestate(Savestate* file)
|
||||||
{
|
{
|
||||||
// no save data, clear the current state
|
// no save data, clear the current state
|
||||||
SRAMType = SaveType::S_NULL;
|
SRAMType = SaveType::S_NULL;
|
||||||
if (SRAMFile) fclose(SRAMFile);
|
|
||||||
SRAM = nullptr;
|
SRAM = nullptr;
|
||||||
SRAMFile = nullptr;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,27 +169,24 @@ void CartGame::DoSavestate(Savestate* file)
|
||||||
file->Var8(&SRAMFlashState.state);
|
file->Var8(&SRAMFlashState.state);
|
||||||
|
|
||||||
file->Var8((u8*)&SRAMType);
|
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;
|
if (SRAM) delete[] SRAM;
|
||||||
|
SRAM = nullptr;
|
||||||
|
|
||||||
strncpy(SRAMPath, path, 1023);
|
// TODO: have type be determined from some list, like in NDSCart
|
||||||
SRAMPath[1023] = '\0';
|
// and not this gross hack!!
|
||||||
SRAMLength = 0;
|
SRAMLength = type;
|
||||||
|
|
||||||
FILE* f = Platform::OpenFile(SRAMPath, "r+b");
|
if (SRAMLength)
|
||||||
if (f)
|
|
||||||
{
|
{
|
||||||
fseek(f, 0, SEEK_END);
|
|
||||||
SRAMLength = (u32)ftell(f);
|
|
||||||
SRAM = new u8[SRAMLength];
|
SRAM = new u8[SRAMLength];
|
||||||
|
memset(SRAM, 0xFF, SRAMLength);
|
||||||
fseek(f, 0, SEEK_SET);
|
|
||||||
fread(SRAM, SRAMLength, 1, f);
|
|
||||||
|
|
||||||
SRAMFile = f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (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)
|
if (!SRAM) return;
|
||||||
{
|
|
||||||
LoadSave(path, 0); // lazy
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(SRAMPath, path, 1023);
|
u32 len = std::min(savelen, SRAMLength);
|
||||||
SRAMPath[1023] = '\0';
|
memcpy(SRAM, savedata, len);
|
||||||
|
Platform::WriteGBASave(savedata, len, 0, len);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 CartGame::ROMRead(u32 addr)
|
u16 CartGame::ROMRead(u32 addr)
|
||||||
|
@ -469,11 +464,7 @@ void CartGame::SRAMWrite_FLASH(u32 addr, u8 val)
|
||||||
u32 start_addr = addr + 0x10000 * SRAMFlashState.bank;
|
u32 start_addr = addr + 0x10000 * SRAMFlashState.bank;
|
||||||
memset((u8*)&SRAM[start_addr], 0xFF, 0x1000);
|
memset((u8*)&SRAM[start_addr], 0xFF, 0x1000);
|
||||||
|
|
||||||
if (SRAMFile)
|
Platform::WriteGBASave(SRAM, SRAMLength, start_addr, 0x1000);
|
||||||
{
|
|
||||||
fseek(SRAMFile, start_addr, SEEK_SET);
|
|
||||||
fwrite((u8*)&SRAM[start_addr], 1, 0x1000, SRAMFile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
SRAMFlashState.state = 0;
|
SRAMFlashState.state = 0;
|
||||||
SRAMFlashState.cmd = 0;
|
SRAMFlashState.cmd = 0;
|
||||||
|
@ -531,11 +522,8 @@ void CartGame::SRAMWrite_SRAM(u32 addr, u8 val)
|
||||||
{
|
{
|
||||||
*(u8*)&SRAM[addr] = val;
|
*(u8*)&SRAM[addr] = val;
|
||||||
|
|
||||||
if (SRAMFile)
|
// TODO: optimize this!!
|
||||||
{
|
Platform::WriteGBASave(SRAM, SRAMLength, addr, 1);
|
||||||
fseek(SRAMFile, addr, SEEK_SET);
|
|
||||||
fwrite((u8*)&SRAM[addr], 1, 1, SRAMFile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
CartGameSolarSensor::CartGameSolarSensor(u8* rom, u32 len) : CartGame(rom, len)
|
||||||
{
|
{
|
||||||
LightEdge = false;
|
|
||||||
LightCounter = 0;
|
|
||||||
LightSample = 0xFF;
|
|
||||||
LightLevel = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CartGameSolarSensor::~CartGameSolarSensor()
|
CartGameSolarSensor::~CartGameSolarSensor()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CartGameSolarSensor::Reset()
|
||||||
|
{
|
||||||
|
LightEdge = false;
|
||||||
|
LightCounter = 0;
|
||||||
|
LightSample = 0xFF;
|
||||||
|
LightLevel = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void CartGameSolarSensor::DoSavestate(Savestate* file)
|
void CartGameSolarSensor::DoSavestate(Savestate* file)
|
||||||
{
|
{
|
||||||
CartGame::DoSavestate(file);
|
CartGame::DoSavestate(file);
|
||||||
|
@ -608,6 +600,86 @@ void CartGameSolarSensor::ProcessGPIO()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CartRAMExpansion::CartRAMExpansion() : CartCommon()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CartRAMExpansion::~CartRAMExpansion()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CartRAMExpansion::Reset()
|
||||||
|
{
|
||||||
|
memset(RAM, 0xFF, sizeof(RAM));
|
||||||
|
RAMEnable = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CartRAMExpansion::DoSavestate(Savestate* file)
|
||||||
|
{
|
||||||
|
CartCommon::DoSavestate(file);
|
||||||
|
|
||||||
|
file->VarArray(RAM, sizeof(RAM));
|
||||||
|
file->Var16(&RAMEnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 CartRAMExpansion::ROMRead(u32 addr)
|
||||||
|
{
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CartRAMExpansion::ROMWrite(u32 addr, u16 val)
|
||||||
|
{
|
||||||
|
addr &= 0x01FFFFFF;
|
||||||
|
|
||||||
|
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()
|
bool Init()
|
||||||
{
|
{
|
||||||
CartROM = nullptr;
|
CartROM = nullptr;
|
||||||
|
@ -626,86 +698,65 @@ void DeInit()
|
||||||
|
|
||||||
void Reset()
|
void Reset()
|
||||||
{
|
{
|
||||||
// Do not reset cartridge ROM.
|
if (Cart) Cart->Reset();
|
||||||
// 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().
|
|
||||||
|
|
||||||
// OpenBusDecay doesn't need to be reset, either, as it will be set
|
|
||||||
// through NDS::SetGBASlotTimings().
|
|
||||||
}
|
|
||||||
|
|
||||||
void Eject()
|
|
||||||
{
|
|
||||||
if (CartROM) delete[] CartROM;
|
|
||||||
|
|
||||||
CartInserted = false;
|
|
||||||
CartROM = NULL;
|
|
||||||
CartROMSize = 0;
|
|
||||||
CartCRC = 0;
|
|
||||||
CartID = 0;
|
|
||||||
|
|
||||||
if (Cart) delete Cart;
|
|
||||||
Cart = nullptr;
|
|
||||||
|
|
||||||
Reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoSavestate(Savestate* file)
|
void DoSavestate(Savestate* file)
|
||||||
{
|
{
|
||||||
file->Section("GBAC"); // Game Boy Advance Cartridge
|
file->Section("GBAC"); // Game Boy Advance Cartridge
|
||||||
|
|
||||||
// logic mostly copied from NDSCart
|
// little state here
|
||||||
|
// no need to save OpenBusDecay, it will be set later
|
||||||
|
|
||||||
// first we need to reload the cart itself,
|
u32 carttype = 0;
|
||||||
// since unlike with DS, it's not loaded in advance
|
u32 cartchk = 0;
|
||||||
|
if (Cart)
|
||||||
file->Var32(&CartROMSize);
|
|
||||||
if (!CartROMSize) // no GBA cartridge state? nothing to do here
|
|
||||||
{
|
{
|
||||||
// do eject the cartridge if something is inserted
|
carttype = Cart->Type();
|
||||||
Eject();
|
cartchk = Cart->Checksum();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 oldCRC = CartCRC;
|
if (file->Saving)
|
||||||
file->Var32(&CartCRC);
|
|
||||||
|
|
||||||
if (CartCRC != oldCRC)
|
|
||||||
{
|
{
|
||||||
// delete and reallocate ROM so that it is zero-padded to its full length
|
file->Var32(&carttype);
|
||||||
if (CartROM) delete[] CartROM;
|
file->Var32(&cartchk);
|
||||||
CartROM = new u8[CartROMSize];
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u32 savetype;
|
||||||
|
file->Var32(&savetype);
|
||||||
|
if (savetype != carttype) return;
|
||||||
|
|
||||||
// only save/load the cartridge header
|
u32 savechk;
|
||||||
//
|
file->Var32(&savechk);
|
||||||
// GBA connectivity on DS mainly involves identifying the title currently
|
if (savechk != cartchk) return;
|
||||||
// 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
|
|
||||||
|
|
||||||
if (Cart) Cart->DoSavestate(file);
|
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' };
|
char gamecode[5] = { '\0' };
|
||||||
memcpy(&gamecode, CartROM + 0xAC, 4);
|
memcpy(&gamecode, CartROM + 0xAC, 4);
|
||||||
printf("GBA game code: %s\n", gamecode);
|
printf("GBA game code: %s\n", gamecode);
|
||||||
|
@ -722,9 +773,6 @@ void LoadROMCommon(const char *sram)
|
||||||
printf("GBA solar sensor support detected!\n");
|
printf("GBA solar sensor support detected!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
CartCRC = CRC32(CartROM, CartROMSize);
|
|
||||||
printf("GBA ROM CRC32: %08X\n", CartCRC);
|
|
||||||
|
|
||||||
CartInserted = true;
|
CartInserted = true;
|
||||||
|
|
||||||
if (solarsensor)
|
if (solarsensor)
|
||||||
|
@ -732,61 +780,61 @@ void LoadROMCommon(const char *sram)
|
||||||
else
|
else
|
||||||
Cart = new CartGame(CartROM, CartROMSize);
|
Cart = new CartGame(CartROM, CartROMSize);
|
||||||
|
|
||||||
|
if (Cart)
|
||||||
|
Cart->Reset();
|
||||||
|
|
||||||
// save
|
// 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
|
// 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);
|
||||||
}
|
|
||||||
|
|
||||||
bool LoadROM(const char* path, const char* sram)
|
// TODO: setup cart save here! from a list or something
|
||||||
{
|
|
||||||
FILE* f = Platform::OpenFile(path, "rb");
|
|
||||||
if (!f)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CartInserted)
|
|
||||||
{
|
|
||||||
Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadROM(const u8* romdata, u32 filelength, const char *sram)
|
void LoadSave(const u8* savedata, u32 savelen)
|
||||||
{
|
{
|
||||||
CartROMSize = 0x200;
|
if (Cart)
|
||||||
while (CartROMSize < filelength)
|
{
|
||||||
CartROMSize <<= 1;
|
// gross hack
|
||||||
|
Cart->SetupSave(savelen);
|
||||||
|
|
||||||
CartROM = new u8[CartROMSize];
|
Cart->LoadSave(savedata, savelen);
|
||||||
memcpy(CartROM, romdata, filelength);
|
}
|
||||||
|
|
||||||
LoadROMCommon(sram);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RelocateSave(const char* path, bool write)
|
void LoadAddon(int type)
|
||||||
{
|
{
|
||||||
if (Cart) Cart->RelocateSave(path, write);
|
CartROMSize = 0;
|
||||||
|
CartROM = nullptr;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case NDS::GBAAddon_RAMExpansion:
|
||||||
|
Cart = new CartRAMExpansion();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printf("GBACart: !! invalid addon type %d\n", type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CartInserted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EjectCart()
|
||||||
|
{
|
||||||
|
if (Cart) delete Cart;
|
||||||
|
Cart = nullptr;
|
||||||
|
|
||||||
|
if (CartROM) delete[] CartROM;
|
||||||
|
|
||||||
|
CartInserted = false;
|
||||||
|
CartROM = nullptr;
|
||||||
|
CartROMSize = 0;
|
||||||
|
CartID = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,10 +32,15 @@ public:
|
||||||
CartCommon();
|
CartCommon();
|
||||||
virtual ~CartCommon();
|
virtual ~CartCommon();
|
||||||
|
|
||||||
|
virtual u32 Type() { return 0x001; }
|
||||||
|
virtual u32 Checksum() { return 0; }
|
||||||
|
|
||||||
|
virtual void Reset();
|
||||||
|
|
||||||
virtual void DoSavestate(Savestate* file);
|
virtual void DoSavestate(Savestate* file);
|
||||||
|
|
||||||
virtual void LoadSave(const char* path, u32 type);
|
virtual void SetupSave(u32 type);
|
||||||
virtual void RelocateSave(const char* path, bool write);
|
virtual void LoadSave(const u8* savedata, u32 savelen);
|
||||||
|
|
||||||
virtual int SetInput(int num, bool pressed);
|
virtual int SetInput(int num, bool pressed);
|
||||||
|
|
||||||
|
@ -53,10 +58,15 @@ public:
|
||||||
CartGame(u8* rom, u32 len);
|
CartGame(u8* rom, u32 len);
|
||||||
virtual ~CartGame() override;
|
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 DoSavestate(Savestate* file) override;
|
||||||
|
|
||||||
virtual void LoadSave(const char* path, u32 type) override;
|
virtual void SetupSave(u32 type) override;
|
||||||
virtual void RelocateSave(const char* path, bool write) override;
|
virtual void LoadSave(const u8* savedata, u32 savelen) override;
|
||||||
|
|
||||||
virtual u16 ROMRead(u32 addr) override;
|
virtual u16 ROMRead(u32 addr) override;
|
||||||
virtual void ROMWrite(u32 addr, u16 val) override;
|
virtual void ROMWrite(u32 addr, u16 val) override;
|
||||||
|
@ -107,11 +117,8 @@ protected:
|
||||||
} SRAMFlashState;
|
} SRAMFlashState;
|
||||||
|
|
||||||
u8* SRAM;
|
u8* SRAM;
|
||||||
FILE* SRAMFile;
|
|
||||||
u32 SRAMLength;
|
u32 SRAMLength;
|
||||||
SaveType SRAMType;
|
SaveType SRAMType;
|
||||||
|
|
||||||
char SRAMPath[1024];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// CartGameSolarSensor -- Boktai game cart
|
// CartGameSolarSensor -- Boktai game cart
|
||||||
|
@ -121,6 +128,10 @@ public:
|
||||||
CartGameSolarSensor(u8* rom, u32 len);
|
CartGameSolarSensor(u8* rom, u32 len);
|
||||||
virtual ~CartGameSolarSensor() override;
|
virtual ~CartGameSolarSensor() override;
|
||||||
|
|
||||||
|
virtual u32 Type() override { return 0x102; }
|
||||||
|
|
||||||
|
virtual void Reset() override;
|
||||||
|
|
||||||
virtual void DoSavestate(Savestate* file) override;
|
virtual void DoSavestate(Savestate* file) override;
|
||||||
|
|
||||||
virtual int SetInput(int num, bool pressed) override;
|
virtual int SetInput(int num, bool pressed) override;
|
||||||
|
@ -136,6 +147,27 @@ private:
|
||||||
u8 LightLevel;
|
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
|
// possible inputs for GBA carts that might accept user input
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -146,17 +178,23 @@ enum
|
||||||
extern bool CartInserted;
|
extern bool CartInserted;
|
||||||
extern u8* CartROM;
|
extern u8* CartROM;
|
||||||
extern u32 CartROMSize;
|
extern u32 CartROMSize;
|
||||||
extern u32 CartCRC;
|
|
||||||
|
|
||||||
bool Init();
|
bool Init();
|
||||||
void DeInit();
|
void DeInit();
|
||||||
void Reset();
|
void Reset();
|
||||||
void Eject();
|
|
||||||
|
|
||||||
void DoSavestate(Savestate* file);
|
void DoSavestate(Savestate* file);
|
||||||
bool LoadROM(const char* path, const char* sram);
|
|
||||||
bool LoadROM(const u8* romdata, u32 filelength, const char *sram);
|
bool LoadROM(const u8* romdata, u32 romlen);
|
||||||
void RelocateSave(const char* path, bool write);
|
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
|
// TODO: make more flexible, support nonbinary inputs
|
||||||
int SetInput(int num, bool pressed);
|
int SetInput(int num, bool pressed);
|
||||||
|
|
176
src/NDS.cpp
176
src/NDS.cpp
|
@ -32,7 +32,6 @@
|
||||||
#include "Wifi.h"
|
#include "Wifi.h"
|
||||||
#include "AREngine.h"
|
#include "AREngine.h"
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
#include "NDSCart_SRAMManager.h"
|
|
||||||
#include "FreeBIOS.h"
|
#include "FreeBIOS.h"
|
||||||
|
|
||||||
#ifdef JIT_ENABLED
|
#ifdef JIT_ENABLED
|
||||||
|
@ -42,6 +41,9 @@
|
||||||
|
|
||||||
#include "DSi.h"
|
#include "DSi.h"
|
||||||
#include "DSi_SPI_TSC.h"
|
#include "DSi_SPI_TSC.h"
|
||||||
|
#include "DSi_NWifi.h"
|
||||||
|
#include "DSi_Camera.h"
|
||||||
|
#include "DSi_DSP.h"
|
||||||
|
|
||||||
|
|
||||||
namespace NDS
|
namespace NDS
|
||||||
|
@ -200,7 +202,6 @@ bool Init()
|
||||||
DMAs[6] = new DMA(1, 2);
|
DMAs[6] = new DMA(1, 2);
|
||||||
DMAs[7] = new DMA(1, 3);
|
DMAs[7] = new DMA(1, 3);
|
||||||
|
|
||||||
if (!NDSCart_SRAMManager::Init()) return false;
|
|
||||||
if (!NDSCart::Init()) return false;
|
if (!NDSCart::Init()) return false;
|
||||||
if (!GBACart::Init()) return false;
|
if (!GBACart::Init()) return false;
|
||||||
if (!GPU::Init()) return false;
|
if (!GPU::Init()) return false;
|
||||||
|
@ -228,7 +229,6 @@ void DeInit()
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
delete DMAs[i];
|
delete DMAs[i];
|
||||||
|
|
||||||
NDSCart_SRAMManager::DeInit();
|
|
||||||
NDSCart::DeInit();
|
NDSCart::DeInit();
|
||||||
GBACart::DeInit();
|
GBACart::DeInit();
|
||||||
GPU::DeInit();
|
GPU::DeInit();
|
||||||
|
@ -353,7 +353,28 @@ void InitTimings()
|
||||||
// handled later: GBA slot, wifi
|
// 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)
|
if (ConsoleType == 1)
|
||||||
{
|
{
|
||||||
|
@ -444,6 +465,8 @@ void SetupDirectBoot()
|
||||||
ARM9->CP15Write(0x911, 0x00000020);
|
ARM9->CP15Write(0x911, 0x00000020);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NDSCart::SetupDirectBoot(romname);
|
||||||
|
|
||||||
ARM9->R[12] = NDSCart::Header.ARM9EntryAddress;
|
ARM9->R[12] = NDSCart::Header.ARM9EntryAddress;
|
||||||
ARM9->R[13] = 0x03002F7C;
|
ARM9->R[13] = 0x03002F7C;
|
||||||
ARM9->R[14] = NDSCart::Header.ARM9EntryAddress;
|
ARM9->R[14] = NDSCart::Header.ARM9EntryAddress;
|
||||||
|
@ -542,7 +565,6 @@ void Reset()
|
||||||
if (ConsoleType == 1)
|
if (ConsoleType == 1)
|
||||||
{
|
{
|
||||||
DSi::LoadBIOS();
|
DSi::LoadBIOS();
|
||||||
DSi::LoadNAND();
|
|
||||||
|
|
||||||
ARM9ClockShift = 2;
|
ARM9ClockShift = 2;
|
||||||
MainRAMMask = 0xFFFFFF;
|
MainRAMMask = 0xFFFFFF;
|
||||||
|
@ -658,6 +680,11 @@ void Reset()
|
||||||
AREngine::Reset();
|
AREngine::Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
Running = true;
|
||||||
|
}
|
||||||
|
|
||||||
void Stop()
|
void Stop()
|
||||||
{
|
{
|
||||||
printf("Stopping: shutdown\n");
|
printf("Stopping: shutdown\n");
|
||||||
|
@ -692,7 +719,14 @@ bool DoSavestate_Scheduler(Savestate* file)
|
||||||
DivDone,
|
DivDone,
|
||||||
SqrtDone,
|
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;
|
int len = Event_MAX;
|
||||||
|
@ -702,7 +736,7 @@ bool DoSavestate_Scheduler(Savestate* file)
|
||||||
{
|
{
|
||||||
SchedEvent* evt = &SchedList[i];
|
SchedEvent* evt = &SchedList[i];
|
||||||
|
|
||||||
u32 funcid = -1;
|
u32 funcid = 0xFFFFFFFF;
|
||||||
if (evt->Func)
|
if (evt->Func)
|
||||||
{
|
{
|
||||||
for (int j = 0; eventfuncs[j]; j++)
|
for (int j = 0; eventfuncs[j]; j++)
|
||||||
|
@ -749,7 +783,7 @@ bool DoSavestate_Scheduler(Savestate* file)
|
||||||
evt->Func = eventfuncs[funcid];
|
evt->Func = eventfuncs[funcid];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
evt->Func = NULL;
|
evt->Func = nullptr;
|
||||||
|
|
||||||
file->Var64(&evt->Timestamp);
|
file->Var64(&evt->Timestamp);
|
||||||
file->Var32(&evt->Param);
|
file->Var32(&evt->Param);
|
||||||
|
@ -763,15 +797,26 @@ bool DoSavestate(Savestate* file)
|
||||||
{
|
{
|
||||||
file->Section("NDSG");
|
file->Section("NDSG");
|
||||||
|
|
||||||
// TODO:
|
if (file->Saving)
|
||||||
// * do something for bool's (sizeof=1)
|
{
|
||||||
// * do something for 'loading DSi-mode savestate in DS mode' and vice-versa
|
u32 console = ConsoleType;
|
||||||
// * add IE2/IF2 there
|
file->Var32(&console);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u32 console;
|
||||||
|
file->Var32(&console);
|
||||||
|
if (console != ConsoleType)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
file->VarArray(MainRAM, 0x400000);
|
file->VarArray(MainRAM, MainRAMMaxSize);
|
||||||
file->VarArray(SharedWRAM, 0x8000);
|
file->VarArray(SharedWRAM, SharedWRAMSize);
|
||||||
file->VarArray(ARM7WRAM, ARM7WRAMSize);
|
file->VarArray(ARM7WRAM, ARM7WRAMSize);
|
||||||
|
|
||||||
|
//file->VarArray(ARM9BIOS, 0x1000);
|
||||||
|
//file->VarArray(ARM7BIOS, 0x4000);
|
||||||
|
|
||||||
file->VarArray(ExMemCnt, 2*sizeof(u16));
|
file->VarArray(ExMemCnt, 2*sizeof(u16));
|
||||||
file->VarArray(ROMSeed0, 2*8);
|
file->VarArray(ROMSeed0, 2*8);
|
||||||
file->VarArray(ROMSeed1, 2*8);
|
file->VarArray(ROMSeed1, 2*8);
|
||||||
|
@ -781,6 +826,8 @@ bool DoSavestate(Savestate* file)
|
||||||
file->VarArray(IME, 2*sizeof(u32));
|
file->VarArray(IME, 2*sizeof(u32));
|
||||||
file->VarArray(IE, 2*sizeof(u32));
|
file->VarArray(IE, 2*sizeof(u32));
|
||||||
file->VarArray(IF, 2*sizeof(u32));
|
file->VarArray(IF, 2*sizeof(u32));
|
||||||
|
file->Var32(&IE2);
|
||||||
|
file->Var32(&IF2);
|
||||||
|
|
||||||
file->Var8(&PostFlag9);
|
file->Var8(&PostFlag9);
|
||||||
file->Var8(&PostFlag7);
|
file->Var8(&PostFlag7);
|
||||||
|
@ -825,11 +872,8 @@ bool DoSavestate(Savestate* file)
|
||||||
file->Var64(&LastSysClockCycles);
|
file->Var64(&LastSysClockCycles);
|
||||||
file->Var64(&FrameStartTimestamp);
|
file->Var64(&FrameStartTimestamp);
|
||||||
file->Var32(&NumFrames);
|
file->Var32(&NumFrames);
|
||||||
if (file->IsAtleastVersion(7, 1))
|
file->Var32(&NumLagFrames);
|
||||||
{
|
file->Bool32(&LagFrameFlag);
|
||||||
file->Var32(&NumLagFrames);
|
|
||||||
file->Bool32(&LagFrameFlag);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: save KeyInput????
|
// TODO: save KeyInput????
|
||||||
file->Var16(&KeyCnt);
|
file->Var16(&KeyCnt);
|
||||||
|
@ -860,13 +904,17 @@ bool DoSavestate(Savestate* file)
|
||||||
ARM7->DoSavestate(file);
|
ARM7->DoSavestate(file);
|
||||||
|
|
||||||
NDSCart::DoSavestate(file);
|
NDSCart::DoSavestate(file);
|
||||||
GBACart::DoSavestate(file);
|
if (ConsoleType == 0)
|
||||||
|
GBACart::DoSavestate(file);
|
||||||
GPU::DoSavestate(file);
|
GPU::DoSavestate(file);
|
||||||
SPU::DoSavestate(file);
|
SPU::DoSavestate(file);
|
||||||
SPI::DoSavestate(file);
|
SPI::DoSavestate(file);
|
||||||
RTC::DoSavestate(file);
|
RTC::DoSavestate(file);
|
||||||
Wifi::DoSavestate(file);
|
Wifi::DoSavestate(file);
|
||||||
|
|
||||||
|
if (ConsoleType == 1)
|
||||||
|
DSi::DoSavestate(file);
|
||||||
|
|
||||||
if (!file->Saving)
|
if (!file->Saving)
|
||||||
{
|
{
|
||||||
GPU::SetPowerCnt(PowerControl9);
|
GPU::SetPowerCnt(PowerControl9);
|
||||||
|
@ -888,73 +936,59 @@ void SetConsoleType(int type)
|
||||||
ConsoleType = 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))
|
if (!NDSCart::LoadROM(romdata, romlen))
|
||||||
{
|
|
||||||
Running = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Failed to load ROM from archive\n");
|
|
||||||
return false;
|
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))
|
if (savedata && savelen)
|
||||||
{
|
NDSCart::LoadSave(savedata, savelen);
|
||||||
Running = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Failed to load ROM %s\n", path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadGBAROM(const char* path, const char* sram)
|
void EjectCart()
|
||||||
{
|
{
|
||||||
if (GBACart::LoadROM(path, sram))
|
NDSCart::EjectCart();
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Failed to load ROM %s\n", path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadGBAROM(const u8* romdata, u32 filelength, const char *filename, const char *sram)
|
bool CartInserted()
|
||||||
{
|
{
|
||||||
if (GBACart::LoadROM(romdata, filelength, sram))
|
return NDSCart::CartInserted;
|
||||||
{
|
}
|
||||||
return true;
|
|
||||||
}
|
bool LoadGBACart(const u8* romdata, u32 romlen, const u8* savedata, u32 savelen)
|
||||||
else
|
{
|
||||||
{
|
if (!GBACart::LoadROM(romdata, romlen))
|
||||||
printf("Failed to load ROM %s from archive\n", filename);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
if (savedata && savelen)
|
||||||
|
GBACart::LoadSave(savedata, savelen);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadGBAAddon(int type)
|
||||||
|
{
|
||||||
|
GBACart::LoadAddon(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EjectGBACart()
|
||||||
|
{
|
||||||
|
GBACart::EjectCart();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadBIOS()
|
void LoadBIOS()
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
Running = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RelocateSave(const char* path, bool write)
|
|
||||||
{
|
|
||||||
printf("SRAM: relocating to %s (write=%s)\n", path, write?"true":"false");
|
|
||||||
NDSCart::RelocateSave(path, write);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
u64 NextTarget()
|
u64 NextTarget()
|
||||||
{
|
{
|
||||||
|
@ -1094,8 +1128,6 @@ u32 RunFrame()
|
||||||
GPU3D::Timestamp-SysTimestamp);
|
GPU3D::Timestamp-SysTimestamp);
|
||||||
#endif
|
#endif
|
||||||
SPU::TransferOutput();
|
SPU::TransferOutput();
|
||||||
|
|
||||||
NDSCart::FlushSRAMFile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// In the context of TASes, frame count is traditionally the primary measure of emulated time,
|
// 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);
|
return SPI_TSC::MicInputFrame(data, samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ImportSRAM(u8* data, u32 length)
|
/*int ImportSRAM(u8* data, u32 length)
|
||||||
{
|
{
|
||||||
return NDSCart::ImportSRAM(data, length);
|
return NDSCart::ImportSRAM(data, length);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
|
||||||
void Halt()
|
void Halt()
|
||||||
|
|
31
src/NDS.h
31
src/NDS.h
|
@ -19,6 +19,8 @@
|
||||||
#ifndef NDS_H
|
#ifndef NDS_H
|
||||||
#define NDS_H
|
#define NDS_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "Savestate.h"
|
#include "Savestate.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
@ -48,8 +50,6 @@ enum
|
||||||
Event_DSi_NWifi,
|
Event_DSi_NWifi,
|
||||||
Event_DSi_CamIRQ,
|
Event_DSi_CamIRQ,
|
||||||
Event_DSi_CamTransfer,
|
Event_DSi_CamTransfer,
|
||||||
|
|
||||||
Event_DSi_RAMSizeChange,
|
|
||||||
Event_DSi_DSP,
|
Event_DSi_DSP,
|
||||||
|
|
||||||
Event_MAX
|
Event_MAX
|
||||||
|
@ -162,6 +162,12 @@ struct MemRegion
|
||||||
u32 Mask;
|
u32 Mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// supported GBA slot addon types
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
GBAAddon_RAMExpansion = 1,
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef JIT_ENABLED
|
#ifdef JIT_ENABLED
|
||||||
extern bool EnableJIT;
|
extern bool EnableJIT;
|
||||||
#endif
|
#endif
|
||||||
|
@ -219,6 +225,7 @@ extern u8* ARM7WRAM;
|
||||||
bool Init();
|
bool Init();
|
||||||
void DeInit();
|
void DeInit();
|
||||||
void Reset();
|
void Reset();
|
||||||
|
void Start();
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
bool DoSavestate(Savestate* file);
|
bool DoSavestate(Savestate* file);
|
||||||
|
@ -229,13 +236,19 @@ void SetARM7RegionTimings(u32 addrstart, u32 addrend, u32 region, int buswidth,
|
||||||
// 0=DS 1=DSi
|
// 0=DS 1=DSi
|
||||||
void SetConsoleType(int type);
|
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 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();
|
u32 RunFrame();
|
||||||
|
|
||||||
|
@ -249,8 +262,6 @@ void SetLidClosed(bool closed);
|
||||||
|
|
||||||
void MicInputFrame(s16* data, int samples);
|
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 ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 param);
|
||||||
void CancelEvent(u32 id);
|
void CancelEvent(u32 id);
|
||||||
|
|
||||||
|
|
460
src/NDSCart.cpp
460
src/NDSCart.cpp
|
@ -22,11 +22,11 @@
|
||||||
#include "DSi.h"
|
#include "DSi.h"
|
||||||
#include "NDSCart.h"
|
#include "NDSCart.h"
|
||||||
#include "ARM.h"
|
#include "ARM.h"
|
||||||
|
#include "CRC32.h"
|
||||||
#include "DSi_AES.h"
|
#include "DSi_AES.h"
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
#include "ROMList.h"
|
#include "ROMList.h"
|
||||||
#include "melonDLDI.h"
|
#include "melonDLDI.h"
|
||||||
#include "NDSCart_SRAMManager.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace NDSCart
|
namespace NDSCart
|
||||||
|
@ -51,12 +51,9 @@ u32 TransferDir;
|
||||||
u8 TransferCmd[8];
|
u8 TransferCmd[8];
|
||||||
|
|
||||||
bool CartInserted;
|
bool CartInserted;
|
||||||
char CartName[256];
|
|
||||||
u8* CartROM;
|
u8* CartROM;
|
||||||
u32 CartROMSize;
|
u32 CartROMSize;
|
||||||
u32 CartID;
|
u32 CartID;
|
||||||
bool CartIsHomebrew;
|
|
||||||
bool CartIsDSi;
|
|
||||||
|
|
||||||
NDSHeader Header;
|
NDSHeader Header;
|
||||||
NDSBanner Banner;
|
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)
|
void Key1_InitKeycode(bool dsi, u32 idcode, u32 level, u32 mod)
|
||||||
{
|
{
|
||||||
// TODO: source the key data from different possible places
|
Key1_LoadKeyBuf(dsi);
|
||||||
if (dsi && NDS::ConsoleType==1)
|
|
||||||
memcpy(Key1_KeyBuf, &DSi::ARM7iBIOS[0xC6D0], 0x1048); // hax
|
|
||||||
else
|
|
||||||
memcpy(Key1_KeyBuf, &NDS::ARM7BIOS[0x30], 0x1048); // hax
|
|
||||||
|
|
||||||
u32 keycode[3] = {idcode, idcode>>1, idcode<<1};
|
u32 keycode[3] = {idcode, idcode>>1, idcode<<1};
|
||||||
if (level >= 1) Key1_ApplyKeycode(keycode, mod);
|
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()
|
void CartCommon::Reset()
|
||||||
{
|
{
|
||||||
CmdEncMode = 0;
|
CmdEncMode = 0;
|
||||||
|
@ -198,11 +222,11 @@ void CartCommon::Reset()
|
||||||
DSiMode = false;
|
DSiMode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CartCommon::SetupDirectBoot()
|
void CartCommon::SetupDirectBoot(std::string romname)
|
||||||
{
|
{
|
||||||
CmdEncMode = 2;
|
CmdEncMode = 2;
|
||||||
DataEncMode = 2;
|
DataEncMode = 2;
|
||||||
DSiMode = IsDSi && NDS::ConsoleType==1;
|
DSiMode = IsDSi && (NDS::ConsoleType==1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CartCommon::DoSavestate(Savestate* file)
|
void CartCommon::DoSavestate(Savestate* file)
|
||||||
|
@ -214,20 +238,11 @@ void CartCommon::DoSavestate(Savestate* file)
|
||||||
file->Bool32(&DSiMode);
|
file->Bool32(&DSiMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CartCommon::LoadSave(const char* path, u32 type)
|
void CartCommon::SetupSave(u32 type)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CartCommon::RelocateSave(const char* path, bool write)
|
void CartCommon::LoadSave(const u8* savedata, u32 savelen)
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int CartCommon::ImportSRAM(const u8* data, u32 length)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CartCommon::FlushSRAMFile()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,11 +407,7 @@ void CartRetail::DoSavestate(Savestate* file)
|
||||||
CartCommon::DoSavestate(file);
|
CartCommon::DoSavestate(file);
|
||||||
|
|
||||||
// we reload the SRAM contents.
|
// we reload the SRAM contents.
|
||||||
// it should be the same file (as it should be the same ROM, duh)
|
// it should be the same file, but the contents may change
|
||||||
// but the contents may change
|
|
||||||
|
|
||||||
//if (!file->Saving && SRAMLength)
|
|
||||||
// delete[] SRAM;
|
|
||||||
|
|
||||||
u32 oldlen = SRAMLength;
|
u32 oldlen = SRAMLength;
|
||||||
|
|
||||||
|
@ -407,13 +418,11 @@ void CartRetail::DoSavestate(Savestate* file)
|
||||||
printf("oh well. loading it anyway. adsfgdsf\n");
|
printf("oh well. loading it anyway. adsfgdsf\n");
|
||||||
|
|
||||||
if (oldlen) delete[] SRAM;
|
if (oldlen) delete[] SRAM;
|
||||||
|
SRAM = nullptr;
|
||||||
if (SRAMLength) SRAM = new u8[SRAMLength];
|
if (SRAMLength) SRAM = new u8[SRAMLength];
|
||||||
}
|
}
|
||||||
if (SRAMLength)
|
if (SRAMLength)
|
||||||
{
|
{
|
||||||
//if (!file->Saving)
|
|
||||||
// SRAM = new u8[SRAMLength];
|
|
||||||
|
|
||||||
file->VarArray(SRAM, SRAMLength);
|
file->VarArray(SRAM, SRAMLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,20 +432,14 @@ void CartRetail::DoSavestate(Savestate* file)
|
||||||
file->Var32(&SRAMAddr);
|
file->Var32(&SRAMAddr);
|
||||||
file->Var8(&SRAMStatus);
|
file->Var8(&SRAMStatus);
|
||||||
|
|
||||||
// SRAMManager might now have an old buffer (or one from the future or alternate timeline!)
|
if ((!file->Saving) && SRAM)
|
||||||
if (!file->Saving)
|
Platform::WriteNDSSave(SRAM, SRAMLength, 0, SRAMLength);
|
||||||
{
|
|
||||||
SRAMFileDirty = false;
|
|
||||||
NDSCart_SRAMManager::RequestFlush();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CartRetail::LoadSave(const char* path, u32 type)
|
void CartRetail::SetupSave(u32 type)
|
||||||
{
|
{
|
||||||
if (SRAM) delete[] SRAM;
|
if (SRAM) delete[] SRAM;
|
||||||
|
SRAM = nullptr;
|
||||||
strncpy(SRAMPath, path, 1023);
|
|
||||||
SRAMPath[1023] = '\0';
|
|
||||||
|
|
||||||
if (type > 10) type = 0;
|
if (type > 10) type = 0;
|
||||||
int sramlen[] =
|
int sramlen[] =
|
||||||
|
@ -455,18 +458,6 @@ void CartRetail::LoadSave(const char* path, u32 type)
|
||||||
memset(SRAM, 0xFF, SRAMLength);
|
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)
|
switch (type)
|
||||||
{
|
{
|
||||||
case 1: SRAMType = 1; break; // EEPROM, small
|
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)
|
if (!SRAM) return;
|
||||||
{
|
|
||||||
LoadSave(path, 0); // lazy
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(SRAMPath, path, 1023);
|
u32 len = std::min(savelen, SRAMLength);
|
||||||
SRAMPath[1023] = '\0';
|
memcpy(SRAM, savedata, len);
|
||||||
|
Platform::WriteNDSSave(savedata, len, 0, len);
|
||||||
FILE* f = Platform::OpenFile(path, "wb");
|
|
||||||
if (!f)
|
|
||||||
{
|
|
||||||
printf("NDSCart_SRAM::RelocateSave: failed to create new file. fuck\n");
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int CartRetail::ROMCommandStart(u8* cmd, u8* data, u32 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)
|
if (pos < 2)
|
||||||
{
|
{
|
||||||
SRAMAddr = val;
|
SRAMAddr = val;
|
||||||
|
SRAMFirstAddr = SRAMAddr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -631,11 +589,15 @@ u8 CartRetail::SRAMWrite_EEPROMTiny(u8 val, u32 pos, bool last)
|
||||||
if (SRAMStatus & (1<<1))
|
if (SRAMStatus & (1<<1))
|
||||||
{
|
{
|
||||||
SRAM[(SRAMAddr + ((SRAMCmd==0x0A)?0x100:0)) & 0x1FF] = val;
|
SRAM[(SRAMAddr + ((SRAMCmd==0x0A)?0x100:0)) & 0x1FF] = val;
|
||||||
SRAMFileDirty |= last;
|
|
||||||
}
|
}
|
||||||
SRAMAddr++;
|
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;
|
return 0;
|
||||||
|
|
||||||
case 0x03: // read low
|
case 0x03: // read low
|
||||||
|
@ -683,6 +645,7 @@ u8 CartRetail::SRAMWrite_EEPROM(u8 val, u32 pos, bool last)
|
||||||
{
|
{
|
||||||
SRAMAddr <<= 8;
|
SRAMAddr <<= 8;
|
||||||
SRAMAddr |= val;
|
SRAMAddr |= val;
|
||||||
|
SRAMFirstAddr = SRAMAddr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -690,11 +653,15 @@ u8 CartRetail::SRAMWrite_EEPROM(u8 val, u32 pos, bool last)
|
||||||
if (SRAMStatus & (1<<1))
|
if (SRAMStatus & (1<<1))
|
||||||
{
|
{
|
||||||
SRAM[SRAMAddr & (SRAMLength-1)] = val;
|
SRAM[SRAMAddr & (SRAMLength-1)] = val;
|
||||||
SRAMFileDirty |= last;
|
|
||||||
}
|
}
|
||||||
SRAMAddr++;
|
SRAMAddr++;
|
||||||
}
|
}
|
||||||
if (last) SRAMStatus &= ~(1<<1);
|
if (last)
|
||||||
|
{
|
||||||
|
SRAMStatus &= ~(1<<1);
|
||||||
|
Platform::WriteNDSSave(SRAM, SRAMLength,
|
||||||
|
SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case 0x03: // read
|
case 0x03: // read
|
||||||
|
@ -735,6 +702,7 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
|
||||||
{
|
{
|
||||||
SRAMAddr <<= 8;
|
SRAMAddr <<= 8;
|
||||||
SRAMAddr |= val;
|
SRAMAddr |= val;
|
||||||
|
SRAMFirstAddr = SRAMAddr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -742,11 +710,15 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
|
||||||
{
|
{
|
||||||
// CHECKME: should it be &=~val ??
|
// CHECKME: should it be &=~val ??
|
||||||
SRAM[SRAMAddr & (SRAMLength-1)] = 0;
|
SRAM[SRAMAddr & (SRAMLength-1)] = 0;
|
||||||
SRAMFileDirty |= last;
|
|
||||||
}
|
}
|
||||||
SRAMAddr++;
|
SRAMAddr++;
|
||||||
}
|
}
|
||||||
if (last) SRAMStatus &= ~(1<<1);
|
if (last)
|
||||||
|
{
|
||||||
|
SRAMStatus &= ~(1<<1);
|
||||||
|
Platform::WriteNDSSave(SRAM, SRAMLength,
|
||||||
|
SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case 0x03: // read
|
case 0x03: // read
|
||||||
|
@ -768,17 +740,22 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
|
||||||
{
|
{
|
||||||
SRAMAddr <<= 8;
|
SRAMAddr <<= 8;
|
||||||
SRAMAddr |= val;
|
SRAMAddr |= val;
|
||||||
|
SRAMFirstAddr = SRAMAddr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (SRAMStatus & (1<<1))
|
if (SRAMStatus & (1<<1))
|
||||||
{
|
{
|
||||||
SRAM[SRAMAddr & (SRAMLength-1)] = val;
|
SRAM[SRAMAddr & (SRAMLength-1)] = val;
|
||||||
SRAMFileDirty |= last;
|
|
||||||
}
|
}
|
||||||
SRAMAddr++;
|
SRAMAddr++;
|
||||||
}
|
}
|
||||||
if (last) SRAMStatus &= ~(1<<1);
|
if (last)
|
||||||
|
{
|
||||||
|
SRAMStatus &= ~(1<<1);
|
||||||
|
Platform::WriteNDSSave(SRAM, SRAMLength,
|
||||||
|
SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case 0x0B: // fast read
|
case 0x0B: // fast read
|
||||||
|
@ -809,6 +786,7 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
|
||||||
{
|
{
|
||||||
SRAMAddr <<= 8;
|
SRAMAddr <<= 8;
|
||||||
SRAMAddr |= val;
|
SRAMAddr |= val;
|
||||||
|
SRAMFirstAddr = SRAMAddr;
|
||||||
}
|
}
|
||||||
if ((pos == 3) && (SRAMStatus & (1<<1)))
|
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;
|
SRAM[SRAMAddr & (SRAMLength-1)] = 0;
|
||||||
SRAMAddr++;
|
SRAMAddr++;
|
||||||
}
|
}
|
||||||
SRAMFileDirty = true;
|
|
||||||
}
|
}
|
||||||
if (last) SRAMStatus &= ~(1<<1);
|
if (last)
|
||||||
|
{
|
||||||
|
SRAMStatus &= ~(1<<1);
|
||||||
|
Platform::WriteNDSSave(SRAM, SRAMLength,
|
||||||
|
SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case 0xDB: // page erase
|
case 0xDB: // page erase
|
||||||
|
@ -827,6 +809,7 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
|
||||||
{
|
{
|
||||||
SRAMAddr <<= 8;
|
SRAMAddr <<= 8;
|
||||||
SRAMAddr |= val;
|
SRAMAddr |= val;
|
||||||
|
SRAMFirstAddr = SRAMAddr;
|
||||||
}
|
}
|
||||||
if ((pos == 3) && (SRAMStatus & (1<<1)))
|
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;
|
SRAM[SRAMAddr & (SRAMLength-1)] = 0;
|
||||||
SRAMAddr++;
|
SRAMAddr++;
|
||||||
}
|
}
|
||||||
SRAMFileDirty = true;
|
|
||||||
}
|
}
|
||||||
if (last) SRAMStatus &= ~(1<<1);
|
if (last)
|
||||||
|
{
|
||||||
|
SRAMStatus &= ~(1<<1);
|
||||||
|
Platform::WriteNDSSave(SRAM, SRAMLength,
|
||||||
|
SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -884,19 +871,12 @@ void CartRetailNAND::DoSavestate(Savestate* file)
|
||||||
BuildSRAMID();
|
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();
|
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)
|
int CartRetailNAND::ROMCommandStart(u8* cmd, u8* data, u32 len)
|
||||||
{
|
{
|
||||||
if (CmdEncMode != 2) return CartCommon::ROMCommandStart(cmd, data, 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))
|
if (SRAMLength && SRAMAddr < (SRAMBase+SRAMLength-0x20000))
|
||||||
{
|
{
|
||||||
memcpy(&SRAM[SRAMAddr - SRAMBase], SRAMWriteBuffer, 0x800);
|
memcpy(&SRAM[SRAMAddr - SRAMBase], SRAMWriteBuffer, 0x800);
|
||||||
SRAMFileDirty = true;
|
Platform::WriteNDSSave(SRAM, SRAMLength, SRAMAddr - SRAMBase, 0x800);
|
||||||
}
|
}
|
||||||
|
|
||||||
SRAMAddr = 0;
|
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)
|
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);
|
ReadOnly = Platform::GetConfigBool(Platform::DLDI_ReadOnly);
|
||||||
|
|
||||||
|
if (SD)
|
||||||
|
{
|
||||||
|
SD->Close();
|
||||||
|
delete SD;
|
||||||
|
}
|
||||||
|
|
||||||
if (Platform::GetConfigBool(Platform::DLDI_Enable))
|
if (Platform::GetConfigBool(Platform::DLDI_Enable))
|
||||||
{
|
{
|
||||||
std::string folderpath;
|
std::string folderpath;
|
||||||
|
@ -1185,29 +1187,15 @@ CartHomebrew::CartHomebrew(u8* rom, u32 len, u32 chipid) : CartCommon(rom, len,
|
||||||
SD = nullptr;
|
SD = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CartHomebrew::~CartHomebrew()
|
void CartHomebrew::SetupDirectBoot(std::string romname)
|
||||||
{
|
{
|
||||||
if (SD)
|
CartCommon::SetupDirectBoot(romname);
|
||||||
{
|
|
||||||
SD->Close();
|
|
||||||
delete SD;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CartHomebrew::Reset()
|
|
||||||
{
|
|
||||||
CartCommon::Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CartHomebrew::SetupDirectBoot()
|
|
||||||
{
|
|
||||||
CartCommon::SetupDirectBoot();
|
|
||||||
|
|
||||||
if (SD)
|
if (SD)
|
||||||
{
|
{
|
||||||
// add the ROM to the SD volume
|
// add the ROM to the SD volume
|
||||||
|
|
||||||
if (!SD->InjectFile(CartName, CartROM, CartROMSize))
|
if (!SD->InjectFile(romname, CartROM, CartROMSize))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// setup argv command line
|
// setup argv command line
|
||||||
|
@ -1216,7 +1204,7 @@ void CartHomebrew::SetupDirectBoot()
|
||||||
int argvlen;
|
int argvlen;
|
||||||
|
|
||||||
strncpy(argv, "fat:/", 511);
|
strncpy(argv, "fat:/", 511);
|
||||||
strncat(argv, CartName, 511);
|
strncat(argv, romname.c_str(), 511);
|
||||||
argvlen = strlen(argv);
|
argvlen = strlen(argv);
|
||||||
|
|
||||||
void (*writefn)(u32,u32) = (NDS::ConsoleType==1) ? DSi::ARM9Write32 : NDS::ARM9Write32;
|
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()
|
bool Init()
|
||||||
{
|
{
|
||||||
|
CartInserted = false;
|
||||||
CartROM = nullptr;
|
CartROM = nullptr;
|
||||||
Cart = nullptr;
|
Cart = nullptr;
|
||||||
|
|
||||||
|
@ -1455,17 +1444,6 @@ void DeInit()
|
||||||
|
|
||||||
void Reset()
|
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();
|
ResetCart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1494,6 +1472,30 @@ void DoSavestate(Savestate* file)
|
||||||
// (TODO: system to verify that indeed the right ROM is loaded)
|
// (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)
|
// (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);
|
if (Cart) Cart->DoSavestate(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1542,11 +1544,6 @@ bool ReadROMParams(u32 gamecode, ROMListEntry* params)
|
||||||
|
|
||||||
void DecryptSecureArea(u8* out)
|
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 gamecode = (u32)Header.GameCode[3] << 24 |
|
||||||
(u32)Header.GameCode[2] << 16 |
|
(u32)Header.GameCode[2] << 16 |
|
||||||
(u32)Header.GameCode[1] << 8 |
|
(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(&Header, CartROM, sizeof(Header));
|
||||||
memcpy(&Banner, CartROM + Header.BannerOffset, sizeof(Banner));
|
memcpy(&Banner, CartROM + Header.BannerOffset, sizeof(Banner));
|
||||||
|
|
||||||
|
@ -1589,7 +1606,10 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
|
||||||
(u32)Header.GameCode[0];
|
(u32)Header.GameCode[0];
|
||||||
|
|
||||||
u8 unitcode = Header.UnitCode;
|
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;
|
ROMListEntry romparams;
|
||||||
if (!ReadROMParams(gamecode, &romparams))
|
if (!ReadROMParams(gamecode, &romparams))
|
||||||
|
@ -1599,7 +1619,7 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
|
||||||
|
|
||||||
romparams.GameCode = gamecode;
|
romparams.GameCode = gamecode;
|
||||||
romparams.ROMSize = CartROMSize;
|
romparams.ROMSize = CartROMSize;
|
||||||
if (*(u32*)&CartROM[0x20] < 0x4000)
|
if (homebrew)
|
||||||
romparams.SaveMemType = 0; // no saveRAM for homebrew
|
romparams.SaveMemType = 0; // no saveRAM for homebrew
|
||||||
else
|
else
|
||||||
romparams.SaveMemType = 2; // assume EEPROM 64k (TODO FIXME)
|
romparams.SaveMemType = 2; // assume EEPROM 64k (TODO FIXME)
|
||||||
|
@ -1607,7 +1627,8 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
|
||||||
else
|
else
|
||||||
printf("ROM entry: %08X %08X\n", romparams.ROMSize, romparams.SaveMemType);
|
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
|
// generate a ROM ID
|
||||||
// note: most games don't check the actual value
|
// 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)
|
if (romparams.SaveMemType >= 8 && romparams.SaveMemType <= 10)
|
||||||
CartID |= 0x08000000; // NAND flag
|
CartID |= 0x08000000; // NAND flag
|
||||||
|
|
||||||
if (CartIsDSi)
|
if (dsi)
|
||||||
CartID |= 0x40000000;
|
CartID |= 0x40000000;
|
||||||
|
|
||||||
// cart ID for Jam with the Band
|
// 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);
|
printf("Cart ID: %08X\n", CartID);
|
||||||
|
|
||||||
u32 arm9base = *(u32*)&CartROM[0x20];
|
if (arm9base >= 0x4000 && arm9base < 0x8000)
|
||||||
|
|
||||||
if (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
|
printf("Re-encrypting cart secure area\n");
|
||||||
if (*(u32*)&CartROM[arm9base] == 0xE7FFDEFF && *(u32*)&CartROM[arm9base+0x10] != 0xE7FFDEFF)
|
|
||||||
{
|
|
||||||
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);
|
Key1_InitKeycode(false, gamecode, 3, 2);
|
||||||
for (u32 i = 0; i < 0x800; i += 8)
|
for (u32 i = 0; i < 0x800; i += 8)
|
||||||
Key1_Encrypt((u32*)&CartROM[arm9base + i]);
|
Key1_Encrypt((u32*)&CartROM[arm9base + i]);
|
||||||
|
|
||||||
Key1_InitKeycode(false, gamecode, 2, 2);
|
Key1_InitKeycode(false, gamecode, 2, 2);
|
||||||
Key1_Encrypt((u32*)&CartROM[arm9base]);
|
Key1_Encrypt((u32*)&CartROM[arm9base]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((arm9base < 0x4000) || (gamecode == 0x23232323))
|
|
||||||
{
|
|
||||||
CartIsHomebrew = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
CartInserted = true;
|
CartInserted = true;
|
||||||
|
|
||||||
u32 irversion = 0;
|
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
|
irversion = 2; // Pokémon HG/SS, B/W, B2/W2
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CartIsHomebrew)
|
if (homebrew)
|
||||||
Cart = new CartHomebrew(CartROM, CartROMSize, CartID);
|
Cart = new CartHomebrew(CartROM, CartROMSize, CartID);
|
||||||
else if (CartID & 0x08000000)
|
else if (CartID & 0x08000000)
|
||||||
Cart = new CartRetailNAND(CartROM, CartROMSize, CartID);
|
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);
|
Cart = new CartRetail(CartROM, CartROMSize, CartID);
|
||||||
|
|
||||||
if (Cart)
|
if (Cart)
|
||||||
{
|
|
||||||
Cart->Reset();
|
Cart->Reset();
|
||||||
if (direct)
|
|
||||||
{
|
|
||||||
NDS::SetupDirectBoot();
|
|
||||||
Cart->SetupDirectBoot();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// encryption
|
if (Cart && romparams.SaveMemType > 0)
|
||||||
Key1_InitKeycode(false, gamecode, 2, 2);
|
Cart->SetupSave(romparams.SaveMemType);
|
||||||
|
|
||||||
// save
|
|
||||||
printf("Save file: %s\n", sram);
|
|
||||||
if (Cart) Cart->LoadSave(sram, romparams.SaveMemType);
|
|
||||||
|
|
||||||
return true;
|
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
|
if (Cart)
|
||||||
// for now we're lazy
|
Cart->LoadSave(savedata, savelen);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct)
|
void SetupDirectBoot(std::string romname)
|
||||||
{
|
{
|
||||||
NDS::Reset();
|
if (Cart)
|
||||||
|
Cart->SetupDirectBoot(romname);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RelocateSave(const char* path, bool write)
|
void EjectCart()
|
||||||
{
|
{
|
||||||
if (Cart) Cart->RelocateSave(path, write);
|
if (!CartInserted) return;
|
||||||
}
|
|
||||||
|
|
||||||
void FlushSRAMFile()
|
// ejecting the cart triggers the gamecard IRQ
|
||||||
{
|
NDS::SetIRQ(0, NDS::IRQ_CartIREQMC);
|
||||||
if (Cart) Cart->FlushSRAMFile();
|
NDS::SetIRQ(1, NDS::IRQ_CartIREQMC);
|
||||||
}
|
|
||||||
|
|
||||||
int ImportSRAM(const u8* data, u32 length)
|
if (Cart) delete Cart;
|
||||||
{
|
Cart = nullptr;
|
||||||
if (Cart) return Cart->ImportSRAM(data, length);
|
|
||||||
return 0;
|
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()
|
void ResetCart()
|
||||||
|
@ -1880,6 +1836,8 @@ void WriteROMCnt(u32 val)
|
||||||
*(u32*)&TransferCmd[0] = *(u32*)&ROMCommand[0];
|
*(u32*)&TransferCmd[0] = *(u32*)&ROMCommand[0];
|
||||||
*(u32*)&TransferCmd[4] = *(u32*)&ROMCommand[4];
|
*(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",
|
/*printf("ROM COMMAND %04X %08X %02X%02X%02X%02X%02X%02X%02X%02X SIZE %04X\n",
|
||||||
SPICnt, ROMCnt,
|
SPICnt, ROMCnt,
|
||||||
TransferCmd[0], TransferCmd[1], TransferCmd[2], TransferCmd[3],
|
TransferCmd[0], TransferCmd[1], TransferCmd[2], TransferCmd[3],
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#ifndef NDSCART_H
|
#ifndef NDSCART_H
|
||||||
#define NDSCART_H
|
#define NDSCART_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "NDS_Header.h"
|
#include "NDS_Header.h"
|
||||||
#include "FATStorage.h"
|
#include "FATStorage.h"
|
||||||
|
@ -33,15 +35,16 @@ public:
|
||||||
CartCommon(u8* rom, u32 len, u32 chipid);
|
CartCommon(u8* rom, u32 len, u32 chipid);
|
||||||
virtual ~CartCommon();
|
virtual ~CartCommon();
|
||||||
|
|
||||||
|
virtual u32 Type() { return 0x001; }
|
||||||
|
virtual u32 Checksum();
|
||||||
|
|
||||||
virtual void Reset();
|
virtual void Reset();
|
||||||
virtual void SetupDirectBoot();
|
virtual void SetupDirectBoot(std::string romname);
|
||||||
|
|
||||||
virtual void DoSavestate(Savestate* file);
|
virtual void DoSavestate(Savestate* file);
|
||||||
|
|
||||||
virtual void LoadSave(const char* path, u32 type);
|
virtual void SetupSave(u32 type);
|
||||||
virtual void RelocateSave(const char* path, bool write);
|
virtual void LoadSave(const u8* savedata, u32 savelen);
|
||||||
virtual int ImportSRAM(const u8* data, u32 length);
|
|
||||||
virtual void FlushSRAMFile();
|
|
||||||
|
|
||||||
virtual int ROMCommandStart(u8* cmd, u8* data, u32 len);
|
virtual int ROMCommandStart(u8* cmd, u8* data, u32 len);
|
||||||
virtual void ROMCommandFinish(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);
|
CartRetail(u8* rom, u32 len, u32 chipid);
|
||||||
virtual ~CartRetail() override;
|
virtual ~CartRetail() override;
|
||||||
|
|
||||||
|
virtual u32 Type() override { return 0x101; }
|
||||||
|
|
||||||
virtual void Reset() override;
|
virtual void Reset() override;
|
||||||
|
|
||||||
virtual void DoSavestate(Savestate* file) override;
|
virtual void DoSavestate(Savestate* file) override;
|
||||||
|
|
||||||
virtual void LoadSave(const char* path, u32 type) override;
|
virtual void SetupSave(u32 type) override;
|
||||||
virtual void RelocateSave(const char* path, bool write) override;
|
virtual void LoadSave(const u8* savedata, u32 savelen) override;
|
||||||
virtual int ImportSRAM(const u8* data, u32 length) override;
|
|
||||||
virtual void FlushSRAMFile() override;
|
|
||||||
|
|
||||||
virtual int ROMCommandStart(u8* cmd, u8* data, u32 len) override;
|
virtual int ROMCommandStart(u8* cmd, u8* data, u32 len) override;
|
||||||
|
|
||||||
|
@ -95,11 +98,9 @@ protected:
|
||||||
u32 SRAMLength;
|
u32 SRAMLength;
|
||||||
u32 SRAMType;
|
u32 SRAMType;
|
||||||
|
|
||||||
char SRAMPath[1024];
|
|
||||||
bool SRAMFileDirty;
|
|
||||||
|
|
||||||
u8 SRAMCmd;
|
u8 SRAMCmd;
|
||||||
u32 SRAMAddr;
|
u32 SRAMAddr;
|
||||||
|
u32 SRAMFirstAddr;
|
||||||
u8 SRAMStatus;
|
u8 SRAMStatus;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -110,12 +111,13 @@ public:
|
||||||
CartRetailNAND(u8* rom, u32 len, u32 chipid);
|
CartRetailNAND(u8* rom, u32 len, u32 chipid);
|
||||||
~CartRetailNAND() override;
|
~CartRetailNAND() override;
|
||||||
|
|
||||||
|
virtual u32 Type() override { return 0x102; }
|
||||||
|
|
||||||
void Reset() override;
|
void Reset() override;
|
||||||
|
|
||||||
void DoSavestate(Savestate* file) override;
|
void DoSavestate(Savestate* file) override;
|
||||||
|
|
||||||
void LoadSave(const char* path, u32 type) override;
|
void LoadSave(const u8* savedata, u32 savelen) override;
|
||||||
int ImportSRAM(const u8* data, u32 length) override;
|
|
||||||
|
|
||||||
int ROMCommandStart(u8* cmd, u8* data, u32 len) override;
|
int ROMCommandStart(u8* cmd, u8* data, u32 len) override;
|
||||||
void ROMCommandFinish(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(u8* rom, u32 len, u32 chipid, u32 irversion);
|
||||||
~CartRetailIR() override;
|
~CartRetailIR() override;
|
||||||
|
|
||||||
|
virtual u32 Type() override { return 0x103; }
|
||||||
|
|
||||||
void Reset() override;
|
void Reset() override;
|
||||||
|
|
||||||
void DoSavestate(Savestate* file) override;
|
void DoSavestate(Savestate* file) override;
|
||||||
|
@ -157,6 +161,8 @@ public:
|
||||||
CartRetailBT(u8* rom, u32 len, u32 chipid);
|
CartRetailBT(u8* rom, u32 len, u32 chipid);
|
||||||
~CartRetailBT() override;
|
~CartRetailBT() override;
|
||||||
|
|
||||||
|
virtual u32 Type() override { return 0x104; }
|
||||||
|
|
||||||
void Reset() override;
|
void Reset() override;
|
||||||
|
|
||||||
void DoSavestate(Savestate* file) override;
|
void DoSavestate(Savestate* file) override;
|
||||||
|
@ -171,8 +177,10 @@ public:
|
||||||
CartHomebrew(u8* rom, u32 len, u32 chipid);
|
CartHomebrew(u8* rom, u32 len, u32 chipid);
|
||||||
~CartHomebrew() override;
|
~CartHomebrew() override;
|
||||||
|
|
||||||
|
virtual u32 Type() override { return 0x201; }
|
||||||
|
|
||||||
void Reset() override;
|
void Reset() override;
|
||||||
void SetupDirectBoot() override;
|
void SetupDirectBoot(std::string romname) override;
|
||||||
|
|
||||||
void DoSavestate(Savestate* file) override;
|
void DoSavestate(Savestate* file) override;
|
||||||
|
|
||||||
|
@ -192,6 +200,7 @@ extern u32 ROMCnt;
|
||||||
|
|
||||||
extern u8 ROMCommand[8];
|
extern u8 ROMCommand[8];
|
||||||
|
|
||||||
|
extern bool CartInserted;
|
||||||
extern u8* CartROM;
|
extern u8* CartROM;
|
||||||
extern u32 CartROMSize;
|
extern u32 CartROMSize;
|
||||||
|
|
||||||
|
@ -207,14 +216,12 @@ void Reset();
|
||||||
void DoSavestate(Savestate* file);
|
void DoSavestate(Savestate* file);
|
||||||
|
|
||||||
void DecryptSecureArea(u8* out);
|
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();
|
bool LoadROM(const u8* romdata, u32 romlen);
|
||||||
|
void LoadSave(const u8* savedata, u32 savelen);
|
||||||
|
void SetupDirectBoot(std::string romname);
|
||||||
|
|
||||||
void RelocateSave(const char* path, bool write);
|
void EjectCart();
|
||||||
|
|
||||||
int ImportSRAM(const u8* data, u32 length);
|
|
||||||
|
|
||||||
void ResetCart();
|
void ResetCart();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -145,6 +145,13 @@ void Mutex_Unlock(Mutex* mutex);
|
||||||
bool Mutex_TryLock(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
|
// local multiplayer comm interface
|
||||||
// packet type: DS-style TX header (12 bytes) + original 802.11 frame
|
// packet type: DS-style TX header (12 bytes) + original 802.11 frame
|
||||||
bool MP_Init();
|
bool MP_Init();
|
||||||
|
|
|
@ -463,6 +463,7 @@ void SetupDirectBoot(bool dsi)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 GetFirmwareLength() { return FirmwareLength; }
|
||||||
u8 GetConsoleType() { return Firmware[0x1D]; }
|
u8 GetConsoleType() { return Firmware[0x1D]; }
|
||||||
u8 GetWifiVersion() { return Firmware[0x2F]; }
|
u8 GetWifiVersion() { return Firmware[0x2F]; }
|
||||||
u8 GetNWifiVersion() { return Firmware[0x1FD]; } // for DSi; will return 0xFF on a DS
|
u8 GetNWifiVersion() { return Firmware[0x1FD]; } // for DSi; will return 0xFF on a DS
|
||||||
|
|
|
@ -28,6 +28,7 @@ void SetupDirectBoot(bool dsi);
|
||||||
|
|
||||||
u32 FixFirmwareLength(u32 originalLength);
|
u32 FixFirmwareLength(u32 originalLength);
|
||||||
|
|
||||||
|
u32 GetFirmwareLength();
|
||||||
u8 GetConsoleType();
|
u8 GetConsoleType();
|
||||||
u8 GetWifiVersion();
|
u8 GetWifiVersion();
|
||||||
u8 GetNWifiVersion();
|
u8 GetNWifiVersion();
|
||||||
|
|
|
@ -43,7 +43,10 @@
|
||||||
* different minor means adjustments may have to be made
|
* 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";
|
const char* magic = "MELN";
|
||||||
|
|
||||||
|
@ -55,7 +58,7 @@ Savestate::Savestate(const char* filename, bool save)
|
||||||
file = Platform::OpenLocalFile(filename, "wb");
|
file = Platform::OpenLocalFile(filename, "wb");
|
||||||
if (!file)
|
if (!file)
|
||||||
{
|
{
|
||||||
printf("savestate: file %s doesn't exist\n", filename);
|
printf("savestate: file %s doesn't exist\n", filename.c_str());
|
||||||
Error = true;
|
Error = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -74,7 +77,7 @@ Savestate::Savestate(const char* filename, bool save)
|
||||||
file = Platform::OpenFile(filename, "rb");
|
file = Platform::OpenFile(filename, "rb");
|
||||||
if (!file)
|
if (!file)
|
||||||
{
|
{
|
||||||
printf("savestate: file %s doesn't exist\n", filename);
|
printf("savestate: file %s doesn't exist\n", filename.c_str());
|
||||||
Error = true;
|
Error = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#ifndef SAVESTATE_H
|
#ifndef SAVESTATE_H
|
||||||
#define SAVESTATE_H
|
#define SAVESTATE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@
|
||||||
class Savestate
|
class Savestate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Savestate(const char* filename, bool save);
|
Savestate(std::string filename, bool save);
|
||||||
~Savestate();
|
~Savestate();
|
||||||
|
|
||||||
bool Error;
|
bool Error;
|
||||||
|
|
|
@ -21,100 +21,12 @@
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Frontend
|
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
|
// setup the display layout based on the provided display size and parameters
|
||||||
// * screenWidth/screenHeight: size of the host display
|
// * screenWidth/screenHeight: size of the host display
|
||||||
// * screenLayout: how the DS screens are laid out
|
// * screenLayout: how the DS screens are laid out
|
||||||
|
|
|
@ -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
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -17,52 +17,37 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ArchiveUtil.h"
|
#include "ArchiveUtil.h"
|
||||||
|
#include "Platform.h"
|
||||||
|
|
||||||
namespace Archive
|
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 *a;
|
||||||
struct archive_entry *entry;
|
struct archive_entry *entry;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
QVector<QString> fileList = {"OK"};
|
QVector<QString> fileList;
|
||||||
|
|
||||||
a = archive_read_new();
|
a = archive_read_new();
|
||||||
|
|
||||||
archive_read_support_filter_all(a);
|
archive_read_support_filter_all(a);
|
||||||
archive_read_support_format_all(a);
|
archive_read_support_format_all(a);
|
||||||
r = archive_read_open_filename(a, path, 10240);
|
|
||||||
if (r != ARCHIVE_OK)
|
|
||||||
{
|
|
||||||
return QVector<QString> {"Err"};
|
|
||||||
}
|
|
||||||
|
|
||||||
while (archive_read_next_header(a, &entry) == ARCHIVE_OK)
|
|
||||||
{
|
|
||||||
fileList.push_back(archive_entry_pathname(entry));
|
|
||||||
archive_read_data_skip(a);
|
|
||||||
}
|
|
||||||
archive_read_close(a);
|
|
||||||
archive_read_free(a);
|
|
||||||
if (r != ARCHIVE_OK)
|
|
||||||
{
|
|
||||||
return QVector<QString> {"Err"};
|
|
||||||
}
|
|
||||||
|
|
||||||
return fileList;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVector<QString> ExtractFileFromArchive(const char* path, const char* wantedFile, QByteArray *romBuffer)
|
//r = archive_read_open_filename(a, path, 10240);
|
||||||
{
|
r = melon_archive_open(a, path, 10240);
|
||||||
struct archive *a = archive_read_new();
|
|
||||||
struct archive_entry *entry;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
archive_read_support_format_all(a);
|
|
||||||
archive_read_support_filter_all(a);
|
|
||||||
|
|
||||||
r = archive_read_open_filename(a, path, 10240);
|
|
||||||
if (r != ARCHIVE_OK)
|
if (r != ARCHIVE_OK)
|
||||||
{
|
{
|
||||||
return QVector<QString> {"Err"};
|
return QVector<QString> {"Err"};
|
||||||
|
@ -70,7 +55,46 @@ QVector<QString> ExtractFileFromArchive(const char* path, const char* wantedFile
|
||||||
|
|
||||||
while (archive_read_next_header(a, &entry) == ARCHIVE_OK)
|
while (archive_read_next_header(a, &entry) == ARCHIVE_OK)
|
||||||
{
|
{
|
||||||
if (strcmp(wantedFile, archive_entry_pathname(entry)) == 0)
|
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);
|
||||||
|
|
||||||
|
if (r != ARCHIVE_OK)
|
||||||
|
{
|
||||||
|
return QVector<QString> {"Err"};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stable_sort(fileList.begin(), fileList.end(), compareCI);
|
||||||
|
fileList.prepend("OK");
|
||||||
|
|
||||||
|
return fileList;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<QString> ExtractFileFromArchive(QString path, QString wantedFile, QByteArray *romBuffer)
|
||||||
|
{
|
||||||
|
struct archive *a = archive_read_new();
|
||||||
|
struct archive_entry *entry;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
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 QVector<QString> {"Err"};
|
||||||
|
}
|
||||||
|
|
||||||
|
while (archive_read_next_header(a, &entry) == ARCHIVE_OK)
|
||||||
|
{
|
||||||
|
if (strcmp(wantedFile.toUtf8().constData(), archive_entry_pathname_utf8(entry)) == 0)
|
||||||
{
|
{
|
||||||
break;
|
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;
|
QByteArray romBuffer;
|
||||||
QVector<QString> extractResult = ExtractFileFromArchive(path, wantedFile, &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);
|
memcpy(*romdata, romBuffer.data(), len);
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,10 +34,11 @@
|
||||||
|
|
||||||
namespace Archive
|
namespace Archive
|
||||||
{
|
{
|
||||||
|
|
||||||
QVector<QString> ListArchive(const char* path);
|
QVector<QString> ListArchive(QString path);
|
||||||
QVector<QString> ExtractFileFromArchive(const char* path, const char* wantedFile, QByteArray *romBuffer);
|
u32 ExtractFileFromArchive(QString path, QString wantedFile, u8** filedata, u32* filesize);
|
||||||
u32 ExtractFileFromArchive(const char* path, const char* wantedFile, u8 **romdata);
|
//QVector<QString> ExtractFileFromArchive(QString path, QString wantedFile, QByteArray *romBuffer);
|
||||||
|
//u32 ExtractFileFromArchive(const char* path, const char* wantedFile, u8 **romdata);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ AudioSettingsDialog::AudioSettingsDialog(QWidget* parent) : QDialog(parent), ui(
|
||||||
connect(grpMicMode, SIGNAL(buttonClicked(int)), this, SLOT(onChangeMicMode(int)));
|
connect(grpMicMode, SIGNAL(buttonClicked(int)), this, SLOT(onChangeMicMode(int)));
|
||||||
grpMicMode->button(Config::MicInputType)->setChecked(true);
|
grpMicMode->button(Config::MicInputType)->setChecked(true);
|
||||||
|
|
||||||
ui->txtMicWavPath->setText(Config::MicWavPath);
|
ui->txtMicWavPath->setText(QString::fromStdString(Config::MicWavPath));
|
||||||
|
|
||||||
bool iswav = (Config::MicInputType == 3);
|
bool iswav = (Config::MicInputType == 3);
|
||||||
ui->txtMicWavPath->setEnabled(iswav);
|
ui->txtMicWavPath->setEnabled(iswav);
|
||||||
|
@ -77,7 +77,7 @@ AudioSettingsDialog::~AudioSettingsDialog()
|
||||||
void AudioSettingsDialog::on_AudioSettingsDialog_accepted()
|
void AudioSettingsDialog::on_AudioSettingsDialog_accepted()
|
||||||
{
|
{
|
||||||
Config::MicInputType = grpMicMode->checkedId();
|
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();
|
Config::Save();
|
||||||
|
|
||||||
closeDlg();
|
closeDlg();
|
||||||
|
|
|
@ -12,6 +12,7 @@ SET(SOURCES_QT_SDL
|
||||||
VideoSettingsDialog.cpp
|
VideoSettingsDialog.cpp
|
||||||
AudioSettingsDialog.cpp
|
AudioSettingsDialog.cpp
|
||||||
FirmwareSettingsDialog.cpp
|
FirmwareSettingsDialog.cpp
|
||||||
|
PathSettingsDialog.cpp
|
||||||
WifiSettingsDialog.cpp
|
WifiSettingsDialog.cpp
|
||||||
InterfaceSettingsDialog.cpp
|
InterfaceSettingsDialog.cpp
|
||||||
ROMInfoDialog.cpp
|
ROMInfoDialog.cpp
|
||||||
|
@ -24,16 +25,16 @@ SET(SOURCES_QT_SDL
|
||||||
font.h
|
font.h
|
||||||
Platform.cpp
|
Platform.cpp
|
||||||
QPathInput.h
|
QPathInput.h
|
||||||
|
ROMManager.cpp
|
||||||
|
SaveManager.cpp
|
||||||
|
|
||||||
ArchiveUtil.h
|
ArchiveUtil.h
|
||||||
ArchiveUtil.cpp
|
ArchiveUtil.cpp
|
||||||
|
|
||||||
../Util_ROM.cpp
|
|
||||||
../Util_Video.cpp
|
../Util_Video.cpp
|
||||||
../Util_Audio.cpp
|
../Util_Audio.cpp
|
||||||
../FrontendUtil.h
|
../FrontendUtil.h
|
||||||
../mic_blow.h
|
../mic_blow.h
|
||||||
../SharedConfig.h
|
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/res/melon.qrc
|
${CMAKE_SOURCE_DIR}/res/melon.qrc
|
||||||
)
|
)
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
#include "ROMManager.h"
|
||||||
|
|
||||||
#include "CheatsDialog.h"
|
#include "CheatsDialog.h"
|
||||||
#include "ui_CheatsDialog.h"
|
#include "ui_CheatsDialog.h"
|
||||||
|
@ -33,15 +34,13 @@ CheatsDialog* CheatsDialog::currentDlg = nullptr;
|
||||||
|
|
||||||
extern std::string EmuDirectory;
|
extern std::string EmuDirectory;
|
||||||
|
|
||||||
namespace Frontend { extern ARCodeFile* CheatFile; }
|
|
||||||
|
|
||||||
|
|
||||||
CheatsDialog::CheatsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::CheatsDialog)
|
CheatsDialog::CheatsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::CheatsDialog)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
codeFile = Frontend::CheatFile;
|
codeFile = ROMManager::GetCheatFile();
|
||||||
|
|
||||||
QStandardItemModel* model = new QStandardItemModel();
|
QStandardItemModel* model = new QStandardItemModel();
|
||||||
ui->tvCodeList->setModel(model);
|
ui->tvCodeList->setModel(model);
|
||||||
|
@ -55,7 +54,7 @@ CheatsDialog::CheatsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::Cheats
|
||||||
{
|
{
|
||||||
ARCodeCat& cat = *i;
|
ARCodeCat& cat = *i;
|
||||||
|
|
||||||
QStandardItem* catitem = new QStandardItem(cat.Name);
|
QStandardItem* catitem = new QStandardItem(QString::fromStdString(cat.Name));
|
||||||
catitem->setEditable(true);
|
catitem->setEditable(true);
|
||||||
catitem->setData(QVariant::fromValue(i));
|
catitem->setData(QVariant::fromValue(i));
|
||||||
root->appendRow(catitem);
|
root->appendRow(catitem);
|
||||||
|
@ -64,7 +63,7 @@ CheatsDialog::CheatsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::Cheats
|
||||||
{
|
{
|
||||||
ARCode& code = *j;
|
ARCode& code = *j;
|
||||||
|
|
||||||
QStandardItem* codeitem = new QStandardItem(code.Name);
|
QStandardItem* codeitem = new QStandardItem(QString::fromStdString(code.Name));
|
||||||
codeitem->setEditable(true);
|
codeitem->setEditable(true);
|
||||||
codeitem->setCheckable(true);
|
codeitem->setCheckable(true);
|
||||||
codeitem->setCheckState(code.Enabled ? Qt::Checked : Qt::Unchecked);
|
codeitem->setCheckState(code.Enabled ? Qt::Checked : Qt::Unchecked);
|
||||||
|
@ -113,13 +112,12 @@ void CheatsDialog::on_btnNewCat_clicked()
|
||||||
|
|
||||||
ARCodeCat cat;
|
ARCodeCat cat;
|
||||||
cat.Codes.clear();
|
cat.Codes.clear();
|
||||||
memset(cat.Name, 0, 128);
|
cat.Name = "(new category)";
|
||||||
strncpy(cat.Name, "(new category)", 127);
|
|
||||||
|
|
||||||
codeFile->Categories.push_back(cat);
|
codeFile->Categories.push_back(cat);
|
||||||
ARCodeCatList::iterator id = codeFile->Categories.end(); id--;
|
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->setEditable(true);
|
||||||
catitem->setData(QVariant::fromValue(id));
|
catitem->setData(QVariant::fromValue(id));
|
||||||
root->appendRow(catitem);
|
root->appendRow(catitem);
|
||||||
|
@ -160,8 +158,7 @@ void CheatsDialog::on_btnNewARCode_clicked()
|
||||||
ARCodeCat& cat = *it_cat;
|
ARCodeCat& cat = *it_cat;
|
||||||
|
|
||||||
ARCode code;
|
ARCode code;
|
||||||
memset(code.Name, 0, 128);
|
code.Name = "(new AR code)";
|
||||||
strncpy(code.Name, "(new AR code)", 127);
|
|
||||||
code.Enabled = true;
|
code.Enabled = true;
|
||||||
code.CodeLen = 0;
|
code.CodeLen = 0;
|
||||||
memset(code.Code, 0, sizeof(code.Code));
|
memset(code.Code, 0, sizeof(code.Code));
|
||||||
|
@ -169,7 +166,7 @@ void CheatsDialog::on_btnNewARCode_clicked()
|
||||||
cat.Codes.push_back(code);
|
cat.Codes.push_back(code);
|
||||||
ARCodeList::iterator id = cat.Codes.end(); id--;
|
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->setEditable(true);
|
||||||
codeitem->setCheckable(true);
|
codeitem->setCheckable(true);
|
||||||
codeitem->setCheckState(code.Enabled ? Qt::Checked : Qt::Unchecked);
|
codeitem->setCheckState(code.Enabled ? Qt::Checked : Qt::Unchecked);
|
||||||
|
@ -275,13 +272,12 @@ void CheatsDialog::onCheatEntryModified(QStandardItem* item)
|
||||||
|
|
||||||
if (item->text().isEmpty())
|
if (item->text().isEmpty())
|
||||||
{
|
{
|
||||||
QString oldname = QString(cat.Name);
|
QString oldname = QString::fromStdString(cat.Name);
|
||||||
item->setText(oldname.isEmpty() ? "(blank category name?)" : oldname);
|
item->setText(oldname.isEmpty() ? "(blank category name?)" : oldname);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strncpy(cat.Name, item->text().toStdString().c_str(), 127);
|
cat.Name = item->text().toStdString();
|
||||||
cat.Name[127] = '\0';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (data.canConvert<ARCodeList::iterator>())
|
else if (data.canConvert<ARCodeList::iterator>())
|
||||||
|
@ -290,13 +286,12 @@ void CheatsDialog::onCheatEntryModified(QStandardItem* item)
|
||||||
|
|
||||||
if (item->text().isEmpty())
|
if (item->text().isEmpty())
|
||||||
{
|
{
|
||||||
QString oldname = QString(code.Name);
|
QString oldname = QString::fromStdString(code.Name);
|
||||||
item->setText(oldname.isEmpty() ? "(blank code name?)" : oldname);
|
item->setText(oldname.isEmpty() ? "(blank code name?)" : oldname);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strncpy(code.Name, item->text().toStdString().c_str(), 127);
|
code.Name = item->text().toStdString();
|
||||||
code.Name[127] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
code.Enabled = (item->checkState() == Qt::Checked);
|
code.Enabled = (item->checkState() == Qt::Checked);
|
||||||
|
|
|
@ -36,268 +36,276 @@ int JoystickID;
|
||||||
|
|
||||||
int WindowWidth;
|
int WindowWidth;
|
||||||
int WindowHeight;
|
int WindowHeight;
|
||||||
int WindowMaximized;
|
bool WindowMaximized;
|
||||||
|
|
||||||
int ScreenRotation;
|
int ScreenRotation;
|
||||||
int ScreenGap;
|
int ScreenGap;
|
||||||
int ScreenLayout;
|
int ScreenLayout;
|
||||||
int ScreenSwap;
|
bool ScreenSwap;
|
||||||
int ScreenSizing;
|
int ScreenSizing;
|
||||||
int IntegerScaling;
|
bool IntegerScaling;
|
||||||
int ScreenAspectTop;
|
int ScreenAspectTop;
|
||||||
int ScreenAspectBot;
|
int ScreenAspectBot;
|
||||||
int ScreenFilter;
|
bool ScreenFilter;
|
||||||
|
|
||||||
int ScreenUseGL;
|
bool ScreenUseGL;
|
||||||
int ScreenVSync;
|
bool ScreenVSync;
|
||||||
int ScreenVSyncInterval;
|
int ScreenVSyncInterval;
|
||||||
|
|
||||||
int _3DRenderer;
|
int _3DRenderer;
|
||||||
int Threaded3D;
|
bool Threaded3D;
|
||||||
|
|
||||||
int GL_ScaleFactor;
|
int GL_ScaleFactor;
|
||||||
int GL_BetterPolygons;
|
bool GL_BetterPolygons;
|
||||||
|
|
||||||
int LimitFPS;
|
bool LimitFPS;
|
||||||
int AudioSync;
|
bool AudioSync;
|
||||||
int ShowOSD;
|
bool ShowOSD;
|
||||||
|
|
||||||
int ConsoleType;
|
int ConsoleType;
|
||||||
int DirectBoot;
|
bool DirectBoot;
|
||||||
|
|
||||||
#ifdef JIT_ENABLED
|
#ifdef JIT_ENABLED
|
||||||
int JIT_Enable = false;
|
bool JIT_Enable = false;
|
||||||
int JIT_MaxBlockSize = 32;
|
int JIT_MaxBlockSize = 32;
|
||||||
int JIT_BranchOptimisations = true;
|
bool JIT_BranchOptimisations = true;
|
||||||
int JIT_LiteralOptimisations = true;
|
bool JIT_LiteralOptimisations = true;
|
||||||
int JIT_FastMemory = true;
|
bool JIT_FastMemory = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int ExternalBIOSEnable;
|
bool ExternalBIOSEnable;
|
||||||
|
|
||||||
char BIOS9Path[1024];
|
std::string BIOS9Path;
|
||||||
char BIOS7Path[1024];
|
std::string BIOS7Path;
|
||||||
char FirmwarePath[1024];
|
std::string FirmwarePath;
|
||||||
|
|
||||||
char DSiBIOS9Path[1024];
|
std::string DSiBIOS9Path;
|
||||||
char DSiBIOS7Path[1024];
|
std::string DSiBIOS7Path;
|
||||||
char DSiFirmwarePath[1024];
|
std::string DSiFirmwarePath;
|
||||||
char DSiNANDPath[1024];
|
std::string DSiNANDPath;
|
||||||
|
|
||||||
int DLDIEnable;
|
bool DLDIEnable;
|
||||||
char DLDISDPath[1024];
|
std::string DLDISDPath;
|
||||||
int DLDISize;
|
int DLDISize;
|
||||||
int DLDIReadOnly;
|
bool DLDIReadOnly;
|
||||||
int DLDIFolderSync;
|
bool DLDIFolderSync;
|
||||||
char DLDIFolderPath[1024];
|
std::string DLDIFolderPath;
|
||||||
|
|
||||||
int DSiSDEnable;
|
bool DSiSDEnable;
|
||||||
char DSiSDPath[1024];
|
std::string DSiSDPath;
|
||||||
int DSiSDSize;
|
int DSiSDSize;
|
||||||
int DSiSDReadOnly;
|
bool DSiSDReadOnly;
|
||||||
int DSiSDFolderSync;
|
bool DSiSDFolderSync;
|
||||||
char DSiSDFolderPath[1024];
|
std::string DSiSDFolderPath;
|
||||||
|
|
||||||
int FirmwareOverrideSettings;
|
bool FirmwareOverrideSettings;
|
||||||
char FirmwareUsername[64];
|
std::string FirmwareUsername;
|
||||||
int FirmwareLanguage;
|
int FirmwareLanguage;
|
||||||
int FirmwareBirthdayMonth;
|
int FirmwareBirthdayMonth;
|
||||||
int FirmwareBirthdayDay;
|
int FirmwareBirthdayDay;
|
||||||
int FirmwareFavouriteColour;
|
int FirmwareFavouriteColour;
|
||||||
char FirmwareMessage[1024];
|
std::string FirmwareMessage;
|
||||||
char FirmwareMAC[18];
|
std::string FirmwareMAC;
|
||||||
int RandomizeMAC;
|
bool RandomizeMAC;
|
||||||
|
|
||||||
int SocketBindAnyAddr;
|
bool SocketBindAnyAddr;
|
||||||
char LANDevice[128];
|
std::string LANDevice;
|
||||||
int DirectLAN;
|
bool DirectLAN;
|
||||||
|
|
||||||
int SavestateRelocSRAM;
|
bool SavestateRelocSRAM;
|
||||||
|
|
||||||
int AudioInterp;
|
int AudioInterp;
|
||||||
int AudioBitrate;
|
int AudioBitrate;
|
||||||
int AudioVolume;
|
int AudioVolume;
|
||||||
int MicInputType;
|
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 MouseHideSeconds;
|
||||||
|
|
||||||
int PauseLostFocus;
|
bool PauseLostFocus;
|
||||||
|
|
||||||
|
|
||||||
const char* kConfigFile = "melonDS.ini";
|
const char* kConfigFile = "melonDS.ini";
|
||||||
|
|
||||||
ConfigEntry ConfigFile[] =
|
ConfigEntry ConfigFile[] =
|
||||||
{
|
{
|
||||||
{"Key_A", 0, &KeyMapping[0], -1, NULL, 0},
|
{"Key_A", 0, &KeyMapping[0], -1},
|
||||||
{"Key_B", 0, &KeyMapping[1], -1, NULL, 0},
|
{"Key_B", 0, &KeyMapping[1], -1},
|
||||||
{"Key_Select", 0, &KeyMapping[2], -1, NULL, 0},
|
{"Key_Select", 0, &KeyMapping[2], -1},
|
||||||
{"Key_Start", 0, &KeyMapping[3], -1, NULL, 0},
|
{"Key_Start", 0, &KeyMapping[3], -1},
|
||||||
{"Key_Right", 0, &KeyMapping[4], -1, NULL, 0},
|
{"Key_Right", 0, &KeyMapping[4], -1},
|
||||||
{"Key_Left", 0, &KeyMapping[5], -1, NULL, 0},
|
{"Key_Left", 0, &KeyMapping[5], -1},
|
||||||
{"Key_Up", 0, &KeyMapping[6], -1, NULL, 0},
|
{"Key_Up", 0, &KeyMapping[6], -1},
|
||||||
{"Key_Down", 0, &KeyMapping[7], -1, NULL, 0},
|
{"Key_Down", 0, &KeyMapping[7], -1},
|
||||||
{"Key_R", 0, &KeyMapping[8], -1, NULL, 0},
|
{"Key_R", 0, &KeyMapping[8], -1},
|
||||||
{"Key_L", 0, &KeyMapping[9], -1, NULL, 0},
|
{"Key_L", 0, &KeyMapping[9], -1},
|
||||||
{"Key_X", 0, &KeyMapping[10], -1, NULL, 0},
|
{"Key_X", 0, &KeyMapping[10], -1},
|
||||||
{"Key_Y", 0, &KeyMapping[11], -1, NULL, 0},
|
{"Key_Y", 0, &KeyMapping[11], -1},
|
||||||
|
|
||||||
{"Joy_A", 0, &JoyMapping[0], -1, NULL, 0},
|
{"Joy_A", 0, &JoyMapping[0], -1},
|
||||||
{"Joy_B", 0, &JoyMapping[1], -1, NULL, 0},
|
{"Joy_B", 0, &JoyMapping[1], -1},
|
||||||
{"Joy_Select", 0, &JoyMapping[2], -1, NULL, 0},
|
{"Joy_Select", 0, &JoyMapping[2], -1},
|
||||||
{"Joy_Start", 0, &JoyMapping[3], -1, NULL, 0},
|
{"Joy_Start", 0, &JoyMapping[3], -1},
|
||||||
{"Joy_Right", 0, &JoyMapping[4], -1, NULL, 0},
|
{"Joy_Right", 0, &JoyMapping[4], -1},
|
||||||
{"Joy_Left", 0, &JoyMapping[5], -1, NULL, 0},
|
{"Joy_Left", 0, &JoyMapping[5], -1},
|
||||||
{"Joy_Up", 0, &JoyMapping[6], -1, NULL, 0},
|
{"Joy_Up", 0, &JoyMapping[6], -1},
|
||||||
{"Joy_Down", 0, &JoyMapping[7], -1, NULL, 0},
|
{"Joy_Down", 0, &JoyMapping[7], -1},
|
||||||
{"Joy_R", 0, &JoyMapping[8], -1, NULL, 0},
|
{"Joy_R", 0, &JoyMapping[8], -1},
|
||||||
{"Joy_L", 0, &JoyMapping[9], -1, NULL, 0},
|
{"Joy_L", 0, &JoyMapping[9], -1},
|
||||||
{"Joy_X", 0, &JoyMapping[10], -1, NULL, 0},
|
{"Joy_X", 0, &JoyMapping[10], -1},
|
||||||
{"Joy_Y", 0, &JoyMapping[11], -1, NULL, 0},
|
{"Joy_Y", 0, &JoyMapping[11], -1},
|
||||||
|
|
||||||
{"HKKey_Lid", 0, &HKKeyMapping[HK_Lid], -1, NULL, 0},
|
{"HKKey_Lid", 0, &HKKeyMapping[HK_Lid], -1},
|
||||||
{"HKKey_Mic", 0, &HKKeyMapping[HK_Mic], -1, NULL, 0},
|
{"HKKey_Mic", 0, &HKKeyMapping[HK_Mic], -1},
|
||||||
{"HKKey_Pause", 0, &HKKeyMapping[HK_Pause], -1, NULL, 0},
|
{"HKKey_Pause", 0, &HKKeyMapping[HK_Pause], -1},
|
||||||
{"HKKey_Reset", 0, &HKKeyMapping[HK_Reset], -1, NULL, 0},
|
{"HKKey_Reset", 0, &HKKeyMapping[HK_Reset], -1},
|
||||||
{"HKKey_FastForward", 0, &HKKeyMapping[HK_FastForward], -1, NULL, 0},
|
{"HKKey_FastForward", 0, &HKKeyMapping[HK_FastForward], -1},
|
||||||
{"HKKey_FastForwardToggle", 0, &HKKeyMapping[HK_FastForwardToggle], -1, NULL, 0},
|
{"HKKey_FastForwardToggle", 0, &HKKeyMapping[HK_FastForwardToggle], -1},
|
||||||
{"HKKey_FullscreenToggle", 0, &HKKeyMapping[HK_FullscreenToggle], -1, NULL, 0},
|
{"HKKey_FullscreenToggle", 0, &HKKeyMapping[HK_FullscreenToggle], -1},
|
||||||
{"HKKey_SwapScreens", 0, &HKKeyMapping[HK_SwapScreens], -1, NULL, 0},
|
{"HKKey_SwapScreens", 0, &HKKeyMapping[HK_SwapScreens], -1},
|
||||||
{"HKKey_SolarSensorDecrease", 0, &HKKeyMapping[HK_SolarSensorDecrease], -1, NULL, 0},
|
{"HKKey_SolarSensorDecrease", 0, &HKKeyMapping[HK_SolarSensorDecrease], -1},
|
||||||
{"HKKey_SolarSensorIncrease", 0, &HKKeyMapping[HK_SolarSensorIncrease], -1, NULL, 0},
|
{"HKKey_SolarSensorIncrease", 0, &HKKeyMapping[HK_SolarSensorIncrease], -1},
|
||||||
{"HKKey_FrameStep", 0, &HKKeyMapping[HK_FrameStep], -1, NULL, 0},
|
{"HKKey_FrameStep", 0, &HKKeyMapping[HK_FrameStep], -1},
|
||||||
|
|
||||||
{"HKJoy_Lid", 0, &HKJoyMapping[HK_Lid], -1, NULL, 0},
|
{"HKJoy_Lid", 0, &HKJoyMapping[HK_Lid], -1},
|
||||||
{"HKJoy_Mic", 0, &HKJoyMapping[HK_Mic], -1, NULL, 0},
|
{"HKJoy_Mic", 0, &HKJoyMapping[HK_Mic], -1},
|
||||||
{"HKJoy_Pause", 0, &HKJoyMapping[HK_Pause], -1, NULL, 0},
|
{"HKJoy_Pause", 0, &HKJoyMapping[HK_Pause], -1},
|
||||||
{"HKJoy_Reset", 0, &HKJoyMapping[HK_Reset], -1, NULL, 0},
|
{"HKJoy_Reset", 0, &HKJoyMapping[HK_Reset], -1},
|
||||||
{"HKJoy_FastForward", 0, &HKJoyMapping[HK_FastForward], -1, NULL, 0},
|
{"HKJoy_FastForward", 0, &HKJoyMapping[HK_FastForward], -1},
|
||||||
{"HKJoy_FastForwardToggle", 0, &HKJoyMapping[HK_FastForwardToggle], -1, NULL, 0},
|
{"HKJoy_FastForwardToggle", 0, &HKJoyMapping[HK_FastForwardToggle], -1},
|
||||||
{"HKJoy_FullscreenToggle", 0, &HKJoyMapping[HK_FullscreenToggle], -1, NULL, 0},
|
{"HKJoy_FullscreenToggle", 0, &HKJoyMapping[HK_FullscreenToggle], -1},
|
||||||
{"HKJoy_SwapScreens", 0, &HKJoyMapping[HK_SwapScreens], -1, NULL, 0},
|
{"HKJoy_SwapScreens", 0, &HKJoyMapping[HK_SwapScreens], -1},
|
||||||
{"HKJoy_SolarSensorDecrease", 0, &HKJoyMapping[HK_SolarSensorDecrease], -1, NULL, 0},
|
{"HKJoy_SolarSensorDecrease", 0, &HKJoyMapping[HK_SolarSensorDecrease], -1},
|
||||||
{"HKJoy_SolarSensorIncrease", 0, &HKJoyMapping[HK_SolarSensorIncrease], -1, NULL, 0},
|
{"HKJoy_SolarSensorIncrease", 0, &HKJoyMapping[HK_SolarSensorIncrease], -1},
|
||||||
{"HKJoy_FrameStep", 0, &HKJoyMapping[HK_FrameStep], -1, NULL, 0},
|
{"HKJoy_FrameStep", 0, &HKJoyMapping[HK_FrameStep], -1},
|
||||||
|
|
||||||
{"JoystickID", 0, &JoystickID, 0, NULL, 0},
|
{"JoystickID", 0, &JoystickID, 0},
|
||||||
|
|
||||||
{"WindowWidth", 0, &WindowWidth, 256, NULL, 0},
|
{"WindowWidth", 0, &WindowWidth, 256},
|
||||||
{"WindowHeight", 0, &WindowHeight, 384, NULL, 0},
|
{"WindowHeight", 0, &WindowHeight, 384},
|
||||||
{"WindowMax", 0, &WindowMaximized, 0, NULL, 0},
|
{"WindowMax", 1, &WindowMaximized, false},
|
||||||
|
|
||||||
{"ScreenRotation", 0, &ScreenRotation, 0, NULL, 0},
|
{"ScreenRotation", 0, &ScreenRotation, 0},
|
||||||
{"ScreenGap", 0, &ScreenGap, 0, NULL, 0},
|
{"ScreenGap", 0, &ScreenGap, 0},
|
||||||
{"ScreenLayout", 0, &ScreenLayout, 0, NULL, 0},
|
{"ScreenLayout", 0, &ScreenLayout, 0},
|
||||||
{"ScreenSwap", 0, &ScreenSwap, 0, NULL, 0},
|
{"ScreenSwap", 1, &ScreenSwap, false},
|
||||||
{"ScreenSizing", 0, &ScreenSizing, 0, NULL, 0},
|
{"ScreenSizing", 0, &ScreenSizing, 0},
|
||||||
{"IntegerScaling", 0, &IntegerScaling, 0, NULL, 0},
|
{"IntegerScaling", 1, &IntegerScaling, false},
|
||||||
{"ScreenAspectTop",0, &ScreenAspectTop,0, NULL, 0},
|
{"ScreenAspectTop",0, &ScreenAspectTop,0},
|
||||||
{"ScreenAspectBot",0, &ScreenAspectBot,0, NULL, 0},
|
{"ScreenAspectBot",0, &ScreenAspectBot,0},
|
||||||
{"ScreenFilter", 0, &ScreenFilter, 1, NULL, 0},
|
{"ScreenFilter", 1, &ScreenFilter, true},
|
||||||
|
|
||||||
{"ScreenUseGL", 0, &ScreenUseGL, 0, NULL, 0},
|
{"ScreenUseGL", 1, &ScreenUseGL, false},
|
||||||
{"ScreenVSync", 0, &ScreenVSync, 0, NULL, 0},
|
{"ScreenVSync", 1, &ScreenVSync, false},
|
||||||
{"ScreenVSyncInterval", 0, &ScreenVSyncInterval, 1, NULL, 0},
|
{"ScreenVSyncInterval", 0, &ScreenVSyncInterval, 1},
|
||||||
|
|
||||||
{"3DRenderer", 0, &_3DRenderer, 0, NULL, 0},
|
{"3DRenderer", 0, &_3DRenderer, 0},
|
||||||
{"Threaded3D", 0, &Threaded3D, 1, NULL, 0},
|
{"Threaded3D", 1, &Threaded3D, true},
|
||||||
|
|
||||||
{"GL_ScaleFactor", 0, &GL_ScaleFactor, 1, NULL, 0},
|
{"GL_ScaleFactor", 0, &GL_ScaleFactor, 1},
|
||||||
{"GL_BetterPolygons", 0, &GL_BetterPolygons, 0, NULL, 0},
|
{"GL_BetterPolygons", 1, &GL_BetterPolygons, false},
|
||||||
|
|
||||||
{"LimitFPS", 0, &LimitFPS, 1, NULL, 0},
|
{"LimitFPS", 1, &LimitFPS, true},
|
||||||
{"AudioSync", 0, &AudioSync, 0, NULL, 0},
|
{"AudioSync", 1, &AudioSync, false},
|
||||||
{"ShowOSD", 0, &ShowOSD, 1, NULL, 0},
|
{"ShowOSD", 1, &ShowOSD, true},
|
||||||
|
|
||||||
{"ConsoleType", 0, &ConsoleType, 0, NULL, 0},
|
{"ConsoleType", 0, &ConsoleType, 0},
|
||||||
{"DirectBoot", 0, &DirectBoot, 1, NULL, 0},
|
{"DirectBoot", 1, &DirectBoot, true},
|
||||||
|
|
||||||
#ifdef JIT_ENABLED
|
#ifdef JIT_ENABLED
|
||||||
{"JIT_Enable", 0, &JIT_Enable, 0, NULL, 0},
|
{"JIT_Enable", 1, &JIT_Enable, false},
|
||||||
{"JIT_MaxBlockSize", 0, &JIT_MaxBlockSize, 32, NULL, 0},
|
{"JIT_MaxBlockSize", 0, &JIT_MaxBlockSize, 32},
|
||||||
{"JIT_BranchOptimisations", 0, &JIT_BranchOptimisations, 1, NULL, 0},
|
{"JIT_BranchOptimisations", 1, &JIT_BranchOptimisations, true},
|
||||||
{"JIT_LiteralOptimisations", 0, &JIT_LiteralOptimisations, 1, NULL, 0},
|
{"JIT_LiteralOptimisations", 1, &JIT_LiteralOptimisations, true},
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
{"JIT_FastMemory", 0, &JIT_FastMemory, 0, NULL, 0},
|
{"JIT_FastMemory", 1, &JIT_FastMemory, false},
|
||||||
#else
|
#else
|
||||||
{"JIT_FastMemory", 0, &JIT_FastMemory, 1, NULL, 0},
|
{"JIT_FastMemory", 1, &JIT_FastMemory, true},
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{"ExternalBIOSEnable", 0, &ExternalBIOSEnable, 0, NULL, 0},
|
{"ExternalBIOSEnable", 1, &ExternalBIOSEnable, false},
|
||||||
|
|
||||||
{"BIOS9Path", 1, BIOS9Path, 0, "", 1023},
|
{"BIOS9Path", 2, &BIOS9Path, ""},
|
||||||
{"BIOS7Path", 1, BIOS7Path, 0, "", 1023},
|
{"BIOS7Path", 2, &BIOS7Path, ""},
|
||||||
{"FirmwarePath", 1, FirmwarePath, 0, "", 1023},
|
{"FirmwarePath", 2, &FirmwarePath, ""},
|
||||||
|
|
||||||
{"DSiBIOS9Path", 1, DSiBIOS9Path, 0, "", 1023},
|
{"DSiBIOS9Path", 2, &DSiBIOS9Path, ""},
|
||||||
{"DSiBIOS7Path", 1, DSiBIOS7Path, 0, "", 1023},
|
{"DSiBIOS7Path", 2, &DSiBIOS7Path, ""},
|
||||||
{"DSiFirmwarePath", 1, DSiFirmwarePath, 0, "", 1023},
|
{"DSiFirmwarePath", 2, &DSiFirmwarePath, ""},
|
||||||
{"DSiNANDPath", 1, DSiNANDPath, 0, "", 1023},
|
{"DSiNANDPath", 2, &DSiNANDPath, ""},
|
||||||
|
|
||||||
{"DLDIEnable", 0, &DLDIEnable, 0, NULL, 0},
|
{"DLDIEnable", 1, &DLDIEnable, false},
|
||||||
{"DLDISDPath", 1, DLDISDPath, 0, "dldi.bin", 1023},
|
{"DLDISDPath", 2, &DLDISDPath, "dldi.bin"},
|
||||||
{"DLDISize", 0, &DLDISize, 0, NULL, 0},
|
{"DLDISize", 0, &DLDISize, 0},
|
||||||
{"DLDIReadOnly", 0, &DLDIReadOnly, 0, NULL, 0},
|
{"DLDIReadOnly", 1, &DLDIReadOnly, false},
|
||||||
{"DLDIFolderSync", 0, &DLDIFolderSync, 0, NULL, 0},
|
{"DLDIFolderSync", 1, &DLDIFolderSync, false},
|
||||||
{"DLDIFolderPath", 1, DLDIFolderPath, 0, "", 1023},
|
{"DLDIFolderPath", 2, &DLDIFolderPath, ""},
|
||||||
|
|
||||||
{"DSiSDEnable", 0, &DSiSDEnable, 0, NULL, 0},
|
{"DSiSDEnable", 1, &DSiSDEnable, false},
|
||||||
{"DSiSDPath", 1, DSiSDPath, 0, "dsisd.bin", 1023},
|
{"DSiSDPath", 2, &DSiSDPath, "dsisd.bin"},
|
||||||
{"DSiSDSize", 0, &DSiSDSize, 0, NULL, 0},
|
{"DSiSDSize", 0, &DSiSDSize, 0},
|
||||||
{"DSiSDReadOnly", 0, &DSiSDReadOnly, 0, NULL, 0},
|
{"DSiSDReadOnly", 1, &DSiSDReadOnly, false},
|
||||||
{"DSiSDFolderSync", 0, &DSiSDFolderSync, 0, NULL, 0},
|
{"DSiSDFolderSync", 1, &DSiSDFolderSync, false},
|
||||||
{"DSiSDFolderPath", 1, DSiSDFolderPath, 0, "", 1023},
|
{"DSiSDFolderPath", 2, &DSiSDFolderPath, ""},
|
||||||
|
|
||||||
{"FirmwareOverrideSettings", 0, &FirmwareOverrideSettings, false, NULL, 0},
|
{"FirmwareOverrideSettings", 1, &FirmwareOverrideSettings, false},
|
||||||
{"FirmwareUsername", 1, FirmwareUsername, 0, "melonDS", 63},
|
{"FirmwareUsername", 2, &FirmwareUsername, "melonDS"},
|
||||||
{"FirmwareLanguage", 0, &FirmwareLanguage, 1, NULL, 0},
|
{"FirmwareLanguage", 0, &FirmwareLanguage, 1},
|
||||||
{"FirmwareBirthdayMonth", 0, &FirmwareBirthdayMonth, 0, NULL, 0},
|
{"FirmwareBirthdayMonth", 0, &FirmwareBirthdayMonth, 1},
|
||||||
{"FirmwareBirthdayDay", 0, &FirmwareBirthdayDay, 0, NULL, 0},
|
{"FirmwareBirthdayDay", 0, &FirmwareBirthdayDay, 1},
|
||||||
{"FirmwareFavouriteColour", 0, &FirmwareFavouriteColour, 0, NULL, 0},
|
{"FirmwareFavouriteColour", 0, &FirmwareFavouriteColour, 0},
|
||||||
{"FirmwareMessage", 1, FirmwareMessage, 0, "", 1023},
|
{"FirmwareMessage", 2, &FirmwareMessage, ""},
|
||||||
{"FirmwareMAC", 1, FirmwareMAC, 0, "", 17},
|
{"FirmwareMAC", 2, &FirmwareMAC, ""},
|
||||||
{"RandomizeMAC", 0, &RandomizeMAC, 0, NULL, 0},
|
{"RandomizeMAC", 1, &RandomizeMAC, false},
|
||||||
|
|
||||||
{"SockBindAnyAddr", 0, &SocketBindAnyAddr, 0, NULL, 0},
|
{"SockBindAnyAddr", 1, &SocketBindAnyAddr, false},
|
||||||
{"LANDevice", 1, LANDevice, 0, "", 127},
|
{"LANDevice", 2, &LANDevice, ""},
|
||||||
{"DirectLAN", 0, &DirectLAN, 0, NULL, 0},
|
{"DirectLAN", 1, &DirectLAN, false},
|
||||||
|
|
||||||
{"SavStaRelocSRAM", 0, &SavestateRelocSRAM, 0, NULL, 0},
|
{"SavStaRelocSRAM", 1, &SavestateRelocSRAM, false},
|
||||||
|
|
||||||
{"AudioInterp", 0, &AudioInterp, 0, NULL, 0},
|
{"AudioInterp", 0, &AudioInterp, 0},
|
||||||
{"AudioBitrate", 0, &AudioBitrate, 0, NULL, 0},
|
{"AudioBitrate", 0, &AudioBitrate, 0},
|
||||||
{"AudioVolume", 0, &AudioVolume, 256, NULL, 0},
|
{"AudioVolume", 0, &AudioVolume, 256},
|
||||||
{"MicInputType", 0, &MicInputType, 1, NULL, 0},
|
{"MicInputType", 0, &MicInputType, 1},
|
||||||
{"MicWavPath", 1, MicWavPath, 0, "", 1023},
|
{"MicWavPath", 2, &MicWavPath, ""},
|
||||||
|
|
||||||
{"LastROMFolder", 1, LastROMFolder, 0, "", 1023},
|
{"LastROMFolder", 2, &LastROMFolder, ""},
|
||||||
|
|
||||||
{"RecentROM_0", 1, RecentROMList[0], 0, "", 1023},
|
{"RecentROM_0", 2, &RecentROMList[0], ""},
|
||||||
{"RecentROM_1", 1, RecentROMList[1], 0, "", 1023},
|
{"RecentROM_1", 2, &RecentROMList[1], ""},
|
||||||
{"RecentROM_2", 1, RecentROMList[2], 0, "", 1023},
|
{"RecentROM_2", 2, &RecentROMList[2], ""},
|
||||||
{"RecentROM_3", 1, RecentROMList[3], 0, "", 1023},
|
{"RecentROM_3", 2, &RecentROMList[3], ""},
|
||||||
{"RecentROM_4", 1, RecentROMList[4], 0, "", 1023},
|
{"RecentROM_4", 2, &RecentROMList[4], ""},
|
||||||
{"RecentROM_5", 1, RecentROMList[5], 0, "", 1023},
|
{"RecentROM_5", 2, &RecentROMList[5], ""},
|
||||||
{"RecentROM_6", 1, RecentROMList[6], 0, "", 1023},
|
{"RecentROM_6", 2, &RecentROMList[6], ""},
|
||||||
{"RecentROM_7", 1, RecentROMList[7], 0, "", 1023},
|
{"RecentROM_7", 2, &RecentROMList[7], ""},
|
||||||
{"RecentROM_8", 1, RecentROMList[8], 0, "", 1023},
|
{"RecentROM_8", 2, &RecentROMList[8], ""},
|
||||||
{"RecentROM_9", 1, RecentROMList[9], 0, "", 1023},
|
{"RecentROM_9", 2, &RecentROMList[9], ""},
|
||||||
|
|
||||||
{"EnableCheats", 0, &EnableCheats, 0, NULL, 0},
|
{"SaveFilePath", 2, &SaveFilePath, ""},
|
||||||
|
{"SavestatePath", 2, &SavestatePath, ""},
|
||||||
|
{"CheatFilePath", 2, &CheatFilePath, ""},
|
||||||
|
|
||||||
{"MouseHide", 0, &MouseHide, 0, NULL, 0},
|
{"EnableCheats", 1, &EnableCheats, false},
|
||||||
{"MouseHideSeconds", 0, &MouseHideSeconds, 5, NULL, 0},
|
|
||||||
{"PauseLostFocus", 0, &PauseLostFocus, 0, NULL, 0},
|
|
||||||
|
|
||||||
{"", -1, NULL, 0, NULL, 0}
|
{"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->Value) break;
|
||||||
|
|
||||||
if (entry->Type == 0)
|
switch (entry->Type)
|
||||||
*(int*)entry->Value = entry->DefaultInt;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
strncpy((char*)entry->Value, entry->DefaultStr, entry->StrLength);
|
case 0: *(int*)entry->Value = std::get<int>(entry->Default); break;
|
||||||
((char*)entry->Value)[entry->StrLength] = '\0';
|
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++;
|
entry++;
|
||||||
|
@ -341,10 +348,12 @@ void Load()
|
||||||
|
|
||||||
if (!strncmp(entry->Name, entryname, 32))
|
if (!strncmp(entry->Name, entryname, 32))
|
||||||
{
|
{
|
||||||
if (entry->Type == 0)
|
switch (entry->Type)
|
||||||
*(int*)entry->Value = strtol(entryval, NULL, 10);
|
{
|
||||||
else
|
case 0: *(int*)entry->Value = strtol(entryval, NULL, 10); break;
|
||||||
strncpy((char*)entry->Value, entryval, entry->StrLength);
|
case 1: *(bool*)entry->Value = strtol(entryval, NULL, 10) ? true:false; break;
|
||||||
|
case 2: *(std::string*)entry->Value = entryval; break;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -366,10 +375,12 @@ void Save()
|
||||||
{
|
{
|
||||||
if (!entry->Value) break;
|
if (!entry->Value) break;
|
||||||
|
|
||||||
if (entry->Type == 0)
|
switch (entry->Type)
|
||||||
fprintf(f, "%s=%d\r\n", entry->Name, *(int*)entry->Value);
|
{
|
||||||
else
|
case 0: fprintf(f, "%s=%d\r\n", entry->Name, *(int*)entry->Value); break;
|
||||||
fprintf(f, "%s=%s\r\n", entry->Name, (char*)entry->Value);
|
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++;
|
entry++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
#ifndef PLATFORMCONFIG_H
|
#ifndef PLATFORMCONFIG_H
|
||||||
#define PLATFORMCONFIG_H
|
#define PLATFORMCONFIG_H
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
HK_Lid = 0,
|
HK_Lid = 0,
|
||||||
|
@ -41,11 +44,9 @@ namespace Config
|
||||||
struct ConfigEntry
|
struct ConfigEntry
|
||||||
{
|
{
|
||||||
char Name[32];
|
char Name[32];
|
||||||
int Type;
|
int Type; // 0=int 1=bool 2=string
|
||||||
void* Value;
|
void* Value; // pointer to the value variable
|
||||||
int DefaultInt;
|
std::variant<int, bool, std::string> Default;
|
||||||
const char* DefaultStr;
|
|
||||||
int StrLength; // should be set to actual array length minus one
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,99 +60,103 @@ extern int JoystickID;
|
||||||
|
|
||||||
extern int WindowWidth;
|
extern int WindowWidth;
|
||||||
extern int WindowHeight;
|
extern int WindowHeight;
|
||||||
extern int WindowMaximized;
|
extern bool WindowMaximized;
|
||||||
|
|
||||||
extern int ScreenRotation;
|
extern int ScreenRotation;
|
||||||
extern int ScreenGap;
|
extern int ScreenGap;
|
||||||
extern int ScreenLayout;
|
extern int ScreenLayout;
|
||||||
extern int ScreenSwap;
|
extern bool ScreenSwap;
|
||||||
extern int ScreenSizing;
|
extern int ScreenSizing;
|
||||||
extern int ScreenAspectTop;
|
extern int ScreenAspectTop;
|
||||||
extern int ScreenAspectBot;
|
extern int ScreenAspectBot;
|
||||||
extern int IntegerScaling;
|
extern bool IntegerScaling;
|
||||||
extern int ScreenFilter;
|
extern bool ScreenFilter;
|
||||||
|
|
||||||
extern int ScreenUseGL;
|
extern bool ScreenUseGL;
|
||||||
extern int ScreenVSync;
|
extern bool ScreenVSync;
|
||||||
extern int ScreenVSyncInterval;
|
extern int ScreenVSyncInterval;
|
||||||
|
|
||||||
extern int _3DRenderer;
|
extern int _3DRenderer;
|
||||||
extern int Threaded3D;
|
extern bool Threaded3D;
|
||||||
|
|
||||||
extern int GL_ScaleFactor;
|
extern int GL_ScaleFactor;
|
||||||
extern int GL_BetterPolygons;
|
extern bool GL_BetterPolygons;
|
||||||
|
|
||||||
extern int LimitFPS;
|
extern bool LimitFPS;
|
||||||
extern int AudioSync;
|
extern bool AudioSync;
|
||||||
extern int ShowOSD;
|
extern bool ShowOSD;
|
||||||
|
|
||||||
extern int ConsoleType;
|
extern int ConsoleType;
|
||||||
extern int DirectBoot;
|
extern bool DirectBoot;
|
||||||
|
|
||||||
#ifdef JIT_ENABLED
|
#ifdef JIT_ENABLED
|
||||||
extern int JIT_Enable;
|
extern bool JIT_Enable;
|
||||||
extern int JIT_MaxBlockSize;
|
extern int JIT_MaxBlockSize;
|
||||||
extern int JIT_BranchOptimisations;
|
extern bool JIT_BranchOptimisations;
|
||||||
extern int JIT_LiteralOptimisations;
|
extern bool JIT_LiteralOptimisations;
|
||||||
extern int JIT_FastMemory;
|
extern bool JIT_FastMemory;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern int ExternalBIOSEnable;
|
extern bool ExternalBIOSEnable;
|
||||||
|
|
||||||
extern char BIOS9Path[1024];
|
extern std::string BIOS9Path;
|
||||||
extern char BIOS7Path[1024];
|
extern std::string BIOS7Path;
|
||||||
extern char FirmwarePath[1024];
|
extern std::string FirmwarePath;
|
||||||
|
|
||||||
extern char DSiBIOS9Path[1024];
|
extern std::string DSiBIOS9Path;
|
||||||
extern char DSiBIOS7Path[1024];
|
extern std::string DSiBIOS7Path;
|
||||||
extern char DSiFirmwarePath[1024];
|
extern std::string DSiFirmwarePath;
|
||||||
extern char DSiNANDPath[1024];
|
extern std::string DSiNANDPath;
|
||||||
|
|
||||||
extern int DLDIEnable;
|
extern bool DLDIEnable;
|
||||||
extern char DLDISDPath[1024];
|
extern std::string DLDISDPath;
|
||||||
extern int DLDISize;
|
extern int DLDISize;
|
||||||
extern int DLDIReadOnly;
|
extern bool DLDIReadOnly;
|
||||||
extern int DLDIFolderSync;
|
extern bool DLDIFolderSync;
|
||||||
extern char DLDIFolderPath[1024];
|
extern std::string DLDIFolderPath;
|
||||||
|
|
||||||
extern int DSiSDEnable;
|
extern bool DSiSDEnable;
|
||||||
extern char DSiSDPath[1024];
|
extern std::string DSiSDPath;
|
||||||
extern int DSiSDSize;
|
extern int DSiSDSize;
|
||||||
extern int DSiSDReadOnly;
|
extern bool DSiSDReadOnly;
|
||||||
extern int DSiSDFolderSync;
|
extern bool DSiSDFolderSync;
|
||||||
extern char DSiSDFolderPath[1024];
|
extern std::string DSiSDFolderPath;
|
||||||
|
|
||||||
extern int FirmwareOverrideSettings;
|
extern bool FirmwareOverrideSettings;
|
||||||
extern char FirmwareUsername[64];
|
extern std::string FirmwareUsername;
|
||||||
extern int FirmwareLanguage;
|
extern int FirmwareLanguage;
|
||||||
extern int FirmwareBirthdayMonth;
|
extern int FirmwareBirthdayMonth;
|
||||||
extern int FirmwareBirthdayDay;
|
extern int FirmwareBirthdayDay;
|
||||||
extern int FirmwareFavouriteColour;
|
extern int FirmwareFavouriteColour;
|
||||||
extern char FirmwareMessage[1024];
|
extern std::string FirmwareMessage;
|
||||||
extern char FirmwareMAC[18];
|
extern std::string FirmwareMAC;
|
||||||
extern int RandomizeMAC;
|
extern bool RandomizeMAC;
|
||||||
|
|
||||||
extern int SocketBindAnyAddr;
|
extern bool SocketBindAnyAddr;
|
||||||
extern char LANDevice[128];
|
extern std::string LANDevice;
|
||||||
extern int DirectLAN;
|
extern bool DirectLAN;
|
||||||
|
|
||||||
extern int SavestateRelocSRAM;
|
extern bool SavestateRelocSRAM;
|
||||||
|
|
||||||
extern int AudioInterp;
|
extern int AudioInterp;
|
||||||
extern int AudioBitrate;
|
extern int AudioBitrate;
|
||||||
extern int AudioVolume;
|
extern int AudioVolume;
|
||||||
extern int MicInputType;
|
extern int MicInputType;
|
||||||
extern char MicWavPath[1024];
|
extern std::string MicWavPath;
|
||||||
|
|
||||||
extern char LastROMFolder[1024];
|
extern std::string LastROMFolder;
|
||||||
|
|
||||||
extern char RecentROMList[10][1024];
|
extern std::string RecentROMList[10];
|
||||||
|
|
||||||
extern int EnableCheats;
|
extern std::string SaveFilePath;
|
||||||
|
extern std::string SavestatePath;
|
||||||
|
extern std::string CheatFilePath;
|
||||||
|
|
||||||
extern int MouseHide;
|
extern bool EnableCheats;
|
||||||
|
|
||||||
|
extern bool MouseHide;
|
||||||
extern int MouseHideSeconds;
|
extern int MouseHideSeconds;
|
||||||
extern int PauseLostFocus;
|
extern bool PauseLostFocus;
|
||||||
|
|
||||||
|
|
||||||
void Load();
|
void Load();
|
||||||
|
|
|
@ -42,27 +42,27 @@ EmuSettingsDialog::EmuSettingsDialog(QWidget* parent) : QDialog(parent), ui(new
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
ui->chkExternalBIOS->setChecked(Config::ExternalBIOSEnable != 0);
|
ui->chkExternalBIOS->setChecked(Config::ExternalBIOSEnable);
|
||||||
ui->txtBIOS9Path->setText(Config::BIOS9Path);
|
ui->txtBIOS9Path->setText(QString::fromStdString(Config::BIOS9Path));
|
||||||
ui->txtBIOS7Path->setText(Config::BIOS7Path);
|
ui->txtBIOS7Path->setText(QString::fromStdString(Config::BIOS7Path));
|
||||||
ui->txtFirmwarePath->setText(Config::FirmwarePath);
|
ui->txtFirmwarePath->setText(QString::fromStdString(Config::FirmwarePath));
|
||||||
|
|
||||||
ui->txtDSiBIOS9Path->setText(Config::DSiBIOS9Path);
|
ui->txtDSiBIOS9Path->setText(QString::fromStdString(Config::DSiBIOS9Path));
|
||||||
ui->txtDSiBIOS7Path->setText(Config::DSiBIOS7Path);
|
ui->txtDSiBIOS7Path->setText(QString::fromStdString(Config::DSiBIOS7Path));
|
||||||
ui->txtDSiFirmwarePath->setText(Config::DSiFirmwarePath);
|
ui->txtDSiFirmwarePath->setText(QString::fromStdString(Config::DSiFirmwarePath));
|
||||||
ui->txtDSiNANDPath->setText(Config::DSiNANDPath);
|
ui->txtDSiNANDPath->setText(QString::fromStdString(Config::DSiNANDPath));
|
||||||
|
|
||||||
ui->cbxConsoleType->addItem("DS");
|
ui->cbxConsoleType->addItem("DS");
|
||||||
ui->cbxConsoleType->addItem("DSi (experimental)");
|
ui->cbxConsoleType->addItem("DSi (experimental)");
|
||||||
ui->cbxConsoleType->setCurrentIndex(Config::ConsoleType);
|
ui->cbxConsoleType->setCurrentIndex(Config::ConsoleType);
|
||||||
|
|
||||||
ui->chkDirectBoot->setChecked(Config::DirectBoot != 0);
|
ui->chkDirectBoot->setChecked(Config::DirectBoot);
|
||||||
|
|
||||||
#ifdef JIT_ENABLED
|
#ifdef JIT_ENABLED
|
||||||
ui->chkEnableJIT->setChecked(Config::JIT_Enable != 0);
|
ui->chkEnableJIT->setChecked(Config::JIT_Enable);
|
||||||
ui->chkJITBranchOptimisations->setChecked(Config::JIT_BranchOptimisations != 0);
|
ui->chkJITBranchOptimisations->setChecked(Config::JIT_BranchOptimisations);
|
||||||
ui->chkJITLiteralOptimisations->setChecked(Config::JIT_LiteralOptimisations != 0);
|
ui->chkJITLiteralOptimisations->setChecked(Config::JIT_LiteralOptimisations);
|
||||||
ui->chkJITFastMemory->setChecked(Config::JIT_FastMemory != 0);
|
ui->chkJITFastMemory->setChecked(Config::JIT_FastMemory);
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
ui->chkJITFastMemory->setDisabled(true);
|
ui->chkJITFastMemory->setDisabled(true);
|
||||||
#endif
|
#endif
|
||||||
|
@ -101,20 +101,20 @@ EmuSettingsDialog::EmuSettingsDialog(QWidget* parent) : QDialog(parent), ui(new
|
||||||
ui->cbxDSiSDSize->addItem(sizelbl);
|
ui->cbxDSiSDSize->addItem(sizelbl);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->cbDLDIEnable->setChecked(Config::DLDIEnable != 0);
|
ui->cbDLDIEnable->setChecked(Config::DLDIEnable);
|
||||||
ui->txtDLDISDPath->setText(Config::DLDISDPath);
|
ui->txtDLDISDPath->setText(QString::fromStdString(Config::DLDISDPath));
|
||||||
ui->cbxDLDISize->setCurrentIndex(Config::DLDISize);
|
ui->cbxDLDISize->setCurrentIndex(Config::DLDISize);
|
||||||
ui->cbDLDIReadOnly->setChecked(Config::DLDIReadOnly != 0);
|
ui->cbDLDIReadOnly->setChecked(Config::DLDIReadOnly);
|
||||||
ui->cbDLDIFolder->setChecked(Config::DLDIFolderSync != 0);
|
ui->cbDLDIFolder->setChecked(Config::DLDIFolderSync);
|
||||||
ui->txtDLDIFolder->setText(Config::DLDIFolderPath);
|
ui->txtDLDIFolder->setText(QString::fromStdString(Config::DLDIFolderPath));
|
||||||
on_cbDLDIEnable_toggled();
|
on_cbDLDIEnable_toggled();
|
||||||
|
|
||||||
ui->cbDSiSDEnable->setChecked(Config::DSiSDEnable != 0);
|
ui->cbDSiSDEnable->setChecked(Config::DSiSDEnable);
|
||||||
ui->txtDSiSDPath->setText(Config::DSiSDPath);
|
ui->txtDSiSDPath->setText(QString::fromStdString(Config::DSiSDPath));
|
||||||
ui->cbxDSiSDSize->setCurrentIndex(Config::DSiSDSize);
|
ui->cbxDSiSDSize->setCurrentIndex(Config::DSiSDSize);
|
||||||
ui->cbDSiSDReadOnly->setChecked(Config::DSiSDReadOnly != 0);
|
ui->cbDSiSDReadOnly->setChecked(Config::DSiSDReadOnly);
|
||||||
ui->cbDSiSDFolder->setChecked(Config::DSiSDFolderSync != 0);
|
ui->cbDSiSDFolder->setChecked(Config::DSiSDFolderSync);
|
||||||
ui->txtDSiSDFolder->setText(Config::DSiSDFolderPath);
|
ui->txtDSiSDFolder->setText(QString::fromStdString(Config::DSiSDFolderPath));
|
||||||
on_cbDSiSDEnable_toggled();
|
on_cbDSiSDEnable_toggled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,8 +140,7 @@ void EmuSettingsDialog::verifyFirmware()
|
||||||
// looked at has 0x180 bytes from the header repeated at 0x3FC80, but
|
// looked at has 0x180 bytes from the header repeated at 0x3FC80, but
|
||||||
// bytes 0x0C-0x14 are different.
|
// bytes 0x0C-0x14 are different.
|
||||||
|
|
||||||
char filename[1024];
|
std::string filename = ui->txtFirmwarePath->text().toStdString();
|
||||||
strncpy(filename, ui->txtFirmwarePath->text().toStdString().c_str(), 1023); filename[1023] = '\0';
|
|
||||||
FILE* f = Platform::OpenLocalFile(filename, "rb");
|
FILE* f = Platform::OpenLocalFile(filename, "rb");
|
||||||
if (!f) return;
|
if (!f) return;
|
||||||
u8 chk1[0x180], chk2[0x180];
|
u8 chk1[0x180], chk2[0x180];
|
||||||
|
@ -175,24 +174,24 @@ void EmuSettingsDialog::done(int r)
|
||||||
verifyFirmware();
|
verifyFirmware();
|
||||||
|
|
||||||
int consoleType = ui->cbxConsoleType->currentIndex();
|
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 jitMaxBlockSize = ui->spnJITMaximumBlockSize->value();
|
||||||
int jitBranchOptimisations = ui->chkJITBranchOptimisations->isChecked() ? 1:0;
|
bool jitBranchOptimisations = ui->chkJITBranchOptimisations->isChecked();
|
||||||
int jitLiteralOptimisations = ui->chkJITLiteralOptimisations->isChecked() ? 1:0;
|
bool jitLiteralOptimisations = ui->chkJITLiteralOptimisations->isChecked();
|
||||||
int jitFastMemory = ui->chkJITFastMemory->isChecked() ? 1:0;
|
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 bios9Path = ui->txtBIOS9Path->text().toStdString();
|
||||||
std::string bios7Path = ui->txtBIOS7Path->text().toStdString();
|
std::string bios7Path = ui->txtBIOS7Path->text().toStdString();
|
||||||
std::string firmwarePath = ui->txtFirmwarePath->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();
|
std::string dldiSDPath = ui->txtDLDISDPath->text().toStdString();
|
||||||
int dldiSize = ui->cbxDLDISize->currentIndex();
|
int dldiSize = ui->cbxDLDISize->currentIndex();
|
||||||
int dldiReadOnly = ui->cbDLDIReadOnly->isChecked() ? 1:0;
|
bool dldiReadOnly = ui->cbDLDIReadOnly->isChecked();
|
||||||
int dldiFolderSync = ui->cbDLDIFolder->isChecked() ? 1:0;
|
bool dldiFolderSync = ui->cbDLDIFolder->isChecked();
|
||||||
std::string dldiFolderPath = ui->txtDLDIFolder->text().toStdString();
|
std::string dldiFolderPath = ui->txtDLDIFolder->text().toStdString();
|
||||||
|
|
||||||
std::string dsiBios9Path = ui->txtDSiBIOS9Path->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 dsiFirmwarePath = ui->txtDSiFirmwarePath->text().toStdString();
|
||||||
std::string dsiNANDPath = ui->txtDSiNANDPath->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();
|
std::string dsiSDPath = ui->txtDSiSDPath->text().toStdString();
|
||||||
int dsiSDSize = ui->cbxDSiSDSize->currentIndex();
|
int dsiSDSize = ui->cbxDSiSDSize->currentIndex();
|
||||||
int dsiSDReadOnly = ui->cbDSiSDReadOnly->isChecked() ? 1:0;
|
bool dsiSDReadOnly = ui->cbDSiSDReadOnly->isChecked();
|
||||||
int dsiSDFolderSync = ui->cbDSiSDFolder->isChecked() ? 1:0;
|
bool dsiSDFolderSync = ui->cbDSiSDFolder->isChecked();
|
||||||
std::string dsiSDFolderPath = ui->txtDSiSDFolder->text().toStdString();
|
std::string dsiSDFolderPath = ui->txtDSiSDFolder->text().toStdString();
|
||||||
|
|
||||||
if (consoleType != Config::ConsoleType
|
if (consoleType != Config::ConsoleType
|
||||||
|
@ -217,25 +216,25 @@ void EmuSettingsDialog::done(int r)
|
||||||
|| jitFastMemory != Config::JIT_FastMemory
|
|| jitFastMemory != Config::JIT_FastMemory
|
||||||
#endif
|
#endif
|
||||||
|| externalBiosEnable != Config::ExternalBIOSEnable
|
|| externalBiosEnable != Config::ExternalBIOSEnable
|
||||||
|| strcmp(Config::BIOS9Path, bios9Path.c_str()) != 0
|
|| bios9Path != Config::BIOS9Path
|
||||||
|| strcmp(Config::BIOS7Path, bios7Path.c_str()) != 0
|
|| bios7Path != Config::BIOS7Path
|
||||||
|| strcmp(Config::FirmwarePath, firmwarePath.c_str()) != 0
|
|| firmwarePath != Config::FirmwarePath
|
||||||
|| dldiEnable != Config::DLDIEnable
|
|| dldiEnable != Config::DLDIEnable
|
||||||
|| strcmp(Config::DLDISDPath, dldiSDPath.c_str()) != 0
|
|| dldiSDPath != Config::DLDISDPath
|
||||||
|| dldiSize != Config::DLDISize
|
|| dldiSize != Config::DLDISize
|
||||||
|| dldiReadOnly != Config::DLDIReadOnly
|
|| dldiReadOnly != Config::DLDIReadOnly
|
||||||
|| dldiFolderSync != Config::DLDIFolderSync
|
|| dldiFolderSync != Config::DLDIFolderSync
|
||||||
|| strcmp(Config::DLDIFolderPath, dldiFolderPath.c_str()) != 0
|
|| dldiFolderPath != Config::DLDIFolderPath
|
||||||
|| strcmp(Config::DSiBIOS9Path, dsiBios9Path.c_str()) != 0
|
|| dsiBios9Path != Config::DSiBIOS9Path
|
||||||
|| strcmp(Config::DSiBIOS7Path, dsiBios7Path.c_str()) != 0
|
|| dsiBios7Path != Config::DSiBIOS7Path
|
||||||
|| strcmp(Config::DSiFirmwarePath, dsiFirmwarePath.c_str()) != 0
|
|| dsiFirmwarePath != Config::DSiFirmwarePath
|
||||||
|| strcmp(Config::DSiNANDPath, dsiNANDPath.c_str()) != 0
|
|| dsiNANDPath != Config::DSiNANDPath
|
||||||
|| dsiSDEnable != Config::DSiSDEnable
|
|| dsiSDEnable != Config::DSiSDEnable
|
||||||
|| strcmp(Config::DSiSDPath, dsiSDPath.c_str()) != 0
|
|| dsiSDPath != Config::DSiSDPath
|
||||||
|| dsiSDSize != Config::DSiSDSize
|
|| dsiSDSize != Config::DSiSDSize
|
||||||
|| dsiSDReadOnly != Config::DSiSDReadOnly
|
|| dsiSDReadOnly != Config::DSiSDReadOnly
|
||||||
|| dsiSDFolderSync != Config::DSiSDFolderSync
|
|| dsiSDFolderSync != Config::DSiSDFolderSync
|
||||||
|| strcmp(Config::DSiSDFolderPath, dsiSDFolderPath.c_str()) != 0)
|
|| dsiSDFolderPath != Config::DSiSDFolderPath)
|
||||||
{
|
{
|
||||||
if (RunningSomething
|
if (RunningSomething
|
||||||
&& QMessageBox::warning(this, "Reset necessary to apply changes",
|
&& QMessageBox::warning(this, "Reset necessary to apply changes",
|
||||||
|
@ -244,28 +243,28 @@ void EmuSettingsDialog::done(int r)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Config::ExternalBIOSEnable = externalBiosEnable;
|
Config::ExternalBIOSEnable = externalBiosEnable;
|
||||||
strncpy(Config::BIOS9Path, bios9Path.c_str(), 1023); Config::BIOS9Path[1023] = '\0';
|
Config::BIOS9Path = bios9Path;
|
||||||
strncpy(Config::BIOS7Path, bios7Path.c_str(), 1023); Config::BIOS7Path[1023] = '\0';
|
Config::BIOS7Path = bios7Path;
|
||||||
strncpy(Config::FirmwarePath, firmwarePath.c_str(), 1023); Config::FirmwarePath[1023] = '\0';
|
Config::FirmwarePath = firmwarePath;
|
||||||
|
|
||||||
Config::DLDIEnable = dldiEnable;
|
Config::DLDIEnable = dldiEnable;
|
||||||
strncpy(Config::DLDISDPath, dldiSDPath.c_str(), 1023); Config::DLDISDPath[1023] = '\0';
|
Config::DLDISDPath = dldiSDPath;
|
||||||
Config::DLDISize = dldiSize;
|
Config::DLDISize = dldiSize;
|
||||||
Config::DLDIReadOnly = dldiReadOnly;
|
Config::DLDIReadOnly = dldiReadOnly;
|
||||||
Config::DLDIFolderSync = dldiFolderSync;
|
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';
|
Config::DSiBIOS9Path = dsiBios9Path;
|
||||||
strncpy(Config::DSiBIOS7Path, dsiBios7Path.c_str(), 1023); Config::DSiBIOS7Path[1023] = '\0';
|
Config::DSiBIOS7Path = dsiBios7Path;
|
||||||
strncpy(Config::DSiFirmwarePath, dsiFirmwarePath.c_str(), 1023); Config::DSiFirmwarePath[1023] = '\0';
|
Config::DSiFirmwarePath = dsiFirmwarePath;
|
||||||
strncpy(Config::DSiNANDPath, dsiNANDPath.c_str(), 1023); Config::DSiNANDPath[1023] = '\0';
|
Config::DSiNANDPath = dsiNANDPath;
|
||||||
|
|
||||||
Config::DSiSDEnable = dsiSDEnable;
|
Config::DSiSDEnable = dsiSDEnable;
|
||||||
strncpy(Config::DSiSDPath, dsiSDPath.c_str(), 1023); Config::DSiSDPath[1023] = '\0';
|
Config::DSiSDPath = dsiSDPath;
|
||||||
Config::DSiSDSize = dsiSDSize;
|
Config::DSiSDSize = dsiSDSize;
|
||||||
Config::DSiSDReadOnly = dsiSDReadOnly;
|
Config::DSiSDReadOnly = dsiSDReadOnly;
|
||||||
Config::DSiSDFolderSync = dsiSDFolderSync;
|
Config::DSiSDFolderSync = dsiSDFolderSync;
|
||||||
strncpy(Config::DSiSDFolderPath, dsiSDFolderPath.c_str(), 1023); Config::DSiSDFolderPath[1023] = '\0';
|
Config::DSiSDFolderPath = dsiSDFolderPath;
|
||||||
|
|
||||||
#ifdef JIT_ENABLED
|
#ifdef JIT_ENABLED
|
||||||
Config::JIT_Enable = jitEnable;
|
Config::JIT_Enable = jitEnable;
|
||||||
|
|
|
@ -35,7 +35,7 @@ FirmwareSettingsDialog::FirmwareSettingsDialog(QWidget* parent) : QDialog(parent
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
|
||||||
ui->usernameEdit->setText(Config::FirmwareUsername);
|
ui->usernameEdit->setText(QString::fromStdString(Config::FirmwareUsername));
|
||||||
|
|
||||||
ui->languageBox->addItems(languages);
|
ui->languageBox->addItems(languages);
|
||||||
ui->languageBox->setCurrentIndex(Config::FirmwareLanguage);
|
ui->languageBox->setCurrentIndex(Config::FirmwareLanguage);
|
||||||
|
@ -59,12 +59,12 @@ FirmwareSettingsDialog::FirmwareSettingsDialog(QWidget* parent) : QDialog(parent
|
||||||
}
|
}
|
||||||
ui->colorsEdit->setCurrentIndex(Config::FirmwareFavouriteColour);
|
ui->colorsEdit->setCurrentIndex(Config::FirmwareFavouriteColour);
|
||||||
|
|
||||||
ui->messageEdit->setText(Config::FirmwareMessage);
|
ui->messageEdit->setText(QString::fromStdString(Config::FirmwareMessage));
|
||||||
|
|
||||||
ui->overrideFirmwareBox->setChecked(Config::FirmwareOverrideSettings);
|
ui->overrideFirmwareBox->setChecked(Config::FirmwareOverrideSettings);
|
||||||
|
|
||||||
ui->txtMAC->setText(Config::FirmwareMAC);
|
ui->txtMAC->setText(QString::fromStdString(Config::FirmwareMAC));
|
||||||
ui->cbRandomizeMAC->setChecked(Config::RandomizeMAC != 0);
|
ui->cbRandomizeMAC->setChecked(Config::RandomizeMAC);
|
||||||
on_cbRandomizeMAC_toggled();
|
on_cbRandomizeMAC_toggled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ void FirmwareSettingsDialog::done(int r)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int newOverride = ui->overrideFirmwareBox->isChecked();
|
bool newOverride = ui->overrideFirmwareBox->isChecked();
|
||||||
|
|
||||||
std::string newName = ui->usernameEdit->text().toStdString();
|
std::string newName = ui->usernameEdit->text().toStdString();
|
||||||
int newLanguage = ui->languageBox->currentIndex();
|
int newLanguage = ui->languageBox->currentIndex();
|
||||||
|
@ -133,16 +133,16 @@ void FirmwareSettingsDialog::done(int r)
|
||||||
std::string newMessage = ui->messageEdit->text().toStdString();
|
std::string newMessage = ui->messageEdit->text().toStdString();
|
||||||
|
|
||||||
std::string newMAC = ui->txtMAC->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
|
if ( newOverride != Config::FirmwareOverrideSettings
|
||||||
|| strcmp(newName.c_str(), Config::FirmwareUsername) != 0
|
|| newName != Config::FirmwareUsername
|
||||||
|| newLanguage != Config::FirmwareLanguage
|
|| newLanguage != Config::FirmwareLanguage
|
||||||
|| newFavColor != Config::FirmwareFavouriteColour
|
|| newFavColor != Config::FirmwareFavouriteColour
|
||||||
|| newBirthdayDay != Config::FirmwareBirthdayDay
|
|| newBirthdayDay != Config::FirmwareBirthdayDay
|
||||||
|| newBirthdayMonth != Config::FirmwareBirthdayMonth
|
|| newBirthdayMonth != Config::FirmwareBirthdayMonth
|
||||||
|| strcmp(newMessage.c_str(), Config::FirmwareMessage) != 0
|
|| newMessage != Config::FirmwareMessage
|
||||||
|| strcmp(newMAC.c_str(), Config::FirmwareMAC) != 0
|
|| newMAC != Config::FirmwareMAC
|
||||||
|| newRandomizeMAC != Config::RandomizeMAC)
|
|| newRandomizeMAC != Config::RandomizeMAC)
|
||||||
{
|
{
|
||||||
if (RunningSomething
|
if (RunningSomething
|
||||||
|
@ -153,14 +153,14 @@ void FirmwareSettingsDialog::done(int r)
|
||||||
|
|
||||||
Config::FirmwareOverrideSettings = newOverride;
|
Config::FirmwareOverrideSettings = newOverride;
|
||||||
|
|
||||||
strncpy(Config::FirmwareUsername, newName.c_str(), 63); Config::FirmwareUsername[63] = '\0';
|
Config::FirmwareUsername = newName;
|
||||||
Config::FirmwareLanguage = newLanguage;
|
Config::FirmwareLanguage = newLanguage;
|
||||||
Config::FirmwareFavouriteColour = newFavColor;
|
Config::FirmwareFavouriteColour = newFavColor;
|
||||||
Config::FirmwareBirthdayDay = newBirthdayDay;
|
Config::FirmwareBirthdayDay = newBirthdayDay;
|
||||||
Config::FirmwareBirthdayMonth = newBirthdayMonth;
|
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::RandomizeMAC = newRandomizeMAC;
|
||||||
|
|
||||||
Config::Save();
|
Config::Save();
|
||||||
|
|
|
@ -109,7 +109,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
currentDlg = new FirmwareSettingsDialog(parent);
|
currentDlg = new FirmwareSettingsDialog(parent);
|
||||||
currentDlg->show();
|
currentDlg->open();
|
||||||
return currentDlg;
|
return currentDlg;
|
||||||
}
|
}
|
||||||
static void closeDlg()
|
static void closeDlg()
|
||||||
|
|
|
@ -318,7 +318,7 @@ bool Init(bool open_adapter)
|
||||||
PCapAdapterData = &Adapters[0];
|
PCapAdapterData = &Adapters[0];
|
||||||
for (int i = 0; i < NumAdapters; i++)
|
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];
|
PCapAdapterData = &Adapters[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -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>
|
|
@ -52,6 +52,7 @@
|
||||||
|
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
#include "ROMManager.h"
|
||||||
#include "LAN_Socket.h"
|
#include "LAN_Socket.h"
|
||||||
#include "LAN_PCap.h"
|
#include "LAN_PCap.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -207,7 +208,7 @@ bool GetConfigArray(ConfigEntry entry, void* data)
|
||||||
{
|
{
|
||||||
case Firm_MAC:
|
case Firm_MAC:
|
||||||
{
|
{
|
||||||
char* mac_in = Config::FirmwareMAC;
|
std::string& mac_in = Config::FirmwareMAC;
|
||||||
u8* mac_out = (u8*)data;
|
u8* mac_out = (u8*)data;
|
||||||
|
|
||||||
int o = 0;
|
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()
|
bool MP_Init()
|
||||||
{
|
{
|
||||||
int opt_true = 1;
|
int opt_true = 1;
|
||||||
|
|
|
@ -45,14 +45,14 @@ ROMInfoDialog::ROMInfoDialog(QWidget* parent) : QDialog(parent), ui(new Ui::ROMI
|
||||||
|
|
||||||
|
|
||||||
u32 iconData[32 * 32];
|
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();
|
iconImage = QImage(reinterpret_cast<unsigned char*>(iconData), 32, 32, QImage::Format_ARGB32).copy();
|
||||||
ui->iconImage->setPixmap(QPixmap::fromImage(iconImage));
|
ui->iconImage->setPixmap(QPixmap::fromImage(iconImage));
|
||||||
|
|
||||||
if (NDSCart::Banner.Version == 0x103)
|
if (NDSCart::Banner.Version == 0x103)
|
||||||
{
|
{
|
||||||
u32 animatedIconData[32 * 32 * 64] = {0};
|
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++)
|
for (int i = 0; i < 64; i++)
|
||||||
{
|
{
|
||||||
|
@ -130,7 +130,7 @@ void ROMInfoDialog::on_saveIconButton_clicked()
|
||||||
{
|
{
|
||||||
QString filename = QFileDialog::getSaveFileName(this,
|
QString filename = QFileDialog::getSaveFileName(this,
|
||||||
"Save Icon",
|
"Save Icon",
|
||||||
Config::LastROMFolder,
|
QString::fromStdString(Config::LastROMFolder),
|
||||||
"PNG Images (*.png)");
|
"PNG Images (*.png)");
|
||||||
if (filename.isEmpty())
|
if (filename.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "FrontendUtil.h"
|
#include "ROMManager.h"
|
||||||
|
|
||||||
namespace Ui { class ROMInfoDialog; }
|
namespace Ui { class ROMInfoDialog; }
|
||||||
class ROMInfoDialog;
|
class ROMInfoDialog;
|
||||||
|
@ -58,7 +58,7 @@ public:
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void done(int r);
|
void done(int r);
|
||||||
|
|
||||||
void on_saveIconButton_clicked();
|
void on_saveIconButton_clicked();
|
||||||
|
|
||||||
void iconSetFrame(int frame);
|
void iconSetFrame(int frame);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -23,7 +23,7 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "FrontendUtil.h"
|
#include "ROMManager.h"
|
||||||
#include "DSi_NAND.h"
|
#include "DSi_NAND.h"
|
||||||
|
|
||||||
#include "TitleManagerDialog.h"
|
#include "TitleManagerDialog.h"
|
||||||
|
@ -111,7 +111,7 @@ void TitleManagerDialog::createTitleItem(u32 category, u32 titleid)
|
||||||
DSi_NAND::GetTitleInfo(category, titleid, version, &header, &banner);
|
DSi_NAND::GetTitleInfo(category, titleid, version, &header, &banner);
|
||||||
|
|
||||||
u32 icondata[32*32];
|
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);
|
QImage iconimg((const uchar*)icondata, 32, 32, QImage::Format_ARGB32);
|
||||||
QIcon icon(QPixmap::fromImage(iconimg.copy()));
|
QIcon icon(QPixmap::fromImage(iconimg.copy()));
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ WifiSettingsDialog::WifiSettingsDialog(QWidget* parent) : QDialog(parent), ui(ne
|
||||||
|
|
||||||
ui->rbDirectMode->setText("Direct mode (requires " PCAP_NAME " and ethernet connection)");
|
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;
|
int sel = 0;
|
||||||
for (int i = 0; i < LAN_PCap::NumAdapters; i++)
|
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));
|
ui->cbxDirectAdapter->addItem(QString(adapter->FriendlyName));
|
||||||
|
|
||||||
if (!strncmp(adapter->DeviceName, Config::LANDevice, 128))
|
if (!strncmp(adapter->DeviceName, Config::LANDevice.c_str(), 128))
|
||||||
sel = i;
|
sel = i;
|
||||||
}
|
}
|
||||||
ui->cbxDirectAdapter->setCurrentIndex(sel);
|
ui->cbxDirectAdapter->setCurrentIndex(sel);
|
||||||
|
|
||||||
ui->rbDirectMode->setChecked(Config::DirectLAN != 0);
|
// errrr???
|
||||||
ui->rbIndirectMode->setChecked(Config::DirectLAN == 0);
|
ui->rbDirectMode->setChecked(Config::DirectLAN);
|
||||||
|
ui->rbIndirectMode->setChecked(!Config::DirectLAN);
|
||||||
if (!haspcap) ui->rbDirectMode->setEnabled(false);
|
if (!haspcap) ui->rbDirectMode->setEnabled(false);
|
||||||
|
|
||||||
updateAdapterControls();
|
updateAdapterControls();
|
||||||
|
@ -87,19 +88,18 @@ void WifiSettingsDialog::done(int r)
|
||||||
|
|
||||||
if (r == QDialog::Accepted)
|
if (r == QDialog::Accepted)
|
||||||
{
|
{
|
||||||
Config::SocketBindAnyAddr = ui->cbBindAnyAddr->isChecked() ? 1:0;
|
Config::SocketBindAnyAddr = ui->cbBindAnyAddr->isChecked();
|
||||||
Config::DirectLAN = ui->rbDirectMode->isChecked() ? 1:0;
|
Config::DirectLAN = ui->rbDirectMode->isChecked();
|
||||||
|
|
||||||
int sel = ui->cbxDirectAdapter->currentIndex();
|
int sel = ui->cbxDirectAdapter->currentIndex();
|
||||||
if (sel < 0 || sel >= LAN_PCap::NumAdapters) sel = 0;
|
if (sel < 0 || sel >= LAN_PCap::NumAdapters) sel = 0;
|
||||||
if (LAN_PCap::NumAdapters < 1)
|
if (LAN_PCap::NumAdapters < 1)
|
||||||
{
|
{
|
||||||
Config::LANDevice[0] = '\0';
|
Config::LANDevice = "";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strncpy(Config::LANDevice, LAN_PCap::Adapters[sel].DeviceName, 127);
|
Config::LANDevice = LAN_PCap::Adapters[sel].DeviceName;
|
||||||
Config::LANDevice[127] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Config::Save();
|
Config::Save();
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -211,8 +211,7 @@ public:
|
||||||
bool hasOGL;
|
bool hasOGL;
|
||||||
QOpenGLContext* getOGLContext();
|
QOpenGLContext* getOGLContext();
|
||||||
|
|
||||||
void loadROM(QString filename);
|
bool preloadROMs(QString filename, QString gbafilename);
|
||||||
void loadROM(QByteArray *romData, QString archiveFileName, QString romFileName);
|
|
||||||
|
|
||||||
void onAppStateChanged(Qt::ApplicationState state);
|
void onAppStateChanged(Qt::ApplicationState state);
|
||||||
|
|
||||||
|
@ -231,10 +230,14 @@ signals:
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onOpenFile();
|
void onOpenFile();
|
||||||
void onOpenFileArchive();
|
|
||||||
void onClickRecentFile();
|
void onClickRecentFile();
|
||||||
void onClearRecentFiles();
|
void onClearRecentFiles();
|
||||||
void onBootFirmware();
|
void onBootFirmware();
|
||||||
|
void onInsertCart();
|
||||||
|
void onEjectCart();
|
||||||
|
void onInsertGBACart();
|
||||||
|
void onInsertGBAAddon();
|
||||||
|
void onEjectGBACart();
|
||||||
void onSaveState();
|
void onSaveState();
|
||||||
void onLoadState();
|
void onLoadState();
|
||||||
void onUndoStateLoad();
|
void onUndoStateLoad();
|
||||||
|
@ -258,11 +261,13 @@ private slots:
|
||||||
void onOpenVideoSettings();
|
void onOpenVideoSettings();
|
||||||
void onOpenAudioSettings();
|
void onOpenAudioSettings();
|
||||||
void onOpenFirmwareSettings();
|
void onOpenFirmwareSettings();
|
||||||
|
void onOpenPathSettings();
|
||||||
void onUpdateAudioSettings();
|
void onUpdateAudioSettings();
|
||||||
void onAudioSettingsFinished(int res);
|
void onAudioSettingsFinished(int res);
|
||||||
void onOpenWifiSettings();
|
void onOpenWifiSettings();
|
||||||
void onWifiSettingsFinished(int res);
|
void onWifiSettingsFinished(int res);
|
||||||
void onFirmwareSettingsFinished(int res);
|
void onFirmwareSettingsFinished(int res);
|
||||||
|
void onPathSettingsFinished(int res);
|
||||||
void onOpenInterfaceSettings();
|
void onOpenInterfaceSettings();
|
||||||
void onInterfaceSettingsFinished(int res);
|
void onInterfaceSettingsFinished(int res);
|
||||||
void onUpdateMouseTimer();
|
void onUpdateMouseTimer();
|
||||||
|
@ -291,16 +296,19 @@ private slots:
|
||||||
void onFullscreenToggled();
|
void onFullscreenToggled();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QStringList currentROM;
|
||||||
|
QStringList currentGBAROM;
|
||||||
QList<QString> recentFileList;
|
QList<QString> recentFileList;
|
||||||
QMenu *recentMenu;
|
QMenu *recentMenu;
|
||||||
void updateRecentFilesMenu();
|
void updateRecentFilesMenu();
|
||||||
|
|
||||||
QString pickAndExtractFileFromArchive(QString archiveFileName, QByteArray *romBuffer);
|
bool verifySetup();
|
||||||
|
QString pickFileFromArchive(QString archiveFileName);
|
||||||
|
QStringList pickROM(bool gba);
|
||||||
|
void updateCartInserted(bool gba);
|
||||||
|
|
||||||
void createScreenPanel();
|
void createScreenPanel();
|
||||||
|
|
||||||
QString loadErrorStr(int error);
|
|
||||||
|
|
||||||
bool pausedManually = false;
|
bool pausedManually = false;
|
||||||
|
|
||||||
int oldW, oldH;
|
int oldW, oldH;
|
||||||
|
@ -312,12 +320,18 @@ public:
|
||||||
ScreenPanelNative* panelNative;
|
ScreenPanelNative* panelNative;
|
||||||
|
|
||||||
QAction* actOpenROM;
|
QAction* actOpenROM;
|
||||||
QAction* actOpenROMArchive;
|
|
||||||
QAction* actBootFirmware;
|
QAction* actBootFirmware;
|
||||||
|
QAction* actCurrentCart;
|
||||||
|
QAction* actInsertCart;
|
||||||
|
QAction* actEjectCart;
|
||||||
|
QAction* actCurrentGBACart;
|
||||||
|
QAction* actInsertGBACart;
|
||||||
|
QAction* actInsertGBAAddon[1];
|
||||||
|
QAction* actEjectGBACart;
|
||||||
|
QAction* actImportSavefile;
|
||||||
QAction* actSaveState[9];
|
QAction* actSaveState[9];
|
||||||
QAction* actLoadState[9];
|
QAction* actLoadState[9];
|
||||||
QAction* actUndoStateLoad;
|
QAction* actUndoStateLoad;
|
||||||
QAction* actImportSavefile;
|
|
||||||
QAction* actQuit;
|
QAction* actQuit;
|
||||||
|
|
||||||
QAction* actPause;
|
QAction* actPause;
|
||||||
|
@ -335,6 +349,7 @@ public:
|
||||||
QAction* actAudioSettings;
|
QAction* actAudioSettings;
|
||||||
QAction* actWifiSettings;
|
QAction* actWifiSettings;
|
||||||
QAction* actFirmwareSettings;
|
QAction* actFirmwareSettings;
|
||||||
|
QAction* actPathSettings;
|
||||||
QAction* actInterfaceSettings;
|
QAction* actInterfaceSettings;
|
||||||
QAction* actSavestateSRAMReloc;
|
QAction* actSavestateSRAMReloc;
|
||||||
QAction* actScreenSize[4];
|
QAction* actScreenSize[4];
|
||||||
|
|
Loading…
Reference in New Issue