diff --git a/Cart_Reader/Cart_Reader.ino b/Cart_Reader/Cart_Reader.ino index d9f2054..2be07e5 100644 --- a/Cart_Reader/Cart_Reader.ino +++ b/Cart_Reader/Cart_Reader.ino @@ -2,15 +2,15 @@ Cartridge Reader for Arduino Mega2560 Author: sanni - Date: 13-01-2019 - Version: 2.4 + Date: 16-01-2018 + Version: 2.5 SD lib: https://github.com/greiman/SdFat LCD lib: https://github.com/adafruit/Adafruit_SSD1306 Clockgen: https://github.com/etherkit/Si5351Arduino RGB Tools lib: https://github.com/joushx/Arduino-RGB-Tools - Compiled with Arduino 1.8.7 + Compiled with Arduino 1.8.8 Thanks to: MichlK - ROM-Reader for Super Nintendo @@ -37,7 +37,7 @@ vogelfreiheit - N64 flashram fix **********************************************************************************/ -char ver[5] = "2.4"; +char ver[5] = "2.5"; /****************************************** Define Starting Point diff --git a/Cart_Reader/N64.ino b/Cart_Reader/N64.ino index d757f7c..603d84e 100644 --- a/Cart_Reader/N64.ino +++ b/Cart_Reader/N64.ino @@ -49,7 +49,8 @@ boolean MN63F81MPN = false; static const char n64MenuItem1[] PROGMEM = "Cart Slot"; static const char n64MenuItem2[] PROGMEM = "Controller"; static const char n64MenuItem3[] PROGMEM = "Flash Repro"; -static const char* const menuOptionsN64[] PROGMEM = {n64MenuItem1, n64MenuItem2, n64MenuItem3}; +static const char n64MenuItem4[] PROGMEM = "Flash Gameshark"; +static const char* const menuOptionsN64[] PROGMEM = {n64MenuItem1, n64MenuItem2, n64MenuItem3, n64MenuItem4}; // N64 controller menu items static const char N64ContMenuItem1[] PROGMEM = "Test Controller"; @@ -74,14 +75,13 @@ static const char N64CRCMenuItem4[] PROGMEM = "Reset"; static const char* const menuOptionsN64CRC[] PROGMEM = {N64CRCMenuItem1, N64CRCMenuItem2, N64CRCMenuItem3, N64CRCMenuItem4}; // Rom menu -static const char N64RomItem1[] PROGMEM = "256KB"; -static const char N64RomItem2[] PROGMEM = "4MB"; -static const char N64RomItem3[] PROGMEM = "8MB"; -static const char N64RomItem4[] PROGMEM = "12MB"; -static const char N64RomItem5[] PROGMEM = "16MB"; -static const char N64RomItem6[] PROGMEM = "32MB"; -static const char N64RomItem7[] PROGMEM = "64MB"; -static const char* const romOptionsN64[] PROGMEM = {N64RomItem1, N64RomItem2, N64RomItem3, N64RomItem4, N64RomItem5, N64RomItem6, N64RomItem7}; +static const char N64RomItem1[] PROGMEM = "4MB"; +static const char N64RomItem2[] PROGMEM = "8MB"; +static const char N64RomItem3[] PROGMEM = "12MB"; +static const char N64RomItem4[] PROGMEM = "16MB"; +static const char N64RomItem5[] PROGMEM = "32MB"; +static const char N64RomItem6[] PROGMEM = "64MB"; +static const char* const romOptionsN64[] PROGMEM = {N64RomItem1, N64RomItem2, N64RomItem3, N64RomItem4, N64RomItem5, N64RomItem6}; // Save menu static const char N64SaveItem1[] PROGMEM = "None"; @@ -96,8 +96,8 @@ void n64Menu() { // create menu with title and 3 options to choose from unsigned char n64Dev; // Copy menuOptions out of progmem - convertPgm(menuOptionsN64, 3); - n64Dev = question_box("Select N64 device", menuOptions, 3, 0); + convertPgm(menuOptionsN64, 4); + n64Dev = question_box("Select N64 device", menuOptions, 4, 0); // wait for user choice to come back from the question box menu switch (n64Dev) @@ -126,6 +126,14 @@ void n64Menu() { mode = mode_N64_Cart; break; + case 3: + display_Clear(); + display_Update(); + setup_N64_Cart(); + flashGameshark_N64(); + printCartInfo_N64(); + mode = mode_N64_Cart; + break; } } @@ -1089,43 +1097,38 @@ void printCartInfo_N64() { // Set cartsize manually unsigned char N64RomMenu; // Copy menuOptions out of progmem - convertPgm(romOptionsN64, 7); - N64RomMenu = question_box("Select ROM size", menuOptions, 7, 0); + convertPgm(romOptionsN64, 6); + N64RomMenu = question_box("Select ROM size", menuOptions, 6, 0); // wait for user choice to come back from the question box menu switch (N64RomMenu) { case 0: - // 1MB, will get reduced to 256KB later - cartSize = 1; - break; - - case 1: // 4MB cartSize = 4; break; - case 2: + case 1: // 8MB cartSize = 8; break; - case 3: + case 2: // 12MB cartSize = 12; break; - case 4: + case 3: // 16MB cartSize = 16; break; - case 5: + case 4: // 32MB cartSize = 32; break; - case 6: + case 5: // 64MB cartSize = 64; break; @@ -2100,14 +2103,7 @@ readn64rom: print_Error(F("SD Error"), true); } - unsigned long romSize; - // 256KB romSize - if (cartSize == 1) - romSize = cartSize * 262144; - else - romSize = cartSize * 1048576; - - for (unsigned long currByte = romBase; currByte < romBase + romSize; currByte += 512) { + for (unsigned long currByte = romBase; currByte < (romBase + (cartSize * 1024 * 1024)); currByte += 512) { // Blink led if (currByte % 16384 == 0) PORTB ^= (1 << 4); @@ -2244,21 +2240,13 @@ void flashRepro_N64() { println_Msg(F("Fujitsu MSP55LV512")); else if ((strcmp(flashid, "227E") == 0) && (strcmp(cartID, "3901") == 0)) println_Msg(F("Intel 512M29EW")); - else if (strcmp(flashid, "0808") == 0) - println_Msg(F("SST 29LE010")); // Print info print_Msg(F("ID: ")); print_Msg(flashid); print_Msg(F(" Size: ")); - if (strcmp(flashid, "0808") == 0) { - print_Msg(128); - println_Msg(F("KB")); - } - else { - print_Msg(cartSize); - println_Msg(F("MB")); - } + print_Msg(cartSize); + println_Msg(F("MB")); println_Msg(""); println_Msg(F("This will erase your")); println_Msg(F("Repro Cartridge.")); @@ -2288,16 +2276,10 @@ void flashRepro_N64() { display_Update(); // Compare file size to flashrom size - if (cartSize == 1) { - if ((fileSize / 1048576 * 4) > cartSize) { - print_Error(F("File too big"), true); - } - } - else { - if ((fileSize / 1048576) > cartSize) { - print_Error(F("File too big"), true); - } + if ((fileSize / 1048576) > cartSize) { + print_Error(F("File too big"), true); } + // Erase needed sectors if (strcmp(flashid, "227E") == 0) { // Spansion S29GL256N or Fujitsu MSP55LV512 with 0x20000 sector size and 32 byte buffer @@ -2316,19 +2298,16 @@ void flashRepro_N64() { // Macronix MX29LV640, C9 is top boot and CB is bottom boot block eraseFlashrom_N64(0x8000); } - else if (strcmp(flashid, "0808") == 0) { - // SST 29LE010, chip erase not needed as eeprom automaticly erases during the write cycle - } // Check if erase was successful - if (blankcheckFlashrom_N64() || (strcmp(flashid, "0808") == 0)) { - if ((strcmp(flashid, "0808") != 0)) - println_Msg(F("OK")); - + if (blankcheckFlashrom_N64()) { // Write flashrom + println_Msg(F("OK")); print_Msg(F("Writing ")); println_Msg(filePath); display_Update(); + + if ((strcmp(cartID, "3901") == 0) && (strcmp(flashid, "227E") == 0)) { // Intel 512M29EW(64MB) with 0x20000 sector size and 128 byte buffer writeFlashBuffer_N64(0x20000, 128); @@ -2350,9 +2329,7 @@ void flashRepro_N64() { writeIntel4400_N64(); resetIntel4400_N64(); } - else if (strcmp(flashid, "0808") == 0) { - writeSST29LE010_N64(); - } + // Close the file: myFile.close(); @@ -2414,18 +2391,6 @@ void resetMSP55LV100_N64(unsigned long flashBase) { delay(100); } -//Reset ST29LE010 -void resetST29LE010_N64(unsigned long flashBase) { - // Send reset Command - setAddress_N64(romBase + 0xAAAA); - writeWord_N64(0xAAAA); - setAddress_N64(romBase + 0x5554); - writeWord_N64(0x5555); - setAddress_N64(romBase + 0xAAAA); - writeWord_N64(0xF0F0); - delay(100); -} - // Common reset command void resetFlashrom_N64(unsigned long flashBase) { // Send reset Command @@ -2568,8 +2533,8 @@ void idFlashrom_N64() { resetFlashrom_N64(romBase); } + //Test for Fujitsu MSP55LV100S (64MB) else { - //Test for Fujitsu MSP55LV100S (64MB) // Send flashrom ID command setAddress_N64(romBase + (0x555 << 1)); writeWord_N64(0xAAAA); @@ -2589,29 +2554,6 @@ void idFlashrom_N64() { cartSize = 64; strncpy(flashid , cartID, 5); } - - else { - //Test for SST 29LE010 - //Send flashrom ID command - setAddress_N64(romBase + 0xAAAA); - writeWord_N64(0xAAAA); - setAddress_N64(romBase + 0x5554); - writeWord_N64(0x5555); - setAddress_N64(romBase + 0xAAAA); - writeWord_N64(0x9090); - - setAddress_N64(romBase); - // Read 1 byte vendor ID - readWord_N64(); - // Read 2 bytes flashrom ID - sprintf(cartID, "%04X", readWord_N64()); - - if (strcmp(cartID, "0808") == 0) { - resetST29LE010_N64(romBase); - cartSize = 1; - strncpy(flashid , cartID, 5); - } - } } } @@ -2817,28 +2759,6 @@ void eraseFlashrom_N64(unsigned long sectorSize) { } } -// SST29LE010 erase command -void eraseSST29LE010_N64() { - print_Msg(F("Erasing...")); - display_Update(); - - //Sending erase command according to datasheet - setAddress_N64(romBase + 0xAAAA); - writeWord_N64(0xAAAA); - setAddress_N64(romBase + 0x5554); - writeWord_N64(0x5555); - setAddress_N64(romBase + 0xAAAA); - writeWord_N64(0x8080); - setAddress_N64(romBase + 0xAAAA); - writeWord_N64(0xAAAA); - setAddress_N64(romBase + 0x5554); - writeWord_N64(0x5555); - setAddress_N64(romBase + 0xAAAA); - writeWord_N64(0x1010); - - delay(20); -} - boolean blankcheckFlashrom_N64() { for (unsigned long currByte = romBase; currByte < romBase + fileSize; currByte += 512) { // Blink led @@ -2850,48 +2770,13 @@ boolean blankcheckFlashrom_N64() { for (int c = 0; c < 512; c += 2) { if (readWord_N64() != 0xFFFF) { - if ((strcmp(flashid, "0808") == 0) && (currByte > romBase + 0x3F) && (currByte < romBase + 0x1080)) { - // Gameshark maps this area to the bootcode of the plugged in cartridge - } - else { - return 0; - } + return 0; } } } return 1; } -// Write SST29LE010 -void writeSST29LE010_N64() { - // Each 29LE010 has 1024 pages, each 128 bytes in size - for (unsigned long currPage = 0; currPage < 1024; currPage++) { - // Fill SD buffer with twice the amount since we flash 2 chips - myFile.read(sdBuffer, 256); - // Blink led - PORTB ^= (1 << 4); - - //Send page write command to both flashroms - setAddress_N64(romBase + 0xAAAA); - writeWord_N64(0xAAAA); - setAddress_N64(romBase + 0x5554); - writeWord_N64(0x5555); - setAddress_N64(romBase + 0xAAAA); - writeWord_N64(0xA0A0); - - // Write 1 page each, one flashrom gets the low byte, the other the high byte. - for (unsigned long currByte = 0; currByte < 256; currByte += 2) { - // Set address - setAddress_N64(romBase + (256 * currPage) + currByte); - // Join two bytes into one word - word currWord = ((sdBuffer[currByte] & 0xFF) << 8) | (sdBuffer[currByte + 1] & 0xFF); - // Send byte data - writeWord_N64(currWord); - } - delay(30); - } -} - // Write Intel flashrom void writeIntel4400_N64() { for (unsigned long currSector = 0; currSector < fileSize; currSector += 131072) { @@ -3125,12 +3010,7 @@ unsigned long verifyFlashrom_N64() { setAddress_N64(romBase + currSector + currSdBuffer + currByte); // Compare both if (readWord_N64() != currWord) { - if ( (strcmp(flashid, "0808") == 0) && (currSector + currSdBuffer + currByte > 0x3F) && (currSector + currSdBuffer + currByte < 0x1080)) { - // Gameshark maps this area to the bootcode of the plugged in cartridge - } - else { - writeErrors++; - } + writeErrors++; // Abord if too many errors if (writeErrors > 20) { print_Msg(F("More than ")); @@ -3153,6 +3033,217 @@ unsigned long verifyFlashrom_N64() { } } +/****************************************** + N64 Gameshark Flash Functions + *****************************************/ +void flashGameshark_N64() { + // Check flashrom ID's + idGameshark_N64(); + + // Check for SST 29LE010 + if (strcmp(flashid, "0808") == 0) { + + println_Msg(""); + println_Msg(F("This will erase your")); + println_Msg(F("Gameshark cartridge")); + println_Msg(F("Attention: Use 3.3V!")); + println_Msg(""); + println_Msg(F("Press Button")); + display_Update(); + wait(); + + // Launch file browser + filePath[0] = '\0'; + sd.chdir("/"); + fileBrowser("Select z64 file"); + display_Clear(); + display_Update(); + + // Create filepath + sprintf(filePath, "%s/%s", filePath, fileName); + + // Open file on sd card + if (myFile.open(filePath, O_READ)) { + // Get rom size from file + fileSize = myFile.fileSize(); + print_Msg(F("File size: ")); + print_Msg(fileSize / 1024); + println_Msg(F("KB")); + display_Update(); + + // Compare file size to flashrom size + if (fileSize > 262144) { + print_Error(F("File too big"), true); + } + + // SST 29LE010, chip erase not needed as this eeprom automaticly erases during the write cycle + eraseGameshark_N64(); + + // Write flashrom + print_Msg(F("Writing ")); + println_Msg(filePath); + display_Update(); + writeGameshark_N64(); + + // Close the file: + myFile.close(); + + // Verify + print_Msg(F("Verifying...")); + display_Update(); + writeErrors = verifyGameshark_N64(); + + if (writeErrors == 0) { + println_Msg(F("OK")); + display_Update(); + } + else { + print_Msg(writeErrors); + print_Msg(F(" bytes ")); + print_Error(F("did not verify."), false); + } + } + else { + print_Error(F("Can't open file"), false); + } + } + // If the ID is unknown show error message + else { + print_Msg(F("ID: ")); + println_Msg(flashid); + print_Error(F("Unknown flashrom"), false); + } + + println_Msg(F("Press Button...")); + display_Update(); + wait(); + display_Clear(); + display_Update(); +} + + +//Test for SST 29LE010 +void idGameshark_N64() { + //Send flashrom ID command + setAddress_N64(romBase + 0xAAAA); + writeWord_N64(0xAAAA); + setAddress_N64(romBase + 0x5554); + writeWord_N64(0x5555); + setAddress_N64(romBase + 0xAAAA); + writeWord_N64(0x9090); + + setAddress_N64(romBase); + // Read 1 byte vendor ID + readWord_N64(); + // Read 2 bytes flashrom ID + sprintf(flashid, "%04X", readWord_N64()); + // Reset flashrom + resetGameshark_N64(); +} + +//Reset ST29LE010 +void resetGameshark_N64() { + // Send reset Command + setAddress_N64(romBase + 0xAAAA); + writeWord_N64(0xAAAA); + setAddress_N64(romBase + 0x5554); + writeWord_N64(0x5555); + setAddress_N64(romBase + 0xAAAA); + writeWord_N64(0xF0F0); + delay(100); +} + +// Send chip erase to the two SST29LE010 inside the Gameshark +void eraseGameshark_N64() { + println_Msg(F("Erasing...")); + display_Update(); + + //Sending erase command according to datasheet + setAddress_N64(romBase + 0xAAAA); + writeWord_N64(0xAAAA); + setAddress_N64(romBase + 0x5554); + writeWord_N64(0x5555); + setAddress_N64(romBase + 0xAAAA); + writeWord_N64(0x8080); + setAddress_N64(romBase + 0xAAAA); + writeWord_N64(0xAAAA); + setAddress_N64(romBase + 0x5554); + writeWord_N64(0x5555); + setAddress_N64(romBase + 0xAAAA); + writeWord_N64(0x1010); + + delay(20); +} + +// Write Gameshark with 2x SST29LE010 Eeproms +void writeGameshark_N64() { + // Each 29LE010 has 1024 pages, each 128 bytes in size + for (unsigned long currPage = 0; currPage < fileSize / 2; currPage += 128) { + // Fill SD buffer with twice the amount since we flash 2 chips + myFile.read(sdBuffer, 256); + // Blink led + PORTB ^= (1 << 4); + + //Send page write command to both flashroms + setAddress_N64(romBase + 0xAAAA); + writeWord_N64(0xAAAA); + setAddress_N64(romBase + 0x5554); + writeWord_N64(0x5555); + setAddress_N64(romBase + 0xAAAA); + writeWord_N64(0xA0A0); + + // Write 1 page each, one flashrom gets the low byte, the other the high byte. + for (unsigned long currByte = 0; currByte < 256; currByte += 2) { + // Set address + setAddress_N64(romBase + 0xC00000 + (currPage * 2) + currByte); + // Join two bytes into one word + word currWord = ((sdBuffer[currByte] & 0xFF) << 8) | (sdBuffer[currByte + 1] & 0xFF); + // Send byte data + writeWord_N64(currWord); + } + delay(30); + } +} + +unsigned long verifyGameshark_N64() { + // Open file on sd card + if (myFile.open(filePath, O_READ)) { + writeErrors = 0; + + for (unsigned long currSector = 0; currSector < fileSize; currSector += 131072) { + // Blink led + PORTB ^= (1 << 4); + for (unsigned long currSdBuffer = 0; currSdBuffer < 131072; currSdBuffer += 512) { + // Fill SD buffer + myFile.read(sdBuffer, 512); + for (int currByte = 0; currByte < 512; currByte += 2) { + // Join two bytes into one word + word currWord = ( ( sdBuffer[currByte] & 0xFF ) << 8 ) | ( sdBuffer[currByte + 1] & 0xFF ); + // Read flash + setAddress_N64(romBase + 0xC00000 + currSector + currSdBuffer + currByte); + // Compare both + if (readWord_N64() != currWord) { + if ( (strcmp(flashid, "0808") == 0) && (currSector + currSdBuffer + currByte > 0x3F) && (currSector + currSdBuffer + currByte < 0x1080)) { + // Gameshark maps this area to the bootcode of the plugged in cartridge + } + else { + writeErrors++; + } + } + } + } + } + // Close the file: + myFile.close(); + return writeErrors; + } + else { + println_Msg(F("Can't open file")); + display_Update(); + return 9999; + } +} + //****************************************** // End of File //******************************************