V2.5 Add Support for Gameshark N64 reflashing (beta)

Sometimes the Gameshark will lock itself up, in this case it helps if you put a 6102 game into the Gamesharks slot and then put both into the Cart Reader and just start dumping the rom as if it was a game.
This commit is contained in:
sanni 2019-01-16 16:50:55 +01:00
parent 8173115c93
commit 642139ca1a
2 changed files with 255 additions and 164 deletions

View File

@ -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

View File

@ -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
//******************************************