mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-06-28 01:49:42 -06:00
actually add DLDI. bahahahhh
This commit is contained in:
287
src/NDSCart.cpp
287
src/NDSCart.cpp
@ -25,7 +25,9 @@
|
||||
#include "CRC32.h"
|
||||
#include "DSi_AES.h"
|
||||
#include "Platform.h"
|
||||
#include "Config.h"
|
||||
#include "ROMList.h"
|
||||
#include "melonDLDI.h"
|
||||
|
||||
|
||||
namespace NDSCart_SRAM
|
||||
@ -464,11 +466,13 @@ u16 SPICnt;
|
||||
u32 ROMCnt;
|
||||
|
||||
u8 ROMCommand[8];
|
||||
u32 ROMDataOut;
|
||||
u32 ROMData;
|
||||
|
||||
u8 DataOut[0x4000];
|
||||
u32 DataOutPos;
|
||||
u32 DataOutLen;
|
||||
u8 TransferData[0x4000];
|
||||
u32 TransferPos;
|
||||
u32 TransferLen;
|
||||
u32 TransferDir;
|
||||
u8 TransferCmd[8];
|
||||
|
||||
bool CartInserted;
|
||||
u8* CartROM;
|
||||
@ -478,6 +482,8 @@ u32 CartID;
|
||||
bool CartIsHomebrew;
|
||||
bool CartIsDSi;
|
||||
|
||||
FILE* CartSD;
|
||||
|
||||
u32 CmdEncMode;
|
||||
u32 DataEncMode;
|
||||
|
||||
@ -489,6 +495,7 @@ u64 Key2_Y;
|
||||
|
||||
void ROMCommand_Retail(u8* cmd);
|
||||
void ROMCommand_RetailNAND(u8* cmd);
|
||||
void ROMCommand_Homebrew(u8* cmd);
|
||||
|
||||
void (*ROMCommandHandler)(u8* cmd);
|
||||
|
||||
@ -615,6 +622,8 @@ bool Init()
|
||||
|
||||
CartROM = NULL;
|
||||
|
||||
CartSD = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -622,6 +631,8 @@ void DeInit()
|
||||
{
|
||||
if (CartROM) delete[] CartROM;
|
||||
|
||||
if (CartSD) fclose(CartSD);
|
||||
|
||||
NDSCart_SRAM::DeInit();
|
||||
}
|
||||
|
||||
@ -635,6 +646,9 @@ void Reset()
|
||||
CartIsHomebrew = false;
|
||||
CartIsDSi = false;
|
||||
|
||||
if (CartSD) fclose(CartSD);
|
||||
CartSD = NULL;
|
||||
|
||||
ROMCommandHandler = NULL;
|
||||
|
||||
NDSCart_SRAM::Reset();
|
||||
@ -650,11 +664,13 @@ void DoSavestate(Savestate* file)
|
||||
file->Var32(&ROMCnt);
|
||||
|
||||
file->VarArray(ROMCommand, 8);
|
||||
file->Var32(&ROMDataOut);
|
||||
file->Var32(&ROMData);
|
||||
|
||||
file->VarArray(DataOut, 0x4000);
|
||||
file->Var32(&DataOutPos);
|
||||
file->Var32(&DataOutLen);
|
||||
file->VarArray(TransferData, 0x4000);
|
||||
file->Var32(&TransferPos);
|
||||
file->Var32(&TransferLen);
|
||||
file->Var32(&TransferDir);
|
||||
file->VarArray(TransferCmd, 8);
|
||||
|
||||
// cart inserted/len/ROM/etc should be already populated
|
||||
// savestate should be loaded after the right game is loaded
|
||||
@ -670,10 +686,8 @@ void DoSavestate(Savestate* file)
|
||||
}
|
||||
|
||||
|
||||
void ApplyDLDIPatch()
|
||||
void ApplyDLDIPatch(const u8* patch, u32 len)
|
||||
{
|
||||
// TODO: embed patches? let the user choose? default to some builtin driver?
|
||||
|
||||
u32 offset = *(u32*)&CartROM[0x20];
|
||||
u32 size = *(u32*)&CartROM[0x2C];
|
||||
|
||||
@ -696,23 +710,7 @@ void ApplyDLDIPatch()
|
||||
return;
|
||||
}
|
||||
|
||||
printf("DLDI shit found at %08X (%08X)\n", dldioffset, offset+dldioffset);
|
||||
|
||||
FILE* f = fopen("dldi.bin", "rb");
|
||||
if (!f)
|
||||
{
|
||||
printf("no DLDI patch available. oh well\n");
|
||||
return;
|
||||
}
|
||||
|
||||
u32 dldisize;
|
||||
fseek(f, 0, SEEK_END);
|
||||
dldisize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
u8* patch = new u8[dldisize];
|
||||
fread(patch, dldisize, 1, f);
|
||||
fclose(f);
|
||||
printf("DLDI structure found at %08X (%08X)\n", dldioffset, offset+dldioffset);
|
||||
|
||||
if (*(u32*)&patch[0] != 0xBF8DA5ED ||
|
||||
*(u32*)&patch[4] != 0x69684320 ||
|
||||
@ -743,7 +741,7 @@ void ApplyDLDIPatch()
|
||||
u32 patchsize = 1 << patch[0x0D];
|
||||
u32 patchend = patchbase + patchsize;
|
||||
|
||||
memcpy(&binary[dldioffset], patch, dldisize);
|
||||
memcpy(&binary[dldioffset], patch, len);
|
||||
|
||||
*(u32*)&binary[dldioffset+0x40] += delta;
|
||||
*(u32*)&binary[dldioffset+0x44] += delta;
|
||||
@ -807,7 +805,6 @@ void ApplyDLDIPatch()
|
||||
memset(&binary[dldioffset+fixstart], 0, fixend-fixstart);
|
||||
}
|
||||
|
||||
delete[] patch;
|
||||
printf("applied DLDI patch\n");
|
||||
}
|
||||
|
||||
@ -987,11 +984,13 @@ bool LoadROM(const char* path, const char* sram, bool direct)
|
||||
Key1_Encrypt((u32*)&CartROM[arm9base]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CartIsHomebrew = true;
|
||||
//ApplyDLDIPatch();
|
||||
}
|
||||
}
|
||||
|
||||
if ((arm9base < 0x4000) || (gamecode == 0x23232323))
|
||||
{
|
||||
CartIsHomebrew = true;
|
||||
if (Config::DLDIEnable)
|
||||
ApplyDLDIPatch(melonDLDI, sizeof(melonDLDI));
|
||||
}
|
||||
|
||||
if (direct)
|
||||
@ -1005,7 +1004,9 @@ bool LoadROM(const char* path, const char* sram, bool direct)
|
||||
CartInserted = true;
|
||||
|
||||
// TODO: support more fancy cart types (homebrew?, flashcarts, etc)
|
||||
if (CartID & 0x08000000)
|
||||
if (CartIsHomebrew)
|
||||
ROMCommandHandler = ROMCommand_Homebrew;
|
||||
else if (CartID & 0x08000000)
|
||||
ROMCommandHandler = ROMCommand_RetailNAND;
|
||||
else
|
||||
ROMCommandHandler = ROMCommand_Retail;
|
||||
@ -1017,6 +1018,13 @@ bool LoadROM(const char* path, const char* sram, bool direct)
|
||||
printf("Save file: %s\n", sram);
|
||||
NDSCart_SRAM::LoadSave(sram, romparams.SaveMemType);
|
||||
|
||||
if (CartIsHomebrew && Config::DLDIEnable)
|
||||
{
|
||||
CartSD = Platform::OpenLocalFile(Config::DLDISDPath, "r+b");
|
||||
}
|
||||
else
|
||||
CartSD = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1034,14 +1042,17 @@ void ResetCart()
|
||||
ROMCnt = 0;
|
||||
|
||||
memset(ROMCommand, 0, 8);
|
||||
ROMDataOut = 0;
|
||||
ROMData = 0;
|
||||
|
||||
Key2_X = 0;
|
||||
Key2_Y = 0;
|
||||
|
||||
memset(DataOut, 0, 0x4000);
|
||||
DataOutPos = 0;
|
||||
DataOutLen = 0;
|
||||
memset(TransferData, 0, 0x4000);
|
||||
TransferPos = 0;
|
||||
TransferLen = 0;
|
||||
TransferDir = 0;
|
||||
memset(TransferCmd, 0, 8);
|
||||
TransferCmd[0] = 0xFF;
|
||||
|
||||
CmdEncMode = 0;
|
||||
DataEncMode = 0;
|
||||
@ -1055,7 +1066,7 @@ void ReadROM(u32 addr, u32 len, u32 offset)
|
||||
if ((addr+len) > CartROMSize)
|
||||
len = CartROMSize - addr;
|
||||
|
||||
memcpy(DataOut+offset, CartROM+addr, len);
|
||||
memcpy(TransferData+offset, CartROM+addr, len);
|
||||
}
|
||||
|
||||
void ReadROM_B7(u32 addr, u32 len, u32 offset)
|
||||
@ -1069,7 +1080,7 @@ void ReadROM_B7(u32 addr, u32 len, u32 offset)
|
||||
addr = 0x8000 + (addr & 0x1FF);
|
||||
}
|
||||
|
||||
memcpy(DataOut+offset, CartROM+addr, len);
|
||||
memcpy(TransferData+offset, CartROM+addr, len);
|
||||
}
|
||||
|
||||
|
||||
@ -1079,16 +1090,41 @@ void ROMEndTransfer(u32 param)
|
||||
|
||||
if (SPICnt & (1<<14))
|
||||
NDS::SetIRQ((NDS::ExMemCnt[0]>>11)&0x1, NDS::IRQ_CartSendDone);
|
||||
|
||||
if (TransferDir == 1)
|
||||
{
|
||||
// finish a write
|
||||
|
||||
u8* cmd = TransferCmd;
|
||||
switch (cmd[0])
|
||||
{
|
||||
case 0xC1:
|
||||
{
|
||||
u32 sector = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4];
|
||||
u64 addr = sector * 0x200ULL;
|
||||
|
||||
if (CartSD)
|
||||
{
|
||||
fseek(CartSD, addr, SEEK_SET);
|
||||
fwrite(TransferData, TransferLen, 1, CartSD);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ROMPrepareData(u32 param)
|
||||
{
|
||||
if (DataOutPos >= DataOutLen)
|
||||
ROMDataOut = 0;
|
||||
else
|
||||
ROMDataOut = *(u32*)&DataOut[DataOutPos];
|
||||
if (TransferDir == 0)
|
||||
{
|
||||
if (TransferPos >= TransferLen)
|
||||
ROMData = 0;
|
||||
else
|
||||
ROMData = *(u32*)&TransferData[TransferPos];
|
||||
|
||||
DataOutPos += 4;
|
||||
TransferPos += 4;
|
||||
}
|
||||
|
||||
ROMCnt |= (1<<23);
|
||||
|
||||
@ -1106,16 +1142,16 @@ void ROMCommand_Retail(u8* cmd)
|
||||
case 0xB7:
|
||||
{
|
||||
u32 addr = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4];
|
||||
memset(DataOut, 0, DataOutLen);
|
||||
memset(TransferData, 0, TransferLen);
|
||||
|
||||
if (((addr + DataOutLen - 1) >> 12) != (addr >> 12))
|
||||
if (((addr + TransferLen - 1) >> 12) != (addr >> 12))
|
||||
{
|
||||
u32 len1 = 0x1000 - (addr & 0xFFF);
|
||||
ReadROM_B7(addr, len1, 0);
|
||||
ReadROM_B7(addr+len1, DataOutLen-len1, len1);
|
||||
ReadROM_B7(addr+len1, TransferLen-len1, len1);
|
||||
}
|
||||
else
|
||||
ReadROM_B7(addr, DataOutLen, 0);
|
||||
ReadROM_B7(addr, TransferLen, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1136,8 +1172,8 @@ void ROMCommand_RetailNAND(u8* cmd)
|
||||
|
||||
// Jam with the Band stores words 6-9 of this at 0x02131BB0
|
||||
// it doesn't seem to use those anywhere later
|
||||
for (u32 pos = 0; pos < DataOutLen; pos += 4)
|
||||
*(u32*)&DataOut[pos] = 0;
|
||||
for (u32 pos = 0; pos < TransferLen; pos += 4)
|
||||
*(u32*)&TransferData[pos] = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1150,16 +1186,16 @@ void ROMCommand_RetailNAND(u8* cmd)
|
||||
case 0xB7:
|
||||
{
|
||||
u32 addr = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4];
|
||||
memset(DataOut, 0, DataOutLen);
|
||||
memset(TransferData, 0, TransferLen);
|
||||
|
||||
if (((addr + DataOutLen - 1) >> 12) != (addr >> 12))
|
||||
if (((addr + TransferLen - 1) >> 12) != (addr >> 12))
|
||||
{
|
||||
u32 len1 = 0x1000 - (addr & 0xFFF);
|
||||
ReadROM_B7(addr, len1, 0);
|
||||
ReadROM_B7(addr+len1, DataOutLen-len1, len1);
|
||||
ReadROM_B7(addr+len1, TransferLen-len1, len1);
|
||||
}
|
||||
else
|
||||
ReadROM_B7(addr, DataOutLen, 0);
|
||||
ReadROM_B7(addr, TransferLen, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1169,13 +1205,59 @@ void ROMCommand_RetailNAND(u8* cmd)
|
||||
// * bit7: busy? error?
|
||||
// * bit5: accessing savemem
|
||||
|
||||
for (u32 pos = 0; pos < DataOutLen; pos += 4)
|
||||
*(u32*)&DataOut[pos] = NDSCart_SRAM::StatusReg * 0x01010101;
|
||||
for (u32 pos = 0; pos < TransferLen; pos += 4)
|
||||
*(u32*)&TransferData[pos] = NDSCart_SRAM::StatusReg * 0x01010101;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("unknown NAND command %02X %04Xn", cmd[0], DataOutLen);
|
||||
printf("unknown NAND command %02X %04Xn", cmd[0], TransferLen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ROMCommand_Homebrew(u8* cmd)
|
||||
{
|
||||
switch (cmd[0])
|
||||
{
|
||||
case 0xB7:
|
||||
{
|
||||
u32 addr = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4];
|
||||
memset(TransferData, 0, TransferLen);
|
||||
|
||||
if (((addr + TransferLen - 1) >> 12) != (addr >> 12))
|
||||
{
|
||||
u32 len1 = 0x1000 - (addr & 0xFFF);
|
||||
ReadROM_B7(addr, len1, 0);
|
||||
ReadROM_B7(addr+len1, TransferLen-len1, len1);
|
||||
}
|
||||
else
|
||||
ReadROM_B7(addr, TransferLen, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC0: // SD read
|
||||
{
|
||||
u32 sector = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4];
|
||||
u64 addr = sector * 0x200ULL;
|
||||
|
||||
if (CartSD)
|
||||
{
|
||||
fseek(CartSD, addr, SEEK_SET);
|
||||
fread(TransferData, TransferLen, 1, CartSD);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC1: // SD write
|
||||
{
|
||||
TransferDir = 1;
|
||||
memcpy(TransferCmd, cmd, 8);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("unknown homebrew cart command %02X\n", cmd[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1215,8 +1297,8 @@ void WriteROMCnt(u32 val)
|
||||
else if (datasize > 0)
|
||||
datasize = 0x100 << datasize;
|
||||
|
||||
DataOutPos = 0;
|
||||
DataOutLen = datasize;
|
||||
TransferPos = 0;
|
||||
TransferLen = datasize;
|
||||
|
||||
// handle KEY1 encryption as needed.
|
||||
// KEY2 encryption is implemented in hardware and doesn't need to be handled.
|
||||
@ -1242,28 +1324,32 @@ void WriteROMCnt(u32 val)
|
||||
cmd[4], cmd[5], cmd[6], cmd[7],
|
||||
datasize);*/
|
||||
|
||||
// default is read
|
||||
// commands that do writes will change this
|
||||
TransferDir = 0;
|
||||
|
||||
switch (cmd[0])
|
||||
{
|
||||
case 0x9F:
|
||||
memset(DataOut, 0xFF, DataOutLen);
|
||||
memset(TransferData, 0xFF, TransferLen);
|
||||
break;
|
||||
|
||||
case 0x00:
|
||||
memset(DataOut, 0, DataOutLen);
|
||||
if (DataOutLen > 0x1000)
|
||||
memset(TransferData, 0, TransferLen);
|
||||
if (TransferLen > 0x1000)
|
||||
{
|
||||
ReadROM(0, 0x1000, 0);
|
||||
for (u32 pos = 0x1000; pos < DataOutLen; pos += 0x1000)
|
||||
memcpy(DataOut+pos, DataOut, 0x1000);
|
||||
for (u32 pos = 0x1000; pos < TransferLen; pos += 0x1000)
|
||||
memcpy(TransferData+pos, TransferData, 0x1000);
|
||||
}
|
||||
else
|
||||
ReadROM(0, DataOutLen, 0);
|
||||
ReadROM(0, TransferLen, 0);
|
||||
break;
|
||||
|
||||
case 0x90:
|
||||
case 0xB8:
|
||||
for (u32 pos = 0; pos < DataOutLen; pos += 4)
|
||||
*(u32*)&DataOut[pos] = CartID;
|
||||
for (u32 pos = 0; pos < TransferLen; pos += 4)
|
||||
*(u32*)&TransferData[pos] = CartID;
|
||||
break;
|
||||
|
||||
case 0x3C:
|
||||
@ -1292,8 +1378,8 @@ void WriteROMCnt(u32 val)
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
for (u32 pos = 0; pos < DataOutLen; pos += 4)
|
||||
*(u32*)&DataOut[pos] = CartID;
|
||||
for (u32 pos = 0; pos < TransferLen; pos += 4)
|
||||
*(u32*)&TransferData[pos] = CartID;
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
@ -1343,29 +1429,52 @@ void WriteROMCnt(u32 val)
|
||||
NDS::ScheduleEvent(NDS::Event_ROMTransfer, false, xfercycle*(cmddelay+4), ROMPrepareData, 0);
|
||||
}
|
||||
|
||||
void AdvanceROMTransfer()
|
||||
{
|
||||
ROMCnt &= ~(1<<23);
|
||||
|
||||
if (TransferPos < TransferLen)
|
||||
{
|
||||
u32 xfercycle = (ROMCnt & (1<<27)) ? 8 : 5;
|
||||
u32 delay = 4;
|
||||
if (!(ROMCnt & (1<<30)))
|
||||
{
|
||||
if (!(TransferPos & 0x1FF))
|
||||
delay += ((ROMCnt >> 16) & 0x3F);
|
||||
}
|
||||
|
||||
NDS::ScheduleEvent(NDS::Event_ROMTransfer, false, xfercycle*delay, ROMPrepareData, 0);
|
||||
}
|
||||
else
|
||||
ROMEndTransfer(0);
|
||||
}
|
||||
|
||||
u32 ReadROMData()
|
||||
{
|
||||
if (ROMCnt & (1<<23))
|
||||
{
|
||||
ROMCnt &= ~(1<<23);
|
||||
|
||||
if (DataOutPos < DataOutLen)
|
||||
{
|
||||
u32 xfercycle = (ROMCnt & (1<<27)) ? 8 : 5;
|
||||
u32 delay = 4;
|
||||
if (!(ROMCnt & (1<<30)))
|
||||
{
|
||||
if (!(DataOutPos & 0x1FF))
|
||||
delay += ((ROMCnt >> 16) & 0x3F);
|
||||
}
|
||||
|
||||
NDS::ScheduleEvent(NDS::Event_ROMTransfer, false, xfercycle*delay, ROMPrepareData, 0);
|
||||
}
|
||||
else
|
||||
ROMEndTransfer(0);
|
||||
AdvanceROMTransfer();
|
||||
}
|
||||
|
||||
return ROMDataOut;
|
||||
return ROMData;
|
||||
}
|
||||
|
||||
void WriteROMData(u32 val)
|
||||
{
|
||||
ROMData = val;
|
||||
|
||||
if (ROMCnt & (1<<23))
|
||||
{
|
||||
if (TransferDir == 1)
|
||||
{
|
||||
if (TransferPos < TransferLen)
|
||||
*(u32*)&TransferData[TransferPos] = ROMData;
|
||||
|
||||
TransferPos += 4;
|
||||
}
|
||||
|
||||
AdvanceROMTransfer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user