diff --git a/include/hardware/lgy.h b/include/hardware/lgy.h index 68598f8..a3257fd 100644 --- a/include/hardware/lgy.h +++ b/include/hardware/lgy.h @@ -107,7 +107,7 @@ Result LGY_setGbaRtc(const GbaRtc rtc); Result LGY_getGbaRtc(GbaRtc *const out); Result LGY_backupGbaSave(void); #ifdef ARM11 -Result LGY_prepareGbaMode(bool gbaBios, u16 saveType, const char *const romPath, const char *const savePath); +Result LGY_prepareGbaMode(bool gbaBios, const char *const romPath, const char *const savePath); void LGY_switchMode(void); void LGY_handleEvents(void); void LGY_deinit(void); diff --git a/source/arm11/hardware/lgy.c b/source/arm11/hardware/lgy.c index 2860018..5502f0b 100644 --- a/source/arm11/hardware/lgy.c +++ b/source/arm11/hardware/lgy.c @@ -10,6 +10,9 @@ #include "arm11/hardware/pdn.h" #include "arm11/hardware/mcu.h" #include "arm11/hardware/lgyfb.h" +#ifndef NDEBUG +#include "arm11/fmt.h" +#endif #define LGY_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x41100) @@ -38,7 +41,7 @@ static void lgySleepIrqHandler(u32 intSource) } } -static Result loadRom(const char *const path) +static Result loadRom(const char *const path, u32 *const rsOut) { Result res; FHandle f; @@ -54,6 +57,7 @@ static Result loadRom(const char *const path) if(res == RES_OK) { + *rsOut = romSize; // Pad ROM area with "open bus" value. memset((void*)(ROM_LOC + romSize), 0xFFFFFFFFu, romSize); } @@ -66,6 +70,103 @@ static Result loadRom(const char *const path) return res; } +// Code based on: https://github.com/Gericom/GBARunner2/blob/master/arm9/source/save/Save.vram.cpp +static void tryDetectSaveType(u32 romSize, u16 *const stOut) +{ +#ifndef NDEBUG + ee_puts("Trying to detect save type..."); +#endif + + u8 saveChipKind = 0; // 0 = none, 1 = EEPROM, 2 = Flash, 3 = SRAM. + const u32 *romPtr = (u32*)(ROM_LOC + 0xE4u); // Skip headers. + for(; romPtr < (u32*)(ROM_LOC + romSize); romPtr++) + { + u32 tmp = *romPtr; + + // "EEPR" + if(tmp == 0x52504545u) + { + saveChipKind = 1; + break; + } + + // "FLAS" + if(tmp == 0x53414C46u) + { + saveChipKind = 2; + break; + } + + // "SRAM" + if(tmp == 0x4D415253u) + { + saveChipKind = 3; + break; + } + } + + if(saveChipKind != 0) + { + static const struct + { + char *str; + u16 saveType; + } saveTypeLut[25] = + { + // EEPROM + // TODO: Which ones are SAVE_TYPE_EEPROM_64k_2? + {"EEPROM_V111", SAVE_TYPE_EEPROM_8k}, // 512 bytes. + {"EEPROM_V120", SAVE_TYPE_EEPROM_64k}, + {"EEPROM_V121", SAVE_TYPE_EEPROM_64k}, + {"EEPROM_V122", SAVE_TYPE_EEPROM_64k}, + {"EEPROM_V124", SAVE_TYPE_EEPROM_64k}, + {"EEPROM_V125", SAVE_TYPE_EEPROM_64k}, + {"EEPROM_V126", SAVE_TYPE_EEPROM_64k}, + + // FLASH + // Assume they all have RTC. + {"FLASH_V120", SAVE_TYPE_FLASH_512k_PSC_RTC}, + {"FLASH_V121", SAVE_TYPE_FLASH_512k_PSC_RTC}, + {"FLASH_V123", SAVE_TYPE_FLASH_512k_PSC_RTC}, + {"FLASH_V124", SAVE_TYPE_FLASH_512k_PSC_RTC}, + {"FLASH_V125", SAVE_TYPE_FLASH_512k_PSC_RTC}, + {"FLASH_V126", SAVE_TYPE_FLASH_512k_PSC_RTC}, + {"FLASH512_V130", SAVE_TYPE_FLASH_512k_PSC_RTC}, + {"FLASH512_V131", SAVE_TYPE_FLASH_512k_PSC_RTC}, + {"FLASH512_V133", SAVE_TYPE_FLASH_512k_PSC_RTC}, + {"FLASH1M_V102", SAVE_TYPE_FLASH_1m_MRX_RTC}, + {"FLASH1M_V103", SAVE_TYPE_FLASH_1m_MRX_RTC}, + + // FRAM & SRAM + {"SRAM_F_V100", SAVE_TYPE_SRAM_256k}, + {"SRAM_F_V102", SAVE_TYPE_SRAM_256k}, + {"SRAM_F_V103", SAVE_TYPE_SRAM_256k}, + + {"SRAM_V110", SAVE_TYPE_SRAM_256k}, + {"SRAM_V111", SAVE_TYPE_SRAM_256k}, + {"SRAM_V112", SAVE_TYPE_SRAM_256k}, + {"SRAM_V113", SAVE_TYPE_SRAM_256k} + }; + + for(u32 i = 0; i < 25; i++) + { + const char *const str = saveTypeLut[i].str; + const u16 saveType = saveTypeLut[i].saveType; + + if(memcmp(romPtr, str, strlen(str)) == 0) + { +#ifndef NDEBUG + ee_printf("Found save type %s.", str); +#endif + *stOut = saveType; + } + } + } +#ifndef NDEBUG + else ee_puts("Could not identify save type. Using none."); +#endif +} + static void setupFcramForGbaMode(void) { // FCRAM reset and clock disable. @@ -78,12 +179,17 @@ static void setupFcramForGbaMode(void) while(REG_PDN_FCRAM_CNT & PDN_FCRAM_CNT_CLK_E_ACK); // Wait until clock is disabled. } -Result LGY_prepareGbaMode(bool gbaBios, u16 saveType, const char *const romPath, const char *const savePath) +Result LGY_prepareGbaMode(bool gbaBios, const char *const romPath, const char *const savePath) { // Load the ROM image. - Result res = loadRom(romPath); + u32 romSize; + Result res = loadRom(romPath, &romSize); if(res != RES_OK) return res; + // Try to detect the save type. + u16 saveType = SAVE_TYPE_NONE; + tryDetectSaveType(romSize, &saveType); + // Prepare ARM9 for GBA mode + settings and save loading. u32 cmdBuf[2]; cmdBuf[0] = (u32)savePath; @@ -132,7 +238,6 @@ void LGY_switchMode(void) } #ifndef NDEBUG -#include "arm11/fmt.h" void debugTests(void) { const u32 kDown = hidKeysDown(); diff --git a/source/arm11/main.c b/source/arm11/main.c index 1c30f00..53fd286 100644 --- a/source/arm11/main.c +++ b/source/arm11/main.c @@ -39,7 +39,7 @@ int main(void) ee_puts("Reading ROM and save..."); Result res; - if((res = LGY_prepareGbaMode(false, SAVE_TYPE_SRAM_256k, "sdmc:/rom.gba", "sdmc:/rom.sav")) == RES_OK) + if((res = LGY_prepareGbaMode(false, "sdmc:/rom.gba", "sdmc:/rom.sav")) == RES_OK) { #ifdef NDEBUG GFX_setForceBlack(false, true);