diff --git a/Cart_Reader/N64.ino b/Cart_Reader/N64.ino index d3e1310..8627793 100644 --- a/Cart_Reader/N64.ino +++ b/Cart_Reader/N64.ino @@ -55,7 +55,7 @@ static const char n64MenuItem1[] PROGMEM = "Game Cartridge"; static const char n64MenuItem2[] PROGMEM = "Controller"; static const char n64MenuItem3[] PROGMEM = "Flash Repro"; static const char n64MenuItem4[] PROGMEM = "Flash Gameshark"; -static const char n64MenuItem5[] PROGMEM = "Backup Xplorer 64"; +static const char n64MenuItem5[] PROGMEM = "Flash Xplorer 64"; //static const char n64MenuItem6[] PROGMEM = "Reset"; (stored in common strings array) static const char* const menuOptionsN64[] PROGMEM = { n64MenuItem1, n64MenuItem2, n64MenuItem3, n64MenuItem4, n64MenuItem5, string_reset2 }; @@ -160,7 +160,7 @@ void n64Menu() { display_Clear(); display_Update(); setup_N64_Cart(); - backupXplorer_N64(); + flashXplorer_N64(); mode = mode_N64_Cart; print_STR(press_button_STR, 1); display_Update(); @@ -4476,11 +4476,139 @@ unsigned long verifyGameshark_N64() { /****************************************** XPLORER 64 Functions *****************************************/ +void flashXplorer_N64() { + // Check flashrom ID's + idXplorer_N64(); + + if (flashid == 0x0808) { + backupXplorer_N64(); + println_Msg(""); + println_Msg(F("This will erase your")); + println_Msg(F("Xplorer64 cartridge")); + println_Msg(F("Attention: Use 3.3V!")); + println_Msg(F("Power OFF if Unsure!")); + // Prints string out of the common strings array either with or without newline + print_STR(press_button_STR, 1); + display_Update(); + wait(); + + // Launch file browser + filePath[0] = '\0'; + sd.chdir("/"); + fileBrowser(F("Select XP64 rom file")); + 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(); + display_Clear(); + 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_FatalError(file_too_big_STR); + } + + // SST 29LE010, chip erase not needed as this eeprom automaticly erases during the write cycle + eraseXplorer_N64(); + blankCheck_XP64(); + + // Write flashrom + display_Clear(); + print_Msg(F("Writing ")); + println_Msg(filePath); + display_Update(); + writeXplorer_N64(); + + // Close the file: + myFile.close(); + + // Verify + print_STR(verifying_STR, 0); + display_Update(); + writeErrors = verifyXplorer_N64(); + + if (writeErrors == 0) { + display_Clear(); + display_Update(); + println_Msg(F("Verfied OK")); + println_Msg(F("")); + println_Msg(F("Turn Cart Reader off now")); + display_Update(); + while (1) + ; + } else { + display_Clear(); + display_Update(); + println_Msg(F("Verification Failed")); + println_Msg(writeErrors); + print_Msg(F(" bytes ")); + print_Error(did_not_verify_STR); + } + } else { + print_Error(F("Can't open file")); + } + } + + // Prints string out of the common strings array either with or without newline + print_STR(press_button_STR, 1); + display_Update(); + wait(); + display_Clear(); + display_Update(); +} + +//Test for SST 29LE010 +void idXplorer_N64() { + flashid = 0x0; + //Send flashrom ID command + oddXPaddrWrite(0x1040AAAA, 0xAAAA); + evenXPaddrWrite(0x10405555, 0x5555); + oddXPaddrWrite(0x1040AAAA, 0x9090); + + setAddress_N64(0x10760000); + readWord_N64(); + setAddress_N64(0x10400D88); + flashid = readWord_N64(); + setAddress_N64(0x10740000); + readWord_N64(); + + if (flashid == 0x0808) { + flashSize = 262144; + } else { + println_Msg(F("Check cart connection")); + println_Msg(F("Unknown Flash ID")); + sprintf(flashid_str, "%04X", flashid); + print_STR(press_button_STR, 1); + display_Update(); + wait(); + mainMenu(); + } + sprintf(flashid_str, "%04X", flashid); + // Reset flashrom + resetXplorer_N64(); +} + +void resetXplorer_N64() { + // Send reset command for SST 29LE010 + oddXPaddrWrite(0x1040AAAA, 0xAAAA); + evenXPaddrWrite(0x10405555, 0x5555); + oddXPaddrWrite(0x1040AAAA, 0xF0F0); + delay(100); +} + // Read rom and save to the SD card void backupXplorer_N64() { // create a new folder EEPROM_readAnything(0, foldern); - sprintf(fileName, "XP64%d", foldern); + sprintf(fileName, "XP64-%d", foldern); strcat(fileName, ".z64"); sd.mkdir("N64/ROM/XPLORER64", true); sd.chdir("N64/ROM/XPLORER64"); @@ -4525,6 +4653,173 @@ void backupXplorer_N64() { println_Msg(F("Done.")); } +unsigned long unscramble(unsigned long addr) { + unsigned long result = (((addr >> 4) & 0x001) | ((addr >> 8) & 0x002) | + ((~addr >> 9) & 0x004) | ((addr >> 3) & 0x008) | + ((addr >> 6) & 0x010) | ((addr >> 2) & 0x020) | + ((~addr << 5) & 0x0C0) | ((~addr << 8) & 0x100) | + ((~addr << 6) & 0x200) | ((~addr << 2) & 0x400) | + ((addr << 6) & 0x800) | (addr & 0x1F000)); + + return result; +} + + +unsigned long scramble(unsigned long addr) { + unsigned long result = (((~addr >> 8) & 0x001) | ((~addr >> 5) & 0x006) | + ((~addr >> 6) & 0x008) | ((addr << 4) & 0x010) | + ((addr >> 6) & 0x020) | ((addr << 3) & 0x040) | + ((addr << 2) & 0x080) | ((~addr >> 2) & 0x100) | + ((addr << 8) & 0x200) | ((addr << 6) & 0x400) | + ((~addr << 9) & 0x800) | (addr & 0x1F000)); + + return result; +} + + +void oddXPaddrWrite(unsigned long addr, word data) { + unsigned long oddAddr = (0x10400000 + ((unscramble((addr & 0xFFFFF) / 2) - 1) * 2)); + setAddress_N64(0x10770000); + readWord_N64(); + readWord_N64(); + setAddress_N64(oddAddr); + writeWord_N64(data); + writeWord_N64(data); + setAddress_N64(0x10740000); + readWord_N64(); + readWord_N64(); + +} + +void evenXPaddrWrite(unsigned long addr, word data) { + unsigned long evenAddr = (0x10400000 + (unscramble((addr & 0xFFFFF) / 2) * 2)); + setAddress_N64(0x10760000); + readWord_N64(); + readWord_N64(); + setAddress_N64(evenAddr); + writeWord_N64(data); + writeWord_N64(data); + setAddress_N64(0x10740000); + readWord_N64(); + readWord_N64(); +} + +void eraseXplorer_N64() { + println_Msg(F("Erasing...")); + display_Update(); + + // Send chip erase to SST 29LE010 / AMTEL AT29LV010A / SST 29EE010 + oddXPaddrWrite(0x1040AAAA, 0xAAAA); + evenXPaddrWrite(0x10405555, 0x5555); + oddXPaddrWrite(0x1040AAAA, 0x8080); + oddXPaddrWrite(0x1040AAAA, 0xAAAA); + evenXPaddrWrite(0x10405555, 0x5555); + oddXPaddrWrite(0x1040AAAA,0x1010); + + delay(20); +} + +void blankCheck_XP64() { + // Blankcheck + println_Msg(F("Blankcheck...")); + display_Update(); + + for (unsigned long currSector = 0; currSector < 262144; currSector += 131072) { + // Blink led + blinkLED(); + for (unsigned long currSdBuffer = 0; currSdBuffer < 131072; currSdBuffer += 512) { + for (int currByte = 0; currByte < 512; currByte += 2) { + // Read flash + setAddress_N64(0x10400000 + currSector + currSdBuffer + currByte); + // Compare both + if (readWord_N64() != 0xFFFF) { + println_Msg(F("Not empty")); + print_FatalError(F("Erase failed")); + } + } + } + } +} + +void writeXplorer_N64() { + // Write Xplorer64 with 2x SST 29LE010 + // Each 29LE010 has 1024 pages, each 128 bytes in size + //Initialize progress bar + uint32_t processedProgressBar = 0; + uint32_t totalProgressBar = (uint32_t)(fileSize); + draw_progressbar(0, totalProgressBar); + for (unsigned long currPage = 0; currPage < fileSize / 2; currPage += 128) { + + // Fill SD buffer with data in the order it will be expected by the CPLD + for (unsigned long i = 0; i < 256; i += 2) { + unsigned long unscrambled_address = (unscramble(((currPage*2) + i) / 2) * 2); + myFile.seek(unscrambled_address); + myFile.read(&sdBuffer[i], 1); + myFile.seek(unscrambled_address + 1); + myFile.read(&sdBuffer[i + 1], 1); + } + + //Send page write command to both flashroms + oddXPaddrWrite(0x1040AAAA, 0xAAAA); + evenXPaddrWrite(0x10405555, 0x5555); + oddXPaddrWrite(0x1040AAAA, 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) { + // Join two bytes into one word + word currWord = ((sdBuffer[currByte] & 0xFF) << 8) | (sdBuffer[currByte + 1] & 0xFF); + // Set address + if ((((currByte/2) >> 4) & 0x1) == 0) { + evenXPaddrWrite(0x10400000 + (currPage*2) + currByte, currWord); + } else { + oddXPaddrWrite(0x10400000 + (currPage*2) + currByte, currWord); + } + } + processedProgressBar += 256; + draw_progressbar(processedProgressBar, totalProgressBar); + blinkLED(); + } +} + +unsigned long verifyXplorer_N64() { + uint32_t processedProgressBar = 0; + uint32_t totalProgressBar = (uint32_t)(262144); + println_Msg(F("")); + draw_progressbar(0, totalProgressBar); + // Open file on sd card + if (myFile.open(filePath, O_READ)) { + myFile.seek(0); + writeErrors = 0; + + for (unsigned long currSector = 0; currSector < 262144; currSector += 131072) { + 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 + 0x400000 + currSector + currSdBuffer + currByte); + // Compare both + if (readWord_N64() != currWord) { + writeErrors++; + } + } + processedProgressBar += 512; + draw_progressbar(processedProgressBar, totalProgressBar); + blinkLED(); + } + } + // Close the file: + myFile.close(); + return writeErrors; + } else { + print_STR(open_file_STR, 1); + display_Update(); + return 9999; + } +} + #endif //******************************************