get further with this

This commit is contained in:
Arisotura
2021-04-13 02:27:17 +02:00
parent 875a305595
commit 9d849ac106
2 changed files with 523 additions and 125 deletions

View File

@ -472,6 +472,10 @@ namespace NDSCart
u16 SPICnt;
u32 ROMCnt;
u8 SPIData;
u32 SPIDataPos;
bool SPIHold;
u8 ROMCommand[8];
u32 ROMData;
@ -490,6 +494,8 @@ bool CartIsDSi;
FILE* CartSD;
CartCommon* Cart;
u32 CmdEncMode;
u32 DataEncMode;
@ -499,14 +505,6 @@ u64 Key2_X;
u64 Key2_Y;
void ROMCommand_Retail(u8* cmd);
void ROMCommand_RetailNAND(u8* cmd);
void ROMCommand_Homebrew(u8* cmd);
void (*ROMCommandHandler)(u8* cmd);
u32 ByteSwap(u32 val)
{
return (val >> 24) | ((val >> 8) & 0xFF00) | ((val << 8) & 0xFF0000) | (val << 24);
@ -623,82 +621,351 @@ void ApplyModcrypt(u32 addr, u32 len, u8* iv)
}
bool Init()
CartCommon::CartCommon(u8* rom, u32 len)
{
if (!NDSCart_SRAM::Init()) return false;
CartROM = NULL;
CartSD = NULL;
return true;
ROM = rom;
ROMLength = len;
}
void DeInit()
CartCommon::~CartCommon()
{
if (CartROM) delete[] CartROM;
if (CartSD) fclose(CartSD);
NDSCart_SRAM::DeInit();
}
void Reset()
void CartCommon::Reset()
{
CartInserted = false;
if (CartROM) delete[] CartROM;
CartROM = NULL;
CartROMSize = 0;
CartID = 0;
CartIsHomebrew = false;
CartIsDSi = false;
if (CartSD) fclose(CartSD);
CartSD = NULL;
ROMCommandHandler = NULL;
NDSCart_SRAM::Reset();
ResetCart();
}
void DoSavestate(Savestate* file)
void CartCommon::DoSavestate(Savestate* file)
{
file->Section("NDSC");
// TODO?
}
file->Var16(&SPICnt);
file->Var32(&ROMCnt);
void CartCommon::ROMCommandStart(u8* cmd)
{
switch (cmd[0])
{
case 0x9F:
memset(TransferData, 0xFF, TransferLen);
break;
file->VarArray(ROMCommand, 8);
file->Var32(&ROMData);
case 0x00:
memset(TransferData, 0, TransferLen);
if (TransferLen > 0x1000)
{
ReadROM(0, 0x1000, 0);
for (u32 pos = 0x1000; pos < TransferLen; pos += 0x1000)
memcpy(TransferData+pos, TransferData, 0x1000);
}
else
ReadROM(0, TransferLen, 0);
break;
file->VarArray(TransferData, 0x4000);
file->Var32(&TransferPos);
file->Var32(&TransferLen);
file->Var32(&TransferDir);
file->VarArray(TransferCmd, 8);
case 0x90:
case 0xB8:
for (u32 pos = 0; pos < TransferLen; pos += 4)
*(u32*)&TransferData[pos] = CartID;
break;
// cart inserted/len/ROM/etc should be already populated
// savestate should be loaded after the right game 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)
case 0x3C:
if (CartInserted)
{
CmdEncMode = 1;
Key1_InitKeycode(false, *(u32*)&CartROM[0xC], 2, 2);
}
break;
file->Var32(&CmdEncMode);
file->Var32(&DataEncMode);
case 0x3D:
if (CartInserted && CartIsDSi)
{
CmdEncMode = 11;
Key1_InitKeycode(true, *(u32*)&CartROM[0xC], 1, 2);
}
break;
// TODO: check KEY1 shit??
default:
if (CmdEncMode == 1 || CmdEncMode == 11)
{
switch (cmd[0] & 0xF0)
{
case 0x40:
DataEncMode = 2;
break;
NDSCart_SRAM::DoSavestate(file);
case 0x10:
for (u32 pos = 0; pos < TransferLen; pos += 4)
*(u32*)&TransferData[pos] = CartID;
break;
case 0x20:
{
u32 addr = (cmd[2] & 0xF0) << 8;
if (CmdEncMode == 11)
{
// TODO: should use entries 0x90/0x92 to determine where the DSi region starts??
// DSi secure area starts with 0x3000 unreadable bytes
u32 arm9i_base = *(u32*)&CartROM[0x1C0];
addr -= 0x4000;
addr += arm9i_base;
}
ReadROM(addr, 0x1000, 0);
}
break;
case 0xA0:
CmdEncMode = 2;
break;
}
}
break;
}
}
void CartCommon::ROMCommandFinish(u8* cmd)
{
}
u8 CartCommon::SPIWrite(u8 val, u32 pos, bool last)
{
return val;
}
void CartCommon::ReadROM(u32 addr, u32 len, u32 offset)
{
if (addr >= ROMLength) return;
if ((addr+len) > ROMLength)
len = ROMLength - addr;
memcpy(TransferData+offset, ROM+addr, len);
}
void ApplyDLDIPatch(const u8* patch, u32 len)
CartRetail::CartRetail(u8* rom, u32 len) : CartCommon(rom, len)
{
u32 offset = *(u32*)&CartROM[0x20];
u32 size = *(u32*)&CartROM[0x2C];
}
u8* binary = &CartROM[offset];
CartRetail::~CartRetail()
{
}
void CartRetail::Reset()
{
}
void CartRetail::DoSavestate(Savestate* file)
{
// TODO?
}
void CartRetail::ROMCommandStart(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;
default:
return CartCommon::ROMCommandStart(cmd);
}
}
u8 CartRetail::SPIWrite(u8 val, u32 pos, bool last)
{
//
}
void CartRetail::ReadROM_B7(u32 addr, u32 len, u32 offset)
{
addr &= (ROMLength-1);
if (addr < 0x8000)
addr = 0x8000 + (addr & 0x1FF);
// TODO: protect DSi secure area
// also protect DSi region if not unlocked
// and other security shenanigans
memcpy(TransferData+offset, ROM+addr, len);
}
CartRetailNAND::CartRetailNAND(u8* rom, u32 len) : CartRetail(rom, len)
{
}
CartRetailNAND::~CartRetailNAND()
{
}
void CartRetailNAND::Reset()
{
}
void CartRetailNAND::DoSavestate(Savestate* file)
{
// TODO?
}
void CartRetailNAND::ROMCommandStart(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;
}
break;
default:
return CartRetail::ROMCommandStart(cmd);
}
}
void CartRetailNAND::ROMCommandFinish(u8* cmd)
{
switch (cmd[0])
{
// TODO!
default:
return CartCommon::ROMCommandFinish(cmd);
}
}
//
CartHomebrew::CartHomebrew(u8* rom, u32 len) : CartCommon(rom, len)
{
}
CartHomebrew::~CartHomebrew()
{
}
void CartHomebrew::Reset()
{
}
void CartHomebrew::DoSavestate(Savestate* file)
{
// TODO?
}
void CartHomebrew::ROMCommandStart(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;
}
break;
default:
return CartCommon::ROMCommandStart(cmd);
}
}
void CartHomebrew::ROMCommandFinish(u8* cmd)
{
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;
default:
return CartCommon::ROMCommandFinish(cmd);
}
}
void CartHomebrew::ApplyDLDIPatch(const u8* patch, u32 len)
{
u32 offset = *(u32*)&ROM[0x20];
u32 size = *(u32*)&ROM[0x2C];
u8* binary = &ROM[offset];
u32 dldioffset = 0;
for (u32 i = 0; i < size; i++)
@ -813,6 +1080,97 @@ void ApplyDLDIPatch(const u8* patch, u32 len)
printf("applied DLDI patch\n");
}
void CartHomebrew::ReadROM_B7(u32 addr, u32 len, u32 offset)
{
// TODO: how strict should this be for homebrew?
addr &= (ROMLength-1);
memcpy(TransferData+offset, ROM+addr, len);
}
/*void ROMCommand_Retail(u8* cmd);
void ROMCommand_RetailNAND(u8* cmd);
void ROMCommand_Homebrew(u8* cmd);
void (*ROMCommandHandler)(u8* cmd);*/
bool Init()
{
if (!NDSCart_SRAM::Init()) return false;
CartROM = nullptr;
CartSD = nullptr;
Cart = nullptr;
return true;
}
void DeInit()
{
if (CartROM) delete[] CartROM;
if (CartSD) fclose(CartSD);
if (Cart) delete Cart;
NDSCart_SRAM::DeInit();
}
void Reset()
{
CartInserted = false;
if (CartROM) delete[] CartROM;
CartROM = nullptr;
CartROMSize = 0;
CartID = 0;
CartIsHomebrew = false;
CartIsDSi = false;
if (CartSD) fclose(CartSD);
CartSD = nullptr;
if (Cart) delete Cart;
Cart = nullptr;
NDSCart_SRAM::Reset();
ResetCart();
}
void DoSavestate(Savestate* file)
{
file->Section("NDSC");
file->Var16(&SPICnt);
file->Var32(&ROMCnt);
file->VarArray(ROMCommand, 8);
file->Var32(&ROMData);
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
// (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)
file->Var32(&CmdEncMode);
file->Var32(&DataEncMode);
// TODO: check KEY1 shit??
NDSCart_SRAM::DoSavestate(file);
}
bool ReadROMParams(u32 gamecode, ROMListEntry* params)
{
@ -975,12 +1333,21 @@ bool LoadROMCommon(u32 filelength, const char *sram, bool direct)
CartInserted = true;
// TODO: support more fancy cart types (homebrew?, flashcarts, etc)
if (CartIsHomebrew)
/*if (CartIsHomebrew)
ROMCommandHandler = ROMCommand_Homebrew;
else if (CartID & 0x08000000)
ROMCommandHandler = ROMCommand_RetailNAND;
else
ROMCommandHandler = ROMCommand_Retail;
ROMCommandHandler = ROMCommand_Retail;*/
// TODO: add case for pokémon typing game
if (CartIsHomebrew)
Cart = new CartHomebrew(CartROM, CartROMSize);
else if (CartID & 0x08000000)
Cart = new CartRetailNAND(CartROM, CartROMSize);
else if (CartID & 0x00010000)
Cart = new CartRetailPoke(CartROM, CartROMSize);
else
Cart = new CartRetail(CartROM, CartROMSize);
// encryption
Key1_InitKeycode(false, gamecode, 2, 2);
@ -1077,6 +1444,10 @@ void ResetCart()
SPICnt = 0;
ROMCnt = 0;
SPIData = 0;
SPIDataPos = 0;
SPIHold = false;
memset(ROMCommand, 0, 8);
ROMData = 0;
@ -1092,9 +1463,11 @@ void ResetCart()
CmdEncMode = 0;
DataEncMode = 0;
if (Cart) Cart->Reset();
}
void ReadROM(u32 addr, u32 len, u32 offset)
/*void ReadROM(u32 addr, u32 len, u32 offset)
{
if (!CartInserted) return;
@ -1117,7 +1490,7 @@ void ReadROM_B7(u32 addr, u32 len, u32 offset)
}
memcpy(TransferData+offset, CartROM+addr, len);
}
}*/
void ROMEndTransfer(u32 param)
@ -1127,7 +1500,7 @@ void ROMEndTransfer(u32 param)
if (SPICnt & (1<<14))
NDS::SetIRQ((NDS::ExMemCnt[0]>>11)&0x1, NDS::IRQ_CartSendDone);
if (TransferDir == 1)
/*if (TransferDir == 1)
{
// finish a write
@ -1147,7 +1520,8 @@ void ROMEndTransfer(u32 param)
}
break;
}
}
}*/
if (Cart) Cart->ROMCommandFinish(TransferCmd);
}
void ROMPrepareData(u32 param)
@ -1171,7 +1545,7 @@ void ROMPrepareData(u32 param)
}
void ROMCommand_Retail(u8* cmd)
/*void ROMCommand_Retail(u8* cmd)
{
switch (cmd[0])
{
@ -1296,7 +1670,7 @@ void ROMCommand_Homebrew(u8* cmd)
printf("unknown homebrew cart command %02X\n", cmd[0]);
break;
}
}
}*/
void WriteROMCnt(u32 val)
@ -1338,33 +1712,32 @@ void WriteROMCnt(u32 val)
// handle KEY1 encryption as needed.
// KEY2 encryption is implemented in hardware and doesn't need to be handled.
u8 cmd[8];
if (CmdEncMode == 1 || CmdEncMode == 11)
{
*(u32*)&cmd[0] = ByteSwap(*(u32*)&ROMCommand[4]);
*(u32*)&cmd[4] = ByteSwap(*(u32*)&ROMCommand[0]);
Key1_Decrypt((u32*)cmd);
u32 tmp = ByteSwap(*(u32*)&cmd[4]);
*(u32*)&cmd[4] = ByteSwap(*(u32*)&cmd[0]);
*(u32*)&cmd[0] = tmp;
*(u32*)&TransferCmd[0] = ByteSwap(*(u32*)&ROMCommand[4]);
*(u32*)&TransferCmd[4] = ByteSwap(*(u32*)&ROMCommand[0]);
Key1_Decrypt((u32*)TransferCmd);
u32 tmp = ByteSwap(*(u32*)&TransferCmd[4]);
*(u32*)&TransferCmd[4] = ByteSwap(*(u32*)&TransferCmd[0]);
*(u32*)&TransferCmd[0] = tmp;
}
else
{
*(u32*)&cmd[0] = *(u32*)&ROMCommand[0];
*(u32*)&cmd[4] = *(u32*)&ROMCommand[4];
*(u32*)&TransferCmd[0] = *(u32*)&ROMCommand[0];
*(u32*)&TransferCmd[4] = *(u32*)&ROMCommand[4];
}
/*printf("ROM COMMAND %04X %08X %02X%02X%02X%02X%02X%02X%02X%02X SIZE %04X\n",
SPICnt, ROMCnt,
cmd[0], cmd[1], cmd[2], cmd[3],
cmd[4], cmd[5], cmd[6], cmd[7],
TransferCmd[0], TransferCmd[1], TransferCmd[2], TransferCmd[3],
TransferCmd[4], TransferCmd[5], TransferCmd[6], TransferCmd[7],
datasize);*/
// default is read
// commands that do writes will change this
TransferDir = 0;
switch (cmd[0])
/*switch (cmd[0])
{
case 0x9F:
memset(TransferData, 0xFF, TransferLen);
@ -1439,7 +1812,8 @@ void WriteROMCnt(u32 val)
else if (ROMCommandHandler)
ROMCommandHandler(cmd);
break;
}
}*/
if (Cart) Cart->ROMCommandStart(TransferCmd);
ROMCnt &= ~(1<<23);
@ -1532,7 +1906,8 @@ u8 ReadSPIData()
if (!(SPICnt & (1<<13))) return 0;
if (SPICnt & (1<<7)) return 0; // checkme
return NDSCart_SRAM::Read();
//return NDSCart_SRAM::Read();
return SPIData;
}
void WriteSPIData(u8 val)
@ -1543,7 +1918,27 @@ void WriteSPIData(u8 val)
if (SPICnt & (1<<7)) printf("!! WRITING AUXSPIDATA DURING PENDING TRANSFER\n");
SPICnt |= (1<<7);
NDSCart_SRAM::Write(val, SPICnt&(1<<6));
//NDSCart_SRAM::Write(val, SPICnt&(1<<6));
bool hold = SPICnt&(1<<6);
bool islast = false;
if (!hold)
{
if (SPIHold) islast = true;
SPIHold = false;
}
else if (hold && (!SPIHold))
{
SPIHold = true;
SPIDataPos = 0;
}
else
{
SPIDataPos++;
}
if (Cart) SPIData = Cart->SPIWrite(val, SPIDataPos, islast);
else SPIData = val; // checkme
// SPI transfers one bit per cycle -> 8 cycles per byte
u32 delay = 8 * (8 << (SPICnt & 0x3));

