From 9335e1d2aa09cf4cad88290a36b695a5011fd1de Mon Sep 17 00:00:00 2001 From: sanni Date: Tue, 27 Jun 2017 23:27:10 +0200 Subject: [PATCH] V27A: Add Mega Drive SRAM read/write Only tested with the game STRIKER. There are probably multiple types of SRAM games so not all will work yet. --- Cart_Reader/Cart_Reader.ino | 7 +- Cart_Reader/MD.ino | 256 ++++++++++++++++++++++++++++++------ Cart_Reader/N64.ino | 4 +- 3 files changed, 221 insertions(+), 46 deletions(-) diff --git a/Cart_Reader/Cart_Reader.ino b/Cart_Reader/Cart_Reader.ino index c128984..d1f7c7e 100644 --- a/Cart_Reader/Cart_Reader.ino +++ b/Cart_Reader/Cart_Reader.ino @@ -2,8 +2,8 @@ Cartridge Reader for Arduino Mega2560 Author: sanni - Date: 2017-06-26 - Version: V27 + Date: 2017-06-27 + Version: V27A SD lib: https://github.com/greiman/SdFat LCD lib: https://github.com/adafruit/Adafruit_SSD1306 @@ -34,7 +34,7 @@ YamaArashi - GBA flashrom bank switch command **********************************************************************************/ -char ver[5] = "V27"; +char ver[5] = "V27A"; /****************************************** Define Output @@ -192,6 +192,7 @@ char cartID[5]; unsigned long cartSize; char flashid[5]; unsigned long fileSize; +unsigned long sramBase; // Variable to count errors unsigned long writeErrors; diff --git a/Cart_Reader/MD.ino b/Cart_Reader/MD.ino index 08d5529..b83bd89 100644 --- a/Cart_Reader/MD.ino +++ b/Cart_Reader/MD.ino @@ -2,6 +2,11 @@ // SEGA MEGA DRIVE //****************************************** +/****************************************** + Variables + *****************************************/ +unsigned long sramEnd; + /****************************************** Menu *****************************************/ @@ -18,7 +23,7 @@ void mdMenu() { unsigned char mainMenu; // Copy menuOptions out of progmem convertPgm(menuOptionsMD, 5); - mainMenu = question_box("MEGA DRIVE Reader", menuOptions, 1, 0); + mainMenu = question_box("MEGA DRIVE Reader", menuOptions, 3, 0); // wait for user choice to come back from the question box menu switch (mainMenu) @@ -31,45 +36,50 @@ void mdMenu() { //compare_checksum_MD(); break; - /*case 1: + case 1: + display_Clear(); + // Does cartridge have SRAM + if ((saveType == 1) || (saveType == 2)) { + // Change working dir to root + sd.chdir("/"); + println_Msg(F("Reading Sram...")); + display_Update(); + readSram_MD(); + } + else { + print_Error(F("Cart has no Sram"), false); + } + break; + + case 2: + display_Clear(); + // Does cartridge have SRAM + if ((saveType == 1) || (saveType == 2)) { + // Change working dir to root + sd.chdir("/"); + // Launch file browser + fileBrowser("Select srm file"); display_Clear(); - // Does cartridge have SRAM - if () { - // Change working dir to root - sd.chdir("/"); - readSRAM_MD(); + + writeSram_MD(); + writeErrors = verifySram_MD(); + if (writeErrors == 0) { + println_Msg(F("Sram verified OK")); + display_Update(); } else { - print_Error(F("Cart has no Sram"), false); + print_Msg(F("Error: ")); + print_Msg(writeErrors); + println_Msg(F(" bytes ")); + print_Error(F("did not verify."), false); } - break; + } + else { + print_Error(F("Cart has no Sram"), false); + } + break; - case 2: - display_Clear(); - // Does cartridge have SRAM - if () { - // Change working dir to root - sd.chdir("/"); - writeSRAM_MD(); - unsigned long wrErrors; - wrErrors = verifySRAM_MD(); - if (wrErrors == 0) { - println_Msg(F("Verified OK")); - display_Update(); - } - else { - print_Msg(F("Error: ")); - print_Msg(wrErrors); - println_Msg(F(" bytes ")); - print_Error(F("did not verify."), false); - } - } - else { - print_Error(F("Cart has no Sram"), false); - } - break; - - case 3: + /*case 3: // Change working dir to root sd.chdir("/"); writeFlash_MD(); @@ -134,7 +144,7 @@ void writeWord_MD(unsigned long myAddress, word myData) { // Arduino running at 16Mhz -> one nop = 62.5ns // Wait till output is stable - __asm__("nop\n\t"); + __asm__("nop\n\t""nop\n\t"); // Switch WR(PH5) to LOW PORTH &= ~(1 << 5); @@ -155,7 +165,7 @@ word readWord_MD(unsigned long myAddress) { PORTL = (myAddress >> 16) & 0xFF; // Arduino running at 16Mhz -> one nop = 62.5ns - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + __asm__("nop\n\t""nop\n\t"); // Setting OE(PH6) LOW PORTH &= ~(1 << 6); @@ -188,8 +198,40 @@ void dataIn_MD() { MEGA DRIVE functions *****************************************/ void getCartInfo_MD() { + // Set control + dataIn_MD(); + cartSize = ((long(readWord_MD(0xD2)) << 16) | readWord_MD(0xD3)) + 1; - sramSize = ((long(readWord_MD(0xDC)) << 16) | readWord_MD(0xDD)) - ((long(readWord_MD(0xDA)) << 16) | readWord_MD(0xDB)) + 2; + + // Check if cart has sram + if ((readWord_MD(0xD8) == 0x5241) && (readWord_MD(0xD9) == 0xF820)) { + // Get sram start and end + sramBase = ((long(readWord_MD(0xDA)) << 16) | readWord_MD(0xDB)); + sramEnd = ((long(readWord_MD(0xDC)) << 16) | readWord_MD(0xDD)); + + // Check alignment of sram + if (sramBase == 0x200001) { + // low byte + saveType = 1; + sramSize = (sramEnd - sramBase + 2) / 2; + // Right shift sram base address so [A21] is set to high 0x200000 = 0b001[0]00000000000000000000 + sramBase = sramBase >> 1; + } + else if (sramBase == 0x200000) { + // high byte + saveType = 2; + sramSize = (sramEnd - sramBase + 1) / 2; + // Right shift sram base address so [A21] is set to high 0x200000 = 0b001[0]00000000000000000000 + sramBase = sramBase / 2; + } + else + print_Error(F("Unknown Sram Base"), true); + } + else { + // Either no save or eeprom save + saveType = 0; + sramSize = 0; + } // Get name for (byte c = 0; c < 48; c += 2) { @@ -219,12 +261,16 @@ void getCartInfo_MD() { print_Msg(cartSize / 1024 / 1024); println_Msg(F("MB")); print_Msg(F("Sram: ")); - print_Msg(sramSize / 1024); - println_Msg(F("KB")); + if (sramSize > 0) { + print_Msg(sramSize / 1024); + println_Msg(F("KB")); + } + else + println_Msg(F("None")); + println_Msg(F(" ")); // Wait for user input if (enable_OLED) { - println_Msg(F(" ")); println_Msg(F("Press Button...")); display_Update(); wait(); @@ -233,6 +279,9 @@ void getCartInfo_MD() { // Read rom and save to the SD card void readROM_MD() { + // Set control + dataIn_MD(); + // Get name, add extension and convert to char array for sd lib strcpy(fileName, romName); strcat(fileName, ".MD"); @@ -279,4 +328,127 @@ void readROM_MD() { // Close the file: myFile.close(); } - + +/****************************************** + SRAM functions +*****************************************/ +// Write sram to cartridge +void writeSram_MD() { + dataOut_MD(); + + // Create filepath + sprintf(filePath, "%s/%s", filePath, fileName); + println_Msg(F("Writing...")); + println_Msg(filePath); + display_Update(); + + // Open file on sd card + if (myFile.open(filePath, O_READ)) { + // Write to the lower byte + if (saveType == 1) { + for (unsigned long currByte = sramBase; currByte < sramBase + sramSize; currByte++) { + writeWord_MD(currByte, (myFile.read() & 0xFF)); + } + } + // Write to the upper byte + else if (saveType == 2) { + for (unsigned long currByte = sramBase; currByte < sramBase + sramSize; currByte++) { + writeWord_MD(currByte, ((myFile.read() << 8 ) & 0xFF)); + } + } + else + print_Error(F("Unknown save type"), false); + + // Close the file: + myFile.close(); + println_Msg(F("Done")); + display_Update(); + } + else { + print_Error(F("SD Error"), true); + } + dataIn_MD(); +} + +// Read sram and save to the SD card +void readSram_MD() { + dataIn_MD(); + + // Get name, add extension and convert to char array for sd lib + strcpy(fileName, romName); + strcat(fileName, ".srm"); + + // create a new folder for the save file + EEPROM_readAnything(10, foldern); + sprintf(folder, "MD/SAVE/%s/%d", romName, foldern); + sd.mkdir(folder, true); + sd.chdir(folder); + + // write new folder number back to eeprom + foldern = foldern + 1; + EEPROM_writeAnything(10, foldern); + + // Open file on sd card + if (!myFile.open(fileName, O_RDWR | O_CREAT)) { + print_Error(F("SD Error"), true); + } + + for (unsigned long currBuffer = sramBase; currBuffer < sramBase + sramSize; currBuffer += 512) { + for (int currWord = 0; currWord < 512; currWord++) { + word myWord = readWord_MD(currBuffer + currWord); + + if (saveType == 2) { + // Only use the upper byte + sdBuffer[currWord] = (( myWord >> 8 ) & 0xFF); + } + else if (saveType == 1) { + // Only use the lower byte + sdBuffer[currWord] = (myWord & 0xFF); + } + } + myFile.write(sdBuffer, 512); + } + // Close the file: + myFile.close(); + print_Msg(F("Saved to ")); + print_Msg(folder); + println_Msg(F("/")); + display_Update(); +} + +unsigned long verifySram_MD() { + dataIn_MD(); + writeErrors = 0; + + // Open file on sd card + if (myFile.open(filePath, O_READ)) { + for (unsigned long currBuffer = sramBase; currBuffer < sramBase + sramSize; currBuffer += 512) { + for (int currWord = 0; currWord < 512; currWord++) { + word myWord = readWord_MD(currBuffer + currWord); + + if (saveType == 2) { + // Only use the upper byte + sdBuffer[currWord] = (( myWord >> 8 ) & 0xFF); + } + else if (saveType == 1) { + // Only use the lower byte + sdBuffer[currWord] = (myWord & 0xFF); + } + } + // Check sdBuffer content against file on sd card + for (int i = 0; i < 512; i++) { + if (myFile.read() != sdBuffer[i]) { + writeErrors++; + } + } + } + + // Close the file: + myFile.close(); + } + else { + print_Error(F("SD Error"), true); + } + // Return 0 if verified ok, or number of errors + return writeErrors; +} diff --git a/Cart_Reader/N64.ino b/Cart_Reader/N64.ino index 1f5e18c..eb905a5 100644 --- a/Cart_Reader/N64.ino +++ b/Cart_Reader/N64.ino @@ -37,7 +37,6 @@ String lastbutton = "N/A"; // Rom base address unsigned long romBase = 0x10000000; -unsigned long sramBase = 0x08000000; // Flashram type byte flashramType = 1; @@ -277,6 +276,9 @@ void setup_N64_Cart() { // Activate Internal Pullup Resistors //PORTH |= (1 << 4); + // Set sram base address + sramBase = 0x08000000; + // Wait until all is stable delay(300);