From b748faecde8bb1c90b545b0b29b735ac65888cf5 Mon Sep 17 00:00:00 2001 From: Richard Weick <55462393+RWeick@users.noreply.github.com> Date: Thu, 7 Sep 2023 21:50:06 -0500 Subject: [PATCH] Update N64.ino This completes the N64 Gameshark functions. It adds the command to enable CPLD address ranges of 0x1EEx_xxxx, 0x1EFx_xxxx, and 0x1ECx_xxxx which are necessary to program the SST 28LF040 eeprom. This also adds full support for the SST 28LF040 eeproms. --- Cart_Reader/N64.ino | 296 +++++++++++++++++++++++++++++++++----------- 1 file changed, 224 insertions(+), 72 deletions(-) diff --git a/Cart_Reader/N64.ino b/Cart_Reader/N64.ino index 9116927..ff35504 100644 --- a/Cart_Reader/N64.ino +++ b/Cart_Reader/N64.ino @@ -4050,7 +4050,9 @@ unsigned long verifyFlashrom_N64() { N64 Gameshark Flash Functions *****************************************/ void flashGameshark_N64() { + int flashSize = 0; // Check flashrom ID's + unlockGSAddressRanges(); idGameshark_N64(); // Check for SST 29LE010 (0808)/SST 28LF040 (0404)/AMTEL AT29LV010A (3535)/SST 29EE010 (0707) @@ -4078,7 +4080,6 @@ void flashGameshark_N64() { filePath[0] = '\0'; sd.chdir("/"); fileBrowser(F("Select z64 file")); - display_Clear(); display_Update(); // Create filepath @@ -4088,18 +4089,25 @@ void flashGameshark_N64() { 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")); + println_Msg(F(" KB")); display_Update(); - // Compare file size to flashrom size - if (fileSize > 262144) { + // Compare file size to flashrom size for 1 Mbit eeproms + if (fileSize > 262144 && (flashid == 0x0808 || flashid == 0x3535 || flashid == 0x0707)) { + print_FatalError(file_too_big_STR); + } + + // Compare file size to flashrom size for 1 Mbit eeproms + if (fileSize > 1048576 && flashid == 0x0404) { print_FatalError(file_too_big_STR); } // SST 29LE010, chip erase not needed as this eeprom automaticly erases during the write cycle eraseGameshark_N64(); + blankCheck_N64(); // Write flashrom print_Msg(F("Writing ")); @@ -4116,14 +4124,19 @@ void flashGameshark_N64() { writeErrors = verifyGameshark_N64(); if (writeErrors == 0) { - println_Msg(F("OK")); + 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 { - print_Msg(writeErrors); + display_Clear(); + display_Update(); + println_Msg(F("Verification Failed")); + println_Msg(writeErrors); print_Msg(F(" bytes ")); print_Error(did_not_verify_STR); } @@ -4131,12 +4144,6 @@ void flashGameshark_N64() { print_Error(F("Can't open file")); } } - // If the ID is unknown show error message - else { - print_Msg(F("ID: ")); - println_Msg(flashid_str); - print_Error(F("Unknown flashrom")); - } // Prints string out of the common strings array either with or without newline print_STR(press_button_STR, 1); @@ -4146,37 +4153,72 @@ void flashGameshark_N64() { display_Update(); } +void unlockGSAddressRanges() { + // This enables using the 0x1EEx_xxxx, 0x1EFx_xxxx, and 0x1ECx_xxxx address ranges, necessary for writing to all supported chips + setAddress_N64(0x10400400); + writeWord_N64(0x1E); + writeWord_N64(0x1E); +} //Test for SST 29LE010 or SST 28LF040 (0404) or AMTEL AT29LV010A (3535) or SST 29EE010 (0707) void idGameshark_N64() { + flashid = 0x0; //Send flashrom ID command - setAddress_N64(romBase + 0xAAAA); + setAddress_N64(0x1EF0AAA8); writeWord_N64(0xAAAA); - setAddress_N64(romBase + 0x5554); + setAddress_N64(0x1EE05554); writeWord_N64(0x5555); - setAddress_N64(romBase + 0xAAAA); + setAddress_N64(0x1EF0AAA8); writeWord_N64(0x9090); - setAddress_N64(romBase); + setAddress_N64(0x1EC00000); // Read 1 byte vendor ID readWord_N64(); // Read 2 bytes flashrom ID flashid = readWord_N64(); + + if (flashid == 0x0808 || flashid == 0x3535 || flashid == 0x0707) { + flashSize = 262144; + } + + if (flashid == 0x0404) { + //Set SST 28LF040 flashrom size + flashSize = 1048574; + if (flashid != 0x0404) { + 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 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); + if (flashid == 0x0808 || flashid == 0x3535 || flashid == 0x0707) { + // Send reset command for SST 29LE010 / AMTEL AT29LV010A / SST 29EE010 + setAddress_N64(0x1EF0AAA8); + writeWord_N64(0xAAAA); + setAddress_N64(0x1EE05554); + writeWord_N64(0x5555); + setAddress_N64(0x1EF0AAA8); + writeWord_N64(0xF0F0); + delay(100); + } else if (flashid == 0x0404) { + // Send reset command for SST 28LF040 + setAddress_N64(0x1EF0AAA8); + writeWord_N64(0xAAAA); + setAddress_N64(0x1EE05554); + writeWord_N64(0x5555); + setAddress_N64(0x1EF0AAA8); + writeWord_N64(0xFFFF); + delay(300); + } } // Read rom and save to the SD card @@ -4203,7 +4245,7 @@ void backupGameshark_N64() { print_FatalError(sd_error_STR); } - for (unsigned long currByte = romBase + 0xC00000; currByte < (romBase + 0xC00000 + 262144); currByte += 512) { + for (unsigned long currByte = romBase + 0xEC00000; currByte < (romBase + 0xEC00000 + flashSize); currByte += 512) { // Blink led if (currByte % 16384 == 0) blinkLED(); @@ -4227,55 +4269,169 @@ void backupGameshark_N64() { myFile.close(); } -// 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); + // Send chip erase to SST 29LE010 / AMTEL AT29LV010A / SST 29EE010 + if (flashid == 0x0808 || flashid == 0x3535 || flashid == 0x0707) { + setAddress_N64(0x1EF0AAA8); + writeWord_N64(0xAAAA); + setAddress_N64(0x1EE05554); + writeWord_N64(0x5555); + setAddress_N64(0x1EF0AAA8); + writeWord_N64(0x8080); + setAddress_N64(0x1EF0AAA8); + writeWord_N64(0xAAAA); + setAddress_N64(0x1EE05554); + writeWord_N64(0x5555); + setAddress_N64(0x1EF0AAA8); + writeWord_N64(0x1010); - delay(20); + delay(20); + } + + if (flashid == 0x0404) { + //Unprotect flash + setAddress_N64(0x1EF03044); + readWord_N64(); + setAddress_N64(0x1EE03040); + readWord_N64(); + setAddress_N64(0x1EE03044); + readWord_N64(); + setAddress_N64(0x1EE00830); + readWord_N64(); + setAddress_N64(0x1EF00834); + readWord_N64(); + setAddress_N64(0x1EF00830); + readWord_N64(); + setAddress_N64(0x1EE00834); + readWord_N64(); + delay(1000); + + //Erase flash + setAddress_N64(0x1EF0AAA8); + writeWord_N64(0xAAAA); + setAddress_N64(0x1EE05554); + writeWord_N64(0x5555); + setAddress_N64(0x1EF0AAA8); + writeWord_N64(0x3030); + setAddress_N64(0x1EF0AAA8); + writeWord_N64(0x3030); + delay(1000); + } } -// 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 - blinkLED(); +void blankCheck_N64() { + // Blankcheck + println_Msg(F("Blankcheck...")); + display_Update(); - //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); + for (unsigned long currSector = 0; currSector < flashSize; 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(romBase + 0xEC00000 + currSector + currSdBuffer + currByte); + // Compare both + if (readWord_N64() != 0xFFFF) { + println_Msg(F("Not empty")); + print_FatalError(F("Erase failed")); + } + } + } } - delay(30); +} + +void writeGameshark_N64() { + // Write Gameshark with 2x SST 29LE010 / AMTEL AT29LV010A / SST 29EE010 Eeproms + if (flashid == 0x0808 || flashid == 0x3535 || flashid == 0x0707) { + // Each 29LE010 has 1024 pages, each 128 bytes in size + myFile.seek(0); + 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 + blinkLED(); + + //Send page write command to both flashroms + setAddress_N64(0x1EF0AAA8); + writeWord_N64(0xAAAA); + setAddress_N64(0x1EE05554); + writeWord_N64(0x5555); + setAddress_N64(0x1EF0AAA8); + 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 + 0xEC00000 + (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); + } + } + + if (flashid == 0x0404) { + // Write Gameshark with 2x SST 28LF040 + //Initialize progress bar + uint32_t processedProgressBar = 0; + uint32_t totalProgressBar = (uint32_t)(fileSize); + draw_progressbar(0, totalProgressBar); + bool toggle = true; + myFile.seek(0); + for (unsigned long currSector = 0; currSector < fileSize; currSector += 16384) { + // Blink led + blinkLED(); + for (unsigned long currSdBuffer = 0; currSdBuffer < 16384; currSdBuffer += 256) { + // Fill SD buffer + myFile.read(sdBuffer, 256); + for (unsigned long currByte = 0; currByte < 256; currByte += 2) { + + // Send byte program command + setAddress_N64(0x1EF0AAA8); + writeWord_N64(0xAAAA); + setAddress_N64(0x1EE05554); + writeWord_N64(0x5555); + setAddress_N64(0x1EF0AAA8); + writeWord_N64(0x1010); + + // Set address + setAddress_N64(romBase + 0xEC00000 + currSector + currSdBuffer + currByte); + + // Join two bytes into one word + word currWord = ((sdBuffer[currByte] & 0xFF) << 8) | (sdBuffer[currByte + 1] & 0xFF); + + // Send byte data + writeWord_N64(currWord); + delayMicroseconds(60); + } + processedProgressBar += 256; + draw_progressbar(processedProgressBar, totalProgressBar); + blinkLED(); + } + } + + //Protect flash + setAddress_N64(0x1EF03044); + readWord_N64(); + setAddress_N64(0x1EE03040); + readWord_N64(); + setAddress_N64(0x1EE03044); + readWord_N64(); + setAddress_N64(0x1EE00830); + readWord_N64(); + setAddress_N64(0x1EF00834); + readWord_N64(); + setAddress_N64(0x1EF00830); + readWord_N64(); + setAddress_N64(0x1EE00814); + readWord_N64(); + delay(1000); } } @@ -4294,14 +4450,10 @@ unsigned long verifyGameshark_N64() { // 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); + setAddress_N64(romBase + 0xEC00000 + currSector + currSdBuffer + currByte); // Compare both if (readWord_N64() != currWord) { - if ((flashid == 0x0808) && (currSector + currSdBuffer + currByte > 0x3F) && (currSector + currSdBuffer + currByte < 0x1080)) { - // Gameshark maps this area to the bootcode of the plugged in cartridge - } else { - writeErrors++; - } + writeErrors++; } } }