Go Down

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

skaman

I forgot one last addition to sanni's code in dumpROM().  The original code is missing the dumpedBytes++ at the end of the Star Ocean section:

Code: [Select]
       // Dump the bytes to SD one by one
        for (long currByte = 0; currByte < 65536; currByte++) {
          do {
            currDumpedByte = dumpByte(currBank, currByte, false);
            if (verifySORead)
              currDumpedByteVerify = dumpByte(currBank, currByte, false);
            else
              currDumpedByteVerify = currDumpedByte;
          }
          while (currDumpedByte != currDumpedByteVerify);
          myFile.write(currDumpedByte);
          dumpedBytes++;
        }


Fixed a bug in getCartInfo() where a checksum byte with upper nibble of 0 has the zero dropped.  This resulted in erroneous checksum error messages.

Code: [Select]
  // Get Checksum as string
  sprintf(checksumStr, "%02X%02X", dumpByte(0, 65503, false), dumpByte(0, 65502, false));

skaman

Added code to dumpROM() for CX4 carts.  Actually only really needed for Mega Man/Rockman X2.

Code: [Select]
  if ((romChips != 67)&&(romChips != 69)&&(romChips != 243)) {
...

  else if(romChips == 243){
  // CX4 - Mega Man X2/Mega Man X3/Rockman X2/Rockman X3: romChips = 243
    display.println("Dumping LoROM");
    display.print("Banks: ");
    display.println(numBanks);
    display.display();

    // Check initial content of mapping register...
    // Mega Man/Rockman X2 should return 1, Mega Man/Rockman X3 should return 0
    byte initialCX4Map = dumpByte(0, 32594, false); //0x7F52
     
    // Mega Man/Rockman X2 needs to be set to 0 before dumping
    setByte(0, 32594, 0);  //0x7F52

      // Read up to 96 banks starting at bank 0×00.
    for (int currBank = 0; currBank < numBanks; currBank++) {

      // give status updates via LCD or LED
      display.print(".");
      display.display();

      // blink led
      if (currBank % 2 != 0)
        rgbLed(off_color);
      else
        rgbLed(busy_color);

      // Dump the bytes to SD one by one
      for (long currByte = 32768; currByte < 65536; currByte++) {
        myFile.write(dumpByte(currBank, currByte, false));
        dumpedBytes++;
      }
    }
    // Return mapping register to initial setting...
    setByte(0, 32594, initialCX4Map);  //0x7F52
  }


credits to byuu (and waterbury) for the CX4 info

skaman

Success!  I managed to enable reliable SPC7110 dumping (FEOEZ).  The dumping code runs all-inclusive (no switching back and forth) and works 100% of the time.   It requires a hardware addition and some changes to the code.

For the hardware addition, you need to add a 21.477272MHz clock signal to Pin 1.  I used the Adafruit Clock Generator module with the Si5351 chip (https://learn.adafruit.com/adafruit-si5351-clock-generator-breakout/overview) to generate the clock signal.  I wired the module up to the I2C with output to Pin 1 of the cart.  Adafruit has a library for the module but I used the Si5351Arduino library (https://github.com/etherkit/Si5351Arduino).

For the code, one big change and a bunch of small changes need to be made.  The big change is that you cannot use setByte() to set the SPC7110 registers - the timing is off.  The slower byte setting routine needs to be added.  sanni's setSRAMByte() code works to set the registers.  The small changes that need to be added are the SPC7110 register settings to fully unlock and dump the cart.  Most of the register changes are outlined in tylau0's code but there are a couple other settings that (may) need to be changed.

I'll clean up my code and post it sometime.

credits to caitsith2 for the SPC7110 unlocking details

MichlK

Success!  I managed to enable reliable SPC7110 dumping (FEOEZ).  The dumping code runs all-inclusive (no switching back and forth) and works 100% of the time.   It requires a hardware addition and some changes to the code.
Never thought that this would be possible with an Arduino... :o Congratz & thanks for sharing!

Best regards
Michael
PS: Back in September last year, I ordered such a clock generator module myself - pretty handy stuff... :)

skaman

Thanks to you, Michael, for getting this started.  Time to add the clock generator to your reader setup!

In the process of trying to add SRAM read/write for FEOEZ, I came across a post by byuu that states that the SPC7110 unlock sequence is unnecessary.  I removed the unlock sequence from my code and the FEOEZ cart still dumps!  The key element is the Clock to Pin 1.  Without the clock, the register changes don't work.

I'll post the code once I figure out why my FEOEZ SRAM dumps are weird.  Anyone got a FEOEZ .srm file they care to share?  If not, I'll have to sit down and actually play this game for awhile.

EDIT:  Nevermind on the savefile.  I figured out why my SRAM dumps were bad - dying battery!  Pulled the old battery and put in a new battery + holder.  FEOEZ SRAM dumping works (well it actually always did just couldn't tell).  Going to add SRAM writes and then look at adding the RTC stuff.

skaman

Here's a logo for the LCD that I use during bootup:

Code: [Select]
//Nintendo Logo 104x16
static const unsigned char PROGMEM nintylogo [] = {
0xF0, 0x3C, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0xF0, 0x3C, 0xF0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x42, 0xFC, 0x3C, 0xF0, 0x00, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0xB9, 0xFC, 0x3C, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00,
0x03, 0xC0, 0x00, 0xA5, 0xFC, 0x3C, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00,
0xB9, 0xFC, 0x3C, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0xA5, 0xF3, 0x3C,
0xF3, 0xCF, 0x0F, 0x0F, 0xF0, 0xF3, 0xC0, 0xFF, 0xC3, 0xFC, 0x42, 0xF3, 0x3C, 0xF3, 0xCF, 0x0F,
0x0F, 0xF0, 0xF3, 0xC0, 0xFF, 0xC3, 0xFC, 0x3C, 0xF3, 0x3C, 0xF3, 0xF3, 0xCF, 0x3C, 0x3C, 0xFC,
0xF3, 0xC3, 0xCF, 0x0F, 0x00, 0xF3, 0x3C, 0xF3, 0xF3, 0xCF, 0x3C, 0x3C, 0xFC, 0xF3, 0xC3, 0xCF,
0x0F, 0x00, 0xF0, 0xFC, 0xF3, 0xC3, 0xCF, 0x3F, 0xFC, 0xF0, 0xF3, 0xC3, 0xCF, 0x0F, 0x00, 0xF0,
0xFC, 0xF3, 0xC3, 0xCF, 0x3F, 0xFC, 0xF0, 0xF3, 0xC3, 0xCF, 0x0F, 0x00, 0xF0, 0xFC, 0xF3, 0xC3,
0xCF, 0x3C, 0x00, 0xF0, 0xF3, 0xC3, 0xCF, 0x0F, 0x00, 0xF0, 0xFC, 0xF3, 0xC3, 0xCF, 0x3C, 0x00,
0xF0, 0xF3, 0xC3, 0xCF, 0x0F, 0x00, 0xF0, 0x3C, 0xF3, 0xC3, 0xCF, 0x0F, 0xFC, 0xF0, 0xF0, 0xFF,
0xC3, 0xFC, 0x00, 0xF0, 0x3C, 0xF3, 0xC3, 0xCF, 0x0F, 0xFC, 0xF0, 0xF0, 0xFF, 0xC3, 0xFC, 0x00
};

void setup() {
...
  display.clearDisplay();
  display.drawBitmap(12, 24, nintylogo, 104, 16, 1);
  display.display();
  delay(1000);
...
}

skaman

Here's the Adafruit Clock Generator code:

Code: [Select]
//**********************************************************************************

// Adafruit Clock Generator
#include <si5351.h>

Si5351 clockgen;

//**********************************************************************************

void setup() {
...
  // Adafruit Clock Generator
  clockgen.init(SI5351_CRYSTAL_LOAD_8PF, 0);
  clockgen.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
  // Setup Clock Generator to 21.477272MHz
  clockgen.set_freq(2147727200ULL, SI5351_PLL_FIXED, SI5351_CLK0);
  clockgen.output_enable(SI5351_CLK0, 1);
  clockgen.output_enable(SI5351_CLK1, 0);
  clockgen.output_enable(SI5351_CLK2, 0);
...
}


Wire the Clock Generator to the I2C (along with power and ground) then connect CLK0 to Pin 1 on the cart.  If you're using only the center 46 pins then you'll need to add a connection to Pin 1.  I couldn't source a matching 8 pin (2x4) connector to add next to my 46 pin connector so I cut up a spare connector and added it to my sanni clone.

Edit:  If you're not using a version of sanni's code with the LCD, then you need to also add the I2C code (Wire.h):

Code: [Select]

// Adafruit Clock Generator
#include <Wire.h>
#include <si5351.h>

Si5351 clockgen;

sanni

Nice work yet again, this is getting better and better :)

skaman

Here's the code changes to dump SPC7110 carts. 

I added SPC7110Check() to check the status of SPC7110 registers 0x4831-0x4834 which are the bank control registers.  setDataOut() and setDataIn() were added to wrap around the calls to setSRAMByte() when setting the SPC7110 registers. 

Code: [Select]

void SPC7110Check(){
    // Check content of mapping registers...
    // Initial values of 0x4831-0x4834 should be set to {0, 1, 2, 0}
    byte SPC7110Reg1 = dumpByte(0, 18481, false); //0x4831
    byte SPC7110Reg2 = dumpByte(0, 18482, false); //0x4832
    byte SPC7110Reg3 = dumpByte(0, 18483, false); //0x4833
    byte SPC7110Reg4 = dumpByte(0, 18484, false); //0x4834
    display.println("Register Settings:");
    display.print("0x4831: ");
    display.print(SPC7110Reg1);
    display.print(",");
    display.print(SPC7110Reg2);
    display.print(",");
    display.print(SPC7110Reg3);
    display.print(",");
    display.println(SPC7110Reg4);
    display.display();
}

void setDataOut(){
  pinMode(d0Pin, OUTPUT);
  pinMode(d1Pin, OUTPUT);
  pinMode(d2Pin, OUTPUT);
  pinMode(d3Pin, OUTPUT);
  pinMode(d4Pin, OUTPUT);
  pinMode(d5Pin, OUTPUT);
  pinMode(d6Pin, OUTPUT);
  pinMode(d7Pin, OUTPUT);
}

void setDataIn(){
  pinMode(d0Pin, INPUT);
  pinMode(d1Pin, INPUT);
  pinMode(d2Pin, INPUT);
  pinMode(d3Pin, INPUT);
  pinMode(d4Pin, INPUT);
  pinMode(d5Pin, INPUT);
  pinMode(d6Pin, INPUT);
  pinMode(d7Pin, INPUT);
 
  // Activate pull-up resistors for input-pins
  writeByteD(255);
  delay(400);
}


I changed romSizeExp in getCartInfo() since we use it to identify the different SPC7110 carts. 

Code: [Select]

void getCartInfo() {
...
  // Check RomSize
  romSizeExp = dumpByte(0, 65495, false); // 0xFFD7
  byte romSizeCalc = romSizeExp - 7;
  romSize = 1;
  while (romSizeCalc--)
    romSize *= 2;
  numBanks = (long(romSize) * 1024 * 1024 / 8) / (32768 + (long(romType) * 32768));
...
}


The dumpROM() routine adds new code to handle carts with romChips 245 and 249.  We'll have to ignore the other non-SPC7110 romChips 245 cart (Hayazashi Nidan Morita Shougi 2) for right now.

Code: [Select]

void dumpROM() {
...
  else if((romChips == 245)||(romChips == 249)){
    // SPC7110
    // Momotarou Dentetsu Happy/Super Power League 4: romChips = 245
    // Far East of Eden Zero: romChips = 249

    // Super Power League 4: 0x0B 
    // Momotarou Dentetsu Happy: 0x0C   
    // Tengai Far East of Eden Zero: 0x0D
    if (romSizeExp == 0x0B){
      romSize = 16;
      numBanks = 32;
    }
    else if(romSizeExp == 0x0C){
      romSize = 24;
      numBanks = 48;
    }
    else if(romSizeExp == 0x0D){
      romSize = 40;
      numBanks = 80;  //HiROM banks
    }
 
    display.println("Dumping HiROM");
    display.print("Banks: ");
    display.println(numBanks);
    display.display();

    display.clearDisplay();
    display.setCursor(0, 0);
    display.display();
    SPC7110Check();

// 0xC00000-0xDFFFFF
    display.println("Dumping 0xC0-DF");
    display.display();
    for(int currBank=192; currBank < 224; currBank++) {
      display.print(".");
      display.display();

      // blink led
      if (currBank % 2 != 0)
        rgbLed(off_color);
      else
        rgbLed(busy_color);
  for(long currByte=0; currByte < 65536; currByte++) {
      myFile.write(dumpByte(currBank, currByte, false));
      dumpedBytes++;
  }
    }

    if(numBanks > 32){
      display.clearDisplay();
      display.setCursor(0, 0);
      display.println("Unlocking SPC7110");
      display.display();
     
      setDataOut();
      // Set 0x4834 to 0xFF
      setSRAMByte(0, 18484, 255, false);
      setDataIn();
      SPC7110Check();

// 0xE00000-0xEFFFFF
      display.println("Dumping 0xE0-EF");
      display.display();
      for(int currBank=224; currBank < 240; currBank++) {
        display.print(".");
        display.display();
     
        // blink led
        if (currBank % 2 != 0)
          rgbLed(off_color);
        else
          rgbLed(busy_color);
    for(long currByte=0; currByte < 65536; currByte++) {
        myFile.write(dumpByte(currBank, currByte, false));
        dumpedBytes++;
    }
      }
         
      if(numBanks > 48){
// 0xF00000-0xFFFFFF
        display.println("");
        display.println("Dumping 0xF0-FF");
        display.display();
        for(int currBank=240; currBank < 256; currBank++) {
          display.print(".");
          display.display();
       
          // blink led
          if (currBank % 2 != 0)
            rgbLed(off_color);
          else
            rgbLed(busy_color);
      for(long currByte=0; currByte < 65536; currByte++) {
          myFile.write(dumpByte(currBank, currByte, false));
          dumpedBytes++;
      }
        }

        display.clearDisplay();
        display.setCursor(0, 0);
        display.display();
        display.println("Remapping Final Bank");
        display.display();
       
        setDataOut();
        // Set 0x4833 to 3
        setSRAMByte(0, 18483, 3, false);
        setDataIn();
        SPC7110Check();

// 0xF00000-0xFFFFFF
        display.println("Dumping 0xF0-FF");
        display.display();
        for(int currBank=240; currBank < 256; currBank++) {
          display.print(".");
          display.display();
       
          // blink led
          if (currBank % 2 != 0)
            rgbLed(off_color);
          else
            rgbLed(busy_color);
          for(long currByte=0; currByte < 65536; currByte++) {
          myFile.write(dumpByte(currBank, currByte, false));
          dumpedBytes++;
          }
        }
      }     
      // Return mapping registers to initial settings...
      setDataOut();
      setSRAMByte(0, 18483, 2, false); //0x4833: 0x2
      setSRAMByte(0, 18484, 0, false); //0x4834: 0x0
      setDataIn();
     }
  }
...
}


The code is tested with FEOEZ but I hope to test with the other SPC7110 carts (MDH and SPL4) soon.

The dumping process should show changes to the registers as they're set.  For FEOEZ, the 0x4831-0x4834 registers should go from {0,1,2,0} to {0,1,2,7} to {0,1,3,7} during the dumping process.  If the registers never change from {0,1,2,0}, then the clock signal is most likely not getting to Pin 1.

I'll post the Read/Write SRAM code next.  The RTC read code is working (I think).  I have to read the RTC documents to see how to interpret the data.

skaman

Adafruit Clock Generator added to the sanni board.



skaman

Here's the SPC7110 Read/Write SRAM.  First, I made a change to romType in getCartInfo() to classify SDD1 and SPC7110 carts as HiROM.  I found it easier to handle the changes to read/write SRAM that way.  I should also get around to modify dumpROM() to reflect the romType change but since the existing code works, I'll wait to clean it up later.

Code: [Select]

void getCartInfo() {
...
  // Check if LoROM or HiROM
  romType = dumpByte(0, 65493, false); // 0xFFD5
  if ((romType == 0x32)||(romType == 0x3A)) // SDD1/SPC7110
    romType = 1;  //HiROM
  else
    romType = romType & 1; // 0xFFD5
...
}


Code was added to readSRAM() to enable the SRAM using register 0x4830.  The modifications to readSRAM() are in the Dump HiRom SRAM section:

Code: [Select]

void readSRAM (char* fileName, char* folder) {
...
  // Dump HiRom SRAM
  else if (romType == 1) {
    // SPC7110 SRAM
    if ((romChips == 245)||(romChips == 249)) {
      // Configure SPC7110 SRAM Register
      setDataOut();
      // Set 0x4830 to 0x80
      setSRAMByte(0, 18480, 128, false);
      setDataIn();

      dumpByte(48, 24576, false); // Preconfigure to fix the corrupt 1st byte
      // Sram size
      long lastByte = (long(sramSize) * 128) + 24576;
      display.println("HiROM SRAM");
      display.print("SRAM Size: ");
      display.println(lastByte);
    display.display();
      for (long currByte = 24576; currByte < lastByte; currByte++) { //startAddr = 0x6000
        myFile.write(dumpByte(48, currByte, false)); //startBank = 0x30
      }
      setDataOut();
      // Reset 0x4830 to 0x0
      setSRAMByte(0, 18480, 0, false);
      setDataIn();
    }
    else {
      dumpByte(48, 24576, true); // Preconfigure to fix the corrupt 1st byte
      // Sram size
      long lastByte = (long(sramSize) * 128) + 24576;
      display.println("HiROM SRAM");
      display.print("SRAM Size: ");
      display.println(lastByte);
    display.display();
      for (long currByte = 24576; currByte < lastByte; currByte++) { //startAddr = 0x6000
        myFile.write(dumpByte(48, currByte, true)); //startBank = 0x30; CS high
      }
    }
  }


I made similar changes to writeSRAM() also in the HiRom section:

Code: [Select]

void writeSRAM () {
...

// HiRom
      else if (sramSize != 0 && romType == 1) {
        // SPC7110 SRAM
        if ((romChips == 245)||(romChips == 249)) {
          // Configure SPC7110 SRAM Register
          // Set 0x4830 to 0x80
          setSRAMByte(0, 18480, 128, false);
         
          long lastByte = (long(sramSize) * 128) + 24576;
         
          display.print(sramSize / 8);
          display.println("Kb HiROM");
          display.println("Writing SRAM...");
          display.display();
         
          // Write to sram bank
          for (long currByte = 24576; currByte < lastByte; currByte++) { //startAddr = 0x6000
            setSRAMByte(48, currByte, myFile.read(), false); //startBank = 0x30
            // blink led
            if (currByte % 100 != 0)
              rgbLed(busy_color);
            else
              rgbLed(off_color);
            // Print Progess to LCD
            progress = currByte * 100 / lastByte;
            if ((progress - lastprogress) > 9) {
              display.print(".");
              display.display();
              lastprogress = progress;
            }
          }
          // Reset SPC7110 SRAM Register
          setDataOut();
          // Reset 0x4830 to 0x0
          setSRAMByte(0, 18480, 0, false);
          setDataIn();
        }
        else {
          long lastByte = (long(sramSize) * 128) + 24576;

          display.print(sramSize / 8);
          display.println("Kb HiROM");
          display.println("Writing SRAM...");
          display.display();
         
          // Write to sram bank
          for (long currByte = 24576; currByte < lastByte; currByte++) { //startAddr = 0x6000
            setSRAMByte(48, currByte, myFile.read(), true); //startBank = 0x30; CS high
            // blink led
              if (currByte % 100 != 0)
                rgbLed(busy_color);
              else
                rgbLed(off_color);
            // Print Progess to LCD
            progress = currByte * 100 / lastByte;
            if ((progress - lastprogress) > 9) {
              display.print(".");
              display.display();
              lastprogress = progress;
            }
          }
        }
      }
...
}


Coming up next:  the FEOEZ RTC reading code.  I've only done the read RTC code so far.  I'm not sure if the write RTC code is really necessary.

skaman

Here's the FEOEZ RTC Read code.  I currently have the call to the RTC code at the end of printinfoGLCD().  The normal cart info is displayed then it checks to see if the cart is FEOEZ.  If the cart is FEOEZ, then it waits for a button press to clear the screen and read the RTC.

Code: [Select]

void printinfoGLCD() {
...
  if(romChips == 249) {
    wait();
    readRTC();
  }
}


I added two routines - showRTC() and readRTC().  readRTC() sets the SPC7110 registers to read the RTC and outputs the data to a file - rtc.ram.  showRTC() opens the rtc.ram file, interprets the data, and displays the date, time, and weekday on screen.

Code: [Select]

void showRTC() {
int   rtc_data[16];
int seconds;
int minutes;
int hours;
int day;
int month;
int year;

int   w;
char *weekday[7] =
        {
           "Sunday",
           "Monday",
           "Tuesday",
           "Wednesday",
           "Thursday",
           "Friday",
           "Saturday"
        };
  //open file on sd card
    if (!myFile.open("rtc.ram", O_RDWR | O_CREAT)) {
    rgbLed(error_color);
    display.println("SD ERROR");
    display.display();
    while (1);
  }

  for(int r = 0; r < 16; r++)
    rtc_data[r] = myFile.read();

  seconds = ((rtc_data[1] & 7)*10) + rtc_data[0];
minutes = ((rtc_data[3] & 7)*10) + rtc_data[2];
hours = ((rtc_data[5] & 3)*10) + rtc_data[4];
year =  rtc_data[11]*10 + rtc_data[10];
year += ( 1900 );
month = ((rtc_data[9] & 1)*10) + rtc_data[8];
day = ((rtc_data[7] & 3)*10) + rtc_data[6];

  display.print("DATE:  ");
  display.print(month);
  display.print("/");
  display.print(day);
  display.print("/");
  display.println(year);
  display.print("TIME:  ");
  display.print(hours);
  display.print(":");
  display.print(minutes);
  display.print(":");
  display.print(seconds);

  if((rtc_data[15] & 4) == 0) { //Check 12/24: 1 = 24H, 0 = 12H
  if((rtc_data[5] & 4) == 4) //If 12H, check PM/AM: 1 = PM, 0 = AM
    display.println(" PM");
  else display.println(" AM");
}
else display.println("");
w = (rtc_data[12] & 7);
  display.print("DAY:   ");
  display.println(weekday[w]);
  display.display();

  // Close the file:
  myFile.close();
}

void readRTC() {
  // Read FEOEZ RTC-4513 Chip

  //open file on sd card
    if (!myFile.open("rtc.ram", O_RDWR | O_CREAT)) {
    rgbLed(error_color);
    display.println("SD ERROR");
    display.display();
    while (1);
  }
  display.clearDisplay();
  display.setCursor(0, 0);

  // Signal beginning of dumping process
  display.println("Reading RTC Chip...");
  display.display();
 
setDataOut();
  // Enable RTC Chip:  0x4840: 0x1
  setSRAMByte(0, 18496, 1, false); //0x4840
  // Set RTC Chip to Read Mode:  0x4841: 0xC
  setSRAMByte(0, 18497, 0xC, false); //0x4841
  // Set RTC to Data Byte 0
  setSRAMByte(0, 18497, 0, false); //0x4841
setDataIn();

  for(int r = 0; r < 16; r++) {   
    // Check RTC Status:  0x4842
    dumpByte(0, 18498, false); //0x4842
    myFile.write(dumpByte(0, 18497, false)); //0x4841
  }
  // Disable RTC Chip:  0x4840: 0x0
  setDataOut();
  setByte(0, 18496, 0);
  setDataIn();

  // Close the file:
  myFile.close();

  showRTC();

  // Signal end of process
  rgbLed(success_color);
  display.println("Saved as rtc.ram");
  display.display();
}

skaman

Ran into an interesting problem while reading a new cart with my sanni clone.  I normally connect the reader thru a USB hub and have not had any problems reading/writing carts. 

I recently picked up a copy of F1 ROC II (Exhaust Heat) which is a Seta DSP (ST-010 chip) cart.  When I first connected the new cart to the reader, the reader could not detect the cart.  I modified the code to force dump all of the banks and they were all FFs.  I moved the reader to a different PC to run more extensive tests and found it dumped 100% with the original code.  The only difference was the direct USB connection vs the USB hub.  I moved the reader back to the original PC and bypassed the USB hub and it worked.

I should be getting the other Seta DSP/RISC carts (ST-011/ST-018) so I'll test those out.  If anyone has a cart that doesn't detect properly (or dumps all FFs), make sure your reader is connected directly to USB (no hub).

skaman

Found a small checksum error bug in the compare_checksum(). Similar to the earlier checksum error bug in getCartInfo().  Need to make sure we compare 4 characters.  The original sprintf code used "%X" which drops leading 0s resulting in an error.

Code: [Select]

void compare_checksum() {
...
  char calcsumStr[5];
  sprintf(calcsumStr, "%04X", calc_checksum(fileName, folder));
...
}


I discovered the bug dumping Super Power League 4 because it has checksum 0x01AA.  I can now confirm that my SPC7110 code changes work with all 3 carts - FEOEZ, MDH, and SPL4. 

The checksum verification code need to be tweaked for MDH - the checksum should be checksum*2.  EDIT:  Here's the calc_checksum code addition:

Code: [Select]

unsigned int calc_checksum (char* fileName, char* folder) {
...
    else if (calcFilesize == 24 || calcFilesize == 28) {
      // Momotarou Dentestu Happy Fix 3MB (24Mbit)
      if ((calcFilesize == 24) && (romSizeExp = 0x0C)) {
       for (unsigned long i = 0; i < myFile.fileSize(); i++) {
          calcChecksum += myFile.read();
       }
       calcChecksum = 2 * calcChecksum;
      }
      else {
        for (unsigned long i = 0; i < (calcFilesize / 16); i++ ) {
          // Add all the bits in the 16Mbit chunks
          for (unsigned long j = 0; j < 2097152; j++) {
            calcChecksum += myFile.read();
          }
          // Add all the chunks together
          calcChecksum +=  calcChecksumChunk;
          calcChecksumChunk = 0;
        }
        // Add the 8Mbit rest
        for (unsigned long j = 0; j < 1048576; j++) {
          calcChecksumChunk += myFile.read();
        }
        calcChecksum +=  2 * calcChecksumChunk;
      }
    }
...
}

skaman

There is a modification to the SPC7110 dumpROM() code that I posted earlier.  The change is needed to handle Hayazashi Nidan Morita Shougi 2 which is the only Seta ST018 cart.  Since the cart uses romChips = 245 (0xF5), we need to separate it from two of the SPC7110 games - Momotarou Dentestu Happy (MDH) and Super Power League 4 (SPL4).  Since MDH and SPL4 are HiROMs and Hayazashi 2 is LoROM, I added a romType check to the SPC7110 section of dumpROM().

Code: [Select]

void dumpROM () {
...
  else if((romChips == 245)||(romChips == 249)){
    if (romType == 0) {
      // ST018
      // Hayazashi Nidan Morita Shougi 2: romChips = 245
      <add LoROM dumping routines>
    ...
    }
    else if (romType == 1) {
      // SPC7110
      // Momotarou Dentetsu Happy/Super Power League 4: romChips = 245
      // Far East of Eden Zero: romChips = 249
      <see SPC7110 code posted above>  
     ...
    }
  }
}


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.  

There is currently a lot of duplication of routines in dumpROM() that needs to be cleaned up.  I'll work on streamlining the code and post the complete code after I wrap up my testing of enhanced carts.

Next up, I'll be testing the ExHiROM cart Tales of Phantasia once it arrives.

Go Up