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.
This commit is contained in:
Richard Weick 2023-09-07 21:50:06 -05:00 committed by GitHub
parent 7cf03d3542
commit b748faecde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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++;
}
}
}