From f4335b92927ec3ba0eb3675eb1c4a5c80bb0a05d Mon Sep 17 00:00:00 2001 From: StapleButter Date: Fri, 3 Feb 2017 16:57:31 +0100 Subject: [PATCH] better save support. not hardcoded filename, support for non-tiny EEPROM and Flash, attempt at autodetecting the right memory type. --- CP15.cpp | 3 +- DMA.cpp | 4 +- NDS.cpp | 7 +- NDSCart.cpp | 344 ++++++++++++++++++++++++++++++++++++++++++++----- main.cpp | 26 ++-- melonDS.depend | 14 +- 6 files changed, 342 insertions(+), 56 deletions(-) diff --git a/CP15.cpp b/CP15.cpp index ded58aa4..4d1fee62 100644 --- a/CP15.cpp +++ b/CP15.cpp @@ -135,7 +135,8 @@ void Write(u32 id, u32 val) return; } - //printf("unknown CP15 write op %03X %08X\n", id, val); + if ((id&0xF00)!=0x700) + printf("unknown CP15 write op %03X %08X\n", id, val); } u32 Read(u32 id) diff --git a/DMA.cpp b/DMA.cpp index e5a38335..6c47f5cf 100644 --- a/DMA.cpp +++ b/DMA.cpp @@ -89,6 +89,8 @@ void DMA::WriteCnt(u32 val) Start(); //else // printf("SPECIAL ARM%d DMA%d START MODE %02X\n", CPU?7:9, Num, StartMode); + if (StartMode!=0x00 && StartMode!=0x10 && StartMode!=0x05 && StartMode!=0x12) + printf("UNIMPLEMENTED ARM%d DMA%d START MODE %02X\n", CPU?7:9, Num, StartMode); } } @@ -110,7 +112,7 @@ void DMA::Start() // special path for cart DMA. this is a gross hack. // emulating it properly requires emulating cart transfer delays, so uh... TODO if (CurSrcAddr==0x04100010 && RemCount==1 && (Cnt & 0x07E00000)==0x07000000 && - ((CPU==0 && StartMode==0x06) || (CPU==1 && StartMode==0x12))) + ((CPU==0 && StartMode==0x05) || (CPU==1 && StartMode==0x12))) { NDSCart::DMA(CurDstAddr); Cnt &= ~0x80000000; diff --git a/NDS.cpp b/NDS.cpp index 413409aa..cd6fd8c0 100644 --- a/NDS.cpp +++ b/NDS.cpp @@ -411,7 +411,6 @@ void ReleaseKey(u32 key) void TouchScreen(u16 x, u16 y) { SPI_TSC::SetTouchCoords(x, y); - printf("touching %d,%d\n", x, y); } void ReleaseScreen() @@ -703,8 +702,8 @@ void StartSqrt() void debug(u32 param) { - printf("ARM9 PC=%08X %08X\n", ARM9->R[15], ARM9->R_IRQ[1]); - printf("ARM7 PC=%08X %08X\n", ARM7->R[15], ARM7->R_IRQ[1]); + printf("ARM9 PC=%08X LR=%08X %08X\n", ARM9->R[15], ARM9->R[14], ARM9->R_IRQ[1]); + printf("ARM7 PC=%08X LR=%08X %08X\n", ARM7->R[15], ARM7->R[14], ARM7->R_IRQ[1]); } @@ -807,7 +806,7 @@ u16 ARM9Read16(u32 addr) return 0xFFFF; } - printf("unknown arm9 read16 %08X\n", addr); + printf("unknown arm9 read16 %08X %08X %08X %08X\n", addr, ARM9->R[15], ARM9->R[1], ARM9->R[2]); return 0; } diff --git a/NDSCart.cpp b/NDSCart.cpp index 145f627e..9a2e0944 100644 --- a/NDSCart.cpp +++ b/NDSCart.cpp @@ -28,7 +28,14 @@ namespace NDSCart_SRAM u8* SRAM; u32 SRAMLength; -u32 AddrLength; +char SRAMPath[256]; + +void (*WriteFunc)(u8 val, bool islast); + +u32 Discover_MemoryType; +u32 Discover_Likeliness; +u8* Discover_Buffer; +u32 Discover_DataPos; u32 Hold; u8 CurCmd; @@ -39,16 +46,31 @@ u8 StatusReg; u32 Addr; +void Write_Null(u8 val, bool islast); +void Write_EEPROMTiny(u8 val, bool islast); +void Write_EEPROM(u8 val, bool islast); +void Write_Flash(u8 val, bool islast); +void Write_Discover(u8 val, bool islast); + + void Init() { SRAM = NULL; } void Reset() +{ + // +} + +void LoadSave(char* path) { if (SRAM) delete[] SRAM; - FILE* f = fopen("rom/nsmb.sav", "rb"); // TODO: NOT HARDCODE THE FILENAME!!! + strncpy(SRAMPath, path, 255); + SRAMPath[255] = '\0'; + + FILE* f = fopen(path, "rb"); if (f) { fseek(f, 0, SEEK_END); @@ -62,17 +84,29 @@ void Reset() switch (SRAMLength) { - case 8192: AddrLength = 2; break; + case 512: WriteFunc = Write_EEPROMTiny; break; + case 8192: + case 65536: WriteFunc = Write_EEPROM; break; + case 256*1024: + case 512*1024: + case 1024*1024: + case 8192*1024: WriteFunc = Write_Flash; break; default: printf("!! BAD SAVE LENGTH %d\n", SRAMLength); - AddrLength = 2; + WriteFunc = Write_Null; break; } } else { - // TODO: autodetect save type SRAMLength = 0; + WriteFunc = Write_Discover; + Discover_MemoryType = 2; + Discover_Likeliness = 0; + + Discover_DataPos = 0; + Discover_Buffer = new u8[256*1024]; + memset(Discover_Buffer, 0, 256*1024); } Hold = 0; @@ -86,10 +120,250 @@ u8 Read() return Data; } +void SetMemoryType() +{ + switch (Discover_MemoryType) + { + case 1: + printf("Save memory type: EEPROM 4k\n"); + WriteFunc = Write_EEPROMTiny; + SRAMLength = 512; + break; + + case 2: + printf("Save memory type: EEPROM 64k\n"); + WriteFunc = Write_EEPROM; + SRAMLength = 8192; + break; + + case 3: + printf("Save memory type: EEPROM 512k\n"); + WriteFunc = Write_EEPROM; + SRAMLength = 65536; + break; + + case 4: + printf("Save memory type: Flash. Hope the size is 256K.\n"); + WriteFunc = Write_Flash; + SRAMLength = 256*1024; + break; + + case 5: + printf("Save memory type: ...something else\n"); + WriteFunc = Write_Null; + SRAMLength = 0; + break; + } + + if (!SRAMLength) + return; + + SRAM = new u8[SRAMLength]; + + // replay writes that occured during discovery + u8 prev_cmd = CurCmd; + u32 pos = 0; + while (pos < 256*1024) + { + u32 len = *(u32*)&Discover_Buffer[pos]; + pos += 4; + if (len == 0) break; + + CurCmd = Discover_Buffer[pos++]; + DataPos = 0; + Addr = 0; + Data = 0; + for (u32 i = 1; i < len; i++) + { + WriteFunc(Discover_Buffer[pos++], (i==(len-1))); + DataPos++; + } + } + + CurCmd = prev_cmd; +} + +void Write_Discover(u8 val, bool islast) +{ + // attempt at autodetecting the type of save memory. + // we basically hope the game will be nice and clear whole pages of memory. + + if (CurCmd == 0x03 || CurCmd == 0x0B) + { + if (Discover_Likeliness) + { + // apply. and pray. + SetMemoryType(); + + DataPos = 0; + Addr = 0; + Data = 0; + return WriteFunc(val, islast); + } + else + { + Data = 0; + return; + } + } + + if (CurCmd == 0x02 || CurCmd == 0x0A) + { + if (DataPos == 0) + Discover_Buffer[Discover_DataPos + 4] = CurCmd; + + Discover_Buffer[Discover_DataPos + 5 + DataPos] = val; + + if (islast) + { + u32 len = DataPos+1; + + *(u32*)&Discover_Buffer[Discover_DataPos] = len+1; + Discover_DataPos += 5+len; + + if (Discover_Likeliness <= len) + { + Discover_Likeliness = len; + + if (len > 3+256) // bigger Flash, FRAM, whatever + { + Discover_MemoryType = 5; + } + else if (len > 2+128) // Flash + { + Discover_MemoryType = 4; + } + else if (len > 2+32) // EEPROM 512k + { + Discover_MemoryType = 3; + } + else if (len > 1+16 || (len != 1+16 && CurCmd != 0x0A)) // EEPROM 64k + { + Discover_MemoryType = 2; + } + else // EEPROM 4k + { + Discover_MemoryType = 1; + } + } + + printf("discover: type=%d likeliness=%d\n", Discover_MemoryType, Discover_Likeliness); + } + } +} + +void Write_Null(u8 val, bool islast) {} + +void Write_EEPROMTiny(u8 val, bool islast) +{ + // TODO +} + +void Write_EEPROM(u8 val, bool islast) +{ + switch (CurCmd) + { + case 0x02: + if (DataPos < 2) + { + Addr <<= 8; + Addr |= val; + Data = 0; + } + else + { + if (Addr < SRAMLength) + SRAM[Addr] = val; + + Addr++; + } + break; + + case 0x03: + if (DataPos < 2) + { + Addr <<= 8; + Addr |= val; + Data = 0; + } + else + { + if (Addr >= SRAMLength) + Data = 0; + else + Data = SRAM[Addr]; + + Addr++; + } + break; + + case 0x9F: + Data = 0xFF; + break; + + default: + if (DataPos==0) + printf("unknown EEPROM save command %02X\n", CurCmd); + break; + } +} + +void Write_Flash(u8 val, bool islast) +{ + switch (CurCmd) + { + case 0x03: + if (DataPos < 3) + { + Addr <<= 8; + Addr |= val; + Data = 0; + } + else + { + if (Addr >= SRAMLength) + Data = 0; + else + Data = SRAM[Addr]; + + Addr++; + } + break; + + case 0x0A: + if (DataPos < 3) + { + Addr <<= 8; + Addr |= val; + Data = 0; + } + else + { + if (Addr < SRAMLength) + SRAM[Addr] = val; + + Addr++; + } + break; + + case 0x9F: + Data = 0xFF; + break; + + default: + if (DataPos==0) + printf("unknown Flash save command %02X\n", CurCmd); + break; + } +} + void Write(u8 val, u32 hold) { + bool islast = false; + if (!hold) { + if (Hold) islast = true; Hold = 0; } @@ -98,7 +372,7 @@ void Write(u8 val, u32 hold) CurCmd = val; Hold = 1; Data = 0; - DataPos = 1; + DataPos = 0; Addr = 0; //printf("save SPI command %02X\n", CurCmd); return; @@ -106,28 +380,13 @@ void Write(u8 val, u32 hold) switch (CurCmd) { - case 0x03: // read - { - if (DataPos < AddrLength+1) - { - Addr <<= 8; - Addr |= val; - Data = 0; - - //if (DataPos == AddrLength) printf("save SPI read %08X\n", Addr); - } - else - { - if (Addr >= SRAMLength) - Data = 0; - else - Data = SRAM[Addr]; - - Addr++; - } - - DataPos++; - } + case 0x02: + case 0x03: + case 0x0A: + case 0x0B: + case 0x9F: + WriteFunc(val, islast); + DataPos++; break; case 0x04: // write disable @@ -144,14 +403,21 @@ void Write(u8 val, u32 hold) Data = 0; break; - case 0x9F: // read JEDEC ID - Data = 0xFF; - break; - default: - printf("unknown save SPI command %02X\n", CurCmd); + if (DataPos==0) + printf("unknown save SPI command %02X\n", CurCmd); break; } + + if (islast && (CurCmd == 0x02 || CurCmd == 0x0A)) + { + FILE* f = fopen(SRAMPath, "wb"); + if (f) + { + fwrite(SRAM, SRAMLength, 1, f); + fclose(f); + } + } } } @@ -347,6 +613,9 @@ void LoadROM(char* path) fclose(f); //CartROM = f; + // temp. TODO: later make this user selectable + // calling this sets up shit for booting from the cart directly. + // normal behavior is booting from the BIOS. NDS::SetupDirectBoot(); CartInserted = true; @@ -382,6 +651,15 @@ void LoadROM(char* path) // encryption Key1_InitKeycode(gamecode, 2, 2); + + + // save + char savepath[256]; + strncpy(savepath, path, 255); + savepath[255] = '\0'; + strncpy(savepath + strlen(path) - 3, "sav", 3); + printf("Save file: %s\n", savepath); + NDSCart_SRAM::LoadSave(savepath); } void ReadROM(u32 addr, u32 len, u32 offset) diff --git a/main.cpp b/main.cpp index 3e0a6a8f..8b299721 100644 --- a/main.cpp +++ b/main.cpp @@ -41,20 +41,26 @@ LRESULT CALLBACK derpo(HWND window, UINT msg, WPARAM wparam, LPARAM lparam) printf("close\n"); { // 6006800 6008000 - FILE* f = fopen("wram.bin", "wb"); - for (u32 i = 0x37F8000; i < 0x3808000; i+=4) + FILE* f = fopen("debug/wram.bin", "wb"); + if (f) { - u32 blarg = NDS::ARM7Read32(i); - fwrite(&blarg, 4, 1, f); + for (u32 i = 0x37F8000; i < 0x3808000; i+=4) + { + u32 blarg = NDS::ARM7Read32(i); + fwrite(&blarg, 4, 1, f); + } + fclose(f); } - fclose(f); - f = fopen("mainram.bin", "wb"); - for (u32 i = 0x2000000; i < 0x2400000; i+=4) + f = fopen("debug/mainram.bin", "wb"); + if (f) { - u32 blarg = NDS::ARM9Read32(i); - fwrite(&blarg, 4, 1, f); + for (u32 i = 0x2000000; i < 0x2400000; i+=4) + { + u32 blarg = NDS::ARM9Read32(i); + fwrite(&blarg, 4, 1, f); + } + fclose(f); } - fclose(f); } PostQuitMessage(0); return 0; diff --git a/melonDS.depend b/melonDS.depend index 61e4016a..18630d91 100644 --- a/melonDS.depend +++ b/melonDS.depend @@ -1,5 +1,5 @@ # depslib dependency file v1.0 -1485974193 source:c:\documents\sources\melonds\main.cpp +1486086940 source:c:\documents\sources\melonds\main.cpp "NDS.h" @@ -10,7 +10,7 @@ 1481161027 c:\documents\sources\melonds\types.h -1485988923 source:c:\documents\sources\melonds\nds.cpp +1486135026 source:c:\documents\sources\melonds\nds.cpp "NDS.h" @@ -24,7 +24,7 @@ "RTC.h" "Wifi.h" -1485981252 source:c:\documents\sources\melonds\arm.cpp +1486085968 source:c:\documents\sources\melonds\arm.cpp "NDS.h" "ARM.h" @@ -71,7 +71,7 @@ 1485799621 c:\documents\sources\melonds\cp15.h -1485901523 source:c:\documents\sources\melonds\cp15.cpp +1486086235 source:c:\documents\sources\melonds\cp15.cpp "NDS.h" @@ -86,7 +86,7 @@ "NDS.h" "SPI.h" -1485993754 source:c:\documents\sources\melonds\gpu2d.cpp +1485994573 source:c:\documents\sources\melonds\gpu2d.cpp "NDS.h" @@ -108,7 +108,7 @@ 1484612398 c:\documents\sources\melonds\fifo.h "types.h" -1485901572 source:c:\documents\sources\melonds\dma.cpp +1486093630 source:c:\documents\sources\melonds\dma.cpp "NDS.h" "DMA.h" @@ -137,7 +137,7 @@ 1485980863 c:\documents\sources\melonds\ndscart.h "types.h" -1485981191 source:c:\documents\sources\melonds\ndscart.cpp +1486137256 source:c:\documents\sources\melonds\ndscart.cpp "NDS.h"