mirror of
https://github.com/sanni/cartreader.git
synced 2024-11-11 07:25:07 +01:00
V19D: Changed the way GBA roms are read
This commit is contained in:
parent
3825590018
commit
ae8d1e1f28
@ -2,8 +2,8 @@
|
||||
Cartridge Reader for Arduino Mega2560
|
||||
|
||||
Author: sanni
|
||||
Date: 2016-09-21
|
||||
Version: V19C
|
||||
Date: 2016-09-27
|
||||
Version: V19D
|
||||
|
||||
SD lib: https://github.com/greiman/SdFat
|
||||
LCD lib: https://github.com/adafruit/Adafruit_SSD1306
|
||||
@ -30,10 +30,10 @@
|
||||
zzattack - multigame pcb fix
|
||||
Pickle - SDD1 fix
|
||||
insidegadgets - GBCartRead
|
||||
lukeskaff - Nintendo DS GBA slot timing
|
||||
RobinTheHood - GameboyAdvanceRomDumper
|
||||
|
||||
**********************************************************************************/
|
||||
char ver[5] = "V19C";
|
||||
char ver[5] = "V19D";
|
||||
|
||||
/******************************************
|
||||
Define Output
|
||||
|
@ -7,6 +7,7 @@
|
||||
*****************************************/
|
||||
char calcChecksumStr[5];
|
||||
byte cartBuffer[512];
|
||||
boolean readType;
|
||||
|
||||
const int nintendoLogo[] PROGMEM = {
|
||||
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() {
|
||||
setROM_GBA();
|
||||
|
||||
// Delay until all is stable
|
||||
delay(500);
|
||||
|
||||
// Print start page
|
||||
getCartInfo_GBA();
|
||||
display_Clear();
|
||||
@ -343,128 +341,163 @@ void setROM_GBA() {
|
||||
PORTH |= (1 << 0) | (1 << 3) | (1 << 5) | (1 << 6);
|
||||
}
|
||||
|
||||
// Read one word and toggle both CS and RD
|
||||
word readWord_GBA(unsigned long myAddress) {
|
||||
//divide address by two since we read two bytes per offset
|
||||
unsigned long currAddress = myAddress / 2;
|
||||
void setAddress_GBA(unsigned long myAddress) {
|
||||
// Switch CS_ROM(PH3) to HIGH
|
||||
PORTH |= (1 << 3);
|
||||
|
||||
// Output address to address pins,
|
||||
PORTF = currAddress & 0xFF;
|
||||
PORTK = (currAddress >> 8) & 0xFF;
|
||||
PORTC = (currAddress >> 16) & 0xFF;
|
||||
// Switch RD(PH6) to HIGH
|
||||
PORTH |= (1 << 6);
|
||||
|
||||
// Wait 30ns, Arduino running at 16Mhz -> one operation = 62.5ns
|
||||
__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
|
||||
// Set address/data ports to output
|
||||
DDRF = 0xFF;
|
||||
DDRK = 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;
|
||||
PORTK = 0XFF;
|
||||
PORTC = 0XFF;
|
||||
|
||||
// Return the read word
|
||||
return tempWord;
|
||||
// Set address/data ports to input
|
||||
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
|
||||
void readBlock_GBA(unsigned long myAddress, byte myArray[] , int numBytes) {
|
||||
// Read multiple bytes into an array toggle both CS and RD each time
|
||||
void readRand_GBA(unsigned long myAddress, byte myArray[] , int numBytes) {
|
||||
for (int currByte = 0; currByte < numBytes; currByte += 2) {
|
||||
unsigned long currAddress = myAddress + currByte;
|
||||
word currWord = readWord_GBA(currAddress);
|
||||
setAddress_GBA(myAddress + currByte);
|
||||
|
||||
word currWord = ((PINF << 8) + PINK) & 0xFFFF;
|
||||
|
||||
myArray[currByte] = (currWord >> 8) & 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
|
||||
*****************************************/
|
||||
// Read info out of rom header
|
||||
void getCartInfo_GBA() {
|
||||
// Read Header into array
|
||||
readBlock_GBA(0, cartBuffer, 192);
|
||||
// Test known Nintendo header for errors and sets read method to either sequential or random access
|
||||
int testHeader() {
|
||||
// Set address to start of rom
|
||||
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++) {
|
||||
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("Press Button..."));
|
||||
display_Update();
|
||||
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
|
||||
@ -495,16 +528,23 @@ void readROM_GBA() {
|
||||
print_Error(F("Can't create file on SD"), true);
|
||||
}
|
||||
|
||||
// Set starting address
|
||||
setAddress_GBA(0);
|
||||
|
||||
if (readType == 0) {
|
||||
setROM_GBA();
|
||||
}
|
||||
|
||||
// Read rom
|
||||
for (int myAddress = 0; myAddress < cartSize; myAddress += 512) {
|
||||
// Fill sdBuffer starting at myAddress and reading 512 bytes
|
||||
readBlock_GBA(myAddress, sdBuffer, 512);
|
||||
// Read either sequentially or in random acces mode
|
||||
if (readType == 1)
|
||||
readSeq_GBA(sdBuffer, 512);
|
||||
else
|
||||
readRand_GBA(myAddress, sdBuffer, 512);
|
||||
|
||||
// Write to SD
|
||||
myFile.write(sdBuffer, 512);
|
||||
|
||||
// Pause between blocks, increase if you get errors every numBytes bytes
|
||||
delayMicroseconds(20);
|
||||
}
|
||||
|
||||
// Close the file:
|
||||
|
@ -110,7 +110,7 @@ void snesMenu() {
|
||||
writeSRAM(0);
|
||||
unsigned long wrErrors = verifySRAM();
|
||||
if (wrErrors == 0) {
|
||||
println_Msg(F("Verified OK"));
|
||||
println_Msg(F("Restored OK"));
|
||||
display_Update();
|
||||
}
|
||||
else {
|
||||
|
Loading…
Reference in New Issue
Block a user