V19D: Changed the way GBA roms are read

This commit is contained in:
sanni 2016-09-27 00:00:22 +02:00 committed by GitHub
parent 3825590018
commit ae8d1e1f28
3 changed files with 147 additions and 107 deletions

View File

@ -2,8 +2,8 @@
Cartridge Reader for Arduino Mega2560 Cartridge Reader for Arduino Mega2560
Author: sanni Author: sanni
Date: 2016-09-21 Date: 2016-09-27
Version: V19C Version: V19D
SD lib: https://github.com/greiman/SdFat SD lib: https://github.com/greiman/SdFat
LCD lib: https://github.com/adafruit/Adafruit_SSD1306 LCD lib: https://github.com/adafruit/Adafruit_SSD1306
@ -30,10 +30,10 @@
zzattack - multigame pcb fix zzattack - multigame pcb fix
Pickle - SDD1 fix Pickle - SDD1 fix
insidegadgets - GBCartRead insidegadgets - GBCartRead
lukeskaff - Nintendo DS GBA slot timing RobinTheHood - GameboyAdvanceRomDumper
**********************************************************************************/ **********************************************************************************/
char ver[5] = "V19C"; char ver[5] = "V19D";
/****************************************** /******************************************
Define Output Define Output

View File

@ -7,6 +7,7 @@
*****************************************/ *****************************************/
char calcChecksumStr[5]; char calcChecksumStr[5];
byte cartBuffer[512]; byte cartBuffer[512];
boolean readType;
const int nintendoLogo[] PROGMEM = { const int nintendoLogo[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x24, 0xFF, 0xAE, 0x51, 0x69, 0x9A, 0xA2, 0x21, 0x3D, 0x84, 0x82, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x24, 0xFF, 0xAE, 0x51, 0x69, 0x9A, 0xA2, 0x21, 0x3D, 0x84, 0x82, 0x0A,
@ -289,9 +290,6 @@ void gbaMenu() {
void setup_GBA() { void setup_GBA() {
setROM_GBA(); setROM_GBA();
// Delay until all is stable
delay(500);
// Print start page // Print start page
getCartInfo_GBA(); getCartInfo_GBA();
display_Clear(); display_Clear();
@ -343,128 +341,163 @@ void setROM_GBA() {
PORTH |= (1 << 0) | (1 << 3) | (1 << 5) | (1 << 6); PORTH |= (1 << 0) | (1 << 3) | (1 << 5) | (1 << 6);
} }
// Read one word and toggle both CS and RD void setAddress_GBA(unsigned long myAddress) {
word readWord_GBA(unsigned long myAddress) { // Switch CS_ROM(PH3) to HIGH
//divide address by two since we read two bytes per offset PORTH |= (1 << 3);
unsigned long currAddress = myAddress / 2;
// Output address to address pins, // Switch RD(PH6) to HIGH
PORTF = currAddress & 0xFF; PORTH |= (1 << 6);
PORTK = (currAddress >> 8) & 0xFF;
PORTC = (currAddress >> 16) & 0xFF;
// Wait 30ns, Arduino running at 16Mhz -> one operation = 62.5ns // Set address/data ports to output
__asm__("nop\n\t");
// Pull CS_ROM(PH3) LOW to latch the address
PORTH &= ~(1 << 3);
// Wait 120ns between pulling CS and RD LOW
__asm__("nop\n\t""nop\n\t");
// Set address/data pins to LOW, this is important
PORTF = 0x0;
PORTK = 0x0;
// Set address/data ports to input so we can read, but don't enable pullups
DDRF = 0x0;
DDRK = 0x0;
// Pull RD(PH6) to LOW to read 16 bytes of data
PORTH &= ~ (1 << 6);
// Wait 120ns for the cartridge rom to write the data to the datalines
__asm__("nop\n\t""nop\n\t");
// Switch CS_ROM(PH3) RD(PH6) to HIGH
PORTH |= (1 << 3) | (1 << 6);
// Read the data off the data lines on the rising edge of the RD line.
word tempWord = ((PINF << 8) + PINK) & 0xFFFF;
// Set address/data pins to output
DDRF = 0xFF; DDRF = 0xFF;
DDRK = 0xFF; DDRK = 0xFF;
DDRC = 0xFF; DDRC = 0xFF;
// Output a high signal so there are no floating pins
// Output address to address pins,
PORTF = (myAddress / 2) & 0xFF;
PORTK = ((myAddress / 2) >> 8) & 0xFF;
PORTC = ((myAddress / 2) >> 16) & 0xFF;
// Pull CS(PH3) to LOW
PORTH &= ~ (1 << 3);
// Output a high signal
PORTF = 0XFF; PORTF = 0XFF;
PORTK = 0XFF; PORTK = 0XFF;
PORTC = 0XFF; PORTC = 0XFF;
// Return the read word // Set address/data ports to input
return tempWord; DDRF = 0x00;
DDRK = 0x00;
// Pull RD(PH6) to LOW
PORTH &= ~ (1 << 6);
} }
// Read multiple bytes into an array by toggling both CS and RD for each byte // Read multiple bytes into an array toggle both CS and RD each time
void readBlock_GBA(unsigned long myAddress, byte myArray[] , int numBytes) { void readRand_GBA(unsigned long myAddress, byte myArray[] , int numBytes) {
for (int currByte = 0; currByte < numBytes; currByte += 2) { for (int currByte = 0; currByte < numBytes; currByte += 2) {
unsigned long currAddress = myAddress + currByte; setAddress_GBA(myAddress + currByte);
word currWord = readWord_GBA(currAddress);
word currWord = ((PINF << 8) + PINK) & 0xFFFF;
myArray[currByte] = (currWord >> 8) & 0xFF; myArray[currByte] = (currWord >> 8) & 0xFF;
myArray[currByte + 1] = currWord & 0xFF; myArray[currByte + 1] = currWord & 0xFF;
} }
setROM_GBA();
} }
// Read multiple bytes into an array but only toggle CS once
void readSeq_GBA(byte myArray[] , int numBytes) {
for (int currByte = 0; currByte < numBytes; currByte += 2) {
word currWord = ((PINF << 8) + PINK) & 0xFFFF;
myArray[currByte] = (currWord >> 8) & 0xFF;
myArray[currByte + 1] = currWord & 0xFF;
// Switch RD(PH6) to HIGH
PORTH |= (1 << 6);
// Pull RD(PH6) to LOW
PORTH &= ~ (1 << 6);
}
}
/****************************************** /******************************************
Game Boy ROM Functions Game Boy ROM Functions
*****************************************/ *****************************************/
// Read info out of rom header // Test known Nintendo header for errors and sets read method to either sequential or random access
void getCartInfo_GBA() { int testHeader() {
// Read Header into array // Set address to start of rom
readBlock_GBA(0, cartBuffer, 192); setAddress_GBA(0);
// Read header into array sequentially
readSeq_GBA(cartBuffer, 192);
// Nintendo logo check // Check if Nintendo logo is read ok
int logoErrors = checkLogo();
if (logoErrors != 0) {
// Nintendo logo has errors -> change read method
setROM_GBA();
setAddress_GBA(0);
// Read Header into array in random access mode
readRand_GBA(0, cartBuffer, 192);
logoErrors = checkLogo();
if (logoErrors == 0) {
readType = 0;
}
}
else {
readType = 1;
}
return logoErrors;
}
// Compare Nintendo logo, 156 bytes starting at 0x04
int checkLogo() {
int errors = 0;
for (int currByte = 0x4; currByte < 0xA0; currByte++) { for (int currByte = 0x4; currByte < 0xA0; currByte++) {
if (pgm_read_byte(&nintendoLogo[currByte]) != cartBuffer[currByte]) { if (pgm_read_byte(&nintendoLogo[currByte]) != cartBuffer[currByte]) {
print_Error(F("Nintendo Logo Error"), false); errors++;
}
}
return errors;
}
// Read info out of rom header
void getCartInfo_GBA() {
// Test rom header for errors
int logoErrors = testHeader();
if (logoErrors != 0) {
print_Error(F("Nintendo Logo Error"), true);
}
else {
// Get cart ID
cartID[0] = char(cartBuffer[0xAC]);
cartID[1] = char(cartBuffer[0xAD]);
cartID[2] = char(cartBuffer[0xAE]);
cartID[3] = char(cartBuffer[0xAF]);
// Dump name into 8.3 compatible format
byte myByte = 0;
byte myLength = 0;
for (int addr = 0xA0; addr <= 0xAB; addr++) {
myByte = cartBuffer[addr];
if (((char(myByte) >= 48 && char(myByte) <= 57) || (char(myByte) >= 65 && char(myByte) <= 122)) && myLength < 8) {
romName[myLength] = char(myByte);
myLength++;
}
}
// Get ROM version
romVersion = cartBuffer[0xBC];
// Get Checksum as string
sprintf(checksumStr, "%02X", cartBuffer[0xBD]);
// Calculate Checksum
int calcChecksum = 0x00;
for (int n = 0xA0; n < 0xBD; n++) {
calcChecksum -= cartBuffer[n];
}
calcChecksum = (calcChecksum - 0x19) & 0xFF;
// Turn into string
sprintf(calcChecksumStr, "%02X", calcChecksum);
// Compare checksum
if (strcmp(calcChecksumStr, checksumStr) != 0) {
print_Msg(F("Result: "));
println_Msg(calcChecksumStr);
print_Error(F("Checksum Error"), false);
println_Msg(F("")); println_Msg(F(""));
println_Msg(F("Press Button...")); println_Msg(F("Press Button..."));
display_Update(); display_Update();
wait(); wait();
break;
} }
} }
// Get cart ID
cartID[0] = char(cartBuffer[0xAC]);
cartID[1] = char(cartBuffer[0xAD]);
cartID[2] = char(cartBuffer[0xAE]);
cartID[3] = char(cartBuffer[0xAF]);
// Dump name into 8.3 compatible format
byte myByte = 0;
byte myLength = 0;
for (int addr = 0xA0; addr <= 0xAB; addr++) {
myByte = cartBuffer[addr];
if (((char(myByte) >= 48 && char(myByte) <= 57) || (char(myByte) >= 65 && char(myByte) <= 122)) && myLength < 8) {
romName[myLength] = char(myByte);
myLength++;
}
}
// Get ROM version
romVersion = cartBuffer[0xBC];
// Get Checksum as string
sprintf(checksumStr, "%02X", cartBuffer[0xBD]);
// Calculate Checksum
int calcChecksum = 0x00;
for (int n = 0xA0; n < 0xBD; n++) {
calcChecksum -= cartBuffer[n];
}
calcChecksum = (calcChecksum - 0x19) & 0xFF;
// Turn into string
sprintf(calcChecksumStr, "%02X", calcChecksum);
// Compare checksum
if (strcmp(calcChecksumStr, checksumStr) != 0) {
print_Msg(F("Result: "));
println_Msg(calcChecksumStr);
print_Error(F("Checksum Error"), false);
println_Msg(F(""));
println_Msg(F("Press Button..."));
display_Update();
wait();
}
} }
// Dump ROM // Dump ROM
@ -495,16 +528,23 @@ void readROM_GBA() {
print_Error(F("Can't create file on SD"), true); print_Error(F("Can't create file on SD"), true);
} }
// Set starting address
setAddress_GBA(0);
if (readType == 0) {
setROM_GBA();
}
// Read rom // Read rom
for (int myAddress = 0; myAddress < cartSize; myAddress += 512) { for (int myAddress = 0; myAddress < cartSize; myAddress += 512) {
// Fill sdBuffer starting at myAddress and reading 512 bytes // Read either sequentially or in random acces mode
readBlock_GBA(myAddress, sdBuffer, 512); if (readType == 1)
readSeq_GBA(sdBuffer, 512);
else
readRand_GBA(myAddress, sdBuffer, 512);
// Write to SD // Write to SD
myFile.write(sdBuffer, 512); myFile.write(sdBuffer, 512);
// Pause between blocks, increase if you get errors every numBytes bytes
delayMicroseconds(20);
} }
// Close the file: // Close the file:

View File

@ -110,7 +110,7 @@ void snesMenu() {
writeSRAM(0); writeSRAM(0);
unsigned long wrErrors = verifySRAM(); unsigned long wrErrors = verifySRAM();
if (wrErrors == 0) { if (wrErrors == 0) {
println_Msg(F("Verified OK")); println_Msg(F("Restored OK"));
display_Update(); display_Update();
} }
else { else {