View File

@ -74,15 +74,16 @@ public:
virtual void Reset();
virtual void DoSavestate(Savestate* file) = 0;
virtual void DoSavestate(Savestate* file);
virtual void ROMCommandStart(u8* cmd);
virtual void ROMCommandFinish(u8* cmd);
virtual u8 SPIRead();
virtual void SPIWrite(u8 val, u32 hold);
virtual u8 SPIWrite(u8 val, u32 pos, bool last);
protected:
void ReadROM(u32 addr, u32 len, u32 offset);
u8* ROM;
u32 ROMLength;
};
@ -99,14 +100,15 @@ public:
virtual void DoSavestate(Savestate* file);
virtual void ROMCommandStart(u8* cmd);
virtual void ROMCommandFinish(u8* cmd);
virtual u8 SPIRead();
virtual void SPIWrite(u8 val, u32 hold);
virtual u8 SPIWrite(u8 val, u32 pos, bool last);
protected:
void ReadROM_B7(u32 addr, u32 len, u32 offset);
};
// CartRetailNAND -- retail cart with NAND SRAM (WarioWare DIY, Jam with the Band, ...)
class CartRetailNAND : public CartCommon
class CartRetailNAND : public CartRetail
{
public:
CartRetailNAND(u8* rom, u32 len);
@ -119,12 +121,11 @@ public:
void ROMCommandStart(u8* cmd);
void ROMCommandFinish(u8* cmd);
u8 SPIRead();
void SPIWrite(u8 val, u32 hold);
u8 SPIWrite(u8 val, u32 pos, bool last);
};
// CartRetailPoke -- Pok<6F>mon cart (SPI IR device and SRAM)
class CartRetailPoke : public CartCommon
class CartRetailPoke : public CartRetail
{
public:
CartRetailPoke(u8* rom, u32 len);
@ -134,12 +135,11 @@ public:
void DoSavestate(Savestate* file);
u8 SPIRead();
void SPIWrite(u8 val, u32 hold);
u8 SPIWrite(u8 val, u32 pos, bool last);
};
// CartRetailBT - Pok<6F>mon Typing Adventure (SPI BT controller)
class CartRetailBT : public CartCommon
class CartRetailBT : public CartRetail
{
public:
CartRetailBT(u8* rom, u32 len);
@ -149,8 +149,7 @@ public:
void DoSavestate(Savestate* file);
u8 SPIRead();
void SPIWrite(u8 val, u32 hold);
u8 SPIWrite(u8 val, u32 pos, bool last);
};
// CartHomebrew -- homebrew 'cart' (no SRAM, DLDI)
@ -166,47 +165,51 @@ public:
void ROMCommandStart(u8* cmd);
void ROMCommandFinish(u8* cmd);
private:
void ApplyDLDIPatch(const u8* patch, u32 len);
void ReadROM_B7(u32 addr, u32 len, u32 offset);
};
extern u16 SPICnt; //
extern u32 ROMCnt; //
extern u16 SPICnt;
extern u32 ROMCnt;
extern u8 ROMCommand[8]; //
extern u8 ROMCommand[8];
extern u8* CartROM; // used only for header??
extern u8* CartROM;
extern u32 CartROMSize;
extern u32 CartID; //
extern u32 CartID;
bool Init(); //
void DeInit(); //
void Reset(); //
bool Init();
void DeInit();
void Reset();
void DoSavestate(Savestate* file); //
void DoSavestate(Savestate* file);
void DecryptSecureArea(u8* out); // direct-boot shito
bool LoadROM(const char* path, const char* sram, bool direct); //
bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct); //
void DecryptSecureArea(u8* out);
bool LoadROM(const char* path, const char* sram, bool direct);
bool LoadROM(const u8* romdata, u32 filelength, const char *sram, bool direct);
void FlushSRAMFile(); //
void FlushSRAMFile();
void RelocateSave(const char* path, bool write); //
void RelocateSave(const char* path, bool write);
int ImportSRAM(const u8* data, u32 length); //
int ImportSRAM(const u8* data, u32 length);
void ResetCart(); //
void ResetCart();
void WriteROMCnt(u32 val); //
u32 ReadROMData(); //
void WriteROMData(u32 val); //
void WriteROMCnt(u32 val);
u32 ReadROMData();
void WriteROMData(u32 val);
void WriteSPICnt(u16 val); //
u8 ReadSPIData(); //
void WriteSPIData(u8 val); //
void WriteSPICnt(u16 val);
u8 ReadSPIData();
void WriteSPIData(u8 val);
void ROMPrepareData(u32 param); // scheduler callbacks
void ROMEndTransfer(u32 param); //
void SPITransferDone(u32 param); //
void ROMPrepareData(u32 param);
void ROMEndTransfer(u32 param);
void SPITransferDone(u32 param);
}