mirror of
https://github.com/rvtr/GodMode9i.git
synced 2025-11-02 00:11:07 -04:00
WIP: Fix NAND cart dumping
This commit is contained in:
parent
531e58531b
commit
d75ab87bfb
@ -20,6 +20,16 @@ extern bool expansionPakFound;
|
||||
|
||||
static sNDSHeaderExt ndsCardHeader;
|
||||
|
||||
void dumpFailMsg(bool save) {
|
||||
font->clear(false);
|
||||
font->printf(0, 0, false, Alignment::left, Palette::white, "Failed to dump the %s.", save ? "save" : "ROM");
|
||||
font->update(false);
|
||||
|
||||
for (int i = 0; i < 60*2; i++) {
|
||||
swiWaitForVBlank();
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// https://github.com/devkitPro/libnds/blob/master/source/common/cardEeprom.c#L74
|
||||
// with Pokémon Mystery Dungeon - Explorers of Sky (128 KiB EEPROM) fixed
|
||||
@ -157,6 +167,28 @@ void cardEepromChipEraseFixed(void) {
|
||||
}
|
||||
}
|
||||
|
||||
u32 cardNandGetSaveSize(void) {
|
||||
u32 id = cardReadID(CARD_CLK_SLOW);
|
||||
|
||||
u16 flags = id >> 16;
|
||||
|
||||
if ((id & 0xFF) == 0xEC) { // Samsung
|
||||
switch(flags) {
|
||||
case 0x8801:
|
||||
return 8 << 20; // 8MByte - Jam with the Band
|
||||
break;
|
||||
case 0x8800:
|
||||
return 16 << 20; // 16MByte - WarioWare D.I.Y.
|
||||
break;
|
||||
case 0xE800:
|
||||
return 82 << 20; // 82MByte - Face Training
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ndsCardSaveDump(const char* filename) {
|
||||
FILE *out = fopen(filename, "wb");
|
||||
if(out) {
|
||||
@ -165,29 +197,76 @@ void ndsCardSaveDump(const char* filename) {
|
||||
font->print(0, 1, false, "Do not remove the NDS card.");
|
||||
font->update(false);
|
||||
|
||||
unsigned char *buffer;
|
||||
auxspi_extra card_type = auxspi_has_extra();
|
||||
if(card_type == AUXSPI_INFRARED) {
|
||||
int size = auxspi_save_size_log_2(card_type);
|
||||
int size_blocks;
|
||||
int type = auxspi_save_type(card_type);
|
||||
if(size < 16)
|
||||
size_blocks = 1;
|
||||
else
|
||||
size_blocks = 1 << (size - 16);
|
||||
u32 LEN = std::min(1 << size, 1 << 16);
|
||||
buffer = new unsigned char[LEN*size_blocks];
|
||||
auxspi_read_data(0, buffer, LEN*size_blocks, type, card_type);
|
||||
fwrite(buffer, 1, LEN*size_blocks, out);
|
||||
} else {
|
||||
int type = cardEepromGetTypeFixed();
|
||||
int size = cardEepromGetSizeFixed();
|
||||
buffer = new unsigned char[size];
|
||||
cardReadEeprom(0, buffer, size, type);
|
||||
fwrite(buffer, 1, size, out);
|
||||
int type = cardEepromGetTypeFixed();
|
||||
|
||||
if(type == -1) { // NAND
|
||||
u32 saveSize = cardNandGetSaveSize();
|
||||
|
||||
if(saveSize == 0) {
|
||||
dumpFailMsg(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// testing print
|
||||
font->clear(false);
|
||||
font->printf(0, 0, false, Alignment::left, Palette::white, "Found NAND save: Size: %d MiB", saveSize >> 20);
|
||||
font->update(false);
|
||||
for(int i = 0; i < 120; i++)
|
||||
swiWaitForVBlank();
|
||||
|
||||
u32 currentSize = saveSize;
|
||||
FILE* destinationFile = fopen(filename, "wb");
|
||||
if (destinationFile) {
|
||||
|
||||
font->print(0, 4, false, "Progress:");
|
||||
font->print(0, 5, false, "[");
|
||||
font->print(-1, 5, false, "]");
|
||||
for (u32 src = 0; src < saveSize; src += 0x8000) {
|
||||
// Print time
|
||||
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||
font->update(true);
|
||||
|
||||
font->print((src / (saveSize / (SCREEN_COLS - 2))) + 1, 5, false, "=");
|
||||
font->printf(0, 6, false, Alignment::left, Palette::white, "%d/%d Bytes", src, saveSize);
|
||||
font->update(false);
|
||||
|
||||
for (u32 i = 0; i < 0x8000; i += 0x200) {
|
||||
cardRead(src+i, copyBuf+i);
|
||||
}
|
||||
if (fwrite(copyBuf, 1, (currentSize >= 0x8000 ? 0x8000 : currentSize), destinationFile) < 1) {
|
||||
dumpFailMsg(true);
|
||||
break;
|
||||
}
|
||||
currentSize -= 0x8000;
|
||||
}
|
||||
fclose(destinationFile);
|
||||
} else {
|
||||
dumpFailMsg(true);
|
||||
}
|
||||
} else { // SPI
|
||||
unsigned char *buffer;
|
||||
auxspi_extra card_type = auxspi_has_extra();
|
||||
if(card_type == AUXSPI_INFRARED) {
|
||||
int size = auxspi_save_size_log_2(card_type);
|
||||
int size_blocks;
|
||||
int type = auxspi_save_type(card_type);
|
||||
if(size < 16)
|
||||
size_blocks = 1;
|
||||
else
|
||||
size_blocks = 1 << (size - 16);
|
||||
u32 LEN = std::min(1 << size, 1 << 16);
|
||||
buffer = new unsigned char[LEN*size_blocks];
|
||||
auxspi_read_data(0, buffer, LEN*size_blocks, type, card_type);
|
||||
fwrite(buffer, 1, LEN*size_blocks, out);
|
||||
} else {
|
||||
int size = cardEepromGetSizeFixed();
|
||||
buffer = new unsigned char[size];
|
||||
cardReadEeprom(0, buffer, size, type);
|
||||
fwrite(buffer, 1, size, out);
|
||||
}
|
||||
delete[] buffer;
|
||||
fclose(out);
|
||||
}
|
||||
delete[] buffer;
|
||||
fclose(out);
|
||||
}
|
||||
}
|
||||
|
||||
@ -312,16 +391,6 @@ void ndsCardSaveRestore(const char *filename) {
|
||||
}
|
||||
}
|
||||
|
||||
void dumpFailMsg(void) {
|
||||
font->clear(false);
|
||||
font->print(0, 0, false, "Failed to dump the ROM.");
|
||||
font->update(false);
|
||||
|
||||
for (int i = 0; i < 60*2; i++) {
|
||||
swiWaitForVBlank();
|
||||
}
|
||||
}
|
||||
|
||||
void ndsCardDump(void) {
|
||||
int pressed = 0;
|
||||
//bool showGameCardMsgAgain = false;
|
||||
@ -619,14 +688,14 @@ void ndsCardDump(void) {
|
||||
cardRead (src+i, copyBuf+i);
|
||||
}
|
||||
if (fwrite(copyBuf, 1, (currentSize>=0x8000 ? 0x8000 : currentSize), destinationFile) < 1) {
|
||||
dumpFailMsg();
|
||||
dumpFailMsg(false);
|
||||
break;
|
||||
}
|
||||
currentSize -= 0x8000;
|
||||
}
|
||||
fclose(destinationFile);
|
||||
} else {
|
||||
dumpFailMsg();
|
||||
dumpFailMsg(false);
|
||||
}
|
||||
ndsCardSaveDump(destSavPath);
|
||||
//}
|
||||
@ -752,7 +821,7 @@ void gbaCartDump(void) {
|
||||
FILE* destinationFile = fopen(destPath, "wb");
|
||||
if (destinationFile) {
|
||||
if (fwrite(GBAROM, 1, romSize, destinationFile) < 1) {
|
||||
dumpFailMsg();
|
||||
dumpFailMsg(false);
|
||||
} else
|
||||
// Check for 64MB GBA Video ROM
|
||||
if (strncmp((char*)0x080000AC, "MSAE", 4)==0 // Shark Tale
|
||||
@ -774,14 +843,14 @@ void gbaCartDump(void) {
|
||||
writeChange(cmd);
|
||||
readChange();
|
||||
if (fwrite(GBAROM + (0x1000 >> 1), 0x1000, 1, destinationFile) < 1) {
|
||||
dumpFailMsg();
|
||||
dumpFailMsg(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(destinationFile);
|
||||
} else {
|
||||
dumpFailMsg();
|
||||
dumpFailMsg(false);
|
||||
}
|
||||
|
||||
// Save file
|
||||
|
||||
@ -85,7 +85,10 @@ typedef struct {
|
||||
u32 romSize; //!< total size of the ROM.
|
||||
|
||||
u32 headerSize; //!< ROM header size.
|
||||
u32 zeros88[14];
|
||||
u32 zeros88[3];
|
||||
u16 nandRomEnd; //!< ROM region end for NAND games.
|
||||
u16 nandRwStart; //!< RW region start for NAND games.
|
||||
u32 zeros98[10];
|
||||
u8 gbaLogo[156]; //!< Nintendo logo needed for booting the game.
|
||||
u16 logoCRC16; //!< Nintendo Logo Checksum, CRC-16.
|
||||
u16 headerCRC16; //!< header checksum, CRC-16.
|
||||
|
||||
@ -42,6 +42,18 @@ enum {
|
||||
ERR_HEAD_CRC = 0x16,
|
||||
} ERROR_CODES;
|
||||
|
||||
// NAND Card commands
|
||||
// https://problemkaputt.de/gbatek-ds-cartridge-nand.htm
|
||||
#define CARD_CMD_NAND_WRITE_BUFFER 0x81
|
||||
#define CARD_CMD_NAND_FLUSH_BUFFER 0x82
|
||||
#define CARD_CMD_NAND_DISCARD_BUFFER 0x84
|
||||
#define CARD_CMD_NAND_WRITE_ENABLE 0x85
|
||||
#define CARD_CMD_NAND_ROM_MODE 0x8B
|
||||
#define CARD_CMD_NAND_RW_MODE 0xB2
|
||||
#define CARD_CMD_NAND_READ_STATUS 0xD6
|
||||
#define CARD_CMD_NAND_UNKNOWN 0xBB
|
||||
#define CARD_CMD_NAND_READ_ID 0x94
|
||||
|
||||
typedef union
|
||||
{
|
||||
char title[4];
|
||||
@ -51,6 +63,8 @@ typedef union
|
||||
static bool twlBlowfish = false;
|
||||
|
||||
static bool normalChip = false; // As defined by GBAtek, normal chip secure area is accessed in blocks of 0x200, other chip in blocks of 0x1000
|
||||
static bool nandChip = false;
|
||||
static bool nandRomMode = true;
|
||||
static u32 portFlags = 0;
|
||||
static u32 headerData[0x1000/sizeof(u32)] = {0};
|
||||
static u32 secureArea[CARD_SECURE_AREA_SIZE/sizeof(u32)] = {0};
|
||||
@ -277,6 +291,7 @@ int cardInit (sNDSHeaderExt* ndsHeader)
|
||||
{
|
||||
u32 portFlagsKey1, portFlagsSecRead;
|
||||
normalChip = false; // As defined by GBAtek, normal chip secure area is accessed in blocks of 0x200, other chip in blocks of 0x1000
|
||||
nandRomMode = true;
|
||||
int secureBlockNumber;
|
||||
int i;
|
||||
u8 cmdData[8] __attribute__ ((aligned));
|
||||
@ -310,10 +325,17 @@ int cardInit (sNDSHeaderExt* ndsHeader)
|
||||
|
||||
toncset(headerData, 0, 0x1000);
|
||||
|
||||
u32 iCardId=cardReadID(CARD_CLK_SLOW);
|
||||
u32 iCardId=cardReadID(CARD_CLK_SLOW);
|
||||
while(REG_ROMCTRL & CARD_BUSY);
|
||||
//u32 iCheapCard=iCardId&0x80000000;
|
||||
|
||||
// Check if NAND
|
||||
nandChip = (iCardId >> 24) & BIT(3);
|
||||
if (nandChip) {
|
||||
cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_BLK_SIZE(1), NULL, 0);
|
||||
nandRomMode = true;
|
||||
}
|
||||
|
||||
// Read the header
|
||||
cardParamCommand (CARD_CMD_HEADER_READ, 0,
|
||||
CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(1) | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F),
|
||||
@ -464,6 +486,16 @@ void cardRead (u32 src, void* dest)
|
||||
return;
|
||||
}
|
||||
|
||||
if (nandChip) {
|
||||
if (src < ndsHeader->nandRomEnd * 0x20000 /*dsi: 80000h?*/ && !nandRomMode) {
|
||||
cardParamCommand(CARD_CMD_NAND_ROM_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_BLK_SIZE(1), NULL, 0);
|
||||
nandRomMode = true;
|
||||
} else if (src > ndsHeader->nandRwStart * 0x20000 /*dsi: 80000h?*/ && nandRomMode) {
|
||||
cardParamCommand(CARD_CMD_NAND_RW_MODE, 0, portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_BLK_SIZE(1), NULL, 0);
|
||||
nandRomMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
cardParamCommand (CARD_CMD_DATA_READ, src,
|
||||
portFlags | CARD_ACTIVATE | CARD_nRESET | CARD_BLK_SIZE(1),
|
||||
dest, 0x200/sizeof(u32));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user