DS-Homebrew / nds-bootstrap

Boot an nds file
https://wiki.ds-homebrew.com/nds-bootstrap/
GNU General Public License v3.0
1.19k stars 76 forks source link

run roms from sd, but read&write save from real NDS cartridges #1414

Open Wokann opened 2 years ago

Wokann commented 2 years ago

Is your feature request related to a problem? Please describe. Nowthat twl can use IR feature by running roms from sd card with real NDS cartridge which has IR (such as HG, SS, B, B2), is there anyway which can let us running roms from sd card and read&write saves directly from real NDS cartridges?

Describe the solution you'd like An option which can let us change the save paths of games (into sd card or dirtectly into real nds cartridges).

Describe alternatives you've considered A branch only let save paths into real nds cartridges.

Additional context This is inspired by slot2 nds flashcart. When i used ewin2 & passme to run Pokemon HG, the game said save error. But when I ran HG with a real hg cartridge, it successed in reading and writing save from cartridge. can it be may more easier to achieve this feature by using twl in dsi or 3ds?

Epicpkmn11 commented 2 years ago

I would think it'd be fairly simple, just need to remove the save redirection patches (way back some games even required a donor cart to hold the save), but... is there any point to this? If you've got the real cart in why not just use it?

If you're just looking to move saves between SD and carts there's programs you can use to dump/inject saves. On DSi there's GodMode9i and on 3DS there's Checkpoint or GodMode9. GodMode9i also works on DS, but it's a bit trickier, there's also NDS Backup Tool which does it over Wi-Fi.

Wokann commented 2 years ago

it can be used to loading unofficial localized translation rom or hacking rom with real nds cartridges saves. don't need to take times in inserting, unpluging nds cartrdges and sd cards to dump savefiles, and using file explorers on computer or godmode9i to manage and rename savefiles.

Wokann commented 2 years ago

Please forgive me for disturbing again. After trying a lot, I still can't find how to remove the save redirection patches. Could you guide me on which files to remove it?

Peter0x44 commented 2 years ago

Could you guide me on which files to remove it?

No such guide exists, it would require changing code of nds-bootstrap

Wokann commented 2 years ago

I mean if I want to remove the save redirection patches, which code on which file is associated with the save redirection function so that I can try to edit it. My problem is I tried to edit code of nds-bootstrap, but it seems the codes I edited aren't associated with the save redirection, so it didn't work. The correct address of the codes which are associated with the save redirection is what I want to be guided for.

RocketRobz commented 2 years ago

https://github.com/DS-Homebrew/nds-bootstrap/blob/master/retail/bootloaderi/source/arm7/patch_arm7.c#L511

Wokann commented 2 years ago

https://github.com/DS-Homebrew/nds-bootstrap/blob/master/retail/bootloaderi/source/arm7/patch_arm7.c#L511

thanks! it works! after comment out this code, nds-bootstrap runs the fans-translated rom with reading save file on nds cartridge! thank you!

Peter0x44 commented 2 years ago

If this feature were to be implemented (properly), I think it would require some sanity checks so people don't end up writing the saves of the wrong game to the wrong cart. Perhaps check the title id of the rom and inserted cart are the same? if not, then use the save on the SD (apply redirection patches)?

Wokann commented 2 years ago

there's new problem happening. I tried Pokemon HGSS, BW, BW2 cartridges, these worked fine with rom in twilightmenu++. But Pokemon DPPt didn't work, even running original dppt rom in twilightmenu++, it can't read the save on cartridges. Also it cannot save the game in twilightmenu, when reset after saveing in game, you will see doctor again. Additonal, when running HGSS\BW12 in twilightmenu++, it will have ap-patched waring while DPPT not. May the problem is about ap patched or others?

what I edited is commenting out from L511 to L532 in /retail/bootloaderi/source/arm7/patch_arm7.c .

Wokann commented 2 years ago

If this feature were to be implemented (properly), I think it would require some sanity checks so people don't end up writing the saves of the wrong game to the wrong cart. Perhaps check the title id of the rom and inserted cart are the same? if not, then use the save on the SD (apply redirection patches)?

if this function can add to nds-bootstrap(switch save game on sd or cartridge and id safe check), people who wants to play fan-translated rom with directly reading cartridge save will be very happy. if they wants to do it now, they need to patch ips on rom dumped from cartridge to get fan-translated rom, and dump cartridge's save, move save to save folder so that fan-translated rom can read save. and restore the save from twilightmenu++ to cartridege is also cumbersome.

Wokann commented 2 years ago

It seems the earlier version of nds-bootstrap can swich option to load rom from retail cartridge or donor ROM after searching in google. it may mean pokemon DP do can load from cartridge? i'm confused about why my nds-bootstrap can‘t load/save on cartridge after removing the save redirection patches.

Wokann commented 2 years ago

If this feature were to be implemented (properly), I think it would require some sanity checks so people don't end up writing the saves of the wrong game to the wrong cart. Perhaps check the title id of the rom and inserted cart are the same? if not, then use the save on the SD (apply redirection patches)?

