mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-06-28 01:49:42 -06:00
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:
460
src/NDSCart.cpp
460
src/NDSCart.cpp
@ -22,11 +22,11 @@
|
||||
#include "DSi.h"
|
||||
#include "NDSCart.h"
|
||||
#include "ARM.h"
|
||||
#include "CRC32.h"
|
||||
#include "DSi_AES.h"
|
||||
#include "Platform.h"
|
||||
#include "ROMList.h"
|
||||
#include "melonDLDI.h"
|
||||
#include "NDSCart_SRAMManager.h"
|
||||
|
||||
|
||||
namespace NDSCart
|
||||
@ -51,12 +51,9 @@ u32 TransferDir;
|
||||
u8 TransferCmd[8];
|
||||
|
||||
bool CartInserted;
|
||||
char CartName[256];
|
||||
u8* CartROM;
|
||||
u32 CartROMSize;
|
||||
u32 CartID;
|
||||
bool CartIsHomebrew;
|
||||
bool CartIsDSi;
|
||||
|
||||
NDSHeader Header;
|
||||
NDSBanner Banner;
|
||||
@ -135,13 +132,24 @@ void Key1_ApplyKeycode(u32* keycode, u32 mod)
|
||||
}
|
||||
}
|
||||
|
||||
void Key1_LoadKeyBuf(bool dsi)
|
||||
{
|
||||
// it is possible that this gets called before the BIOSes are loaded
|
||||
// so we will read from the BIOS files directly
|
||||
|
||||
std::string path = Platform::GetConfigString(dsi ? Platform::DSi_BIOS7Path : Platform::BIOS7Path);
|
||||
FILE* f = Platform::OpenLocalFile(path, "rb");
|
||||
if (f)
|
||||
{
|
||||
fseek(f, dsi ? 0xC6D0 : 0x0030, SEEK_SET);
|
||||
fread(Key1_KeyBuf, 0x1048, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
void Key1_InitKeycode(bool dsi, u32 idcode, u32 level, u32 mod)
|
||||
{
|
||||
// TODO: source the key data from different possible places
|
||||
if (dsi && NDS::ConsoleType==1)
|
||||
memcpy(Key1_KeyBuf, &DSi::ARM7iBIOS[0xC6D0], 0x1048); // hax
|
||||
else
|
||||
memcpy(Key1_KeyBuf, &NDS::ARM7BIOS[0x30], 0x1048); // hax
|
||||
Key1_LoadKeyBuf(dsi);
|
||||
|
||||
u32 keycode[3] = {idcode, idcode>>1, idcode<<1};
|
||||
if (level >= 1) Key1_ApplyKeycode(keycode, mod);
|
||||
@ -191,6 +199,22 @@ CartCommon::~CartCommon()
|
||||
{
|
||||
}
|
||||
|
||||
u32 CartCommon::Checksum()
|
||||
{
|
||||
u32 crc = CRC32(ROM, 0x40);
|
||||
|
||||
crc = CRC32(&ROM[Header.ARM9ROMOffset], Header.ARM9Size, crc);
|
||||
crc = CRC32(&ROM[Header.ARM7ROMOffset], Header.ARM7Size, crc);
|
||||
|
||||
if (IsDSi)
|
||||
{
|
||||
crc = CRC32(&ROM[Header.DSiARM9iROMOffset], Header.DSiARM9iSize, crc);
|
||||
crc = CRC32(&ROM[Header.DSiARM7iROMOffset], Header.DSiARM7iSize, crc);
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
void CartCommon::Reset()
|
||||
{
|
||||
CmdEncMode = 0;
|
||||
@ -198,11 +222,11 @@ void CartCommon::Reset()
|
||||
DSiMode = false;
|
||||
}
|
||||
|
||||
void CartCommon::SetupDirectBoot()
|
||||
void CartCommon::SetupDirectBoot(std::string romname)
|
||||
{
|
||||
CmdEncMode = 2;
|
||||
DataEncMode = 2;
|
||||
DSiMode = IsDSi && NDS::ConsoleType==1;
|
||||
DSiMode = IsDSi && (NDS::ConsoleType==1);
|
||||
}
|
||||
|
||||
void CartCommon::DoSavestate(Savestate* file)
|
||||
@ -214,20 +238,11 @@ void CartCommon::DoSavestate(Savestate* file)
|
||||
file->Bool32(&DSiMode);
|
||||
}
|
||||
|
||||
void CartCommon::LoadSave(const char* path, u32 type)
|
||||
void CartCommon::SetupSave(u32 type)
|
||||
{
|
||||
}
|
||||
|
||||
void CartCommon::RelocateSave(const char* path, bool write)
|
||||
{
|
||||
}
|
||||
|
||||
int CartCommon::ImportSRAM(const u8* data, u32 length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CartCommon::FlushSRAMFile()
|
||||
void CartCommon::LoadSave(const u8* savedata, u32 savelen)
|
||||
{
|
||||
}
|
||||
|
||||
@ -392,11 +407,7 @@ void CartRetail::DoSavestate(Savestate* file)
|
||||
CartCommon::DoSavestate(file);
|
||||
|
||||
// we reload the SRAM contents.
|
||||
// it should be the same file (as it should be the same ROM, duh)
|
||||
// but the contents may change
|
||||
|
||||
//if (!file->Saving && SRAMLength)
|
||||
// delete[] SRAM;
|
||||
// it should be the same file, but the contents may change
|
||||
|
||||
u32 oldlen = SRAMLength;
|
||||
|
||||
@ -407,13 +418,11 @@ void CartRetail::DoSavestate(Savestate* file)
|
||||
printf("oh well. loading it anyway. adsfgdsf\n");
|
||||
|
||||
if (oldlen) delete[] SRAM;
|
||||
SRAM = nullptr;
|
||||
if (SRAMLength) SRAM = new u8[SRAMLength];
|
||||
}
|
||||
if (SRAMLength)
|
||||
{
|
||||
//if (!file->Saving)
|
||||
// SRAM = new u8[SRAMLength];
|
||||
|
||||
file->VarArray(SRAM, SRAMLength);
|
||||
}
|
||||
|
||||
@ -423,20 +432,14 @@ void CartRetail::DoSavestate(Savestate* file)
|
||||
file->Var32(&SRAMAddr);
|
||||
file->Var8(&SRAMStatus);
|
||||
|
||||
// SRAMManager might now have an old buffer (or one from the future or alternate timeline!)
|
||||
if (!file->Saving)
|
||||
{
|
||||
SRAMFileDirty = false;
|
||||
NDSCart_SRAMManager::RequestFlush();
|
||||
}
|
||||
if ((!file->Saving) && SRAM)
|
||||
Platform::WriteNDSSave(SRAM, SRAMLength, 0, SRAMLength);
|
||||
}
|
||||
|
||||
void CartRetail::LoadSave(const char* path, u32 type)
|
||||
void CartRetail::SetupSave(u32 type)
|
||||
{
|
||||
if (SRAM) delete[] SRAM;
|
||||
|
||||
strncpy(SRAMPath, path, 1023);
|
||||
SRAMPath[1023] = '\0';
|
||||
SRAM = nullptr;
|
||||
|
||||
if (type > 10) type = 0;
|
||||
int sramlen[] =
|
||||
@ -455,18 +458,6 @@ void CartRetail::LoadSave(const char* path, u32 type)
|
||||
memset(SRAM, 0xFF, SRAMLength);
|
||||
}
|
||||
|
||||
FILE* f = Platform::OpenFile(path, "rb");
|
||||
if (f)
|
||||
{
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fread(SRAM, 1, SRAMLength, f);
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
SRAMFileDirty = false;
|
||||
NDSCart_SRAMManager::Setup(path, SRAM, SRAMLength);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 1: SRAMType = 1; break; // EEPROM, small
|
||||
@ -483,47 +474,13 @@ void CartRetail::LoadSave(const char* path, u32 type)
|
||||
}
|
||||
}
|
||||
|
||||
void CartRetail::RelocateSave(const char* path, bool write)
|
||||
void CartRetail::LoadSave(const u8* savedata, u32 savelen)
|
||||
{
|
||||
if (!write)
|
||||
{
|
||||
LoadSave(path, 0); // lazy
|
||||
return;
|
||||
}
|
||||
if (!SRAM) return;
|
||||
|
||||
strncpy(SRAMPath, path, 1023);
|
||||
SRAMPath[1023] = '\0';
|
||||
|
||||
FILE* f = Platform::OpenFile(path, "wb");
|
||||
if (!f)
|
||||
{
|
||||
printf("NDSCart_SRAM::RelocateSave: failed to create new file. fuck\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite(SRAM, SRAMLength, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
int CartRetail::ImportSRAM(const u8* data, u32 length)
|
||||
{
|
||||
memcpy(SRAM, data, std::min(length, SRAMLength));
|
||||
FILE* f = Platform::OpenFile(SRAMPath, "wb");
|
||||
if (f)
|
||||
{
|
||||
fwrite(SRAM, SRAMLength, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return length - SRAMLength;
|
||||
}
|
||||
|
||||
void CartRetail::FlushSRAMFile()
|
||||
{
|
||||
if (!SRAMFileDirty) return;
|
||||
|
||||
SRAMFileDirty = false;
|
||||
NDSCart_SRAMManager::RequestFlush();
|
||||
u32 len = std::min(savelen, SRAMLength);
|
||||
memcpy(SRAM, savedata, len);
|
||||
Platform::WriteNDSSave(savedata, len, 0, len);
|
||||
}
|
||||
|
||||
int CartRetail::ROMCommandStart(u8* cmd, u8* data, u32 len)
|
||||
@ -624,6 +581,7 @@ u8 CartRetail::SRAMWrite_EEPROMTiny(u8 val, u32 pos, bool last)
|
||||
if (pos < 2)
|
||||
{
|
||||
SRAMAddr = val;
|
||||
SRAMFirstAddr = SRAMAddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -631,11 +589,15 @@ u8 CartRetail::SRAMWrite_EEPROMTiny(u8 val, u32 pos, bool last)
|
||||
if (SRAMStatus & (1<<1))
|
||||
{
|
||||
SRAM[(SRAMAddr + ((SRAMCmd==0x0A)?0x100:0)) & 0x1FF] = val;
|
||||
SRAMFileDirty |= last;
|
||||
}
|
||||
SRAMAddr++;
|
||||
}
|
||||
if (last) SRAMStatus &= ~(1<<1);
|
||||
if (last)
|
||||
{
|
||||
SRAMStatus &= ~(1<<1);
|
||||
Platform::WriteNDSSave(SRAM, SRAMLength,
|
||||
(SRAMFirstAddr + ((SRAMCmd==0x0A)?0x100:0)) & 0x1FF, SRAMAddr-SRAMFirstAddr);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 0x03: // read low
|
||||
@ -683,6 +645,7 @@ u8 CartRetail::SRAMWrite_EEPROM(u8 val, u32 pos, bool last)
|
||||
{
|
||||
SRAMAddr <<= 8;
|
||||
SRAMAddr |= val;
|
||||
SRAMFirstAddr = SRAMAddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -690,11 +653,15 @@ u8 CartRetail::SRAMWrite_EEPROM(u8 val, u32 pos, bool last)
|
||||
if (SRAMStatus & (1<<1))
|
||||
{
|
||||
SRAM[SRAMAddr & (SRAMLength-1)] = val;
|
||||
SRAMFileDirty |= last;
|
||||
}
|
||||
SRAMAddr++;
|
||||
}
|
||||
if (last) SRAMStatus &= ~(1<<1);
|
||||
if (last)
|
||||
{
|
||||
SRAMStatus &= ~(1<<1);
|
||||
Platform::WriteNDSSave(SRAM, SRAMLength,
|
||||
SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 0x03: // read
|
||||
@ -735,6 +702,7 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
|
||||
{
|
||||
SRAMAddr <<= 8;
|
||||
SRAMAddr |= val;
|
||||
SRAMFirstAddr = SRAMAddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -742,11 +710,15 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
|
||||
{
|
||||
// CHECKME: should it be &=~val ??
|
||||
SRAM[SRAMAddr & (SRAMLength-1)] = 0;
|
||||
SRAMFileDirty |= last;
|
||||
}
|
||||
SRAMAddr++;
|
||||
}
|
||||
if (last) SRAMStatus &= ~(1<<1);
|
||||
if (last)
|
||||
{
|
||||
SRAMStatus &= ~(1<<1);
|
||||
Platform::WriteNDSSave(SRAM, SRAMLength,
|
||||
SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 0x03: // read
|
||||
@ -768,17 +740,22 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
|
||||
{
|
||||
SRAMAddr <<= 8;
|
||||
SRAMAddr |= val;
|
||||
SRAMFirstAddr = SRAMAddr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SRAMStatus & (1<<1))
|
||||
{
|
||||
SRAM[SRAMAddr & (SRAMLength-1)] = val;
|
||||
SRAMFileDirty |= last;
|
||||
}
|
||||
SRAMAddr++;
|
||||
}
|
||||
if (last) SRAMStatus &= ~(1<<1);
|
||||
if (last)
|
||||
{
|
||||
SRAMStatus &= ~(1<<1);
|
||||
Platform::WriteNDSSave(SRAM, SRAMLength,
|
||||
SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 0x0B: // fast read
|
||||
@ -809,6 +786,7 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
|
||||
{
|
||||
SRAMAddr <<= 8;
|
||||
SRAMAddr |= val;
|
||||
SRAMFirstAddr = SRAMAddr;
|
||||
}
|
||||
if ((pos == 3) && (SRAMStatus & (1<<1)))
|
||||
{
|
||||
@ -817,9 +795,13 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
|
||||
SRAM[SRAMAddr & (SRAMLength-1)] = 0;
|
||||
SRAMAddr++;
|
||||
}
|
||||
SRAMFileDirty = true;
|
||||
}
|
||||
if (last) SRAMStatus &= ~(1<<1);
|
||||
if (last)
|
||||
{
|
||||
SRAMStatus &= ~(1<<1);
|
||||
Platform::WriteNDSSave(SRAM, SRAMLength,
|
||||
SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 0xDB: // page erase
|
||||
@ -827,6 +809,7 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
|
||||
{
|
||||
SRAMAddr <<= 8;
|
||||
SRAMAddr |= val;
|
||||
SRAMFirstAddr = SRAMAddr;
|
||||
}
|
||||
if ((pos == 3) && (SRAMStatus & (1<<1)))
|
||||
{
|
||||
@ -835,9 +818,13 @@ u8 CartRetail::SRAMWrite_FLASH(u8 val, u32 pos, bool last)
|
||||
SRAM[SRAMAddr & (SRAMLength-1)] = 0;
|
||||
SRAMAddr++;
|
||||
}
|
||||
SRAMFileDirty = true;
|
||||
}
|
||||
if (last) SRAMStatus &= ~(1<<1);
|
||||
if (last)
|
||||
{
|
||||
SRAMStatus &= ~(1<<1);
|
||||
Platform::WriteNDSSave(SRAM, SRAMLength,
|
||||
SRAMFirstAddr & (SRAMLength-1), SRAMAddr-SRAMFirstAddr);
|
||||
}
|
||||
return 0;
|
||||
|
||||
default:
|
||||
@ -884,19 +871,12 @@ void CartRetailNAND::DoSavestate(Savestate* file)
|
||||
BuildSRAMID();
|
||||
}
|
||||
|
||||
void CartRetailNAND::LoadSave(const char* path, u32 type)
|
||||
void CartRetailNAND::LoadSave(const u8* savedata, u32 savelen)
|
||||
{
|
||||
CartRetail::LoadSave(path, type);
|
||||
CartRetail::LoadSave(savedata, savelen);
|
||||
BuildSRAMID();
|
||||
}
|
||||
|
||||
int CartRetailNAND::ImportSRAM(const u8* data, u32 length)
|
||||
{
|
||||
int ret = CartRetail::ImportSRAM(data, length);
|
||||
BuildSRAMID();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CartRetailNAND::ROMCommandStart(u8* cmd, u8* data, u32 len)
|
||||
{
|
||||
if (CmdEncMode != 2) return CartCommon::ROMCommandStart(cmd, data, len);
|
||||
@ -926,7 +906,7 @@ int CartRetailNAND::ROMCommandStart(u8* cmd, u8* data, u32 len)
|
||||
if (SRAMLength && SRAMAddr < (SRAMBase+SRAMLength-0x20000))
|
||||
{
|
||||
memcpy(&SRAM[SRAMAddr - SRAMBase], SRAMWriteBuffer, 0x800);
|
||||
SRAMFileDirty = true;
|
||||
Platform::WriteNDSSave(SRAM, SRAMLength, SRAMAddr - SRAMBase, 0x800);
|
||||
}
|
||||
|
||||
SRAMAddr = 0;
|
||||
@ -1164,8 +1144,30 @@ u8 CartRetailBT::SPIWrite(u8 val, u32 pos, bool last)
|
||||
|
||||
CartHomebrew::CartHomebrew(u8* rom, u32 len, u32 chipid) : CartCommon(rom, len, chipid)
|
||||
{
|
||||
SD = nullptr;
|
||||
}
|
||||
|
||||
CartHomebrew::~CartHomebrew()
|
||||
{
|
||||
if (SD)
|
||||
{
|
||||
SD->Close();
|
||||
delete SD;
|
||||
}
|
||||
}
|
||||
|
||||
void CartHomebrew::Reset()
|
||||
{
|
||||
CartCommon::Reset();
|
||||
|
||||
ReadOnly = Platform::GetConfigBool(Platform::DLDI_ReadOnly);
|
||||
|
||||
if (SD)
|
||||
{
|
||||
SD->Close();
|
||||
delete SD;
|
||||
}
|
||||
|
||||
if (Platform::GetConfigBool(Platform::DLDI_Enable))
|
||||
{
|
||||
std::string folderpath;
|
||||
@ -1185,29 +1187,15 @@ CartHomebrew::CartHomebrew(u8* rom, u32 len, u32 chipid) : CartCommon(rom, len,
|
||||
SD = nullptr;
|
||||
}
|
||||
|
||||
CartHomebrew::~CartHomebrew()
|
||||
void CartHomebrew::SetupDirectBoot(std::string romname)
|
||||
{
|
||||
if (SD)
|
||||
{
|
||||
SD->Close();
|
||||
delete SD;
|
||||
}
|
||||
}
|
||||
|
||||
void CartHomebrew::Reset()
|
||||
{
|
||||
CartCommon::Reset();
|
||||
}
|
||||
|
||||
void CartHomebrew::SetupDirectBoot()
|
||||
{
|
||||
CartCommon::SetupDirectBoot();
|
||||
CartCommon::SetupDirectBoot(romname);
|
||||
|
||||
if (SD)
|
||||
{
|
||||
// add the ROM to the SD volume
|
||||
|
||||
if (!SD->InjectFile(CartName, CartROM, CartROMSize))
|
||||
if (!SD->InjectFile(romname, CartROM, CartROMSize))
|
||||
return;
|
||||
|
||||
// setup argv command line
|
||||
@ -1216,7 +1204,7 @@ void CartHomebrew::SetupDirectBoot()
|
||||
int argvlen;
|
||||
|
||||
strncpy(argv, "fat:/", 511);
|
||||
strncat(argv, CartName, 511);
|
||||
strncat(argv, romname.c_str(), 511);
|
||||
argvlen = strlen(argv);
|
||||
|
||||
void (*writefn)(u32,u32) = (NDS::ConsoleType==1) ? DSi::ARM9Write32 : NDS::ARM9Write32;
|
||||
@ -1441,6 +1429,7 @@ void CartHomebrew::ReadROM_B7(u32 addr, u32 len, u8* data, u32 offset)
|
||||
|
||||
bool Init()
|
||||
{
|
||||
CartInserted = false;
|
||||
CartROM = nullptr;
|
||||
Cart = nullptr;
|
||||
|
||||
@ -1455,17 +1444,6 @@ void DeInit()
|
||||
|
||||
void Reset()
|
||||
{
|
||||
CartInserted = false;
|
||||
if (CartROM) delete[] CartROM;
|
||||
CartROM = nullptr;
|
||||
CartROMSize = 0;
|
||||
CartID = 0;
|
||||
CartIsHomebrew = false;
|
||||
CartIsDSi = false;
|
||||
|
||||
if (Cart) delete Cart;
|
||||
Cart = nullptr;
|
||||
|
||||
ResetCart();
|
||||
}
|
||||
|
||||
@ -1494,6 +1472,30 @@ void DoSavestate(Savestate* file)
|
||||
// (TODO: system to verify that indeed the right ROM is loaded)
|
||||
// (what to CRC? whole ROM? code binaries? latter would be more convenient for ie. romhaxing)
|
||||
|
||||
u32 carttype = 0;
|
||||
u32 cartchk = 0;
|
||||
if (Cart)
|
||||
{
|
||||
carttype = Cart->Type();
|
||||
cartchk = Cart->Checksum();
|
||||
}
|
||||
|
||||
if (file->Saving)
|
||||
{
|
||||
file->Var32(&carttype);
|
||||
file->Var32(&cartchk);
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 savetype;
|
||||
file->Var32(&savetype);
|
||||
if (savetype != carttype) return;
|
||||
|
||||
u32 savechk;
|
||||
file->Var32(&savechk);
|
||||
if (savechk != cartchk) return;
|
||||
}
|
||||
|
||||
if (Cart) Cart->DoSavestate(file);
|
||||
}
|
||||
|
||||
@ -1542,11 +1544,6 @@ bool ReadROMParams(u32 gamecode, ROMListEntry* params)
|
||||
|
||||
void DecryptSecureArea(u8* out)
|
||||
{
|
||||
// TODO: source decryption data from different possible sources
|
||||
// * original DS-mode ARM7 BIOS has the key data at 0x30
|
||||
// * .srl ROMs (VC dumps) have encrypted secure areas but have precomputed
|
||||
// decryption data at 0x1000 (and at the beginning of the DSi region if any)
|
||||
|
||||
u32 gamecode = (u32)Header.GameCode[3] << 24 |
|
||||
(u32)Header.GameCode[2] << 16 |
|
||||
(u32)Header.GameCode[1] << 8 |
|
||||
@ -1576,8 +1573,28 @@ void DecryptSecureArea(u8* out)
|
||||
}
|
||||
}
|
||||
|
||||
bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
|
||||
bool LoadROM(const u8* romdata, u32 romlen)
|
||||
{
|
||||
if (CartInserted)
|
||||
EjectCart();
|
||||
|
||||
CartROMSize = 0x200;
|
||||
while (CartROMSize < romlen)
|
||||
CartROMSize <<= 1;
|
||||
|
||||
try
|
||||
{
|
||||
CartROM = new u8[CartROMSize];
|
||||
}
|
||||
catch (const std::bad_alloc& e)
|
||||
{
|
||||
printf("NDSCart: failed to allocate memory for ROM (%d bytes)\n", CartROMSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(CartROM, 0, CartROMSize);
|
||||
memcpy(CartROM, romdata, romlen);
|
||||
|
||||
memcpy(&Header, CartROM, sizeof(Header));
|
||||
memcpy(&Banner, CartROM + Header.BannerOffset, sizeof(Banner));
|
||||
|
||||
@ -1589,7 +1606,10 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
|
||||
(u32)Header.GameCode[0];
|
||||
|
||||
u8 unitcode = Header.UnitCode;
|
||||
CartIsDSi = (unitcode & 0x02) != 0;
|
||||
bool dsi = (unitcode & 0x02) != 0;
|
||||
|
||||
u32 arm9base = Header.ARM9ROMOffset;
|
||||
bool homebrew = (arm9base < 0x4000) || (gamecode == 0x23232323);
|
||||
|
||||
ROMListEntry romparams;
|
||||
if (!ReadROMParams(gamecode, &romparams))
|
||||
@ -1599,7 +1619,7 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
|
||||
|
||||
romparams.GameCode = gamecode;
|
||||
romparams.ROMSize = CartROMSize;
|
||||
if (*(u32*)&CartROM[0x20] < 0x4000)
|
||||
if (homebrew)
|
||||
romparams.SaveMemType = 0; // no saveRAM for homebrew
|
||||
else
|
||||
romparams.SaveMemType = 2; // assume EEPROM 64k (TODO FIXME)
|
||||
@ -1607,7 +1627,8 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
|
||||
else
|
||||
printf("ROM entry: %08X %08X\n", romparams.ROMSize, romparams.SaveMemType);
|
||||
|
||||
if (romparams.ROMSize != filelength) printf("!! bad ROM size %d (expected %d) rounded to %d\n", filelength, romparams.ROMSize, CartROMSize);
|
||||
if (romparams.ROMSize != romlen)
|
||||
printf("!! bad ROM size %d (expected %d) rounded to %d\n", romlen, romparams.ROMSize, CartROMSize);
|
||||
|
||||
// generate a ROM ID
|
||||
// note: most games don't check the actual value
|
||||
@ -1622,7 +1643,7 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
|
||||
if (romparams.SaveMemType >= 8 && romparams.SaveMemType <= 10)
|
||||
CartID |= 0x08000000; // NAND flag
|
||||
|
||||
if (CartIsDSi)
|
||||
if (dsi)
|
||||
CartID |= 0x40000000;
|
||||
|
||||
// cart ID for Jam with the Band
|
||||
@ -1633,34 +1654,24 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
|
||||
|
||||
printf("Cart ID: %08X\n", CartID);
|
||||
|
||||
u32 arm9base = *(u32*)&CartROM[0x20];
|
||||
|
||||
if (arm9base < 0x8000)
|
||||
if (arm9base >= 0x4000 && arm9base < 0x8000)
|
||||
{
|
||||
if (arm9base >= 0x4000)
|
||||
// reencrypt secure area if needed
|
||||
if (*(u32*)&CartROM[arm9base] == 0xE7FFDEFF && *(u32*)&CartROM[arm9base+0x10] != 0xE7FFDEFF)
|
||||
{
|
||||
// reencrypt secure area if needed
|
||||
if (*(u32*)&CartROM[arm9base] == 0xE7FFDEFF && *(u32*)&CartROM[arm9base+0x10] != 0xE7FFDEFF)
|
||||
{
|
||||
printf("Re-encrypting cart secure area\n");
|
||||
printf("Re-encrypting cart secure area\n");
|
||||
|
||||
strncpy((char*)&CartROM[arm9base], "encryObj", 8);
|
||||
strncpy((char*)&CartROM[arm9base], "encryObj", 8);
|
||||
|
||||
Key1_InitKeycode(false, gamecode, 3, 2);
|
||||
for (u32 i = 0; i < 0x800; i += 8)
|
||||
Key1_Encrypt((u32*)&CartROM[arm9base + i]);
|
||||
Key1_InitKeycode(false, gamecode, 3, 2);
|
||||
for (u32 i = 0; i < 0x800; i += 8)
|
||||
Key1_Encrypt((u32*)&CartROM[arm9base + i]);
|
||||
|
||||
Key1_InitKeycode(false, gamecode, 2, 2);
|
||||
Key1_Encrypt((u32*)&CartROM[arm9base]);
|
||||
}
|
||||
Key1_InitKeycode(false, gamecode, 2, 2);
|
||||
Key1_Encrypt((u32*)&CartROM[arm9base]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((arm9base < 0x4000) || (gamecode == 0x23232323))
|
||||
{
|
||||
CartIsHomebrew = true;
|
||||
}
|
||||
|
||||
CartInserted = true;
|
||||
|
||||
u32 irversion = 0;
|
||||
@ -1672,7 +1683,7 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
|
||||
irversion = 2; // Pokémon HG/SS, B/W, B2/W2
|
||||
}
|
||||
|
||||
if (CartIsHomebrew)
|
||||
if (homebrew)
|
||||
Cart = new CartHomebrew(CartROM, CartROMSize, CartID);
|
||||
else if (CartID & 0x08000000)
|
||||
Cart = new CartRetailNAND(CartROM, CartROMSize, CartID);
|
||||
@ -1684,99 +1695,44 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
|
||||
Cart = new CartRetail(CartROM, CartROMSize, CartID);
|
||||
|
||||
if (Cart)
|
||||
{
|
||||
Cart->Reset();
|
||||
if (direct)
|
||||
{
|
||||
NDS::SetupDirectBoot();
|
||||
Cart->SetupDirectBoot();
|
||||
}
|
||||
}
|
||||
|
||||
// encryption
|
||||
Key1_InitKeycode(false, gamecode, 2, 2);
|
||||
|
||||
// save
|
||||
printf("Save file: %s\n", sram);
|
||||
if (Cart) Cart->LoadSave(sram, romparams.SaveMemType);
|
||||
if (Cart && romparams.SaveMemType > 0)
|
||||
Cart->SetupSave(romparams.SaveMemType);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadROM(const char* path, const char* sram, bool direct)
|
||||
void LoadSave(const u8* savedata, u32 savelen)
|
||||
{
|
||||
// TODO: streaming mode? for really big ROMs or systems with limited RAM
|
||||
// for now we're lazy
|
||||
// also TODO: validate what we're loading!!
|
||||
|
||||
FILE* f = Platform::OpenFile(path, "rb");
|
||||
if (!f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
NDS::Reset();
|
||||
|
||||
char* romname = strrchr((char*)path, '/');
|
||||
if (!romname)
|
||||
{
|
||||
romname = strrchr((char*)path, '\\');
|
||||
if (!romname)
|
||||
romname = (char*)&path[-1];
|
||||
}
|
||||
romname++;
|
||||
strncpy(CartName, romname, 255); CartName[255] = '\0';
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
u32 len = (u32)ftell(f);
|
||||
|
||||
CartROMSize = 0x200;
|
||||
while (CartROMSize < len)
|
||||
CartROMSize <<= 1;
|
||||
|
||||
CartROM = new u8[CartROMSize];
|
||||
memset(CartROM, 0, CartROMSize);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fread(CartROM, 1, len, f);
|
||||
|
||||
fclose(f);
|
||||
|
||||
return LoadROMCommon(len, sram, direct);
|
||||
if (Cart)
|
||||
Cart->LoadSave(savedata, savelen);
|
||||
}
|
||||
|
||||
bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct)
|
||||
void SetupDirectBoot(std::string romname)
|
||||
{
|
||||
NDS::Reset();
|
||||
|
||||
// TODO: make it more meaningful?
|
||||
strncpy(CartName, "rom.nds", 256);
|
||||
|
||||
u32 len = filelength;
|
||||
CartROMSize = 0x200;
|
||||
while (CartROMSize < len)
|
||||
CartROMSize <<= 1;
|
||||
|
||||
CartROM = new u8[CartROMSize];
|
||||
memset(CartROM, 0, CartROMSize);
|
||||
memcpy(CartROM, romdata, filelength);
|
||||
|
||||
return LoadROMCommon(filelength, sram, direct);
|
||||
if (Cart)
|
||||
Cart->SetupDirectBoot(romname);
|
||||
}
|
||||
|
||||
void RelocateSave(const char* path, bool write)
|
||||
void EjectCart()
|
||||
{
|
||||
if (Cart) Cart->RelocateSave(path, write);
|
||||
}
|
||||
if (!CartInserted) return;
|
||||
|
||||
void FlushSRAMFile()
|
||||
{
|
||||
if (Cart) Cart->FlushSRAMFile();
|
||||
}
|
||||
// ejecting the cart triggers the gamecard IRQ
|
||||
NDS::SetIRQ(0, NDS::IRQ_CartIREQMC);
|
||||
NDS::SetIRQ(1, NDS::IRQ_CartIREQMC);
|
||||
|
||||
int ImportSRAM(const u8* data, u32 length)
|
||||
{
|
||||
if (Cart) return Cart->ImportSRAM(data, length);
|
||||
return 0;
|
||||
if (Cart) delete Cart;
|
||||
Cart = nullptr;
|
||||
|
||||
CartInserted = false;
|
||||
if (CartROM) delete[] CartROM;
|
||||
CartROM = nullptr;
|
||||
CartROMSize = 0;
|
||||
CartID = 0;
|
||||
|
||||
// CHECKME: does an eject imply anything for the ROM/SPI transfer registers?
|
||||
}
|
||||
|
||||
void ResetCart()
|
||||
@ -1880,6 +1836,8 @@ void WriteROMCnt(u32 val)
|
||||
*(u32*)&TransferCmd[0] = *(u32*)&ROMCommand[0];
|
||||
*(u32*)&TransferCmd[4] = *(u32*)&ROMCommand[4];
|
||||
|
||||
memset(TransferData, 0xFF, TransferLen);
|
||||
|
||||
/*printf("ROM COMMAND %04X %08X %02X%02X%02X%02X%02X%02X%02X%02X SIZE %04X\n",
|
||||
SPICnt, ROMCnt,
|
||||
TransferCmd[0], TransferCmd[1], TransferCmd[2], TransferCmd[3],
|
||||
|
Reference in New Issue
Block a user