aboutsummaryrefslogtreecommitdiffhomepage
path: root/Cart_Reader/SV.ino
diff options
context:
space:
mode:
authorsanni <[email protected]>2018-10-22 20:29:49 +0200
committersanni <[email protected]>2018-10-22 20:29:49 +0200
commitce4f7aeeeea2a5261a06c0e7c2e5de00ef116cae (patch)
tree529b14b0da8c1100ba44ea0c06d2bd06c8fbbd7e /Cart_Reader/SV.ino
parent7127c7755936bdf9259582748450f398c0b0adc5 (diff)
downloadcartreader-ce4f7aeeeea2a5261a06c0e7c2e5de00ef116cae.tar.gz
cartreader-ce4f7aeeeea2a5261a06c0e7c2e5de00ef116cae.zip
V2.2: Add Satellaview support
Supported carts so far: -BS-X Sorewa Namaewo Nusumareta Machino Monogatari
Diffstat (limited to 'Cart_Reader/SV.ino')
-rw-r--r--Cart_Reader/SV.ino457
1 files changed, 457 insertions, 0 deletions
diff --git a/Cart_Reader/SV.ino b/Cart_Reader/SV.ino
new file mode 100644
index 0000000..423cae4
--- /dev/null
+++ b/Cart_Reader/SV.ino
@@ -0,0 +1,457 @@
+//******************************************
+// SNES Satellaview 8M Memory pack code by tamanegi_taro
+// Revision 1.0.0 October 22nd 2018
+//******************************************
+
+/******************************************
+ Satellaview 8M Memory Pack
+******************************************/
+/******************************************
+ Prototype Declarations
+ *****************************************/
+/* Hoping that sanni will use this progressbar function */
+extern void draw_progressbar(uint32_t processedsize, uint32_t totalsize);
+
+//void svMenu();
+void readROM_SV();
+//void setup_SV();
+void writeROM_SV (void);
+void eraseCheck_SV(void);
+void supplyCheck_SV(void);
+void writeCheck_SV(void);
+void detectCheck_SV(void);
+void eraseAll_SV(void);
+
+/******************************************
+ Variables
+ *****************************************/
+//No global variables
+
+/******************************************
+ Menu
+*****************************************/
+// SV flash menu items
+static const char svFlashMenuItem1[] PROGMEM = "Read Memory Pack";
+static const char svFlashMenuItem2[] PROGMEM = "Write Memory Pack";
+static const char svFlashMenuItem3[] PROGMEM = "Back";
+static const char* const menuOptionsSVFlash[] PROGMEM = {svFlashMenuItem1, svFlashMenuItem2, svFlashMenuItem3};
+
+
+void svMenu() {
+ // create menu with title and 3 options to choose from
+ unsigned char mainMenu;
+ // Copy menuOptions out of progmem
+ convertPgm(menuOptionsSVFlash, 3);
+ mainMenu = question_box("Satellaview 8M Memory", menuOptions, 3, 0);
+
+ // wait for user choice to come back from the question box menu
+ switch (mainMenu)
+ {
+ // Read memory pack
+ case 0:
+ readROM_SV();
+ break;
+
+ // Write memory pack
+ case 1:
+ writeROM_SV();
+ break;
+
+ // Reset
+ case 2:
+ asm volatile (" jmp 0");
+ break;
+ }
+}
+
+// Read memory pack to SD card
+void readROM_SV() {
+ // Set control
+ dataIn();
+ controlIn_SNES();
+
+ // Get name, add extension and convert to char array for sd lib
+ strcpy(fileName, "MEMPACK.sfc");
+
+ // create a new folder for the save file
+ EEPROM_readAnything(10, foldern);
+ sprintf(folder, "SNES/ROM/%s/%d", "MEMPACK", foldern);
+ sd.mkdir(folder, true);
+ sd.chdir(folder);
+
+ //clear the screen
+ display_Clear();
+ print_Msg(F("Saving to "));
+ print_Msg(folder);
+ println_Msg(F("/..."));
+ display_Update();
+
+ // write new folder number back to eeprom
+ foldern = foldern + 1;
+ EEPROM_writeAnything(10, foldern);
+
+ //open file on sd card
+ if (!myFile.open(fileName, O_RDWR | O_CREAT)) {
+ print_Error(F("Can't create file on SD"), true);
+ }
+
+ // Read Banks
+ for (int currBank = 0x40; currBank < 0x50; currBank++) {
+ // Dump the bytes to SD 512B at a time
+ for (long currByte = 0; currByte < 65536; currByte += 512) {
+ draw_progressbar((currBank - 0x40) * 0x10000 + currByte, 0x100000);
+ for (int c = 0; c < 512; c++) {
+ sdBuffer[c] = readBank_SNES(currBank, currByte + c);
+ }
+ myFile.write(sdBuffer, 512);
+ }
+ }
+ draw_progressbar(0x100000, 0x100000); //Finish drawing progress bar
+
+ // Close the file:
+ myFile.close();
+ println_Msg(F("Read pack completed"));
+ display_Update();
+ wait();
+}
+
+
+/******************************************
+ Setup
+ *****************************************/
+void setup_SV() {
+ // Set cicrstPin(PG1) to Output
+ DDRG |= (1 << 1);
+ // Output a high signal until we're ready to start
+ PORTG |= (1 << 1);
+ // Set cichstPin(PG0) to Input
+ DDRG &= ~(1 << 0);
+
+ // Adafruit Clock Generator
+ clockgen.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
+ clockgen.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
+ clockgen.set_pll(SI5351_PLL_FIXED, SI5351_PLLB);
+ clockgen.set_freq(2147727200ULL, SI5351_CLK0);
+ clockgen.set_freq(307200000ULL, SI5351_CLK2);
+ clockgen.output_enable(SI5351_CLK0, 1);
+ clockgen.output_enable(SI5351_CLK1, 0);
+ clockgen.output_enable(SI5351_CLK2, 1);
+
+ // Set Address Pins to Output
+ //A0-A7
+ DDRF = 0xFF;
+ //A8-A15
+ DDRK = 0xFF;
+ //BA0-BA7
+ DDRL = 0xFF;
+ //PA0-PA7
+ DDRA = 0xFF;
+
+ // Set Control Pins to Output RST(PH0) CS(PH3) WR(PH5) RD(PH6)
+ DDRH |= (1 << 0) | (1 << 3) | (1 << 5) | (1 << 6);
+ // Switch RST(PH0) and WR(PH5) to HIGH
+ PORTH |= (1 << 0) | (1 << 5);
+ // Switch CS(PH3) and RD(PH6) to LOW
+ PORTH &= ~((1 << 3) | (1 << 6));
+
+ // Set Refresh(PE5) to Output
+ DDRE |= (1 << 5);
+ // Switch Refresh(PE5) to LOW (needed for SA-1)
+ PORTE &= ~(1 << 5);
+
+ // Set CPU Clock(PH1) to Output
+ DDRH |= (1 << 1);
+ //PORTH &= ~(1 << 1);
+
+ // Set IRQ(PH4) to Input
+ DDRH &= ~(1 << 4);
+ // Activate Internal Pullup Resistors
+ //PORTH |= (1 << 4);
+
+ // Set expand(PG5) to output
+ DDRG |= (1 << 5);
+ // Output High
+ PORTG |= (1 << 5);
+
+ // Set Data Pins (D0-D7) to Input
+ DDRC = 0x00;
+ // Enable Internal Pullups
+ //PORTC = 0xFF;
+
+ // Unused pins
+ // Set wram(PE4) to Output
+ DDRE |= (1 << 4);
+ //PORTE &= ~(1 << 4);
+ // Set pawr(PJ1) to Output
+ DDRJ |= (1 << 1);
+ //PORTJ &= ~(1 << 1);
+ // Set pard(PJ0) to Output
+ DDRJ |= (1 << 0);
+ //PORTJ &= ~(1 << 0);
+
+ // Start CIC by outputting a low signal to cicrstPin(PG1)
+ PORTG &= ~(1 << 1);
+
+ // Wait for CIC reset
+ delay(1000);
+}
+
+
+
+void writeROM_SV (void) {
+ // Get Checksum as string to make sure that BS-X cart is inserted
+ dataIn();
+ controlIn_SNES();
+ sprintf(checksumStr, "%02X%02X", readBank_SNES(0, 65503), readBank_SNES(0, 65502));
+
+ //if CRC is not 8B86, BS-X cart is not inserted. Display error and reset
+ if(strcmp("8B86", checksumStr) != 0)
+ {
+ display_Clear();
+ print_Error(F("Error: Must use BS-X cart"), true);
+ }
+
+ //Display file Browser and wait user to select a file. Size must be 1MB.
+ filePath[0] = '\0';
+ sd.chdir("/");
+ fileBrowser("Select sfc file");
+ // Create filepath
+ sprintf(filePath, "%s/%s", filePath, fileName);
+ display_Clear();
+
+ //open file on sd card
+ if (myFile.open(filePath, O_READ)) {
+
+ fileSize = myFile.fileSize();
+ if (fileSize != 0x100000) {
+ println_Msg(F("File must be 1MB"));
+ display_Update();
+ myFile.close();
+ wait();
+ return;
+ }
+
+ //Disable 8M memory pack write protection
+ dataOut();
+ controlOut_SNES();
+ writeBank_SNES(0x0C, 0x5000, 0x80); //Modify write enable register
+ writeBank_SNES(0x0E, 0x5000, 0x80); //Commit register modification
+
+ //Erase memory pack
+ println_Msg(F("Erasing pack..."));
+ display_Update();
+ eraseAll_SV();
+
+ //Blank check
+ //Set pins to input
+ dataIn();
+ controlIn_SNES();
+ println_Msg(F("Blank check..."));
+ display_Update();
+ for (int currBank = 0xC0; currBank < 0xD0; currBank++) {
+ draw_progressbar(((currBank - 0xC0) * 0x10000), 0x100000);
+ for (long currByte = 0; currByte < 65536; currByte++) {
+ if(0xFF != readBank_SNES(currBank, currByte))
+ {
+ println_Msg(F(""));
+ println_Msg(F("Erase failed"));
+ display_Update();
+ myFile.close();
+ wait();
+ return;
+ }
+ }
+ }
+ draw_progressbar(0x100000, 0x100000);
+
+ //Write memory pack
+ dataOut();
+ controlOut_SNES();
+ println_Msg(F("Writing pack..."));
+ display_Update();
+ for (int currBank = 0xC0; currBank < 0xD0; currBank++) {
+ draw_progressbar(((currBank - 0xC0) * 0x10000), 0x100000);
+ for (long currByte = 0; currByte < 65536; currByte++) {
+
+ writeBank_SNES(0xC0, 0x0000, 0x10); //Program Byte
+ writeBank_SNES(currBank, currByte, myFile.read());
+ writeBank_SNES(0xC0, 0x0000, 0x70); //Status Mode
+ writeCheck_SV();
+ }
+ }
+
+ writeBank_SNES(0xC0, 0x0000, 0x70); //Status Mode
+ writeCheck_SV();
+ writeBank_SNES(0xC0, 0x0000, 0xFF); //Terminate write
+ draw_progressbar(0x100000, 0x100000);
+
+
+ //Verify
+ dataIn(); //Set pins to input
+ controlIn_SNES();
+ myFile.seekSet(0); // Go back to file beginning
+ println_Msg(F("Verifying..."));
+ display_Update();
+ for (int currBank = 0xC0; currBank < 0xD0; currBank++) {
+ draw_progressbar(((currBank - 0xC0) * 0x10000), 0x100000);
+ for (long currByte = 0; currByte < 65536; currByte++) {
+ if(myFile.read() != readBank_SNES(currBank, currByte))
+ {
+ println_Msg(F(""));
+ println_Msg(F("Verify failed"));
+ display_Update();
+ myFile.close();
+ wait();
+ return;
+ }
+ }
+ }
+
+ // Close the file:
+ myFile.close();
+ draw_progressbar(0x100000, 0x100000);
+ println_Msg(F("Finished successfully"));
+ display_Update();
+ wait();
+
+ }
+ else {
+ print_Error(F("File doesn't exist"), false);
+ }
+}
+
+void eraseCheck_SV(void) {
+ byte ret;
+ dataIn();
+ controlIn_SNES();
+
+ // Read register
+ ret = readBank_SNES(0xC0, 0x0004);
+
+ // CE or OE must be toggled with each subsequent status read or the
+ // completion of a program or erase operation will not be evident.
+ while ((ret & 0x80) == 0x00) { //Wait until X.bit7 = 1
+ controlOut_SNES();
+ // Switch CS(PH3) High
+ PORTH |= (1 << 3);
+ // Leave CE high for at least 60ns
+ __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
+ controlIn_SNES();
+ // Leave CE low for at least 50ns
+ __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
+ // Read register
+ ret = readBank_SNES(0xC0, 0x0004);
+ }
+ // Switch to write
+ dataOut();
+ controlOut_SNES();
+}
+
+void supplyCheck_SV(void) {
+ byte ret;
+ dataIn();
+ controlIn_SNES();
+
+ // Read register
+ ret = readBank_SNES(0xC0, 0x0004);
+
+ // CE or OE must be toggled with each subsequent status read or the
+ // completion of a program or erase operation will not be evident.
+ while ((ret & 0x08) == 0x08) { //Wait until X.bit3 = 0
+ controlOut_SNES();
+ // Switch CS(PH3) High
+ PORTH |= (1 << 3);
+ // Leave CE high for at least 60ns
+ __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
+ controlIn_SNES();
+ // Leave CE low for at least 50ns
+ __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
+ // Read register
+ ret = readBank_SNES(0xC0, 0x0004);
+ }
+ // Switch to write
+ dataOut();
+ controlOut_SNES();
+}
+
+void writeCheck_SV(void) {
+ byte ret;
+ dataIn();
+ controlIn_SNES();
+
+ // Read register
+ ret = readBank_SNES(0xC0, 0x0000);
+
+ // CE or OE must be toggled with each subsequent status read or the
+ // completion of a program or erase operation will not be evident.
+ while ((ret & 0x80) == 0x00) {
+ controlOut_SNES();
+ // Switch CS(PH3) High
+ PORTH |= (1 << 3);
+ // Leave CE high for at least 60ns
+ __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
+ controlIn_SNES();
+ // Leave CE low for at least 50ns
+ __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
+ // Read register
+ ret = readBank_SNES(0xC0, 0x0000);
+ }
+ // Switch to write
+ dataOut();
+ controlOut_SNES();
+}
+
+
+void detectCheck_SV(void) {
+ int i = 0;
+ byte ret;
+ dataIn();
+ controlIn_SNES();
+
+ // Read register
+ ret = readBank_SNES(0xC0, 0x0002);
+
+ // CE or OE must be toggled with each subsequent status read or the
+ // completion of a program or erase operation will not be evident.
+ while ((ret & 0x80) == 0x00) {
+ i++;
+ if( i > 10000)
+ {
+ //timeout
+ break;
+ }
+ controlOut_SNES();
+ // Switch CS(PH3) High
+ PORTH |= (1 << 3);
+ // Leave CE high for at least 60ns
+ __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
+ controlIn_SNES();
+ // Leave CE low for at least 50ns
+ __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
+ // Read register
+ ret = readBank_SNES(0xC0, 0x0002);
+ }
+ // Switch to write
+ dataOut();
+ controlOut_SNES();
+}
+
+
+void eraseAll_SV(void)
+{
+ dataOut();
+ controlOut_SNES();
+ writeBank_SNES(0xC0, 0x0000, 0x50); //Clear Status Registers
+ writeBank_SNES(0xC0, 0x0000, 0x71); //Status Mode
+ supplyCheck_SV();
+ writeBank_SNES(0xC0, 0x0000, 0xA7); //Chip Erase
+ writeBank_SNES(0xC0, 0x0000, 0xD0); //Confirm
+ writeBank_SNES(0xC0, 0x0000, 0x71); //Status Mode
+ eraseCheck_SV();
+ writeBank_SNES(0xC0, 0x0000, 0xFF); //Teriminate
+}
+
+//******************************************
+// End of File
+//******************************************
+