From 9eca87d9750e4071f82ff5f460dde7908e3a687d Mon Sep 17 00:00:00 2001 From: sanni Date: Wed, 28 Oct 2020 18:44:13 +0100 Subject: [PATCH] V5.5: Reduce memory usage in Filebrowser --- Cart_Reader/Cart_Reader.ino | 28 +- Cart_Reader/GBA.ino | 17 +- Cart_Reader/GBM.ino | 886 ++++++++++++++++++++++++++++++++++++ Cart_Reader/GBSmart.ino | 7 +- Cart_Reader/MD.ino | 4 +- Cart_Reader/NP.ino | 885 +---------------------------------- Cart_Reader/PCE.ino | 14 +- Cart_Reader/README.md | 1 + Cart_Reader/options.h | 19 +- 9 files changed, 935 insertions(+), 926 deletions(-) create mode 100644 Cart_Reader/GBM.ino diff --git a/Cart_Reader/Cart_Reader.ino b/Cart_Reader/Cart_Reader.ino index 9b9a460..8de7c1e 100644 --- a/Cart_Reader/Cart_Reader.ino +++ b/Cart_Reader/Cart_Reader.ino @@ -1,16 +1,17 @@ /********************************************************************************** Cartridge Reader for Arduino Mega2560 - Author: sanni - Date: 06.07.2020 - Version: 5.4 + Date: 28.10.2020 + Version: 5.5 - SD lib: https://github.com/greiman/SdFat - LCD lib: https://github.com/adafruit/Adafruit_SSD1306 - Clockgen: https://github.com/etherkit/Si5351Arduino - RGB Tools lib: https://github.com/joushx/Arduino-RGB-Tools + SD lib: https://github.com/greiman/SdFat + LCD lib: https://github.com/adafruit/Adafruit_SSD1306 + GFX Lib: https://github.com/adafruit/Adafruit-GFX-Library + BusIO: https://github.com/adafruit/Adafruit_BusIO + RGB Tools lib: https://github.com/joushx/Arduino-RGB-Tools + SI5351 lib: https://github.com/etherkit/Si5351Arduino - Compiled with Arduino 1.8.12 + Compiled with Arduino 1.8.13 Thanks to: MichlK - ROM-Reader for Super Nintendo @@ -42,7 +43,7 @@ **********************************************************************************/ #include -char ver[5] = "5.4"; +char ver[5] = "5.5"; #include "options.h" @@ -192,7 +193,7 @@ boolean ignoreError = 0; // File browser #define FILENAME_LENGTH 32 #define FILEPATH_LENGTH 64 -#define FILEOPTS_LENGTH 20 +#define FILEOPTS_LENGTH 18 char fileName[FILENAME_LENGTH]; char filePath[FILEPATH_LENGTH]; @@ -201,7 +202,6 @@ byte lastPage; byte numPages; boolean root = 0; boolean filebrowse = 0; -char fileOptions[30][FILEOPTS_LENGTH]; // Common char romName[17]; @@ -1390,16 +1390,12 @@ browserstart: else if (myFile.isDir()) { // Copy full dirname into fileNames snprintf(fileNames[currFile], FILENAME_LENGTH, "%s%s", "/", nameStr); - // Copy short string into fileOptions - snprintf(fileOptions[currFile], FILEOPTS_LENGTH, "%s%s", "/", nameStr); currFile++; } // It's just a file else if (myFile.isFile()) { // Copy full filename into fileNames snprintf(fileNames[currFile], FILENAME_LENGTH, "%s", nameStr); - // Copy short string into fileOptions - snprintf(fileOptions[currFile], FILEOPTS_LENGTH, "%s", nameStr); currFile++; } myFile.close(); @@ -1451,7 +1447,7 @@ page: for (byte i = 0; i < 8; i++ ) { // Copy short string into fileOptions - snprintf( answers[i], FILEOPTS_LENGTH, "%s", fileOptions[ ((currPage - 1) * 7 + i)] ); + snprintf( answers[i], FILEOPTS_LENGTH, "%s", fileNames[ ((currPage - 1) * 7 + i)] ); } // Create menu with title and 1-7 options to choose from diff --git a/Cart_Reader/GBA.ino b/Cart_Reader/GBA.ino index e788c96..67ea192 100644 --- a/Cart_Reader/GBA.ino +++ b/Cart_Reader/GBA.ino @@ -2060,8 +2060,13 @@ void idFlashrom_GBA() { resetMX29GL128E_GBA(); } else { + println_Msg(F("Error")); + println_Msg(F("")); + println_Msg(F("Unknown Flash")); + print_Msg(F("Flash ID: ")); println_Msg(flashid); - print_Error(F("Unknown Flashid"), true); + println_Msg(F("")); + print_Error(F("Check voltage"), true); } } } @@ -2508,7 +2513,7 @@ void flashRepro_GBA() { println_Msg(""); println_Msg(F("This will erase your")); println_Msg(F("Repro Cartridge.")); - println_Msg(F("Please use 3.3V!")); + println_Msg(F("")); println_Msg(""); println_Msg(F("Press Button")); display_Update(); @@ -2633,9 +2638,13 @@ void flashRepro_GBA() { } } else { - print_Msg(F("ID: ")); + println_Msg(F("Error")); + println_Msg(F("")); + println_Msg(F("Unknown Flash")); + print_Msg(F("Flash ID: ")); println_Msg(flashid); - print_Error(F("Unknown Flash ID"), true); + println_Msg(F("")); + print_Error(F("Check voltage"), true); } } diff --git a/Cart_Reader/GBM.ino b/Cart_Reader/GBM.ino new file mode 100644 index 0000000..066afaf --- /dev/null +++ b/Cart_Reader/GBM.ino @@ -0,0 +1,886 @@ +/****************************************** + GB MEMORY MODULE +******************************************/ + +#include "options.h" +#ifdef enable_GBX + +/****************************************** + Menu +*****************************************/ +// GBM menu items +static const char gbmMenuItem1[] PROGMEM = "Read ID"; +static const char gbmMenuItem2[] PROGMEM = "Read Flash"; +static const char gbmMenuItem3[] PROGMEM = "Erase Flash"; +static const char gbmMenuItem4[] PROGMEM = "Blankcheck"; +static const char gbmMenuItem5[] PROGMEM = "Write Flash"; +static const char gbmMenuItem6[] PROGMEM = "Read Mapping"; +static const char gbmMenuItem7[] PROGMEM = "Write Mapping"; +static const char* const menuOptionsGBM[] PROGMEM = {gbmMenuItem1, gbmMenuItem2, gbmMenuItem3, gbmMenuItem4, gbmMenuItem5, gbmMenuItem6, gbmMenuItem7}; + +void gbmMenu() { + // create menu with title and 7 options to choose from + unsigned char mainMenu; + // Copy menuOptions out of progmem + convertPgm(menuOptionsGBM, 7); + mainMenu = question_box(F("GB Memory Menu"), menuOptions, 7, 0); + + // wait for user choice to come back from the question box menu + switch (mainMenu) + { + // Read Flash ID + case 0: + // Clear screen + display_Clear(); + readFlashID_GBM(); + break; + + // Read Flash + case 1: + // Clear screen + display_Clear(); + // Print warning + println_Msg(F("Attention")); + println_Msg(F("Always power cycle")); + println_Msg(F("cartreader directly")); + println_Msg(F("before reading")); + println_Msg(""); + println_Msg(F("Press Button")); + println_Msg(F("to continue")); + display_Update(); + wait(); + // Clear screen + display_Clear(); + + // Reset to root directory + sd.chdir("/"); + + // Enable access to ports 0120h + send_GBM(0x09); + // Map entire flashrom + send_GBM(0x04); + // Disable ports 0x0120... + send_GBM(0x08); + // Read 1MB rom + readROM_GBM(64); + break; + + // Erase Flash + case 2: + // Clear screen + display_Clear(); + // Print warning + println_Msg(F("Attention")); + println_Msg(F("This will erase your")); + println_Msg(F("NP Cartridge.")); + println_Msg(""); + println_Msg(""); + println_Msg(F("Press Button")); + println_Msg(F("to continue")); + display_Update(); + wait(); + // Clear screen + display_Clear(); + eraseFlash_GBM(); + break; + + // Blankcheck Flash + case 3: + // Clear screen + display_Clear(); + if (blankcheckFlash_GBM()) { + println_Msg(F("OK")); + display_Update(); + } + else { + println_Msg(F("ERROR")); + display_Update(); + } + break; + + // Write Flash + case 4: + // Clear screen + display_Clear(); + + filePath[0] = '\0'; + sd.chdir("/"); + // Launch file browser + fileBrowser(F("Select 1MB file")); + display_Clear(); + sprintf(filePath, "%s/%s", filePath, fileName); + + // Write rom + writeFlash_GBM(); + break; + + // Read mapping + case 5: + // Clear screen + display_Clear(); + + // Reset to root directory + sd.chdir("/"); + + // Read mapping + readMapping_GBM(); + break; + + // Write mapping + case 6: + // Clear screen + display_Clear(); + + // Print warning + println_Msg(F("Attention")); + println_Msg(F("This will erase your")); + println_Msg(F("NP Cartridge's")); + println_Msg(F("mapping data")); + println_Msg(""); + println_Msg(F("Press Button")); + println_Msg(F("to continue")); + display_Update(); + wait(); + + // Reset to root directory + sd.chdir("/"); + + // Clear screen + display_Clear(); + + // Clear filepath + filePath[0] = '\0'; + + // Reset to root directory + sd.chdir("/"); + + // Launch file browser + fileBrowser(F("Select MAP file")); + display_Clear(); + sprintf(filePath, "%s/%s", filePath, fileName); + display_Update(); + + // Clear screen + display_Clear(); + + // Erase mapping + eraseMapping_GBM(); + if (blankcheckMapping_GBM()) { + println_Msg(F("OK")); + display_Update(); + } + else { + print_Error(F("Erasing failed"), false); + break; + } + + // Write mapping + writeMapping_GBM(); + break; + } + println_Msg(F("")); + println_Msg(F("Press Button...")); + display_Update(); + wait(); +} + +/****************************************** + Setup +*****************************************/ +void setup_GBM() { + // Set RST(PH0) to Input + DDRH &= ~(1 << 0); + // Activate Internal Pullup Resistors + PORTH |= (1 << 0); + + // Set Address Pins to Output + //A0-A7 + DDRF = 0xFF; + //A8-A15 + DDRK = 0xFF; + + // Set Control Pins to Output RST(PH0) CS(PH3) WR(PH5) RD(PH6) + DDRH |= (1 << 3) | (1 << 5) | (1 << 6); + // Output a high signal on all pins, pins are active low therefore everything is disabled now + PORTH |= (1 << 3) | (1 << 5) | (1 << 6); + + // Set Data Pins (D0-D7) to Input + DDRC = 0x00; + + delay(400); + + // Check for Nintendo Power GB Memory cart + byte timeout = 0; + + // First byte of NP register is always 0x21 + while (readByte_GBM(0x120) != 0x21) { + // Enable ports 0x120h (F2) + send_GBM(0x09); + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + timeout++; + if (timeout > 10) { + println_Msg(F("Error: Time Out")); + print_Error(F("Please power cycle"), true); + } + } +} + +/********************** + LOW LEVEL +**********************/ +// Read one word out of the cartridge +byte readByte_GBM(word myAddress) { + // Set data pins to Input + DDRC = 0x0; + PORTF = myAddress & 0xFF; + PORTK = (myAddress >> 8) & 0xFF; + + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Switch CS(PH3) and RD(PH6) to LOW + PORTH &= ~(1 << 3); + PORTH &= ~(1 << 6); + + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Read + byte tempByte = PINC; + + // Switch CS(PH3) and RD(PH6) to HIGH + PORTH |= (1 << 6); + PORTH |= (1 << 3); + + return tempByte; +} + +// Write one word to data pins of the cartridge +void writeByte_GBM(word myAddress, byte myData) { + // Set data pins to Output + DDRC = 0xFF; + PORTF = myAddress & 0xFF; + PORTK = (myAddress >> 8) & 0xFF; + PORTC = myData; + + // Pull CS(PH3) and write(PH5) low + PORTH &= ~(1 << 3); + PORTH &= ~(1 << 5); + + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Pull CS(PH3) and write(PH5) high + PORTH |= (1 << 5); + PORTH |= (1 << 3); + + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Set data pins to Input (or read errors??!) + DDRC = 0x0; +} + +/********************** + HELPER FUNCTIONS +**********************/ +void printSdBuffer(word startByte, word numBytes) { + for (int currByte = 0; currByte < numBytes; currByte += 10) { + for (byte c = 0; c < 10; c++) { + // Convert to char array so we don't lose leading zeros + char currByteStr[2]; + sprintf(currByteStr, "%02X", sdBuffer[startByte + currByte + c]); + print_Msg(currByteStr); + } + // Add a new line every 10 bytes + println_Msg(""); + } + display_Update(); +} + +void readROM_GBM(word numBanks) { + println_Msg(F("Reading Rom...")); + display_Update(); + + // Get name, add extension and convert to char array for sd lib + EEPROM_readAnything(0, foldern); + sprintf(fileName, "GBM%d", foldern); + strcat(fileName, ".bin"); + sd.mkdir("NP", true); + sd.chdir("NP"); + // write new folder number back to eeprom + foldern = foldern + 1; + EEPROM_writeAnything(0, foldern); + + // Open file on sd card + if (!myFile.open(fileName, O_RDWR | O_CREAT)) { + print_Error(F("Can't create file on SD"), true); + } + else { + // Read rom + word currAddress = 0; + + for (word currBank = 1; currBank < numBanks; currBank++) { + // Set rom bank + writeByte_GBM(0x2100, currBank); + + // Switch bank start address + if (currBank > 1) { + currAddress = 0x4000; + } + + for (; currAddress < 0x7FFF; currAddress += 512) { + for (int currByte = 0; currByte < 512; currByte++) { + sdBuffer[currByte] = readByte_GBM(currAddress + currByte); + } + myFile.write(sdBuffer, 512); + } + } + + // Close the file: + myFile.close(); + + // Signal end of process + print_Msg(F("Saved to NP/")); + println_Msg(fileName); + display_Update(); + } +} + +/********************** + GB Memory Functions +**********************/ +void send_GBM(byte myCommand) { + switch (myCommand) { + case 0x01: + //CMD_01h -> ??? + writeByte_GBM(0x0120, 0x01); + writeByte_GBM(0x013F, 0xA5); + break; + + case 0x02: + //CMD_02h -> Write enable Step 2 + writeByte_GBM(0x0120, 0x02); + writeByte_GBM(0x013F, 0xA5); + break; + + case 0x03: + //CMD_03h -> Undo write Step 2 + writeByte_GBM(0x0120, 0x03); + writeByte_GBM(0x013F, 0xA5); + break; + + case 0x04: + //CMD_04h -> Map entire flashrom (MBC4 mode) + writeByte_GBM(0x0120, 0x04); + writeByte_GBM(0x013F, 0xA5); + break; + + case 0x05: + //CMD_05h -> Map menu (MBC5 mode) + writeByte_GBM(0x0120, 0x05); + writeByte_GBM(0x013F, 0xA5); + break; + + case 0x08: + //CMD_08h -> disable writes/reads to/from special Nintendo Power registers (those at 0120h..013Fh) + writeByte_GBM(0x0120, 0x08); + writeByte_GBM(0x013F, 0xA5); + break; + + case 0x09: + //CMD_09h Wakeup -> re-enable access to ports 0120h..013Fh + writeByte_GBM(0x0120, 0x09); + writeByte_GBM(0x0121, 0xAA); + writeByte_GBM(0x0122, 0x55); + writeByte_GBM(0x013F, 0xA5); + break; + + case 0x0A: + //CMD_0Ah -> Write enable Step 1 + writeByte_GBM(0x0120, 0x0A); + writeByte_GBM(0x0125, 0x62); + writeByte_GBM(0x0126, 0x04); + writeByte_GBM(0x013F, 0xA5); + break; + + case 0x10: + //CMD_10h -> disable writes to normal MBC registers (such like 2100h) + writeByte_GBM(0x0120, 0x10); + writeByte_GBM(0x013F, 0xA5); + break; + + case 0x11: + //CMD_11h -> re-enable access to MBC registers like 0x2100 + writeByte_GBM(0x0120, 0x11); + writeByte_GBM(0x013F, 0xA5); + break; + + default: + print_Error(F("Unknown Command"), true); + break; + } +} + +void send_GBM(byte myCommand, word myAddress, byte myData) { + byte myAddrLow = myAddress & 0xFF; + byte myAddrHigh = (myAddress >> 8) & 0xFF; + + switch (myCommand) { + case 0x0F: + // CMD_0Fh -> Write address/byte to flash + writeByte_GBM(0x0120, 0x0F); + writeByte_GBM(0x0125, myAddrHigh); + writeByte_GBM(0x0126, myAddrLow); + writeByte_GBM(0x0127, myData); + writeByte_GBM(0x013F, 0xA5); + break; + + default: + print_Error(F("Unknown Command"), true); + break; + } +} + +void switchGame_GBM(byte myData) { + // Enable ports 0x0120 (F2) + send_GBM(0x09); + + //CMD_C0h -> map selected game without reset + writeByte_GBM(0x0120, 0xC0 & myData); + writeByte_GBM(0x013F, 0xA5); +} + +void resetFlash_GBM() { + // Enable ports 0x0120 (F2) + send_GBM(0x09); + + // Send reset command + writeByte_GBM(0x2100, 0x01); + send_GBM(0x0F, 0x5555, 0xAA); + send_GBM(0x0F, 0x2AAA, 0x55); + send_GBM(0x0F, 0x5555, 0xF0); + delay(100); +} + +boolean readFlashID_GBM() { + // Enable ports 0x0120 (F2) + send_GBM(0x09); + + writeByte_GBM(0x2100, 0x01); + // Read ID command + send_GBM(0x0F, 0x5555, 0xAA); + send_GBM(0x0F, 0x2AAA, 0x55); + send_GBM(0x0F, 0x5555, 0x90); + + // Read the two id bytes into a string + sprintf(flashid, "%02X%02X", readByte_GBM(0), readByte_GBM(1)); + if (strcmp(flashid, "C289") == 0) { + print_Msg(F("Flash ID: ")); + println_Msg(flashid); + display_Update(); + resetFlash_GBM(); + return 1; + } + else { + print_Msg(F("Flash ID: ")); + println_Msg(flashid); + print_Error(F("Unknown Flash ID"), true); + resetFlash_GBM(); + return 0; + } +} + +void eraseFlash_GBM() { + println_Msg(F("Erasing...")); + display_Update(); + + //enable access to ports 0120h + send_GBM(0x09); + // Enable write + send_GBM(0x0A); + send_GBM(0x2); + + // Unprotect sector 0 + send_GBM(0x0F, 0x5555, 0xAA); + send_GBM(0x0F, 0x2AAA, 0x55); + send_GBM(0x0F, 0x5555, 0x60); + send_GBM(0x0F, 0x5555, 0xAA); + send_GBM(0x0F, 0x2AAA, 0x55); + send_GBM(0x0F, 0x5555, 0x40); + + // Wait for unprotect to complete + while ((readByte_GBM(0) & 0x80) != 0x80) {} + + // Send erase command + send_GBM(0x0F, 0x5555, 0xaa); + send_GBM(0x0F, 0x2AAA, 0x55); + send_GBM(0x0F, 0x5555, 0x80); + send_GBM(0x0F, 0x5555, 0xaa); + send_GBM(0x0F, 0x2AAA, 0x55); + send_GBM(0x0F, 0x5555, 0x10); + + // Wait for erase to complete + while ((readByte_GBM(0) & 0x80) != 0x80) {} + + // Reset flashrom + resetFlash_GBM(); +} + +boolean blankcheckFlash_GBM() { + print_Msg(F("Blankcheck...")); + display_Update(); + + //enable access to ports 0120h (F2) + send_GBM(0x09); + + // Map entire flashrom + send_GBM(0x04); + // Disable ports 0x0120... + send_GBM(0x08); + + // Read rom + word currAddress = 0; + + for (byte currBank = 1; currBank < 64; currBank++) { + // Set rom bank + writeByte_GBM(0x2100, currBank); + + // Switch bank start address + if (currBank > 1) { + currAddress = 0x4000; + } + + for (; currAddress < 0x7FFF; currAddress++) { + if (readByte_GBM(currAddress) != 0xFF) { + return 0; + } + } + } + return 1; +} + +void writeFlash_GBM() { + print_Msg(F("Writing...")); + display_Update(); + + // Open file on sd card + if (myFile.open(filePath, O_READ)) { + // Get rom size from file + fileSize = myFile.fileSize(); + if ((fileSize / 0x4000) > 64) { + print_Error(F("File is too big."), true); + } + + // Enable access to ports 0120h + send_GBM(0x09); + // Enable write + send_GBM(0x0A); + send_GBM(0x2); + + // Map entire flash rom + send_GBM(0x4); + + // Set bank for unprotect command, writes to 0x5555 need odd bank number + writeByte_GBM(0x2100, 0x1); + + // Disable ports 0x2100 and 0x120 or else those addresses will not be writable + send_GBM(0x10); + send_GBM(0x08); + + // Unprotect sector 0 + writeByte_GBM(0x5555, 0xAA); + writeByte_GBM(0x2AAA, 0x55); + writeByte_GBM(0x5555, 0x60); + writeByte_GBM(0x5555, 0xAA); + writeByte_GBM(0x2AAA, 0x55); + writeByte_GBM(0x5555, 0x40); + + // Check if flashrom is ready for writing or busy + while ((readByte_GBM(0) & 0x80) != 0x80) {} + + // first bank: 0x0000-0x7FFF, + word currAddress = 0x0; + + // Write 63 banks + for (byte currBank = 0x1; currBank < (fileSize / 0x4000); currBank++) { + // Blink led + PORTB ^= (1 << 4); + + // all following banks: 0x4000-0x7FFF + if (currBank > 1) { + currAddress = 0x4000; + } + + // Write single bank in 128 byte steps + for (; currAddress < 0x7FFF; currAddress += 128) { + // Fill SD buffer + myFile.read(sdBuffer, 128); + + // Enable access to ports 0x120 and 0x2100 + send_GBM(0x09); + send_GBM(0x11); + + // Set bank + writeByte_GBM(0x2100, 0x1); + + // Disable ports 0x2100 and 0x120 or else those addresses will not be writable + send_GBM(0x10); + send_GBM(0x08); + + // Write flash buffer command + writeByte_GBM(0x5555, 0xAA); + writeByte_GBM(0x2AAA, 0x55); + writeByte_GBM(0x5555, 0xA0); + + // Wait until flashrom is ready again + while ((readByte_GBM(0) & 0x80) != 0x80) {} + + // Enable access to ports 0x120 and 0x2100 + send_GBM(0x09); + send_GBM(0x11); + + // Set bank + writeByte_GBM(0x2100, currBank); + + // Disable ports 0x2100 and 0x120 or else those addresses will not be writable + send_GBM(0x10); + send_GBM(0x08); + + // Fill flash buffer + for (word currByte = 0; currByte < 128; currByte++) { + writeByte_GBM(currAddress + currByte, sdBuffer[currByte]); + } + // Execute write + writeByte_GBM(currAddress + 127, 0xFF); + + // Wait for write to complete + while ((readByte_GBM(currAddress) & 0x80) != 0x80) {} + } + } + // Close the file: + myFile.close(); + println_Msg(F("Done")); + } + else { + print_Error(F("Can't open file"), false); + } +} + +void readMapping_GBM() { + // Enable ports 0x0120 + send_GBM(0x09); + + // Set WE and WP + send_GBM(0x0A); + send_GBM(0x2); + + // Enable hidden mapping area + writeByte_GBM(0x2100, 0x01); + send_GBM(0x0F, 0x5555, 0xAA); + send_GBM(0x0F, 0x2AAA, 0x55); + send_GBM(0x0F, 0x5555, 0x77); + send_GBM(0x0F, 0x5555, 0xAA); + send_GBM(0x0F, 0x2AAA, 0x55); + send_GBM(0x0F, 0x5555, 0x77); + + // Read mapping + println_Msg(F("Reading Mapping...")); + display_Update(); + + // Get name, add extension and convert to char array for sd lib + EEPROM_readAnything(0, foldern); + sprintf(fileName, "GBM%d", foldern); + strcat(fileName, ".map"); + sd.mkdir("NP", true); + sd.chdir("NP"); + // write new folder number back to eeprom + foldern = foldern + 1; + EEPROM_writeAnything(0, foldern); + + // Open file on sd card + if (!myFile.open(fileName, O_RDWR | O_CREAT)) { + print_Error(F("Can't create file on SD"), true); + } + else { + for (byte currByte = 0; currByte < 128; currByte++) { + sdBuffer[currByte] = readByte_GBM(currByte); + } + myFile.write(sdBuffer, 128); + + // Close the file: + myFile.close(); + + // Signal end of process + printSdBuffer(0, 20); + printSdBuffer(102, 20); + println_Msg(""); + print_Msg(F("Saved to NP/")); + println_Msg(fileName); + display_Update(); + } + + // Reset flash to leave hidden mapping area + resetFlash_GBM(); +} + +void eraseMapping_GBM() { + println_Msg(F("Erasing...")); + display_Update(); + + //enable access to ports 0120h + send_GBM(0x09); + // Enable write + send_GBM(0x0A); + send_GBM(0x2); + + // Unprotect sector 0 + send_GBM(0x0F, 0x5555, 0xAA); + send_GBM(0x0F, 0x2AAA, 0x55); + send_GBM(0x0F, 0x5555, 0x60); + send_GBM(0x0F, 0x5555, 0xAA); + send_GBM(0x0F, 0x2AAA, 0x55); + send_GBM(0x0F, 0x5555, 0x40); + + // Wait for unprotect to complete + while ((readByte_GBM(0) & 0x80) != 0x80) {} + + // Send erase command + send_GBM(0x0F, 0x5555, 0xAA); + send_GBM(0x0F, 0x2AAA, 0x55); + send_GBM(0x0F, 0x5555, 0x60); + send_GBM(0x0F, 0x5555, 0xAA); + send_GBM(0x0F, 0x2AAA, 0x55); + send_GBM(0x0F, 0x5555, 0x04); + + // Wait for erase to complete + while ((readByte_GBM(0) & 0x80) != 0x80) {} + + // Reset flashrom + resetFlash_GBM(); +} + +boolean blankcheckMapping_GBM() { + print_Msg(F("Blankcheck...")); + display_Update(); + + // Enable ports 0x0120 + send_GBM(0x09); + + // Set WE and WP + send_GBM(0x0A); + send_GBM(0x2); + + // Enable hidden mapping area + writeByte_GBM(0x2100, 0x01); + send_GBM(0x0F, 0x5555, 0xAA); + send_GBM(0x0F, 0x2AAA, 0x55); + send_GBM(0x0F, 0x5555, 0x77); + send_GBM(0x0F, 0x5555, 0xAA); + send_GBM(0x0F, 0x2AAA, 0x55); + send_GBM(0x0F, 0x5555, 0x77); + + // Disable ports 0x0120... + send_GBM(0x08); + + // Read rom + for (byte currByte = 0; currByte < 128; currByte++) { + if (readByte_GBM(currByte) != 0xFF) { + return 0; + } + } + return 1; +} + +void writeMapping_GBM() { + print_Msg(F("Writing...")); + display_Update(); + + // Open file on sd card + if (myFile.open(filePath, O_READ)) { + // Get map file size and check if it exceeds 128KByte + if (myFile.fileSize() > 0x80) { + print_Error(F("File is too big."), true); + } + + // Enable access to ports 0120h + send_GBM(0x09); + + // Enable write + send_GBM(0x0A); + send_GBM(0x2); + + // Map entire flash rom + send_GBM(0x4); + + // Set bank, writes to 0x5555 need odd bank number + writeByte_GBM(0x2100, 0x1); + + // Disable ports 0x2100 and 0x120 or else those addresses will not be writable + send_GBM(0x10); + send_GBM(0x08); + + // Unlock write to map area + writeByte_GBM(0x5555, 0xAA); + writeByte_GBM(0x2AAA, 0x55); + writeByte_GBM(0x5555, 0x60); + writeByte_GBM(0x5555, 0xAA); + writeByte_GBM(0x2AAA, 0x55); + writeByte_GBM(0x5555, 0xE0); + + // Check if flashrom is ready for writing or busy + while ((readByte_GBM(0) & 0x80) != 0x80) {} + + // Fill SD buffer + myFile.read(sdBuffer, 128); + + // Enable access to ports 0x120 and 0x2100 + send_GBM(0x09); + send_GBM(0x11); + + // Set bank + writeByte_GBM(0x2100, 0x1); + + // Disable ports 0x2100 and 0x120 or else those addresses will not be writable + send_GBM(0x10); + send_GBM(0x08); + + // Write flash buffer command + writeByte_GBM(0x5555, 0xAA); + writeByte_GBM(0x2AAA, 0x55); + writeByte_GBM(0x5555, 0xA0); + + // Wait until flashrom is ready again + while ((readByte_GBM(0) & 0x80) != 0x80) {} + + // Enable access to ports 0x120 and 0x2100 + send_GBM(0x09); + send_GBM(0x11); + + // Set bank + writeByte_GBM(0x2100, 0); + + // Disable ports 0x2100 and 0x120 or else those addresses will not be writable + send_GBM(0x10); + send_GBM(0x08); + + // Fill flash buffer + for (word currByte = 0; currByte < 128; currByte++) { + // Blink led + PORTB ^= (1 << 4); + + writeByte_GBM(currByte, sdBuffer[currByte]); + } + // Execute write + writeByte_GBM(127, 0xFF); + + // Close the file: + myFile.close(); + println_Msg(F("Done")); + } + else { + print_Error(F("Can't open file"), false); + } +} + +#endif + +//****************************************** +// End of File +//****************************************** diff --git a/Cart_Reader/GBSmart.ino b/Cart_Reader/GBSmart.ino index 34d4c9f..d7712e3 100644 --- a/Cart_Reader/GBSmart.ino +++ b/Cart_Reader/GBSmart.ino @@ -54,8 +54,13 @@ GBSmartGameInfo gbSmartGames[GB_SMART_GAMES_PER_PAGE]; byte signature[48]; uint16_t gameMenuStartBank; +#ifdef enable_NP extern boolean hasMenu; extern byte numGames; +#else +boolean hasMenu; +byte numGames; +#endif byte readByte_GBS(word myAddress) { PORTF = myAddress & 0xFF; @@ -776,4 +781,4 @@ uint8_t gbSmartGetResizeParam(uint8_t rom_size, uint8_t sram_size) return (sram_size | rom_size); } -#endif \ No newline at end of file +#endif diff --git a/Cart_Reader/MD.ino b/Cart_Reader/MD.ino index ce429ce..a76536c 100644 --- a/Cart_Reader/MD.ino +++ b/Cart_Reader/MD.ino @@ -97,7 +97,7 @@ void mdLoadConf() { char line[64]; int n; int i; - while ((n = myFile.fgets(line, sizeof(line)-1)) > 0) { + while ((n = myFile.fgets(line, sizeof(line) - 1)) > 0) { // preprocess for (i = 0; i < n; i++) { if (line[i] == ';') { @@ -1191,7 +1191,7 @@ unsigned long verifySram_MD() { for (unsigned long currBuffer = sramBase; currBuffer < sramBase + sramSize; currBuffer += 256) { for (int currWord = 0; currWord < 256; currWord++) { word myWord = readWord_MD(currBuffer + currWord); - + if (saveType == 2) { // Only use the upper byte sdBuffer[currWord * 2] = (( myWord >> 8 ) & 0xFF); diff --git a/Cart_Reader/NP.ino b/Cart_Reader/NP.ino index 90647fd..b76c404 100644 --- a/Cart_Reader/NP.ino +++ b/Cart_Reader/NP.ino @@ -1,15 +1,10 @@ //****************************************** -// NINTENDO POWER MODULE +// NINTENDO POWER SF MEMORY MODULE //****************************************** -// (GB Memory starts at around line 1740) #include "options.h" #ifdef enable_NP -/****************************************** - SF Memory Cassette -******************************************/ - /****************************************** SF Memory Clock Source ******************************************/ @@ -1742,884 +1737,6 @@ void write_SFM(int startBank, uint32_t pos) { } } -/****************************************** - GB Memory Cassette -******************************************/ - -/****************************************** - Menu -*****************************************/ -// GBM menu items -static const char gbmMenuItem1[] PROGMEM = "Read ID"; -static const char gbmMenuItem2[] PROGMEM = "Read Flash"; -static const char gbmMenuItem3[] PROGMEM = "Erase Flash"; -static const char gbmMenuItem4[] PROGMEM = "Blankcheck"; -static const char gbmMenuItem5[] PROGMEM = "Write Flash"; -static const char gbmMenuItem6[] PROGMEM = "Read Mapping"; -static const char gbmMenuItem7[] PROGMEM = "Write Mapping"; -static const char* const menuOptionsGBM[] PROGMEM = {gbmMenuItem1, gbmMenuItem2, gbmMenuItem3, gbmMenuItem4, gbmMenuItem5, gbmMenuItem6, gbmMenuItem7}; - -void gbmMenu() { - // create menu with title and 7 options to choose from - unsigned char mainMenu; - // Copy menuOptions out of progmem - convertPgm(menuOptionsGBM, 7); - mainMenu = question_box(F("GB Memory Menu"), menuOptions, 7, 0); - - // wait for user choice to come back from the question box menu - switch (mainMenu) - { - // Read Flash ID - case 0: - // Clear screen - display_Clear(); - readFlashID_GBM(); - break; - - // Read Flash - case 1: - // Clear screen - display_Clear(); - // Print warning - println_Msg(F("Attention")); - println_Msg(F("Always power cycle")); - println_Msg(F("cartreader directly")); - println_Msg(F("before reading")); - println_Msg(""); - println_Msg(F("Press Button")); - println_Msg(F("to continue")); - display_Update(); - wait(); - // Clear screen - display_Clear(); - - // Reset to root directory - sd.chdir("/"); - - // Enable access to ports 0120h - send_GBM(0x09); - // Map entire flashrom - send_GBM(0x04); - // Disable ports 0x0120... - send_GBM(0x08); - // Read 1MB rom - readROM_GBM(64); - break; - - // Erase Flash - case 2: - // Clear screen - display_Clear(); - // Print warning - println_Msg(F("Attention")); - println_Msg(F("This will erase your")); - println_Msg(F("NP Cartridge.")); - println_Msg(""); - println_Msg(""); - println_Msg(F("Press Button")); - println_Msg(F("to continue")); - display_Update(); - wait(); - // Clear screen - display_Clear(); - eraseFlash_GBM(); - break; - - // Blankcheck Flash - case 3: - // Clear screen - display_Clear(); - if (blankcheckFlash_GBM()) { - println_Msg(F("OK")); - display_Update(); - } - else { - println_Msg(F("ERROR")); - display_Update(); - } - break; - - // Write Flash - case 4: - // Clear screen - display_Clear(); - - filePath[0] = '\0'; - sd.chdir("/"); - // Launch file browser - fileBrowser(F("Select 1MB file")); - display_Clear(); - sprintf(filePath, "%s/%s", filePath, fileName); - - // Write rom - writeFlash_GBM(); - break; - - // Read mapping - case 5: - // Clear screen - display_Clear(); - - // Reset to root directory - sd.chdir("/"); - - // Read mapping - readMapping_GBM(); - break; - - // Write mapping - case 6: - // Clear screen - display_Clear(); - - // Print warning - println_Msg(F("Attention")); - println_Msg(F("This will erase your")); - println_Msg(F("NP Cartridge's")); - println_Msg(F("mapping data")); - println_Msg(""); - println_Msg(F("Press Button")); - println_Msg(F("to continue")); - display_Update(); - wait(); - - // Reset to root directory - sd.chdir("/"); - - // Clear screen - display_Clear(); - - // Clear filepath - filePath[0] = '\0'; - - // Reset to root directory - sd.chdir("/"); - - // Launch file browser - fileBrowser(F("Select MAP file")); - display_Clear(); - sprintf(filePath, "%s/%s", filePath, fileName); - display_Update(); - - // Clear screen - display_Clear(); - - // Erase mapping - eraseMapping_GBM(); - if (blankcheckMapping_GBM()) { - println_Msg(F("OK")); - display_Update(); - } - else { - print_Error(F("Erasing failed"), false); - break; - } - - // Write mapping - writeMapping_GBM(); - break; - } - println_Msg(F("")); - println_Msg(F("Press Button...")); - display_Update(); - wait(); -} - -/****************************************** - Setup -*****************************************/ -void setup_GBM() { - // Set RST(PH0) to Input - DDRH &= ~(1 << 0); - // Activate Internal Pullup Resistors - PORTH |= (1 << 0); - - // Set Address Pins to Output - //A0-A7 - DDRF = 0xFF; - //A8-A15 - DDRK = 0xFF; - - // Set Control Pins to Output RST(PH0) CS(PH3) WR(PH5) RD(PH6) - DDRH |= (1 << 3) | (1 << 5) | (1 << 6); - // Output a high signal on all pins, pins are active low therefore everything is disabled now - PORTH |= (1 << 3) | (1 << 5) | (1 << 6); - - // Set Data Pins (D0-D7) to Input - DDRC = 0x00; - - delay(400); - - // Check for Nintendo Power GB Memory cart - byte timeout = 0; - - // First byte of NP register is always 0x21 - while (readByte_GBM(0x120) != 0x21) { - // Enable ports 0x120h (F2) - send_GBM(0x09); - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); - timeout++; - if (timeout > 10) { - println_Msg(F("Error: Time Out")); - print_Error(F("Please power cycle"), true); - } - } -} - -/********************** - LOW LEVEL -**********************/ -// Read one word out of the cartridge -byte readByte_GBM(word myAddress) { - // Set data pins to Input - DDRC = 0x0; - PORTF = myAddress & 0xFF; - PORTK = (myAddress >> 8) & 0xFF; - - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); - - // Switch CS(PH3) and RD(PH6) to LOW - PORTH &= ~(1 << 3); - PORTH &= ~(1 << 6); - - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); - - // Read - byte tempByte = PINC; - - // Switch CS(PH3) and RD(PH6) to HIGH - PORTH |= (1 << 6); - PORTH |= (1 << 3); - - return tempByte; -} - -// Write one word to data pins of the cartridge -void writeByte_GBM(word myAddress, byte myData) { - // Set data pins to Output - DDRC = 0xFF; - PORTF = myAddress & 0xFF; - PORTK = (myAddress >> 8) & 0xFF; - PORTC = myData; - - // Pull CS(PH3) and write(PH5) low - PORTH &= ~(1 << 3); - PORTH &= ~(1 << 5); - - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); - - // Pull CS(PH3) and write(PH5) high - PORTH |= (1 << 5); - PORTH |= (1 << 3); - - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); - - // Set data pins to Input (or read errors??!) - DDRC = 0x0; -} - -/********************** - HELPER FUNCTIONS -**********************/ -void printSdBuffer(word startByte, word numBytes) { - for (int currByte = 0; currByte < numBytes; currByte += 10) { - for (byte c = 0; c < 10; c++) { - // Convert to char array so we don't lose leading zeros - char currByteStr[2]; - sprintf(currByteStr, "%02X", sdBuffer[startByte + currByte + c]); - print_Msg(currByteStr); - } - // Add a new line every 10 bytes - println_Msg(""); - } - display_Update(); -} - -void readROM_GBM(word numBanks) { - println_Msg(F("Reading Rom...")); - display_Update(); - - // Get name, add extension and convert to char array for sd lib - EEPROM_readAnything(0, foldern); - sprintf(fileName, "GBM%d", foldern); - strcat(fileName, ".bin"); - sd.mkdir("NP", true); - sd.chdir("NP"); - // write new folder number back to eeprom - foldern = foldern + 1; - EEPROM_writeAnything(0, foldern); - - // Open file on sd card - if (!myFile.open(fileName, O_RDWR | O_CREAT)) { - print_Error(F("Can't create file on SD"), true); - } - else { - // Read rom - word currAddress = 0; - - for (word currBank = 1; currBank < numBanks; currBank++) { - // Set rom bank - writeByte_GBM(0x2100, currBank); - - // Switch bank start address - if (currBank > 1) { - currAddress = 0x4000; - } - - for (; currAddress < 0x7FFF; currAddress += 512) { - for (int currByte = 0; currByte < 512; currByte++) { - sdBuffer[currByte] = readByte_GBM(currAddress + currByte); - } - myFile.write(sdBuffer, 512); - } - } - - // Close the file: - myFile.close(); - - // Signal end of process - print_Msg(F("Saved to NP/")); - println_Msg(fileName); - display_Update(); - } -} - -/********************** - GB Memory Functions -**********************/ -void send_GBM(byte myCommand) { - switch (myCommand) { - case 0x01: - //CMD_01h -> ??? - writeByte_GBM(0x0120, 0x01); - writeByte_GBM(0x013F, 0xA5); - break; - - case 0x02: - //CMD_02h -> Write enable Step 2 - writeByte_GBM(0x0120, 0x02); - writeByte_GBM(0x013F, 0xA5); - break; - - case 0x03: - //CMD_03h -> Undo write Step 2 - writeByte_GBM(0x0120, 0x03); - writeByte_GBM(0x013F, 0xA5); - break; - - case 0x04: - //CMD_04h -> Map entire flashrom (MBC4 mode) - writeByte_GBM(0x0120, 0x04); - writeByte_GBM(0x013F, 0xA5); - break; - - case 0x05: - //CMD_05h -> Map menu (MBC5 mode) - writeByte_GBM(0x0120, 0x05); - writeByte_GBM(0x013F, 0xA5); - break; - - case 0x08: - //CMD_08h -> disable writes/reads to/from special Nintendo Power registers (those at 0120h..013Fh) - writeByte_GBM(0x0120, 0x08); - writeByte_GBM(0x013F, 0xA5); - break; - - case 0x09: - //CMD_09h Wakeup -> re-enable access to ports 0120h..013Fh - writeByte_GBM(0x0120, 0x09); - writeByte_GBM(0x0121, 0xAA); - writeByte_GBM(0x0122, 0x55); - writeByte_GBM(0x013F, 0xA5); - break; - - case 0x0A: - //CMD_0Ah -> Write enable Step 1 - writeByte_GBM(0x0120, 0x0A); - writeByte_GBM(0x0125, 0x62); - writeByte_GBM(0x0126, 0x04); - writeByte_GBM(0x013F, 0xA5); - break; - - case 0x10: - //CMD_10h -> disable writes to normal MBC registers (such like 2100h) - writeByte_GBM(0x0120, 0x10); - writeByte_GBM(0x013F, 0xA5); - break; - - case 0x11: - //CMD_11h -> re-enable access to MBC registers like 0x2100 - writeByte_GBM(0x0120, 0x11); - writeByte_GBM(0x013F, 0xA5); - break; - - default: - print_Error(F("Unknown Command"), true); - break; - } -} - -void send_GBM(byte myCommand, word myAddress, byte myData) { - byte myAddrLow = myAddress & 0xFF; - byte myAddrHigh = (myAddress >> 8) & 0xFF; - - switch (myCommand) { - case 0x0F: - // CMD_0Fh -> Write address/byte to flash - writeByte_GBM(0x0120, 0x0F); - writeByte_GBM(0x0125, myAddrHigh); - writeByte_GBM(0x0126, myAddrLow); - writeByte_GBM(0x0127, myData); - writeByte_GBM(0x013F, 0xA5); - break; - - default: - print_Error(F("Unknown Command"), true); - break; - } -} - -void switchGame_GBM(byte myData) { - // Enable ports 0x0120 (F2) - send_GBM(0x09); - - //CMD_C0h -> map selected game without reset - writeByte_GBM(0x0120, 0xC0 & myData); - writeByte_GBM(0x013F, 0xA5); -} - -void resetFlash_GBM() { - // Enable ports 0x0120 (F2) - send_GBM(0x09); - - // Send reset command - writeByte_GBM(0x2100, 0x01); - send_GBM(0x0F, 0x5555, 0xAA); - send_GBM(0x0F, 0x2AAA, 0x55); - send_GBM(0x0F, 0x5555, 0xF0); - delay(100); -} - -boolean readFlashID_GBM() { - // Enable ports 0x0120 (F2) - send_GBM(0x09); - - writeByte_GBM(0x2100, 0x01); - // Read ID command - send_GBM(0x0F, 0x5555, 0xAA); - send_GBM(0x0F, 0x2AAA, 0x55); - send_GBM(0x0F, 0x5555, 0x90); - - // Read the two id bytes into a string - sprintf(flashid, "%02X%02X", readByte_GBM(0), readByte_GBM(1)); - if (strcmp(flashid, "C289") == 0) { - print_Msg(F("Flash ID: ")); - println_Msg(flashid); - display_Update(); - resetFlash_GBM(); - return 1; - } - else { - print_Msg(F("Flash ID: ")); - println_Msg(flashid); - print_Error(F("Unknown Flash ID"), true); - resetFlash_GBM(); - return 0; - } -} - -void eraseFlash_GBM() { - println_Msg(F("Erasing...")); - display_Update(); - - //enable access to ports 0120h - send_GBM(0x09); - // Enable write - send_GBM(0x0A); - send_GBM(0x2); - - // Unprotect sector 0 - send_GBM(0x0F, 0x5555, 0xAA); - send_GBM(0x0F, 0x2AAA, 0x55); - send_GBM(0x0F, 0x5555, 0x60); - send_GBM(0x0F, 0x5555, 0xAA); - send_GBM(0x0F, 0x2AAA, 0x55); - send_GBM(0x0F, 0x5555, 0x40); - - // Wait for unprotect to complete - while ((readByte_GBM(0) & 0x80) != 0x80) {} - - // Send erase command - send_GBM(0x0F, 0x5555, 0xaa); - send_GBM(0x0F, 0x2AAA, 0x55); - send_GBM(0x0F, 0x5555, 0x80); - send_GBM(0x0F, 0x5555, 0xaa); - send_GBM(0x0F, 0x2AAA, 0x55); - send_GBM(0x0F, 0x5555, 0x10); - - // Wait for erase to complete - while ((readByte_GBM(0) & 0x80) != 0x80) {} - - // Reset flashrom - resetFlash_GBM(); -} - -boolean blankcheckFlash_GBM() { - print_Msg(F("Blankcheck...")); - display_Update(); - - //enable access to ports 0120h (F2) - send_GBM(0x09); - - // Map entire flashrom - send_GBM(0x04); - // Disable ports 0x0120... - send_GBM(0x08); - - // Read rom - word currAddress = 0; - - for (byte currBank = 1; currBank < 64; currBank++) { - // Set rom bank - writeByte_GBM(0x2100, currBank); - - // Switch bank start address - if (currBank > 1) { - currAddress = 0x4000; - } - - for (; currAddress < 0x7FFF; currAddress++) { - if (readByte_GBM(currAddress) != 0xFF) { - return 0; - } - } - } - return 1; -} - -void writeFlash_GBM() { - print_Msg(F("Writing...")); - display_Update(); - - // Open file on sd card - if (myFile.open(filePath, O_READ)) { - // Get rom size from file - fileSize = myFile.fileSize(); - if ((fileSize / 0x4000) > 64) { - print_Error(F("File is too big."), true); - } - - // Enable access to ports 0120h - send_GBM(0x09); - // Enable write - send_GBM(0x0A); - send_GBM(0x2); - - // Map entire flash rom - send_GBM(0x4); - - // Set bank for unprotect command, writes to 0x5555 need odd bank number - writeByte_GBM(0x2100, 0x1); - - // Disable ports 0x2100 and 0x120 or else those addresses will not be writable - send_GBM(0x10); - send_GBM(0x08); - - // Unprotect sector 0 - writeByte_GBM(0x5555, 0xAA); - writeByte_GBM(0x2AAA, 0x55); - writeByte_GBM(0x5555, 0x60); - writeByte_GBM(0x5555, 0xAA); - writeByte_GBM(0x2AAA, 0x55); - writeByte_GBM(0x5555, 0x40); - - // Check if flashrom is ready for writing or busy - while ((readByte_GBM(0) & 0x80) != 0x80) {} - - // first bank: 0x0000-0x7FFF, - word currAddress = 0x0; - - // Write 63 banks - for (byte currBank = 0x1; currBank < (fileSize / 0x4000); currBank++) { - // Blink led - PORTB ^= (1 << 4); - - // all following banks: 0x4000-0x7FFF - if (currBank > 1) { - currAddress = 0x4000; - } - - // Write single bank in 128 byte steps - for (; currAddress < 0x7FFF; currAddress += 128) { - // Fill SD buffer - myFile.read(sdBuffer, 128); - - // Enable access to ports 0x120 and 0x2100 - send_GBM(0x09); - send_GBM(0x11); - - // Set bank - writeByte_GBM(0x2100, 0x1); - - // Disable ports 0x2100 and 0x120 or else those addresses will not be writable - send_GBM(0x10); - send_GBM(0x08); - - // Write flash buffer command - writeByte_GBM(0x5555, 0xAA); - writeByte_GBM(0x2AAA, 0x55); - writeByte_GBM(0x5555, 0xA0); - - // Wait until flashrom is ready again - while ((readByte_GBM(0) & 0x80) != 0x80) {} - - // Enable access to ports 0x120 and 0x2100 - send_GBM(0x09); - send_GBM(0x11); - - // Set bank - writeByte_GBM(0x2100, currBank); - - // Disable ports 0x2100 and 0x120 or else those addresses will not be writable - send_GBM(0x10); - send_GBM(0x08); - - // Fill flash buffer - for (word currByte = 0; currByte < 128; currByte++) { - writeByte_GBM(currAddress + currByte, sdBuffer[currByte]); - } - // Execute write - writeByte_GBM(currAddress + 127, 0xFF); - - // Wait for write to complete - while ((readByte_GBM(currAddress) & 0x80) != 0x80) {} - } - } - // Close the file: - myFile.close(); - println_Msg(F("Done")); - } - else { - print_Error(F("Can't open file"), false); - } -} - -void readMapping_GBM() { - // Enable ports 0x0120 - send_GBM(0x09); - - // Set WE and WP - send_GBM(0x0A); - send_GBM(0x2); - - // Enable hidden mapping area - writeByte_GBM(0x2100, 0x01); - send_GBM(0x0F, 0x5555, 0xAA); - send_GBM(0x0F, 0x2AAA, 0x55); - send_GBM(0x0F, 0x5555, 0x77); - send_GBM(0x0F, 0x5555, 0xAA); - send_GBM(0x0F, 0x2AAA, 0x55); - send_GBM(0x0F, 0x5555, 0x77); - - // Read mapping - println_Msg(F("Reading Mapping...")); - display_Update(); - - // Get name, add extension and convert to char array for sd lib - EEPROM_readAnything(0, foldern); - sprintf(fileName, "GBM%d", foldern); - strcat(fileName, ".map"); - sd.mkdir("NP", true); - sd.chdir("NP"); - // write new folder number back to eeprom - foldern = foldern + 1; - EEPROM_writeAnything(0, foldern); - - // Open file on sd card - if (!myFile.open(fileName, O_RDWR | O_CREAT)) { - print_Error(F("Can't create file on SD"), true); - } - else { - for (byte currByte = 0; currByte < 128; currByte++) { - sdBuffer[currByte] = readByte_GBM(currByte); - } - myFile.write(sdBuffer, 128); - - // Close the file: - myFile.close(); - - // Signal end of process - printSdBuffer(0, 20); - printSdBuffer(102, 20); - println_Msg(""); - print_Msg(F("Saved to NP/")); - println_Msg(fileName); - display_Update(); - } - - // Reset flash to leave hidden mapping area - resetFlash_GBM(); -} - -void eraseMapping_GBM() { - println_Msg(F("Erasing...")); - display_Update(); - - //enable access to ports 0120h - send_GBM(0x09); - // Enable write - send_GBM(0x0A); - send_GBM(0x2); - - // Unprotect sector 0 - send_GBM(0x0F, 0x5555, 0xAA); - send_GBM(0x0F, 0x2AAA, 0x55); - send_GBM(0x0F, 0x5555, 0x60); - send_GBM(0x0F, 0x5555, 0xAA); - send_GBM(0x0F, 0x2AAA, 0x55); - send_GBM(0x0F, 0x5555, 0x40); - - // Wait for unprotect to complete - while ((readByte_GBM(0) & 0x80) != 0x80) {} - - // Send erase command - send_GBM(0x0F, 0x5555, 0xAA); - send_GBM(0x0F, 0x2AAA, 0x55); - send_GBM(0x0F, 0x5555, 0x60); - send_GBM(0x0F, 0x5555, 0xAA); - send_GBM(0x0F, 0x2AAA, 0x55); - send_GBM(0x0F, 0x5555, 0x04); - - // Wait for erase to complete - while ((readByte_GBM(0) & 0x80) != 0x80) {} - - // Reset flashrom - resetFlash_GBM(); -} - -boolean blankcheckMapping_GBM() { - print_Msg(F("Blankcheck...")); - display_Update(); - - // Enable ports 0x0120 - send_GBM(0x09); - - // Set WE and WP - send_GBM(0x0A); - send_GBM(0x2); - - // Enable hidden mapping area - writeByte_GBM(0x2100, 0x01); - send_GBM(0x0F, 0x5555, 0xAA); - send_GBM(0x0F, 0x2AAA, 0x55); - send_GBM(0x0F, 0x5555, 0x77); - send_GBM(0x0F, 0x5555, 0xAA); - send_GBM(0x0F, 0x2AAA, 0x55); - send_GBM(0x0F, 0x5555, 0x77); - - // Disable ports 0x0120... - send_GBM(0x08); - - // Read rom - for (byte currByte = 0; currByte < 128; currByte++) { - if (readByte_GBM(currByte) != 0xFF) { - return 0; - } - } - return 1; -} - -void writeMapping_GBM() { - print_Msg(F("Writing...")); - display_Update(); - - // Open file on sd card - if (myFile.open(filePath, O_READ)) { - // Get map file size and check if it exceeds 128KByte - if (myFile.fileSize() > 0x80) { - print_Error(F("File is too big."), true); - } - - // Enable access to ports 0120h - send_GBM(0x09); - - // Enable write - send_GBM(0x0A); - send_GBM(0x2); - - // Map entire flash rom - send_GBM(0x4); - - // Set bank, writes to 0x5555 need odd bank number - writeByte_GBM(0x2100, 0x1); - - // Disable ports 0x2100 and 0x120 or else those addresses will not be writable - send_GBM(0x10); - send_GBM(0x08); - - // Unlock write to map area - writeByte_GBM(0x5555, 0xAA); - writeByte_GBM(0x2AAA, 0x55); - writeByte_GBM(0x5555, 0x60); - writeByte_GBM(0x5555, 0xAA); - writeByte_GBM(0x2AAA, 0x55); - writeByte_GBM(0x5555, 0xE0); - - // Check if flashrom is ready for writing or busy - while ((readByte_GBM(0) & 0x80) != 0x80) {} - - // Fill SD buffer - myFile.read(sdBuffer, 128); - - // Enable access to ports 0x120 and 0x2100 - send_GBM(0x09); - send_GBM(0x11); - - // Set bank - writeByte_GBM(0x2100, 0x1); - - // Disable ports 0x2100 and 0x120 or else those addresses will not be writable - send_GBM(0x10); - send_GBM(0x08); - - // Write flash buffer command - writeByte_GBM(0x5555, 0xAA); - writeByte_GBM(0x2AAA, 0x55); - writeByte_GBM(0x5555, 0xA0); - - // Wait until flashrom is ready again - while ((readByte_GBM(0) & 0x80) != 0x80) {} - - // Enable access to ports 0x120 and 0x2100 - send_GBM(0x09); - send_GBM(0x11); - - // Set bank - writeByte_GBM(0x2100, 0); - - // Disable ports 0x2100 and 0x120 or else those addresses will not be writable - send_GBM(0x10); - send_GBM(0x08); - - // Fill flash buffer - for (word currByte = 0; currByte < 128; currByte++) { - // Blink led - PORTB ^= (1 << 4); - - writeByte_GBM(currByte, sdBuffer[currByte]); - } - // Execute write - writeByte_GBM(127, 0xFF); - - // Close the file: - myFile.close(); - println_Msg(F("Done")); - } - else { - print_Error(F("Can't open file"), false); - } -} - #endif //****************************************** diff --git a/Cart_Reader/PCE.ino b/Cart_Reader/PCE.ino index dd2462f..292b358 100644 --- a/Cart_Reader/PCE.ino +++ b/Cart_Reader/PCE.ino @@ -585,7 +585,7 @@ void read_tennokoe_bank_PCE(int bank_index) println_Msg(F("RAM bank size: 2KB")); // Get name, add extension and convert to char array for sd lib - sprintf(fileName, "BANKRAM%d.sav", bank_index+1); + sprintf(fileName, "BANKRAM%d.sav", bank_index + 1); // create a new folder for the save file EEPROM_readAnything(0, foldern); @@ -603,7 +603,7 @@ void read_tennokoe_bank_PCE(int bank_index) // write new folder number back to eeprom foldern = foldern + 1; EEPROM_writeAnything(0, foldern); - + //open file on sd card if (!myFile.open(fileName, O_RDWR | O_CREAT)) { print_Error(F("Can't create file on SD"), true); @@ -620,7 +620,7 @@ void read_tennokoe_bank_PCE(int bank_index) data_input_PCE(); //Read Tennokoe bank RAM - read_bank_PCE_RAM(0x080000 + 2048UL*bank_index, block_index); + read_bank_PCE_RAM(0x080000 + 2048UL * bank_index, block_index); //Lock Tennokoe Bank RAM data_output_PCE(); @@ -726,7 +726,7 @@ void write_tennokoe_bank_PCE(int bank_index) unlock_tennokoe_bank_RAM(); data_input_PCE(); //Read Tennokoe bank RAM - read_bank_PCE_RAM(0x080000 + 2048UL*bank_index, block_index); + read_bank_PCE_RAM(0x080000 + 2048UL * bank_index, block_index); //Lock Tennokoe Bank RAM data_output_PCE(); lock_tennokoe_bank_RAM(); @@ -750,7 +750,7 @@ void write_tennokoe_bank_PCE(int bank_index) println_Msg(F(" bytes ")); print_Error(F("did not verify."), false); } - + pin_init_PCE(); // Close the file: @@ -862,8 +862,8 @@ void pceMenu() { if (pce_internal_mode == HUCARD || pce_internal_mode == HUCARD_NOSWAP) { - sprintf(pceCartMenuItem2, "Read RAM Bank %d", tennokoe_bank_index+1); - sprintf(pceCartMenuItem3, "Write RAM Bank %d", tennokoe_bank_index+1); + sprintf(pceCartMenuItem2, "Read RAM Bank %d", tennokoe_bank_index + 1); + sprintf(pceCartMenuItem3, "Write RAM Bank %d", tennokoe_bank_index + 1); strcpy(menuOptionspceCart[0], pceCartMenuItem1); strcpy(menuOptionspceCart[1], pceCartMenuItem2); strcpy(menuOptionspceCart[2], pceCartMenuItem3); diff --git a/Cart_Reader/README.md b/Cart_Reader/README.md index c3d3b63..302c8ab 100644 --- a/Cart_Reader/README.md +++ b/Cart_Reader/README.md @@ -60,5 +60,6 @@ Needed libraries(already included in the portable Arduino IDE under Releases) SD lib: https://github.com/greiman/SdFat LCD lib: https://github.com/adafruit/Adafruit_SSD1306 GFX Lib: https://github.com/adafruit/Adafruit-GFX-Library +BusIO: https://github.com/adafruit/Adafruit_BusIO RGB Tools lib: https://github.com/joushx/Arduino-RGB-Tools SI5351 lib: https://github.com/etherkit/Si5351Arduino diff --git a/Cart_Reader/options.h b/Cart_Reader/options.h index 5845ab3..31d8ca1 100644 --- a/Cart_Reader/options.h +++ b/Cart_Reader/options.h @@ -16,20 +16,15 @@ #define enable_Button2 // define enable_XXX to enable +#define enable_FLASH +#define enable_GBX #define enable_MD -#define enable_SMS - -#define enable_PCE - +#define enable_N64 #define enable_NES +#define enable_NGP +#define enable_NP +#define enable_PCE +#define enable_SMS #define enable_SNES #define enable_SV -#define enable_NP -#define enable_GBX -#define enable_N64 - #define enable_WS - -#define enable_NGP - -#define enable_FLASH