For sanity checks, it seems "const char getRomTid(const tNDSHeader ndsHeader)" may be used to get the game code of SD card's rom, but I'm not skilled enough to find which code can bu used to check the game code of NDS cartridge in slot1.

Epicpkmn11 commented 2 years ago

This is where it reads the cart's header for checking if it's an IR game: https://github.com/DS-Homebrew/nds-bootstrap/blob/0138e6a32a82216318e779ce91db7425bd18b326/retail/arm9/source/conf_sd.cpp#L727-L787

Wokann commented 2 years ago

This is where it reads the cart's header for checking if it's an IR game:

https://github.com/DS-Homebrew/nds-bootstrap/blob/0138e6a32a82216318e779ce91db7425bd18b326/retail/arm9/source/conf_sd.cpp#L727-L787

If this feature were to be implemented (properly), I think it would require some sanity checks so people don't end up writing the saves of the wrong game to the wrong cart. Perhaps check the title id of the rom and inserted cart are the same? if not, then use the save on the SD (apply redirection patches)?

thanks~ I finally made it. Compare gamecode between cartridge and rom to decide whether save on sd card or cartridge. First in retail/bootloaderi/source/arm7/main.arm7.c L1633-L1640,enable all slot1. https://github.com/DS-Homebrew/nds-bootstrap/blob/master/retail/bootloaderi/source/arm7/main.arm7.c#L1633-L1640

—————————————————————————————————————— if (!gameOnFlashcard && REG_SCFG_EXT != 0 && !(REG_SCFG_MC & BIT(0))) { my_enableSlot1(); } ——————————————————————————————————————

then in retail/bootloaderi/source/arm7/patch_arm7.c, add some include, and copy some code from retail/arm9/source/conf_sd.cpp#L727-L787, then compare gamecode between cartridge and rom to decide whether save on sd card or cartridge. https://github.com/DS-Homebrew/nds-bootstrap/blob/master/retail/bootloaderi/source/arm7/patch_arm7.c#L508-L1539 —————————————————————————————————————— // Read the header u32 iCardId = cardReadID(CARD_CLK_SLOW); bool normalChip = (iCardId & BIT(31)) != 0; // ROM chip ID MSB
char headerData[0x1000]; cardParamCommand (CARD_CMD_HEADER_READ, 0, CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(1) | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F), (u32 *)headerData , 0x200 / sizeof(u32));

if ((headerData[0x12] != 0) || (headerData[0x1BF] != 0)) {
    // Extended header found
    if(normalChip) {
        for(int i = 0; i < 8; i++) {
            cardParamCommand (CARD_CMD_HEADER_READ, i * 0x200,
                CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(1) | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F),
                (u32 *)headerData + i * 0x200 / sizeof(u32), 0x200 / sizeof(u32));
        }
    }else {
        cardParamCommand (CARD_CMD_HEADER_READ, 0,
            CARD_ACTIVATE | CARD_nRESET | CARD_CLK_SLOW | CARD_BLK_SIZE(4) | CARD_DELAY1(0x1FFF) | CARD_DELAY2(0x3F),
            (u32 *)headerData, 0x1000 / sizeof(u32));
    }
}

if (a7GetReloc(ndsHeader, moduleParams)) {
    u32 saveResult = 0;

    //compare gamecode between cartridge and rom
    //if match, save in cartridge
    //if not, save on sd
    if (memcmp(headerData + 0xC, romTid, 4) == 0) {
    } 
    else{ 

    if (newArm7binarySize==0x2352C || newArm7binarySize==0x235DC || newArm7binarySize==0x23CAC || newArm7binarySize==0x245C4 || newArm7binarySize==0x24DA8 || newArm7binarySize==0x24F50) {
        saveResult = savePatchInvertedThumb(ce7, ndsHeader, moduleParams, saveFileCluster);    
    } else if (isSdk5(moduleParams)) {
        // SDK 5
        saveResult = savePatchV5(ce7, ndsHeader, saveFileCluster);
    } else {
        if (patchOffsetCache.savePatchType == 0) {
            saveResult = savePatchV1(ce7, ndsHeader, moduleParams, saveFileCluster);
            if (!saveResult) {
                patchOffsetCache.savePatchType = 1;
            }
        }
        if (!saveResult && patchOffsetCache.savePatchType == 1) {
            saveResult = savePatchV2(ce7, ndsHeader, moduleParams, saveFileCluster);
            if (!saveResult) {
                patchOffsetCache.savePatchType = 2;
            }
        }
        if (!saveResult && patchOffsetCache.savePatchType == 2) {
            saveResult = savePatchUniversal(ce7, ndsHeader, moduleParams, saveFileCluster);
        }
    }
    }
    if (!saveResult) {
        patchOffsetCache.savePatchType = 0;
    } /*else if (strncmp(romTid, "AMH", 3) == 0) {
        aFile* savFile = (aFile*)(dsiSD ? SAV_FILE_LOCATION : SAV_FILE_LOCATION_ALT);
        fileRead((char*)0x02440000, *savFile, 0, 0x40000, 0);
    }*/
}

——————————————————————————————————————