diff options
-rw-r--r-- | src/NDSCart.cpp | 208 |
1 files changed, 134 insertions, 74 deletions
diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp index cca5cfa..c959663 100644 --- a/src/NDSCart.cpp +++ b/src/NDSCart.cpp @@ -153,8 +153,8 @@ void LoadSave(const char* path, u32 type) case 256*1024: case 512*1024: case 1024*1024: - case 8192*1024: - case 32768*1024: WriteFunc = Write_Flash; break; + case 8192*1024: WriteFunc = Write_Flash; break; + case 32768*1024: WriteFunc = Write_Null; break; // NAND FLASH, handled differently default: printf("!! BAD SAVE LENGTH %d\n", SRAMLength); case 0: @@ -484,6 +484,12 @@ u64 Key2_X; u64 Key2_Y; +void ROMCommand_Retail(u8* cmd); +void ROMCommand_RetailNAND(u8* cmd); + +void (*ROMCommandHandler)(u8* cmd); + + u32 ByteSwap(u32 val) { return (val >> 24) | ((val >> 8) & 0xFF00) | ((val << 8) & 0xFF0000) | (val << 24); @@ -625,6 +631,8 @@ void Reset() CartID = 0; CartIsHomebrew = false; + ROMCommandHandler = NULL; + CmdEncMode = 0; DataEncMode = 0; @@ -908,10 +916,22 @@ bool LoadROM(const char* path, const char* sram, bool direct) else printf("ROM entry: %08X %08X %08X\n", romparams[0], romparams[1], romparams[2]); + if (romparams[0] != len) printf("!! bad ROM size %d (expected %d) rounded to %d\n", len, romparams[0], CartROMSize); + // generate a ROM ID // note: most games don't check the actual value // it just has to stay the same throughout gameplay - CartID = 0x00001FC2; + CartID = 0x000000C2; + + if (CartROMSize <= 128*1024*1024) + CartID |= ((CartROMSize >> 20) - 1) << 8; + else + CartID |= (0x100 - (CartROMSize >> 28)) << 8; + + if (romparams[1] == 8) + CartID |= 0x08000000; // NAND flag + + printf("Cart ID: %08X\n", CartID); if (*(u32*)&CartROM[0x20] < 0x4000) { @@ -928,6 +948,12 @@ bool LoadROM(const char* path, const char* sram, bool direct) CartInserted = true; + // TODO: support more fancy cart types (homebrew?, flashcarts, etc) + if (CartID & 0x08000000) + ROMCommandHandler = ROMCommand_RetailNAND; + else + ROMCommandHandler = ROMCommand_Retail; + u32 arm9base = *(u32*)&CartROM[0x20]; if (arm9base < 0x8000) { @@ -1020,7 +1046,88 @@ void ROMPrepareData(u32 param) NDS::CheckDMAs(0, 0x05); } -u32 sc_addr = 0; + +void ROMCommand_Retail(u8* cmd) +{ + switch (cmd[0]) + { + case 0xB7: + { + u32 addr = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; + memset(DataOut, 0, DataOutLen); + + if (((addr + DataOutLen - 1) >> 12) != (addr >> 12)) + { + u32 len1 = 0x1000 - (addr & 0xFFF); + ReadROM_B7(addr, len1, 0); + ReadROM_B7(addr+len1, DataOutLen-len1, len1); + } + else + ReadROM_B7(addr, DataOutLen, 0); + } + break; + + default: + printf("unknown retail cart command %02X\n", cmd[0]); + break; + } +} + +void ROMCommand_RetailNAND(u8* cmd) +{ + switch (cmd[0]) + { + case 0x94: // NAND init + { + // initial value: should have bit7 clear + NDSCart_SRAM::StatusReg = 0; + + // 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; + } + break; + + case 0xB2: // set savemem addr + { + NDSCart_SRAM::StatusReg |= 0x20; + } + break; + + case 0xB7: + { + u32 addr = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; + memset(DataOut, 0, DataOutLen); + + if (((addr + DataOutLen - 1) >> 12) != (addr >> 12)) + { + u32 len1 = 0x1000 - (addr & 0xFFF); + ReadROM_B7(addr, len1, 0); + ReadROM_B7(addr+len1, DataOutLen-len1, len1); + } + else + ReadROM_B7(addr, DataOutLen, 0); + } + break; + + case 0xD6: // NAND status + { + // status reg bits: + // * bit7: busy? error? + // * bit5: accessing savemem + + for (u32 pos = 0; pos < DataOutLen; pos += 4) + *(u32*)&DataOut[pos] = NDSCart_SRAM::StatusReg * 0x01010101; + } + break; + + default: + printf("unknown NAND command %02X %04Xn", cmd[0], DataOutLen); + break; + } +} + void WriteROMCnt(u32 val) { @@ -1111,81 +1218,34 @@ void WriteROMCnt(u32 val) if (CartInserted) CmdEncMode = 1; break; - case 0xB7: - { - u32 addr = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; - memset(DataOut, 0, DataOutLen); - - if (((addr + DataOutLen - 1) >> 12) != (addr >> 12)) - { - u32 len1 = 0x1000 - (addr & 0xFFF); - ReadROM_B7(addr, len1, 0); - ReadROM_B7(addr+len1, DataOutLen-len1, len1); - } - else - ReadROM_B7(addr, DataOutLen, 0); - } - break; - - - // SUPERCARD EMULATION TEST - // TODO: INTEGRATE BETTER!!!! - - case 0x70: // init??? returns whether SDHC addressing should be used - for (u32 pos = 0; pos < DataOutLen; pos += 4) - *(u32*)&DataOut[pos] = 0; - break; - - case 0x53: // set address for read - sc_addr = (cmd[1]<<24) | (cmd[2]<<16) | (cmd[3]<<8) | cmd[4]; - printf("SUPERCARD: read %08X\n", sc_addr); - break; - - case 0x80: // read operation busy, I guess - // TODO: make it take some time - for (u32 pos = 0; pos < DataOutLen; pos += 4) - *(u32*)&DataOut[pos] = 0; - break; - - case 0x81: // read data - { - if (DataOutLen != 0x200) - printf("SUPERCARD: BOGUS READ %d\n", DataOutLen); - - // TODO: this is really inefficient. just testing - FILE* f = fopen("scsd.bin", "rb"); - fseek(f, sc_addr, SEEK_SET); - fread(DataOut, 1, 0x200, f); - fclose(f); - } - break; - - // SUPERCARD EMULATION TEST END - - default: - switch (cmd[0] & 0xF0) + if (CmdEncMode == 1) { - case 0x40: - DataEncMode = 2; - break; - - case 0x10: - for (u32 pos = 0; pos < DataOutLen; pos += 4) - *(u32*)&DataOut[pos] = CartID; - break; - - case 0x20: + switch (cmd[0] & 0xF0) { - u32 addr = (cmd[2] & 0xF0) << 8; - ReadROM(addr, 0x1000, 0); + case 0x40: + DataEncMode = 2; + break; + + case 0x10: + for (u32 pos = 0; pos < DataOutLen; pos += 4) + *(u32*)&DataOut[pos] = CartID; + break; + + case 0x20: + { + u32 addr = (cmd[2] & 0xF0) << 8; + ReadROM(addr, 0x1000, 0); + } + break; + + case 0xA0: + CmdEncMode = 2; + break; } - break; - - case 0xA0: - CmdEncMode = 2; - break; } + else if (ROMCommandHandler) + ROMCommandHandler(cmd); break; } |