mirror of
https://github.com/sanni/cartreader.git
synced 2024-12-27 05:21:53 +01:00
Merge pull request #847 from RWeick/master
Update N64.ino to add full dump and programming support for the Xplorer 64. Firmware must be unscrambled in order to be written to the Xplorer 64 with this function. Firmware dumped via this function are unscrambled. Firmware extracted directly from the eeproms in an eeprom programmer are scrambled and must be unscrambled before being used with this.
This commit is contained in:
commit
3a30c0f5ed
@ -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
|
||||
|
||||
//******************************************
|
||||
|
Loading…
Reference in New Issue
Block a user