Go Down

Topic: ROM-Reader for Super Nintendo / Super Famicom Game Cartridges (Read 7112 times) previous topic - next topic

skaman

Got around to redumping Star Ocean.  With the Adafruit Clock Generator connected, Star Ocean cart no longer needs the verifySORead code.  The SDD1 carts now dump correctly every time.

skaman

Made a huge time savings in calc_checksum().  Added a 512 byte buffer for the myFile.read() and it now completes the task in seconds versus minutes.  I'll post the code after I clean it up.

EDIT:  Applied the same 512 byte buffer to myFile.write() in dumpROM() and it cut my dump times by more than half!  Got a 2MB (16Mbit) LoROM dumping AND checking the checksum in 1 minute - it used to take around ~3:50. 

In case anyone cares, the 512 byte buffer was chosen as it is the minimum block size used by the SD card.  Reading and writing anything less than 512 bytes to the SD card slows things down.

sanni

I've confirmed all of the SDD1, SuperFX, SPC7110 and Seta DSP (ST010/ST011/ST018) carts dump properly.  I also tested one of the CX4 carts - Rockman/Mega Man X2.  The other CX4 cart - Rockman/Mega Man X3 should work but it is untested.  
This is so amazing  :)
It perfectly shows the power of open source  8)

I toyed around with Eagle a little more:



It's based on the Mega shield by Sparkfun: https://www.sparkfun.com/products/9346
Using the SNES cartslot from here: https://github.com/Sputnick85/eagle_nintendo
And some parts out of those libs: https://github.com/sparkfun/SparkFun-Eagle-Libraries
It then was autorouted with the help of: freerouting.net

skaman

Okay, here's the SD buffer code to speed up reads and writes.  I'll post the complete dump code after I test the ExHiROM carts and a couple other enhanced chip carts.

First off we add the SDBuffer[512] in the define section.

Next, my current calc_checksum() code.  Some of it is untested as I don't have all of the different sizes (missing 1.5MB, 2.5MB & "Normal" 3MB).  I referred to ROMs from the GoodSets where needed.

Code: [Select]

//Define Cart Reader Variables
...
byte SDBuffer[512];
...

//*************************CALCULATE CHECKSUM**************************************
unsigned int calc_checksum (char* fileName, char* folder) {
  unsigned int calcChecksum = 0;
  unsigned int calcChecksumChunk = 0;
  int calcFilesize = 0;
  unsigned int c = 0;
  unsigned long i = 0;
  unsigned long j = 0;

  if (strcmp(folder, "root") != 0)
    sd.chdir(folder);

  // If file exists
  if (myFile.open(fileName, O_READ)) {
    calcFilesize = myFile.fileSize() * 8 / 1024 / 1024;
    if (calcFilesize == 12 || calcFilesize == 20) {
      // Divide filesize by 8 to get number of 8Mbit chunks
      for (i = 0; i < (calcFilesize / 8); i++ ) {
        // Add all the bits in the 8Mbit chunks
        for (j = 0; j < (1048576 / 512); j++) {
          myFile.read(SDBuffer, 512);
          for (c = 0; c < 512; c++) {
            calcChecksumChunk += SDBuffer[c];
          }
        }
        calcChecksum = calcChecksumChunk;
      }
      calcChecksumChunk = 0;
      // Add the 4Mbit rest
      for (j = 0; j < (524288 / 512); j++) {
        myFile.read(SDBuffer, 512);
        for (c = 0; c < 512; c++) {
          calcChecksumChunk += SDBuffer[c];
        }
      }
      calcChecksum +=  2 * calcChecksumChunk;
    }
    else if (calcFilesize == 24 || calcFilesize == 28) {
      // Momotarou Dentestu Happy Fix 3MB (24Mbit)
      if ((calcFilesize == 24) && (romSizeExp = 0x0C)) {
        for (i = 0; i < (myFile.fileSize() / 512); i++) {
          myFile.read(SDBuffer, 512);
          for (c = 0; c < 512; c++) {
            calcChecksumChunk += SDBuffer[c];
          }
        }
        calcChecksum = 2 * calcChecksumChunk;
      }
      else {
        for (i = 0; i < (calcFilesize / 16); i++ ) {
          // Add all the bits in the 16Mbit chunks
          for (j = 0; j < (2097152 / 512); j++) {
            myFile.read(SDBuffer, 512);
            for (c = 0; c < 512; c++) {
              calcChecksumChunk += SDBuffer[c];
            }
          }
          calcChecksum = calcChecksumChunk;
        }
        calcChecksumChunk = 0;
        // Add the 8Mbit rest
        for (j = 0; j < (1048576 / 512); j++) {
          myFile.read(SDBuffer, 512);
          for (c = 0; c < 512; c++) {
            calcChecksumChunk += SDBuffer[c];
          }
        }
        calcChecksum +=  2 * calcChecksumChunk;
      }
    }
    else if (calcFilesize == 48) {
 // Star Ocean/Tales of Phantasia Fix 6MB (48Mbit)
 // Add the 4MB (32Mbit) start
      for (j = 0; j < (4194304 / 512); j++) {
        myFile.read(SDBuffer, 512);
        for (c = 0; c < 512; c++) {
          calcChecksumChunk += SDBuffer[c];
        }
        calcChecksum = calcChecksumChunk;
      }
      calcChecksumChunk = 0;
      // Add the 2MB (16Mbit) end
      for (j = 0; j < (2097152 / 512); j++) {
        myFile.read(SDBuffer, 512);
        for (c = 0; c < 512; c++) {
          calcChecksumChunk += SDBuffer[c];
        }
      }
      calcChecksum +=  2 * calcChecksumChunk;
    }
    else {
    //calcFilesize == 2, 4, 8, 16, 32, 40, etc
      for (i = 0; i < (myFile.fileSize() / 512); i++) {
        myFile.read(SDBuffer, 512);
        for (c = 0; c < 512; c++) {
          calcChecksumChunk += SDBuffer[c];
        }
        calcChecksum = calcChecksumChunk;
      }
    }
    myFile.close();
    sd.chdir();
    return (calcChecksum);
  }
  // Else show error
  else {
    display.println("ERROR");
    display.println("DUMP ROM 1ST");
    display.display();
    return 0;
  }
}


The checksum calculation greatly benefits from the 512 byte buffer.  We read the file on the SD card in 512 byte chunks to perform our calculation.  Calculations used to take minutes but now it takes only seconds to complete.

Now for the dumping code.  In an effort to streamline the dumpROM() code, I created a dumpLoROM() and dumpHiROM().  These routines dump 512 bytes into the SDBuffer then writes the buffer to the file on the SD card.

Code: [Select]

long dumpLoROM() {
  display.println("Dumping LoROM");
  display.print("Banks: ");
  display.println(numBanks);
  display.display();
  long dumpedBytes = 0;
  // Read up to 96 banks starting at bank 0x00.
  for (int currBank = 0; currBank < numBanks; currBank++) {
    // give status updates via LCD
    display.print(".");
    display.display();

    // Dump the bytes to SD
    for (long currByte = 0x8000; currByte < 0x10000; currByte += 512) {
      for (unsigned long c = 0; c < 512; c++) {
        SDBuffer[c] = dumpByte(currBank, currByte + c, false);
        dumpedBytes++;
      }
      myFile.write(SDBuffer, 512);
    }
  }
  return(dumpedBytes);
}

long dumpHiROM(int currBank, int endBank, long dumpedBytes) {
  for(currBank; currBank < endBank; currBank++) {
    // give status updates via LCD
    display.print(".");
    display.display();
   
    // Dump the bytes to SD
   for(long currByte=0; currByte < 0x10000; currByte += 512) {
      for (unsigned long c = 0; c < 512; c++) {
        SDBuffer[c] = dumpByte(currBank, currByte + c, false);
        dumpedBytes++;
      }
      myFile.write(SDBuffer, 512);
   }
  }
  return(dumpedBytes);
}


So substitute dumpLoROM() and dumpHiROM() into dumpROM() where needed.  Here's the calls as I have them right now.

Code: [Select]

void dumpROM() {
...
  long dumpedBytes = 0;
  ...
  if ((romChips != 67)&&(romChips != 69)&&(romChips != 245)&&(romChips != 249)) {
    if (romType == 0) {
     ...
       dumpedBytes = dumpLoROM();
    ...
    }
    else if (romType == 1) {
      ...
        dumpedBytes = dumpHiROM(0xC0, numBanks + 0xC0, dumpedBytes);
    ...
    }
  }
  else if((romChips == 67)||(romChips ==69)) {
    // SDD1
    // Street Fighter Alpha/Zero 2 (J, U, E): romChips = 67
    // Star Ocean (J): romChips = 69
    ...
      dumpedBytes = dumpHiROM(0xF0, 0x100, dumpedBytes);
  ...
  }
  else if((romChips == 245)||(romChips == 249)){
    if (romType == 0) {
      // ST018
      // Hayazashi Nidan Morita Shougi 2: romChips = 245
      dumpedBytes = dumpLoROM();
    }
    else if (romType == 1) {
      // SPC7110
      // Momotarou Dentetsu Happy/Super Power League 4: romChips = 245
      // Far East of Eden Zero: romChips = 249
    ...
      dumpedBytes = dumpHiROM(0xC0, 0xE0, dumpedBytes);
    ...
      dumpedBytes = dumpHiROM(0xE0, 0xF0, dumpedBytes);
    ...         
      dumpedBytes = dumpHiROM(0xF0, 0x100, dumpedBytes);
    ...
      dumpedBytes = dumpHiROM(0xF0, 0x100, dumpedBytes);
    ...
    }
  }
}

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy