From 8e155cf97b1a4d30a2cdeb80eed72e7bb082654f Mon Sep 17 00:00:00 2001 From: Kreeblah Date: Thu, 24 Feb 2022 15:59:25 -0800 Subject: [PATCH] Fixed build warnings --- Cart_Reader/GB.ino | 3418 +++++++++++++++++++------------------- Cart_Reader/NES.ino | 4 +- Cart_Reader/PCE.ino | 1910 ++++++++++----------- Cart_Reader/SMS.ino | 4 +- Cart_Reader/snes_clk.cpp | 4 +- 5 files changed, 2670 insertions(+), 2670 deletions(-) diff --git a/Cart_Reader/GB.ino b/Cart_Reader/GB.ino index f03c029..f0a7169 100644 --- a/Cart_Reader/GB.ino +++ b/Cart_Reader/GB.ino @@ -1,1709 +1,1709 @@ -//****************************************** -// GAME BOY MODULE -//****************************************** - -#include "options.h" -#ifdef enable_GBX - -/****************************************** - Variables - *****************************************/ -// Game Boy -int sramBanks; -int romBanks; -word lastByte = 0; - -/****************************************** - Menu - *****************************************/ -// GBx start menu -static const char gbxMenuItem1[] PROGMEM = "Game Boy (Color)"; -static const char gbxMenuItem2[] PROGMEM = "Game Boy Advance"; -static const char gbxMenuItem3[] PROGMEM = "Flash GBC Cart"; -static const char gbxMenuItem4[] PROGMEM = "Reset"; -static const char* const menuOptionsGBx[] PROGMEM = {gbxMenuItem1, gbxMenuItem2, gbxMenuItem3, gbxMenuItem4}; - -// GB menu items -static const char GBMenuItem1[] PROGMEM = "Read Rom"; -static const char GBMenuItem2[] PROGMEM = "Read Save"; -static const char GBMenuItem3[] PROGMEM = "Write Save"; -static const char GBMenuItem4[] PROGMEM = "Reset"; -static const char* const menuOptionsGB[] PROGMEM = {GBMenuItem1, GBMenuItem2, GBMenuItem3, GBMenuItem4}; - -// GB Flash items -static const char GBFlashItem1[] PROGMEM = "CFI Cart"; -static const char GBFlashItem2[] PROGMEM = "CFI Cart and Save"; -static const char GBFlashItem3[] PROGMEM = "29F Cart (MBC3)"; -static const char GBFlashItem4[] PROGMEM = "29F Cart (MBC5)"; -static const char GBFlashItem5[] PROGMEM = "NPower GB Memory"; -static const char GBFlashItem6[] PROGMEM = "GB Smart"; -static const char GBFlashItem7[] PROGMEM = "Reset"; -static const char* const menuOptionsGBFlash[] PROGMEM = {GBFlashItem1, GBFlashItem2, GBFlashItem3, GBFlashItem4, GBFlashItem5, GBFlashItem6, GBFlashItem7}; - -// Start menu for both GB and GBA -void gbxMenu() { - // create menu with title and 4 options to choose from - unsigned char gbType; - // Copy menuOptions out of progmem - convertPgm(menuOptionsGBx, 4); - gbType = question_box(F("Select Game Boy"), menuOptions, 4, 0); - - // wait for user choice to come back from the question box menu - switch (gbType) - { - case 0: - display_Clear(); - display_Update(); - setup_GB(); - mode = mode_GB; - break; - - case 1: - display_Clear(); - display_Update(); - setup_GBA(); - mode = mode_GBA; - break; - - case 2: - // create submenu with title and 7 options to choose from - unsigned char gbFlash; - // Copy menuOptions out of progmem - convertPgm(menuOptionsGBFlash, 7); - gbFlash = question_box(F("Select type"), menuOptions, 7, 0); - - // wait for user choice to come back from the question box menu - switch (gbFlash) - { - case 0: - // Flash CFI - display_Clear(); - display_Update(); - setup_GB(); - mode = mode_GB; - - // Change working dir to root - sd.chdir("/"); - // Launch filebrowser - filePath[0] = '\0'; - sd.chdir("/"); - fileBrowser(F("Select file")); - display_Clear(); - identifyCFI_GB(); - if (!writeCFI_GB()) { - display_Clear(); - println_Msg(F("Flashing failed, time out!")); - println_Msg(F("Press button...")); - display_Update(); - wait(); - } - // Reset - wait(); - resetArduino(); - break; - - case 1: - // Flash CFI and Save - display_Clear(); - display_Update(); - setup_GB(); - mode = mode_GB; - - // Change working dir to root - sd.chdir("/"); - // Launch filebrowser - filePath[0] = '\0'; - sd.chdir("/"); - fileBrowser(F("Select file")); - display_Clear(); - identifyCFI_GB(); - if (!writeCFI_GB()) { - display_Clear(); - println_Msg(F("Flashing failed, time out!")); - println_Msg(F("Press button...")); - display_Update(); - wait(); - resetArduino(); - } - getCartInfo_GB(); - // Does cartridge have SRAM - if (lastByte > 0) { - // Remove file name ending - int pos = -1; - while (fileName[++pos] != '\0') { - if (fileName[pos] == '.') { - fileName[pos] = '\0'; - break; - } - } - sprintf(filePath, "/GB/SAVE/%s/", fileName); - bool saveFound = false; - if (sd.exists(filePath)) { - EEPROM_readAnything(0, foldern); - for (int i = foldern; i >= 0; i--) { - sprintf(filePath, "/GB/SAVE/%s/%d/%s.SAV", fileName, i, fileName); - if (sd.exists(filePath)) { - print_Msg(F("Save number ")); - print_Msg(i); - println_Msg(F(" found.")); - saveFound = true; - sprintf(filePath, "/GB/SAVE/%s/%d", fileName, i); - sprintf(fileName, "%s.SAV", fileName); - writeSRAM_GB(); - unsigned long wrErrors; - wrErrors = verifySRAM_GB(); - if (wrErrors == 0) { - println_Msg(F("Verified OK")); - display_Update(); - } - else { - print_Msg(F("Error: ")); - print_Msg(wrErrors); - println_Msg(F(" bytes ")); - print_Error(F("did not verify."), false); - } - break; - } - } - } - if (!saveFound) { - println_Msg(F("Error: No save found.")); - } - } - else { - print_Error(F("Cart has no Sram"), false); - } - // Reset - wait(); - resetArduino(); - break; - - case 2: - //Flash MBC3 - display_Clear(); - display_Update(); - setup_GB(); - mode = mode_GB; - - // Change working dir to root - sd.chdir("/"); - //MBC3 - writeFlash29F_GB(3); - // Reset - wait(); - resetArduino(); - break; - - case 3: - //Flash MBC5 - display_Clear(); - display_Update(); - setup_GB(); - mode = mode_GB; - - // Change working dir to root - sd.chdir("/"); - //MBC5 - writeFlash29F_GB(5); - // Reset - wait(); - resetArduino(); - break; - - case 4: - // Flash GB Memory - display_Clear(); - display_Update(); - setup_GBM(); - mode = mode_GBM; - break; - - case 5: - // Flash GB Smart - display_Clear(); - display_Update(); - setup_GBSmart(); - mode = mode_GB_GBSmart; - break; - - case 6: - resetArduino(); - break; - } - break; - - case 3: - resetArduino(); - break; - } -} - -void gbMenu() { - // create menu with title and 3 options to choose from - unsigned char mainMenu; - // Copy menuOptions out of progmem - convertPgm(menuOptionsGB, 4); - mainMenu = question_box(F("GB Cart Reader"), menuOptions, 4, 0); - - // wait for user choice to come back from the question box menu - switch (mainMenu) - { - case 0: - display_Clear(); - // Change working dir to root - sd.chdir("/"); - readROM_GB(); - compare_checksum_GB(); - break; - - case 1: - display_Clear(); - // Does cartridge have SRAM - if (lastByte > 0) { - // Change working dir to root - sd.chdir("/"); - readSRAM_GB(); - } - else { - print_Error(F("Cart has no Sram"), false); - } - break; - - case 2: - display_Clear(); - // Does cartridge have SRAM - if (lastByte > 0) { - // Change working dir to root - sd.chdir("/"); - filePath[0] = '\0'; - fileBrowser(F("Select sav file")); - writeSRAM_GB(); - unsigned long wrErrors; - wrErrors = verifySRAM_GB(); - if (wrErrors == 0) { - println_Msg(F("Verified OK")); - display_Update(); - } - else { - print_Msg(F("Error: ")); - print_Msg(wrErrors); - println_Msg(F(" bytes ")); - print_Error(F("did not verify."), false); - } - } - else { - print_Error(F("Cart has no Sram"), false); - } - break; - - case 3: - resetArduino(); - break; - } - println_Msg(F("")); - println_Msg(F("Press Button...")); - display_Update(); - wait(); -} - -/****************************************** - Setup - *****************************************/ -void setup_GB() { - // Set Address Pins to Output - //A0-A7 - DDRF = 0xFF; - //A8-A15 - DDRK = 0xFF; - - // Set Control Pins to Output RST(PH0) CLK(PH1) CS(PH3) WR(PH5) RD(PH6) - DDRH |= (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 6); - // Output a high signal on all pins, pins are active low therefore everything is disabled now - PORTH |= (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 6); - - // Set Data Pins (D0-D7) to Input - DDRC = 0x00; - // Disable Internal Pullups - //PORTC = 0x00; - - delay(400); - - // Print start page - getCartInfo_GB(); - showCartInfo_GB(); -} - -void showCartInfo_GB() { - display_Clear(); - if (strcmp(checksumStr, "00") != 0) { - println_Msg(F("GB Cart Info")); - print_Msg(F("Name: ")); - println_Msg(romName); - print_Msg(F("Mapper: ")); - - if ((romType == 0) || (romType == 8) || (romType == 9)) - print_Msg(F("none")); - else if ((romType == 1) || (romType == 2) || (romType == 3)) - print_Msg(F("MBC1")); - else if ((romType == 5) || (romType == 6)) - print_Msg(F("MBC2")); - else if ((romType == 11) || (romType == 12) || (romType == 13)) - print_Msg(F("MMM01")); - else if ((romType == 15) || (romType == 16) || (romType == 17) || (romType == 18) || (romType == 19)) - print_Msg(F("MBC3")); - else if ((romType == 21) || (romType == 22) || (romType == 23)) - print_Msg(F("MBC4")); - else if ((romType == 25) || (romType == 26) || (romType == 27) || (romType == 28) || (romType == 29) || (romType == 309)) - print_Msg(F("MBC5")); - if (romType == 252) - print_Msg(F("Camera")); - - println_Msg(F(" ")); - print_Msg(F("Rom Size: ")); - switch (romSize) { - case 0: - print_Msg(F("32KB")); - break; - - case 1: - print_Msg(F("64KB")); - break; - - case 2: - print_Msg(F("128KB")); - break; - - case 3: - print_Msg(F("256KB")); - break; - - case 4: - print_Msg(F("512KB")); - break; - - case 5: - print_Msg(F("1MB")); - break; - - case 6: - print_Msg(F("2MB")); - break; - - case 7: - print_Msg(F("4MB")); - break; - } - - println_Msg(F("")); - print_Msg(F("Banks: ")); - println_Msg(romBanks); - - print_Msg(F("Sram Size: ")); - switch (sramSize) { - case 0: - if (romType == 6) { - print_Msg(F("512B")); - } - else { - print_Msg(F("none")); - } - break; - case 1: - print_Msg(F("2KB")); - break; - - case 2: - print_Msg(F("8KB")); - break; - - case 3: - print_Msg(F("32KB")); - break; - - case 4: - print_Msg(F("128KB")); - break; - - default: print_Msg(F("none")); - } - println_Msg(F("")); - print_Msg(F("Checksum: ")); - println_Msg(checksumStr); - display_Update(); - - // Wait for user input - println_Msg(F("Press Button...")); - display_Update(); - wait(); - } - else { - print_Error(F("GAMEPAK ERROR"), true); - } -} - -/****************************************** - Low level functions -*****************************************/ -// Switch data pins to read -void dataIn_GB() { - // Set to Input - DDRC = 0x00; -} - -byte readByte_GB(word myAddress) { - PORTF = myAddress & 0xFF; - PORTK = (myAddress >> 8) & 0xFF; - - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); - - // Switch RD(PH6) to LOW - PORTH &= ~(1 << 6); - - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); - - // Read - byte tempByte = PINC; - - // Switch and RD(PH6) to HIGH - PORTH |= (1 << 6); - - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); - - return tempByte; -} - -void writeByte_GB(int myAddress, byte myData) { - PORTF = myAddress & 0xFF; - PORTK = (myAddress >> 8) & 0xFF; - PORTC = myData; - - // Arduino running at 16Mhz -> one nop = 62.5ns - // Wait till output is stable - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); - - // Pull WR(PH5) low - PORTH &= ~(1 << 5); - - // Leave WE low for at least 60ns - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); - - // Pull WR(PH5) HIGH - PORTH |= (1 << 5); - - // Leave WE high for at least 50ns - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); -} - -byte readByteCLK_GB(word myAddress) { - PORTF = myAddress & 0xFF; - PORTK = (myAddress >> 8) & 0xFF; - - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); - - // Pull CS(PH3) CLK(PH1)(for FRAM MOD) LOW - PORTH &= ~((1 << 3) | (1 << 1)); - // Pull RD(PH6) LOW - PORTH &= ~(1 << 6); - - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); - - // Read - byte tempByte = PINC; - - // Pull RD(PH6) HIGH - PORTH |= (1 << 6); - // Pull CS(PH3) CLK(PH1)(for FRAM MOD) HIGH - PORTH |= (1 << 3) | (1 << 1); - - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); - - return tempByte; -} - -void writeByteCLK_GB(int myAddress, byte myData) { - PORTF = myAddress & 0xFF; - PORTK = (myAddress >> 8) & 0xFF; - PORTC = myData; - - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); - - // Pull CS(PH3) CLK(PH1)(for FRAM MOD) LOW - PORTH &= ~((1 << 3) | (1 << 1)); - // Pull WR(PH5) low - PORTH &= ~(1 << 5); - - // Leave WE low for at least 60ns - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); - - // Pull WR(PH5) HIGH - PORTH |= (1 << 5); - // Pull CS(PH3) CLK(PH1)(for FRAM MOD) HIGH - PORTH |= (1 << 3) | (1 << 1); - - // Leave WE high for at least 50ns - __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); -} - -/****************************************** - Game Boy functions -*****************************************/ -// Read Cartridge Header -void getCartInfo_GB() { - romType = readByteCLK_GB(0x0147); - romSize = readByteCLK_GB(0x0148); - sramSize = readByteCLK_GB(0x0149); - - // ROM banks - switch (romSize) { - case 0x00: - romBanks = 2; - break; - case 0x01: - romBanks = 4; - break; - case 0x02: - romBanks = 8; - break; - case 0x03: - romBanks = 16; - break; - case 0x04: - romBanks = 32; - break; - case 0x05: - romBanks = 64; - break; - case 0x06: - romBanks = 128; - break; - case 0x07: - romBanks = 256; - break; - default: - romBanks = 2; - } - - // SRAM banks - sramBanks = 0; - if (romType == 6) { - sramBanks = 1; - } - - // SRAM size - switch (sramSize) { - case 2: - sramBanks = 1; - break; - case 3: - sramBanks = 4; - break; - case 4: - sramBanks = 16; - break; - case 5: - sramBanks = 8; - break; - } - - // Last byte of SRAM - if (romType == 6) { - lastByte = 0xA1FF; - } - if (sramSize == 1) { - lastByte = 0xA7FF; - } - else if (sramSize > 1) { - lastByte = 0xBFFF; - } - - // Get Checksum as string - sprintf(checksumStr, "%02X%02X", readByteCLK_GB(0x014E), readByteCLK_GB(0x014F)); - - // Get name - byte myByte = 0; - byte myLength = 0; - - for (int addr = 0x0134; addr <= 0x13C; addr++) { - myByte = readByteCLK_GB(addr); - if (((char(myByte) >= 48 && char(myByte) <= 57) || (char(myByte) >= 65 && char(myByte) <= 122)) && myLength < 15) { - romName[myLength] = char(myByte); - myLength++; - } - } -} - -/****************************************** - ROM functions -*****************************************/ -// Read ROM -void readROM_GB() { - // Get name, add extension and convert to char array for sd lib - strcpy(fileName, romName); - strcat(fileName, ".GB"); - - // create a new folder for the rom file - EEPROM_readAnything(0, foldern); - sprintf(folder, "GB/ROM/%s/%d", romName, foldern); - sd.mkdir(folder, true); - sd.chdir(folder); - - 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(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); - } - - word romAddress = 0; - - //Initialize progress bar - uint32_t processedProgressBar = 0; - uint32_t totalProgressBar = (uint32_t)(romBanks - 1); - draw_progressbar(0, totalProgressBar); - - for (word currBank = 1; currBank < romBanks; currBank++) { - // Switch data pins to output - dataOut(); - - // Set ROM bank for MBC2/3/4/5 - if (romType >= 5) { - writeByte_GB(0x2100, currBank); - } - // Set ROM bank for MBC1 - else { - writeByte_GB(0x6000, 0); - writeByte_GB(0x4000, currBank >> 5); - writeByte_GB(0x2000, currBank & 0x1F); - } - - // Switch data pins to intput - dataIn_GB(); - - // Second bank starts at 0x4000 - if (currBank > 1) { - romAddress = 0x4000; - } - - // Read banks and save to SD - while (romAddress <= 0x7FFF) { - for (int i = 0; i < 512; i++) { - sdBuffer[i] = readByteCLK_GB(romAddress + i); - } - myFile.write(sdBuffer, 512); - romAddress += 512; - } - - processedProgressBar += 1; - draw_progressbar(processedProgressBar, totalProgressBar); - } - - // Close the file: - myFile.close(); -} - -// Calculate checksum -unsigned int calc_checksum_GB (char* fileName, char* folder) { - unsigned int calcChecksum = 0; - // int calcFilesize = 0; // unused - unsigned long i = 0; - int c = 0; - - if (strcmp(folder, "root") != 0) - sd.chdir(folder); - - // If file exists - if (myFile.open(fileName, O_READ)) { - //calcFilesize = myFile.fileSize() * 8 / 1024 / 1024; // unused - for (i = 0; i < (myFile.fileSize() / 512); i++) { - myFile.read(sdBuffer, 512); - for (c = 0; c < 512; c++) { - calcChecksum += sdBuffer[c]; - } - } - myFile.close(); - sd.chdir(); - // Subtract checksum bytes - calcChecksum -= readByteCLK_GB(0x014E); - calcChecksum -= readByteCLK_GB(0x014F); - - // Return result - return (calcChecksum); - } - // Else show error - else { - print_Error(F("DUMP ROM 1ST"), false); - return 0; - } -} - -// Compare checksum -boolean compare_checksum_GB() { - - println_Msg(F("Calculating Checksum")); - display_Update(); - - strcpy(fileName, romName); - strcat(fileName, ".GB"); - - // last used rom folder - EEPROM_readAnything(0, foldern); - sprintf(folder, "GB/ROM/%s/%d", romName, foldern - 1); - - char calcsumStr[5]; - sprintf(calcsumStr, "%04X", calc_checksum_GB(fileName, folder)); - - if (strcmp(calcsumStr, checksumStr) == 0) { - print_Msg(F("Result: ")); - println_Msg(calcsumStr); - println_Msg(F("Checksum matches")); - display_Update(); - return 1; - } - else { - print_Msg(F("Result: ")); - println_Msg(calcsumStr); - print_Error(F("Checksum Error"), false); - return 0; - } -} - -/****************************************** - SRAM functions -*****************************************/ -// Read RAM -void readSRAM_GB() { - // Does cartridge have RAM - if (lastByte > 0) { - - // Get name, add extension and convert to char array for sd lib - strcpy(fileName, romName); - strcat(fileName, ".sav"); - - // create a new folder for the save file - EEPROM_readAnything(0, foldern); - sprintf(folder, "GB/SAVE/%s/%d", romName, foldern); - sd.mkdir(folder, true); - sd.chdir(folder); - - // 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("SD Error"), true); - } - - dataIn_GB(); - - // MBC2 Fix - readByteCLK_GB(0x0134); - - dataOut(); - if (romType <= 4) { - writeByte_GB(0x6000, 1); - } - - // Initialise MBC - writeByte_GB(0x0000, 0x0A); - - // Switch SRAM banks - for (byte currBank = 0; currBank < sramBanks; currBank++) { - dataOut(); - writeByte_GB(0x4000, currBank); - - // Read SRAM - dataIn_GB(); - for (word sramAddress = 0xA000; sramAddress <= lastByte; sramAddress += 64) { - for (byte i = 0; i < 64; i++) { - sdBuffer[i] = readByteCLK_GB(sramAddress + i); - } - myFile.write(sdBuffer, 64); - } - } - - // Disable SRAM - dataOut(); - writeByte_GB(0x0000, 0x00); - dataIn_GB(); - - // Close the file: - myFile.close(); - - // Signal end of process - print_Msg(F("Saved to ")); - print_Msg(folder); - println_Msg(F("/")); - display_Update(); - } - else { - print_Error(F("Cart has no SRAM"), false); - } -} - -// Write RAM -void writeSRAM_GB() { - // Does cartridge have SRAM - if (lastByte > 0) { - // Create filepath - sprintf(filePath, "%s/%s", filePath, fileName); - - //open file on sd card - if (myFile.open(filePath, O_READ)) { - // Set pins to input - dataIn_GB(); - - // MBC2 Fix - readByteCLK_GB(0x0134); - - dataOut(); - - // Enable SRAM for MBC1 - if (romType <= 4) { - writeByte_GB(0x6000, 1); - } - - // Initialise MBC - writeByte_GB(0x0000, 0x0A); - - // Switch RAM banks - for (byte currBank = 0; currBank < sramBanks; currBank++) { - writeByte_GB(0x4000, currBank); - - // Write RAM - for (word sramAddress = 0xA000; sramAddress <= lastByte; sramAddress++) { - writeByteCLK_GB(sramAddress, myFile.read()); - } - } - // Disable SRAM - writeByte_GB(0x0000, 0x00); - - // Set pins to input - dataIn_GB(); - - // Close the file: - myFile.close(); - display_Clear(); - println_Msg(F("SRAM writing finished")); - display_Update(); - - } - else { - print_Error(F("File doesnt exist"), false); - } - } - else { - print_Error(F("Cart has no SRAM"), false); - } -} - -// Check if the SRAM was written without any error -unsigned long verifySRAM_GB() { - - //open file on sd card - if (myFile.open(filePath, O_READ)) { - - // Variable for errors - writeErrors = 0; - - dataIn_GB(); - - // MBC2 Fix - readByteCLK_GB(0x0134); - - // Check SRAM size - if (lastByte > 0) { - dataOut(); - if (romType <= 4) { // MBC1 - writeByte_GB(0x6000, 1); // Set RAM Mode - } - - // Initialise MBC - writeByte_GB(0x0000, 0x0A); - - // Switch SRAM banks - for (byte currBank = 0; currBank < sramBanks; currBank++) { - dataOut(); - writeByte_GB(0x4000, currBank); - - // Read SRAM - dataIn_GB(); - for (word sramAddress = 0xA000; sramAddress <= lastByte; sramAddress += 64) { - //fill sdBuffer - myFile.read(sdBuffer, 64); - for (int c = 0; c < 64; c++) { - if (readByteCLK_GB(sramAddress + c) != sdBuffer[c]) { - writeErrors++; - } - } - } - } - dataOut(); - // Disable RAM - writeByte_GB(0x0000, 0x00); - dataIn_GB(); - } - // Close the file: - myFile.close(); - return writeErrors; - } - else { - print_Error(F("Can't open file"), true); - } -} - -/****************************************** - 29F016/29F032/29F033 flashrom functions -*****************************************/ -// Write 29F032 flashrom -// A0-A13 directly connected to cart edge -> 16384(0x0-0x3FFF) bytes per bank -> 256(0x0-0xFF) banks -// A14-A21 connected to MBC5 -void writeFlash29F_GB(byte MBC) { - // Launch filebrowser - filePath[0] = '\0'; - sd.chdir("/"); - fileBrowser(F("Select file")); - display_Clear(); - - // Create filepath - sprintf(filePath, "%s/%s", filePath, fileName); - - // Open file on sd card - if (myFile.open(filePath, O_READ)) { - // Get rom size from file - myFile.seekCur(0x147); - romType = myFile.read(); - romSize = myFile.read(); - // Go back to file beginning - myFile.seekSet(0); - - // ROM banks - switch (romSize) { - case 0x00: - romBanks = 2; - break; - case 0x01: - romBanks = 4; - break; - case 0x02: - romBanks = 8; - break; - case 0x03: - romBanks = 16; - break; - case 0x04: - romBanks = 32; - break; - case 0x05: - romBanks = 64; - break; - case 0x06: - romBanks = 128; - break; - case 0x07: - romBanks = 256; - break; - default: - romBanks = 2; - } - - // Set data pins to output - dataOut(); - - // Set ROM bank hi 0 - writeByte_GB(0x3000, 0); - // Set ROM bank low 0 - writeByte_GB(0x2000, 0); - delay(100); - - // Reset flash - writeByte_GB(0x555, 0xf0); - delay(100); - - // ID command sequence - writeByte_GB(0x555, 0xaa); - writeByte_GB(0x2aa, 0x55); - writeByte_GB(0x555, 0x90); - - dataIn_GB(); - - // Read the two id bytes into a string - sprintf(flashid, "%02X%02X", readByte_GB(0), readByte_GB(1)); - - if (strcmp(flashid, "04D4") == 0) { - println_Msg(F("MBM29F033C")); - print_Msg(F("Banks: ")); - print_Msg(romBanks); - println_Msg(F("/256")); - display_Update(); - } - else if (strcmp(flashid, "0141") == 0) { - println_Msg(F("AM29F032B")); - print_Msg(F("Banks: ")); - print_Msg(romBanks); - println_Msg(F("/256")); - display_Update(); - } - else if (strcmp(flashid, "01AD") == 0) { - println_Msg(F("AM29F016B")); - print_Msg(F("Banks: ")); - print_Msg(romBanks); - println_Msg(F("/128")); - display_Update(); - } - else if (strcmp(flashid, "04AD") == 0) { - println_Msg(F("AM29F016D")); - print_Msg(F("Banks: ")); - print_Msg(romBanks); - println_Msg(F("/128")); - display_Update(); - } - else if (strcmp(flashid, "01D5") == 0) { - println_Msg(F("AM29F080B")); - print_Msg(F("Banks: ")); - print_Msg(romBanks); - println_Msg(F("/64")); - display_Update(); - } - else { - print_Msg(F("Flash ID: ")); - println_Msg(flashid); - display_Update(); - print_Error(F("Unknown flashrom"), true); - } - dataOut(); - - // Reset flash - writeByte_GB(0x555, 0xf0); - - delay(100); - println_Msg(F("Erasing flash")); - display_Update(); - - // Erase flash - writeByte_GB(0x555, 0xaa); - writeByte_GB(0x2aa, 0x55); - writeByte_GB(0x555, 0x80); - writeByte_GB(0x555, 0xaa); - writeByte_GB(0x2aa, 0x55); - writeByte_GB(0x555, 0x10); - - dataIn_GB(); - - // Read the status register - byte statusReg = readByte_GB(0); - - // After a completed erase D7 will output 1 - while ((statusReg & 0x80) != 0x80) { - // Blink led - blinkLED(); - delay(100); - // Update Status - statusReg = readByte_GB(0); - } - - // Blankcheck - println_Msg(F("Blankcheck")); - display_Update(); - - // Read x number of banks - for (int currBank = 0; currBank < romBanks; currBank++) { - // Blink led - blinkLED(); - - dataOut(); - - // Set ROM bank - writeByte_GB(0x2000, currBank); - dataIn(); - - for (unsigned int currAddr = 0x4000; currAddr < 0x7FFF; currAddr += 512) { - for (int currByte = 0; currByte < 512; currByte++) { - sdBuffer[currByte] = readByte_GB(currAddr + currByte); - } - for (int j = 0; j < 512; j++) { - if (sdBuffer[j] != 0xFF) { - println_Msg(F("Not empty")); - print_Error(F("Erase failed"), true); - } - } - } - } - - if (MBC == 3) { - println_Msg(F("Writing flash MBC3")); - display_Update(); - - // Write flash - dataOut(); - - word currAddr = 0; - word endAddr = 0x3FFF; - - for (int currBank = 0; currBank < romBanks; currBank++) { - // Blink led - blinkLED(); - - // Set ROM bank - writeByte_GB(0x2100, currBank); - - if (currBank > 0) { - currAddr = 0x4000; - endAddr = 0x7FFF; - } - - while (currAddr <= endAddr) { - myFile.read(sdBuffer, 512); - - for (int currByte = 0; currByte < 512; currByte++) { - // Write command sequence - writeByte_GB(0x555, 0xaa); - writeByte_GB(0x2aa, 0x55); - writeByte_GB(0x555, 0xa0); - // Write current byte - writeByte_GB(currAddr + currByte, sdBuffer[currByte]); - - // Set data pins to input - dataIn(); - - // Setting CS(PH3) and OE/RD(PH6) LOW - PORTH &= ~((1 << 3) | (1 << 6)); - - // Busy check - while ((PINC & 0x80) != (sdBuffer[currByte] & 0x80)) { - } - - // Switch CS(PH3) and OE/RD(PH6) to HIGH - PORTH |= (1 << 3) | (1 << 6); - - // Set data pins to output - dataOut(); - } - currAddr += 512; - } - } - } - - else if (MBC == 5) { - println_Msg(F("Writing flash MBC5")); - display_Update(); - - // Write flash - dataOut(); - - for (int currBank = 0; currBank < romBanks; currBank++) { - // Blink led - blinkLED(); - - // Set ROM bank - writeByte_GB(0x2000, currBank); - // 0x2A8000 fix - writeByte_GB(0x4000, 0x0); - - for (unsigned int currAddr = 0x4000; currAddr < 0x7FFF; currAddr += 512) { - myFile.read(sdBuffer, 512); - - for (int currByte = 0; currByte < 512; currByte++) { - // Write command sequence - writeByte_GB(0x555, 0xaa); - writeByte_GB(0x2aa, 0x55); - writeByte_GB(0x555, 0xa0); - // Write current byte - writeByte_GB(currAddr + currByte, sdBuffer[currByte]); - - // Set data pins to input - dataIn(); - - // Setting CS(PH3) and OE/RD(PH6) LOW - PORTH &= ~((1 << 3) | (1 << 6)); - - // Busy check - while ((PINC & 0x80) != (sdBuffer[currByte] & 0x80)) { - } - - // Switch CS(PH3) and OE/RD(PH6) to HIGH - PORTH |= (1 << 3) | (1 << 6); - - // Set data pins to output - dataOut(); - } - } - } - } - - // Set data pins to input again - dataIn_GB(); - - println_Msg(F("Verifying")); - display_Update(); - - // Go back to file beginning - myFile.seekSet(0); - //unsigned int addr = 0; // unused - writeErrors = 0; - - // Verify flashrom - word romAddress = 0; - - // Read number of banks and switch banks - for (word bank = 1; bank < romBanks; bank++) { - // Switch data pins to output - dataOut(); - - if (romType >= 5) { // MBC2 and above - writeByte_GB(0x2100, bank); // Set ROM bank - } - else { // MBC1 - writeByte_GB(0x6000, 0); // Set ROM Mode - writeByte_GB(0x4000, bank >> 5); // Set bits 5 & 6 (01100000) of ROM bank - writeByte_GB(0x2000, bank & 0x1F); // Set bits 0 & 4 (00011111) of ROM bank - } - - // Switch data pins to intput - dataIn_GB(); - - if (bank > 1) { - romAddress = 0x4000; - } - // Blink led - blinkLED(); - - // Read up to 7FFF per bank - while (romAddress <= 0x7FFF) { - // Fill sdBuffer - myFile.read(sdBuffer, 512); - // Compare - for (int i = 0; i < 512; i++) { - if (readByte_GB(romAddress + i) != sdBuffer[i]) { - writeErrors++; - } - } - romAddress += 512; - } - } - // Close the file: - myFile.close(); - - if (writeErrors == 0) { - println_Msg(F("OK")); - display_Update(); - } - else { - print_Msg(F("Error: ")); - print_Msg(writeErrors); - println_Msg(F(" bytes ")); - print_Error(F("did not verify."), false); - } - } - else { - println_Msg(F("Can't open file")); - display_Update(); - } -} - -/****************************************** - CFU flashrom functions -*****************************************/ - -/* - Flash chips can either be in x8 mode or x16 mode and sometimes the two - least significant bits on flash cartridges' data lines are swapped. - This function reads a byte and compensates for the differences. - This is only necessary for commands to the flash, not for data read from the flash, the MBC or SRAM. - - address needs to be the x8 mode address of the flash register that should be read. -*/ -byte readByteCompensated(int address) { - byte data = readByte_GB(address >> (flashX16Mode ? 1 : 0)); - if (flashSwitchLastBits) { - return (data & 0b11111100) | ((data << 1) & 0b10) | ((data >> 1) & 0b01); - } - return data; -} - -/* - Flash chips can either be in x8 mode or x16 mode and sometimes the two - least significant bits on flash cartridges' data lines are swapped. - This function writes a byte and compensates for the differences. - This is only necessary for commands to the flash, not for data written to the flash, the MBC or SRAM. - . - address needs to be the x8 mode address of the flash register that should be read. -*/ -byte writeByteCompensated(int address, byte data) { - if (flashSwitchLastBits) { - data = (data & 0b11111100) | ((data << 1) & 0b10) | ((data >> 1) & 0b01); - } - writeByte_GB(address >> (flashX16Mode ? 1 : 0), data); -} - -void startCFIMode(boolean x16Mode) { - if (x16Mode) { - writeByte_GB(0x555, 0xf0); //x16 mode reset command - delay(500); - writeByte_GB(0x555, 0xf0); //Double reset to get out of possible Autoselect + CFI mode - delay(500); - writeByte_GB(0x55, 0x98); //x16 CFI Query command - } else { - writeByte_GB(0xAAA, 0xf0); //x8 mode reset command - delay(100); - writeByte_GB(0xAAA, 0xf0); //Double reset to get out of possible Autoselect + CFI mode - delay(100); - writeByte_GB(0xAA, 0x98); //x8 CFI Query command - } -} - -/* Identify the different flash chips. - Sets the global variables flashBanks, flashX16Mode and flashSwitchLastBits -*/ -void identifyCFI_GB() { - // Reset flash - display_Clear(); - dataOut(); - writeByte_GB(0x6000, 0); // Set ROM Mode - writeByte_GB(0x2000, 0); // Set Bank to 0 - writeByte_GB(0x3000, 0); - - startCFIMode(false); // Trying x8 mode first - - dataIn_GB(); - display_Clear(); - // Try x8 mode first - char cfiQRYx8[7]; - char cfiQRYx16[7]; - sprintf(cfiQRYx8, "%02X%02X%02X", readByte_GB(0x20), readByte_GB(0x22), readByte_GB(0x24)); - sprintf(cfiQRYx16, "%02X%02X%02X", readByte_GB(0x10), readByte_GB(0x11), readByte_GB(0x12)); // some devices use x8-style CFI Query command even though they are in x16 command mode - if (strcmp(cfiQRYx8, "515259") == 0) { // QRY in x8 mode - println_Msg(F("Normal CFI x8 Mode")); - flashX16Mode = false; - flashSwitchLastBits = false; - } else if (strcmp(cfiQRYx8, "52515A") == 0) { // QRY in x8 mode with switched last bit - println_Msg(F("Switched CFI x8 Mode")); - flashX16Mode = false; - flashSwitchLastBits = true; - } else if (strcmp(cfiQRYx16, "515259") == 0) { // QRY in x16 mode - println_Msg(F("Normal CFI x16 Mode")); - flashX16Mode = true; - flashSwitchLastBits = false; - } else if (strcmp(cfiQRYx16, "52515A") == 0) { // QRY in x16 mode with switched last bit - println_Msg(F("Switched CFI x16 Mode")); - flashX16Mode = true; - flashSwitchLastBits = true; - } else { - startCFIMode(true); // Try x16 mode next - sprintf(cfiQRYx16, "%02X%02X%02X", readByte_GB(0x10), readByte_GB(0x11), readByte_GB(0x12)); - if (strcmp(cfiQRYx16, "515259") == 0) { // QRY in x16 mode - println_Msg(F("Normal CFI x16 Mode")); - flashX16Mode = true; - flashSwitchLastBits = false; - } else if (strcmp(cfiQRYx16, "52515A") == 0) { // QRY in x16 mode with switched last bit - println_Msg(F("Switched CFI x16 Mode")); - flashX16Mode = true; - flashSwitchLastBits = true; - } else { - println_Msg(F("CFI Query failed!")); - display_Update(); - wait(); - return 0; - } - } - dataIn_GB(); - flashBanks = 1 << (readByteCompensated(0x4E) - 14); // - flashX16Mode); - dataOut(); - - // Reset flash - writeByteCompensated(0xAAA, 0xf0); - delay(100); -} - -// Write 29F032 flashrom -// A0-A13 directly connected to cart edge -> 16384(0x0-0x3FFF) bytes per bank -> 256(0x0-0xFF) banks -// A14-A21 connected to MBC5 -// identifyFlash_GB() needs to be run before this! -bool writeCFI_GB() { - // Create filepath - sprintf(filePath, "%s/%s", filePath, fileName); - - // Open file on sd card - if (myFile.open(filePath, O_READ)) { - // Get rom size from file - myFile.seekCur(0x147); - romType = myFile.read(); - romSize = myFile.read(); - // Go back to file beginning - myFile.seekSet(0); - - // ROM banks - switch (romSize) { - case 0x00: - romBanks = 2; - break; - case 0x01: - romBanks = 4; - break; - case 0x02: - romBanks = 8; - break; - case 0x03: - romBanks = 16; - break; - case 0x04: - romBanks = 32; - break; - case 0x05: - romBanks = 64; - break; - case 0x06: - romBanks = 128; - break; - case 0x07: - romBanks = 256; - break; - default: - romBanks = 2; - } - - if (romBanks <= flashBanks) { - print_Msg(F("Using ")); - print_Msg(romBanks); - print_Msg(F("/")); - print_Msg(flashBanks); - println_Msg(F(" Banks")); - display_Update(); - } else { - println_Msg(F("Error: Flash has too few banks!")); - print_Msg(F("Has ")); - print_Msg(flashBanks); - println_Msg(F(" banks,")); - print_Msg(F("but needs ")); - print_Msg(romBanks); - println_Msg(F(".")); - println_Msg(F("Press button...")); - display_Update(); - wait(); - resetArduino(); - } - - // Set data pins to output - dataOut(); - - // Set ROM bank hi 0 - writeByte_GB(0x3000, 0); - // Set ROM bank low 0 - writeByte_GB(0x2000, 0); - delay(100); - - // Reset flash - writeByteCompensated(0xAAA, 0xf0); - delay(100); - dataOut(); - - // Reset flash - writeByte_GB(0x555, 0xf0); - - delay(100); - println_Msg(F("Erasing flash")); - display_Update(); - - // Erase flash - writeByteCompensated(0xAAA, 0xaa); - writeByteCompensated(0x555, 0x55); - writeByteCompensated(0xAAA, 0x80); - writeByteCompensated(0xAAA, 0xaa); - writeByteCompensated(0x555, 0x55); - writeByteCompensated(0xAAA, 0x10); - - dataIn_GB(); - - // Read the status register - byte statusReg = readByte_GB(0); - - // After a completed erase D7 will output 1 - while ((statusReg & 0x80) != 0x80) { - // Blink led - blinkLED(); - delay(100); - // Update Status - statusReg = readByte_GB(0); - } - - // Blankcheck - println_Msg(F("Blankcheck")); - display_Update(); - - // Read x number of banks - for (int currBank = 0; currBank < romBanks; currBank++) { - // Blink led - blinkLED(); - - dataOut(); - - // Set ROM bank - writeByte_GB(0x2000, currBank); - dataIn(); - - for (unsigned int currAddr = 0x4000; currAddr < 0x7FFF; currAddr += 512) { - for (int currByte = 0; currByte < 512; currByte++) { - sdBuffer[currByte] = readByte_GB(currAddr + currByte); - } - for (int j = 0; j < 512; j++) { - if (sdBuffer[j] != 0xFF) { - println_Msg(F("Not empty")); - print_Error(F("Erase failed"), true); - } - } - } - } - - println_Msg(F("Writing flash MBC3/5")); - display_Update(); - - // Write flash - dataOut(); - - word currAddr = 0; - word endAddr = 0x3FFF; - - for (int currBank = 0; currBank < romBanks; currBank++) { - // Blink led - blinkLED(); - - // Set ROM bank - writeByte_GB(0x2100, currBank); - // 0x2A8000 fix - writeByte_GB(0x4000, 0x0); - - if (currBank > 0) { - currAddr = 0x4000; - endAddr = 0x7FFF; - } - - while (currAddr <= endAddr) { - myFile.read(sdBuffer, 512); - - for (int currByte = 0; currByte < 512; currByte++) { - // Write command sequence - writeByteCompensated(0xAAA, 0xaa); - writeByteCompensated(0x555, 0x55); - writeByteCompensated(0xAAA, 0xa0); - - // Write current byte - writeByte_GB(currAddr + currByte, sdBuffer[currByte]); - - // Set data pins to input - dataIn(); - - // Setting CS(PH3) and OE/RD(PH6) LOW - PORTH &= ~((1 << 3) | (1 << 6)); - - // Busy check - short i = 0; - while ((PINC & 0x80) != (sdBuffer[currByte] & 0x80)) { - i++; - if (i > 500) { - if (currAddr < 0x4000) { // This happens when trying to flash an MBC5 as if it was an MBC3. Retry to flash as MBC5, starting from last successfull byte. - currByte--; - currAddr += 0x4000; - endAddr = 0x7FFF; - break; - } else { // If a timeout happens while trying to flash MBC5-style, flashing failed. - return false; - } - } - } - - // Switch CS(PH3) and OE/RD(PH6) to HIGH - PORTH |= (1 << 3) | (1 << 6); - __asm__("nop\n\tnop\n\tnop\n\t"); // Waste a few CPU cycles to remove write errors - - // Set data pins to output - dataOut(); - } - currAddr += 512; - } - } - - // Set data pins to input again - dataIn_GB(); - - display_Clear(); - println_Msg(F("Verifying")); - display_Update(); - - // Go back to file beginning - myFile.seekSet(0); - //unsigned int addr = 0; // unused - writeErrors = 0; - - // Verify flashrom - word romAddress = 0; - - // Read number of banks and switch banks - for (word bank = 1; bank < romBanks; bank++) { - // Switch data pins to output - dataOut(); - - if (romType >= 5) { // MBC2 and above - writeByte_GB(0x2100, bank); // Set ROM bank - } - else { // MBC1 - writeByte_GB(0x6000, 0); // Set ROM Mode - writeByte_GB(0x4000, bank >> 5); // Set bits 5 & 6 (01100000) of ROM bank - writeByte_GB(0x2000, bank & 0x1F); // Set bits 0 & 4 (00011111) of ROM bank - } - - // Switch data pins to intput - dataIn_GB(); - - if (bank > 1) { - romAddress = 0x4000; - } - // Blink led - blinkLED(); - - // Read up to 7FFF per bank - while (romAddress <= 0x7FFF) { - // Fill sdBuffer - myFile.read(sdBuffer, 512); - // Compare - for (int i = 0; i < 512; i++) { - if (readByte_GB(romAddress + i) != sdBuffer[i]) { - writeErrors++; - } - } - romAddress += 512; - } - } - // Close the file: - myFile.close(); - - if (writeErrors == 0) { - println_Msg(F("OK")); - display_Update(); - } - else { - print_Msg(F("Error: ")); - print_Msg(writeErrors); - println_Msg(F(" bytes ")); - print_Error(F("did not verify."), false); - } - } - else { - println_Msg(F("Can't open file")); - display_Update(); - } - return true; -} - -#endif - -//****************************************** -// End of File -//****************************************** +//****************************************** +// GAME BOY MODULE +//****************************************** + +#include "options.h" +#ifdef enable_GBX + +/****************************************** + Variables + *****************************************/ +// Game Boy +int sramBanks; +int romBanks; +word lastByte = 0; + +/****************************************** + Menu + *****************************************/ +// GBx start menu +static const char gbxMenuItem1[] PROGMEM = "Game Boy (Color)"; +static const char gbxMenuItem2[] PROGMEM = "Game Boy Advance"; +static const char gbxMenuItem3[] PROGMEM = "Flash GBC Cart"; +static const char gbxMenuItem4[] PROGMEM = "Reset"; +static const char* const menuOptionsGBx[] PROGMEM = {gbxMenuItem1, gbxMenuItem2, gbxMenuItem3, gbxMenuItem4}; + +// GB menu items +static const char GBMenuItem1[] PROGMEM = "Read Rom"; +static const char GBMenuItem2[] PROGMEM = "Read Save"; +static const char GBMenuItem3[] PROGMEM = "Write Save"; +static const char GBMenuItem4[] PROGMEM = "Reset"; +static const char* const menuOptionsGB[] PROGMEM = {GBMenuItem1, GBMenuItem2, GBMenuItem3, GBMenuItem4}; + +// GB Flash items +static const char GBFlashItem1[] PROGMEM = "CFI Cart"; +static const char GBFlashItem2[] PROGMEM = "CFI Cart and Save"; +static const char GBFlashItem3[] PROGMEM = "29F Cart (MBC3)"; +static const char GBFlashItem4[] PROGMEM = "29F Cart (MBC5)"; +static const char GBFlashItem5[] PROGMEM = "NPower GB Memory"; +static const char GBFlashItem6[] PROGMEM = "GB Smart"; +static const char GBFlashItem7[] PROGMEM = "Reset"; +static const char* const menuOptionsGBFlash[] PROGMEM = {GBFlashItem1, GBFlashItem2, GBFlashItem3, GBFlashItem4, GBFlashItem5, GBFlashItem6, GBFlashItem7}; + +// Start menu for both GB and GBA +void gbxMenu() { + // create menu with title and 4 options to choose from + unsigned char gbType; + // Copy menuOptions out of progmem + convertPgm(menuOptionsGBx, 4); + gbType = question_box(F("Select Game Boy"), menuOptions, 4, 0); + + // wait for user choice to come back from the question box menu + switch (gbType) + { + case 0: + display_Clear(); + display_Update(); + setup_GB(); + mode = mode_GB; + break; + + case 1: + display_Clear(); + display_Update(); + setup_GBA(); + mode = mode_GBA; + break; + + case 2: + // create submenu with title and 7 options to choose from + unsigned char gbFlash; + // Copy menuOptions out of progmem + convertPgm(menuOptionsGBFlash, 7); + gbFlash = question_box(F("Select type"), menuOptions, 7, 0); + + // wait for user choice to come back from the question box menu + switch (gbFlash) + { + case 0: + // Flash CFI + display_Clear(); + display_Update(); + setup_GB(); + mode = mode_GB; + + // Change working dir to root + sd.chdir("/"); + // Launch filebrowser + filePath[0] = '\0'; + sd.chdir("/"); + fileBrowser(F("Select file")); + display_Clear(); + identifyCFI_GB(); + if (!writeCFI_GB()) { + display_Clear(); + println_Msg(F("Flashing failed, time out!")); + println_Msg(F("Press button...")); + display_Update(); + wait(); + } + // Reset + wait(); + resetArduino(); + break; + + case 1: + // Flash CFI and Save + display_Clear(); + display_Update(); + setup_GB(); + mode = mode_GB; + + // Change working dir to root + sd.chdir("/"); + // Launch filebrowser + filePath[0] = '\0'; + sd.chdir("/"); + fileBrowser(F("Select file")); + display_Clear(); + identifyCFI_GB(); + if (!writeCFI_GB()) { + display_Clear(); + println_Msg(F("Flashing failed, time out!")); + println_Msg(F("Press button...")); + display_Update(); + wait(); + resetArduino(); + } + getCartInfo_GB(); + // Does cartridge have SRAM + if (lastByte > 0) { + // Remove file name ending + int pos = -1; + while (fileName[++pos] != '\0') { + if (fileName[pos] == '.') { + fileName[pos] = '\0'; + break; + } + } + sprintf(filePath, "/GB/SAVE/%s/", fileName); + bool saveFound = false; + if (sd.exists(filePath)) { + EEPROM_readAnything(0, foldern); + for (int i = foldern; i >= 0; i--) { + sprintf(filePath, "/GB/SAVE/%s/%d/%s.SAV", fileName, i, fileName); + if (sd.exists(filePath)) { + print_Msg(F("Save number ")); + print_Msg(i); + println_Msg(F(" found.")); + saveFound = true; + sprintf(filePath, "/GB/SAVE/%s/%d", fileName, i); + sprintf(fileName, "%s.SAV", fileName); + writeSRAM_GB(); + unsigned long wrErrors; + wrErrors = verifySRAM_GB(); + if (wrErrors == 0) { + println_Msg(F("Verified OK")); + display_Update(); + } + else { + print_Msg(F("Error: ")); + print_Msg(wrErrors); + println_Msg(F(" bytes ")); + print_Error(F("did not verify."), false); + } + break; + } + } + } + if (!saveFound) { + println_Msg(F("Error: No save found.")); + } + } + else { + print_Error(F("Cart has no Sram"), false); + } + // Reset + wait(); + resetArduino(); + break; + + case 2: + //Flash MBC3 + display_Clear(); + display_Update(); + setup_GB(); + mode = mode_GB; + + // Change working dir to root + sd.chdir("/"); + //MBC3 + writeFlash29F_GB(3); + // Reset + wait(); + resetArduino(); + break; + + case 3: + //Flash MBC5 + display_Clear(); + display_Update(); + setup_GB(); + mode = mode_GB; + + // Change working dir to root + sd.chdir("/"); + //MBC5 + writeFlash29F_GB(5); + // Reset + wait(); + resetArduino(); + break; + + case 4: + // Flash GB Memory + display_Clear(); + display_Update(); + setup_GBM(); + mode = mode_GBM; + break; + + case 5: + // Flash GB Smart + display_Clear(); + display_Update(); + setup_GBSmart(); + mode = mode_GB_GBSmart; + break; + + case 6: + resetArduino(); + break; + } + break; + + case 3: + resetArduino(); + break; + } +} + +void gbMenu() { + // create menu with title and 3 options to choose from + unsigned char mainMenu; + // Copy menuOptions out of progmem + convertPgm(menuOptionsGB, 4); + mainMenu = question_box(F("GB Cart Reader"), menuOptions, 4, 0); + + // wait for user choice to come back from the question box menu + switch (mainMenu) + { + case 0: + display_Clear(); + // Change working dir to root + sd.chdir("/"); + readROM_GB(); + compare_checksum_GB(); + break; + + case 1: + display_Clear(); + // Does cartridge have SRAM + if (lastByte > 0) { + // Change working dir to root + sd.chdir("/"); + readSRAM_GB(); + } + else { + print_Error(F("Cart has no Sram"), false); + } + break; + + case 2: + display_Clear(); + // Does cartridge have SRAM + if (lastByte > 0) { + // Change working dir to root + sd.chdir("/"); + filePath[0] = '\0'; + fileBrowser(F("Select sav file")); + writeSRAM_GB(); + unsigned long wrErrors; + wrErrors = verifySRAM_GB(); + if (wrErrors == 0) { + println_Msg(F("Verified OK")); + display_Update(); + } + else { + print_Msg(F("Error: ")); + print_Msg(wrErrors); + println_Msg(F(" bytes ")); + print_Error(F("did not verify."), false); + } + } + else { + print_Error(F("Cart has no Sram"), false); + } + break; + + case 3: + resetArduino(); + break; + } + println_Msg(F("")); + println_Msg(F("Press Button...")); + display_Update(); + wait(); +} + +/****************************************** + Setup + *****************************************/ +void setup_GB() { + // Set Address Pins to Output + //A0-A7 + DDRF = 0xFF; + //A8-A15 + DDRK = 0xFF; + + // Set Control Pins to Output RST(PH0) CLK(PH1) CS(PH3) WR(PH5) RD(PH6) + DDRH |= (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 6); + // Output a high signal on all pins, pins are active low therefore everything is disabled now + PORTH |= (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 6); + + // Set Data Pins (D0-D7) to Input + DDRC = 0x00; + // Disable Internal Pullups + //PORTC = 0x00; + + delay(400); + + // Print start page + getCartInfo_GB(); + showCartInfo_GB(); +} + +void showCartInfo_GB() { + display_Clear(); + if (strcmp(checksumStr, "00") != 0) { + println_Msg(F("GB Cart Info")); + print_Msg(F("Name: ")); + println_Msg(romName); + print_Msg(F("Mapper: ")); + + if ((romType == 0) || (romType == 8) || (romType == 9)) + print_Msg(F("none")); + else if ((romType == 1) || (romType == 2) || (romType == 3)) + print_Msg(F("MBC1")); + else if ((romType == 5) || (romType == 6)) + print_Msg(F("MBC2")); + else if ((romType == 11) || (romType == 12) || (romType == 13)) + print_Msg(F("MMM01")); + else if ((romType == 15) || (romType == 16) || (romType == 17) || (romType == 18) || (romType == 19)) + print_Msg(F("MBC3")); + else if ((romType == 21) || (romType == 22) || (romType == 23)) + print_Msg(F("MBC4")); + else if ((romType == 25) || (romType == 26) || (romType == 27) || (romType == 28) || (romType == 29) || (romType == 309)) + print_Msg(F("MBC5")); + if (romType == 252) + print_Msg(F("Camera")); + + println_Msg(F(" ")); + print_Msg(F("Rom Size: ")); + switch (romSize) { + case 0: + print_Msg(F("32KB")); + break; + + case 1: + print_Msg(F("64KB")); + break; + + case 2: + print_Msg(F("128KB")); + break; + + case 3: + print_Msg(F("256KB")); + break; + + case 4: + print_Msg(F("512KB")); + break; + + case 5: + print_Msg(F("1MB")); + break; + + case 6: + print_Msg(F("2MB")); + break; + + case 7: + print_Msg(F("4MB")); + break; + } + + println_Msg(F("")); + print_Msg(F("Banks: ")); + println_Msg(romBanks); + + print_Msg(F("Sram Size: ")); + switch (sramSize) { + case 0: + if (romType == 6) { + print_Msg(F("512B")); + } + else { + print_Msg(F("none")); + } + break; + case 1: + print_Msg(F("2KB")); + break; + + case 2: + print_Msg(F("8KB")); + break; + + case 3: + print_Msg(F("32KB")); + break; + + case 4: + print_Msg(F("128KB")); + break; + + default: print_Msg(F("none")); + } + println_Msg(F("")); + print_Msg(F("Checksum: ")); + println_Msg(checksumStr); + display_Update(); + + // Wait for user input + println_Msg(F("Press Button...")); + display_Update(); + wait(); + } + else { + print_Error(F("GAMEPAK ERROR"), true); + } +} + +/****************************************** + Low level functions +*****************************************/ +// Switch data pins to read +void dataIn_GB() { + // Set to Input + DDRC = 0x00; +} + +byte readByte_GB(word myAddress) { + PORTF = myAddress & 0xFF; + PORTK = (myAddress >> 8) & 0xFF; + + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Switch RD(PH6) to LOW + PORTH &= ~(1 << 6); + + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Read + byte tempByte = PINC; + + // Switch and RD(PH6) to HIGH + PORTH |= (1 << 6); + + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + return tempByte; +} + +void writeByte_GB(int myAddress, byte myData) { + PORTF = myAddress & 0xFF; + PORTK = (myAddress >> 8) & 0xFF; + PORTC = myData; + + // Arduino running at 16Mhz -> one nop = 62.5ns + // Wait till output is stable + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Pull WR(PH5) low + PORTH &= ~(1 << 5); + + // Leave WE low for at least 60ns + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Pull WR(PH5) HIGH + PORTH |= (1 << 5); + + // Leave WE high for at least 50ns + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); +} + +byte readByteCLK_GB(word myAddress) { + PORTF = myAddress & 0xFF; + PORTK = (myAddress >> 8) & 0xFF; + + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Pull CS(PH3) CLK(PH1)(for FRAM MOD) LOW + PORTH &= ~((1 << 3) | (1 << 1)); + // Pull RD(PH6) LOW + PORTH &= ~(1 << 6); + + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Read + byte tempByte = PINC; + + // Pull RD(PH6) HIGH + PORTH |= (1 << 6); + // Pull CS(PH3) CLK(PH1)(for FRAM MOD) HIGH + PORTH |= (1 << 3) | (1 << 1); + + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + return tempByte; +} + +void writeByteCLK_GB(int myAddress, byte myData) { + PORTF = myAddress & 0xFF; + PORTK = (myAddress >> 8) & 0xFF; + PORTC = myData; + + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Pull CS(PH3) CLK(PH1)(for FRAM MOD) LOW + PORTH &= ~((1 << 3) | (1 << 1)); + // Pull WR(PH5) low + PORTH &= ~(1 << 5); + + // Leave WE low for at least 60ns + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Pull WR(PH5) HIGH + PORTH |= (1 << 5); + // Pull CS(PH3) CLK(PH1)(for FRAM MOD) HIGH + PORTH |= (1 << 3) | (1 << 1); + + // Leave WE high for at least 50ns + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t"); +} + +/****************************************** + Game Boy functions +*****************************************/ +// Read Cartridge Header +void getCartInfo_GB() { + romType = readByteCLK_GB(0x0147); + romSize = readByteCLK_GB(0x0148); + sramSize = readByteCLK_GB(0x0149); + + // ROM banks + switch (romSize) { + case 0x00: + romBanks = 2; + break; + case 0x01: + romBanks = 4; + break; + case 0x02: + romBanks = 8; + break; + case 0x03: + romBanks = 16; + break; + case 0x04: + romBanks = 32; + break; + case 0x05: + romBanks = 64; + break; + case 0x06: + romBanks = 128; + break; + case 0x07: + romBanks = 256; + break; + default: + romBanks = 2; + } + + // SRAM banks + sramBanks = 0; + if (romType == 6) { + sramBanks = 1; + } + + // SRAM size + switch (sramSize) { + case 2: + sramBanks = 1; + break; + case 3: + sramBanks = 4; + break; + case 4: + sramBanks = 16; + break; + case 5: + sramBanks = 8; + break; + } + + // Last byte of SRAM + if (romType == 6) { + lastByte = 0xA1FF; + } + if (sramSize == 1) { + lastByte = 0xA7FF; + } + else if (sramSize > 1) { + lastByte = 0xBFFF; + } + + // Get Checksum as string + sprintf(checksumStr, "%02X%02X", readByteCLK_GB(0x014E), readByteCLK_GB(0x014F)); + + // Get name + byte myByte = 0; + byte myLength = 0; + + for (int addr = 0x0134; addr <= 0x13C; addr++) { + myByte = readByteCLK_GB(addr); + if (((char(myByte) >= 48 && char(myByte) <= 57) || (char(myByte) >= 65 && char(myByte) <= 122)) && myLength < 15) { + romName[myLength] = char(myByte); + myLength++; + } + } +} + +/****************************************** + ROM functions +*****************************************/ +// Read ROM +void readROM_GB() { + // Get name, add extension and convert to char array for sd lib + strcpy(fileName, romName); + strcat(fileName, ".GB"); + + // create a new folder for the rom file + EEPROM_readAnything(0, foldern); + sprintf(folder, "GB/ROM/%s/%d", romName, foldern); + sd.mkdir(folder, true); + sd.chdir(folder); + + 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(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); + } + + word romAddress = 0; + + //Initialize progress bar + uint32_t processedProgressBar = 0; + uint32_t totalProgressBar = (uint32_t)(romBanks - 1); + draw_progressbar(0, totalProgressBar); + + for (word currBank = 1; currBank < romBanks; currBank++) { + // Switch data pins to output + dataOut(); + + // Set ROM bank for MBC2/3/4/5 + if (romType >= 5) { + writeByte_GB(0x2100, currBank); + } + // Set ROM bank for MBC1 + else { + writeByte_GB(0x6000, 0); + writeByte_GB(0x4000, currBank >> 5); + writeByte_GB(0x2000, currBank & 0x1F); + } + + // Switch data pins to intput + dataIn_GB(); + + // Second bank starts at 0x4000 + if (currBank > 1) { + romAddress = 0x4000; + } + + // Read banks and save to SD + while (romAddress <= 0x7FFF) { + for (int i = 0; i < 512; i++) { + sdBuffer[i] = readByteCLK_GB(romAddress + i); + } + myFile.write(sdBuffer, 512); + romAddress += 512; + } + + processedProgressBar += 1; + draw_progressbar(processedProgressBar, totalProgressBar); + } + + // Close the file: + myFile.close(); +} + +// Calculate checksum +unsigned int calc_checksum_GB (char* fileName, char* folder) { + unsigned int calcChecksum = 0; + // int calcFilesize = 0; // unused + unsigned long i = 0; + int c = 0; + + if (strcmp(folder, "root") != 0) + sd.chdir(folder); + + // If file exists + if (myFile.open(fileName, O_READ)) { + //calcFilesize = myFile.fileSize() * 8 / 1024 / 1024; // unused + for (i = 0; i < (myFile.fileSize() / 512); i++) { + myFile.read(sdBuffer, 512); + for (c = 0; c < 512; c++) { + calcChecksum += sdBuffer[c]; + } + } + myFile.close(); + sd.chdir(); + // Subtract checksum bytes + calcChecksum -= readByteCLK_GB(0x014E); + calcChecksum -= readByteCLK_GB(0x014F); + + // Return result + return (calcChecksum); + } + // Else show error + else { + print_Error(F("DUMP ROM 1ST"), false); + return 0; + } +} + +// Compare checksum +boolean compare_checksum_GB() { + + println_Msg(F("Calculating Checksum")); + display_Update(); + + strcpy(fileName, romName); + strcat(fileName, ".GB"); + + // last used rom folder + EEPROM_readAnything(0, foldern); + sprintf(folder, "GB/ROM/%s/%d", romName, foldern - 1); + + char calcsumStr[5]; + sprintf(calcsumStr, "%04X", calc_checksum_GB(fileName, folder)); + + if (strcmp(calcsumStr, checksumStr) == 0) { + print_Msg(F("Result: ")); + println_Msg(calcsumStr); + println_Msg(F("Checksum matches")); + display_Update(); + return 1; + } + else { + print_Msg(F("Result: ")); + println_Msg(calcsumStr); + print_Error(F("Checksum Error"), false); + return 0; + } +} + +/****************************************** + SRAM functions +*****************************************/ +// Read RAM +void readSRAM_GB() { + // Does cartridge have RAM + if (lastByte > 0) { + + // Get name, add extension and convert to char array for sd lib + strcpy(fileName, romName); + strcat(fileName, ".sav"); + + // create a new folder for the save file + EEPROM_readAnything(0, foldern); + sprintf(folder, "GB/SAVE/%s/%d", romName, foldern); + sd.mkdir(folder, true); + sd.chdir(folder); + + // 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("SD Error"), true); + } + + dataIn_GB(); + + // MBC2 Fix + readByteCLK_GB(0x0134); + + dataOut(); + if (romType <= 4) { + writeByte_GB(0x6000, 1); + } + + // Initialise MBC + writeByte_GB(0x0000, 0x0A); + + // Switch SRAM banks + for (byte currBank = 0; currBank < sramBanks; currBank++) { + dataOut(); + writeByte_GB(0x4000, currBank); + + // Read SRAM + dataIn_GB(); + for (word sramAddress = 0xA000; sramAddress <= lastByte; sramAddress += 64) { + for (byte i = 0; i < 64; i++) { + sdBuffer[i] = readByteCLK_GB(sramAddress + i); + } + myFile.write(sdBuffer, 64); + } + } + + // Disable SRAM + dataOut(); + writeByte_GB(0x0000, 0x00); + dataIn_GB(); + + // Close the file: + myFile.close(); + + // Signal end of process + print_Msg(F("Saved to ")); + print_Msg(folder); + println_Msg(F("/")); + display_Update(); + } + else { + print_Error(F("Cart has no SRAM"), false); + } +} + +// Write RAM +void writeSRAM_GB() { + // Does cartridge have SRAM + if (lastByte > 0) { + // Create filepath + sprintf(filePath, "%s/%s", filePath, fileName); + + //open file on sd card + if (myFile.open(filePath, O_READ)) { + // Set pins to input + dataIn_GB(); + + // MBC2 Fix + readByteCLK_GB(0x0134); + + dataOut(); + + // Enable SRAM for MBC1 + if (romType <= 4) { + writeByte_GB(0x6000, 1); + } + + // Initialise MBC + writeByte_GB(0x0000, 0x0A); + + // Switch RAM banks + for (byte currBank = 0; currBank < sramBanks; currBank++) { + writeByte_GB(0x4000, currBank); + + // Write RAM + for (word sramAddress = 0xA000; sramAddress <= lastByte; sramAddress++) { + writeByteCLK_GB(sramAddress, myFile.read()); + } + } + // Disable SRAM + writeByte_GB(0x0000, 0x00); + + // Set pins to input + dataIn_GB(); + + // Close the file: + myFile.close(); + display_Clear(); + println_Msg(F("SRAM writing finished")); + display_Update(); + + } + else { + print_Error(F("File doesnt exist"), false); + } + } + else { + print_Error(F("Cart has no SRAM"), false); + } +} + +// Check if the SRAM was written without any error +unsigned long verifySRAM_GB() { + + //open file on sd card + if (myFile.open(filePath, O_READ)) { + + // Variable for errors + writeErrors = 0; + + dataIn_GB(); + + // MBC2 Fix + readByteCLK_GB(0x0134); + + // Check SRAM size + if (lastByte > 0) { + dataOut(); + if (romType <= 4) { // MBC1 + writeByte_GB(0x6000, 1); // Set RAM Mode + } + + // Initialise MBC + writeByte_GB(0x0000, 0x0A); + + // Switch SRAM banks + for (byte currBank = 0; currBank < sramBanks; currBank++) { + dataOut(); + writeByte_GB(0x4000, currBank); + + // Read SRAM + dataIn_GB(); + for (word sramAddress = 0xA000; sramAddress <= lastByte; sramAddress += 64) { + //fill sdBuffer + myFile.read(sdBuffer, 64); + for (int c = 0; c < 64; c++) { + if (readByteCLK_GB(sramAddress + c) != sdBuffer[c]) { + writeErrors++; + } + } + } + } + dataOut(); + // Disable RAM + writeByte_GB(0x0000, 0x00); + dataIn_GB(); + } + // Close the file: + myFile.close(); + return writeErrors; + } + else { + print_Error(F("Can't open file"), true); + } +} + +/****************************************** + 29F016/29F032/29F033 flashrom functions +*****************************************/ +// Write 29F032 flashrom +// A0-A13 directly connected to cart edge -> 16384(0x0-0x3FFF) bytes per bank -> 256(0x0-0xFF) banks +// A14-A21 connected to MBC5 +void writeFlash29F_GB(byte MBC) { + // Launch filebrowser + filePath[0] = '\0'; + sd.chdir("/"); + fileBrowser(F("Select file")); + display_Clear(); + + // Create filepath + sprintf(filePath, "%s/%s", filePath, fileName); + + // Open file on sd card + if (myFile.open(filePath, O_READ)) { + // Get rom size from file + myFile.seekCur(0x147); + romType = myFile.read(); + romSize = myFile.read(); + // Go back to file beginning + myFile.seekSet(0); + + // ROM banks + switch (romSize) { + case 0x00: + romBanks = 2; + break; + case 0x01: + romBanks = 4; + break; + case 0x02: + romBanks = 8; + break; + case 0x03: + romBanks = 16; + break; + case 0x04: + romBanks = 32; + break; + case 0x05: + romBanks = 64; + break; + case 0x06: + romBanks = 128; + break; + case 0x07: + romBanks = 256; + break; + default: + romBanks = 2; + } + + // Set data pins to output + dataOut(); + + // Set ROM bank hi 0 + writeByte_GB(0x3000, 0); + // Set ROM bank low 0 + writeByte_GB(0x2000, 0); + delay(100); + + // Reset flash + writeByte_GB(0x555, 0xf0); + delay(100); + + // ID command sequence + writeByte_GB(0x555, 0xaa); + writeByte_GB(0x2aa, 0x55); + writeByte_GB(0x555, 0x90); + + dataIn_GB(); + + // Read the two id bytes into a string + sprintf(flashid, "%02X%02X", readByte_GB(0), readByte_GB(1)); + + if (strcmp(flashid, "04D4") == 0) { + println_Msg(F("MBM29F033C")); + print_Msg(F("Banks: ")); + print_Msg(romBanks); + println_Msg(F("/256")); + display_Update(); + } + else if (strcmp(flashid, "0141") == 0) { + println_Msg(F("AM29F032B")); + print_Msg(F("Banks: ")); + print_Msg(romBanks); + println_Msg(F("/256")); + display_Update(); + } + else if (strcmp(flashid, "01AD") == 0) { + println_Msg(F("AM29F016B")); + print_Msg(F("Banks: ")); + print_Msg(romBanks); + println_Msg(F("/128")); + display_Update(); + } + else if (strcmp(flashid, "04AD") == 0) { + println_Msg(F("AM29F016D")); + print_Msg(F("Banks: ")); + print_Msg(romBanks); + println_Msg(F("/128")); + display_Update(); + } + else if (strcmp(flashid, "01D5") == 0) { + println_Msg(F("AM29F080B")); + print_Msg(F("Banks: ")); + print_Msg(romBanks); + println_Msg(F("/64")); + display_Update(); + } + else { + print_Msg(F("Flash ID: ")); + println_Msg(flashid); + display_Update(); + print_Error(F("Unknown flashrom"), true); + } + dataOut(); + + // Reset flash + writeByte_GB(0x555, 0xf0); + + delay(100); + println_Msg(F("Erasing flash")); + display_Update(); + + // Erase flash + writeByte_GB(0x555, 0xaa); + writeByte_GB(0x2aa, 0x55); + writeByte_GB(0x555, 0x80); + writeByte_GB(0x555, 0xaa); + writeByte_GB(0x2aa, 0x55); + writeByte_GB(0x555, 0x10); + + dataIn_GB(); + + // Read the status register + byte statusReg = readByte_GB(0); + + // After a completed erase D7 will output 1 + while ((statusReg & 0x80) != 0x80) { + // Blink led + blinkLED(); + delay(100); + // Update Status + statusReg = readByte_GB(0); + } + + // Blankcheck + println_Msg(F("Blankcheck")); + display_Update(); + + // Read x number of banks + for (int currBank = 0; currBank < romBanks; currBank++) { + // Blink led + blinkLED(); + + dataOut(); + + // Set ROM bank + writeByte_GB(0x2000, currBank); + dataIn(); + + for (unsigned int currAddr = 0x4000; currAddr < 0x7FFF; currAddr += 512) { + for (int currByte = 0; currByte < 512; currByte++) { + sdBuffer[currByte] = readByte_GB(currAddr + currByte); + } + for (int j = 0; j < 512; j++) { + if (sdBuffer[j] != 0xFF) { + println_Msg(F("Not empty")); + print_Error(F("Erase failed"), true); + } + } + } + } + + if (MBC == 3) { + println_Msg(F("Writing flash MBC3")); + display_Update(); + + // Write flash + dataOut(); + + word currAddr = 0; + word endAddr = 0x3FFF; + + for (int currBank = 0; currBank < romBanks; currBank++) { + // Blink led + blinkLED(); + + // Set ROM bank + writeByte_GB(0x2100, currBank); + + if (currBank > 0) { + currAddr = 0x4000; + endAddr = 0x7FFF; + } + + while (currAddr <= endAddr) { + myFile.read(sdBuffer, 512); + + for (int currByte = 0; currByte < 512; currByte++) { + // Write command sequence + writeByte_GB(0x555, 0xaa); + writeByte_GB(0x2aa, 0x55); + writeByte_GB(0x555, 0xa0); + // Write current byte + writeByte_GB(currAddr + currByte, sdBuffer[currByte]); + + // Set data pins to input + dataIn(); + + // Setting CS(PH3) and OE/RD(PH6) LOW + PORTH &= ~((1 << 3) | (1 << 6)); + + // Busy check + while ((PINC & 0x80) != (sdBuffer[currByte] & 0x80)) { + } + + // Switch CS(PH3) and OE/RD(PH6) to HIGH + PORTH |= (1 << 3) | (1 << 6); + + // Set data pins to output + dataOut(); + } + currAddr += 512; + } + } + } + + else if (MBC == 5) { + println_Msg(F("Writing flash MBC5")); + display_Update(); + + // Write flash + dataOut(); + + for (int currBank = 0; currBank < romBanks; currBank++) { + // Blink led + blinkLED(); + + // Set ROM bank + writeByte_GB(0x2000, currBank); + // 0x2A8000 fix + writeByte_GB(0x4000, 0x0); + + for (unsigned int currAddr = 0x4000; currAddr < 0x7FFF; currAddr += 512) { + myFile.read(sdBuffer, 512); + + for (int currByte = 0; currByte < 512; currByte++) { + // Write command sequence + writeByte_GB(0x555, 0xaa); + writeByte_GB(0x2aa, 0x55); + writeByte_GB(0x555, 0xa0); + // Write current byte + writeByte_GB(currAddr + currByte, sdBuffer[currByte]); + + // Set data pins to input + dataIn(); + + // Setting CS(PH3) and OE/RD(PH6) LOW + PORTH &= ~((1 << 3) | (1 << 6)); + + // Busy check + while ((PINC & 0x80) != (sdBuffer[currByte] & 0x80)) { + } + + // Switch CS(PH3) and OE/RD(PH6) to HIGH + PORTH |= (1 << 3) | (1 << 6); + + // Set data pins to output + dataOut(); + } + } + } + } + + // Set data pins to input again + dataIn_GB(); + + println_Msg(F("Verifying")); + display_Update(); + + // Go back to file beginning + myFile.seekSet(0); + //unsigned int addr = 0; // unused + writeErrors = 0; + + // Verify flashrom + word romAddress = 0; + + // Read number of banks and switch banks + for (word bank = 1; bank < romBanks; bank++) { + // Switch data pins to output + dataOut(); + + if (romType >= 5) { // MBC2 and above + writeByte_GB(0x2100, bank); // Set ROM bank + } + else { // MBC1 + writeByte_GB(0x6000, 0); // Set ROM Mode + writeByte_GB(0x4000, bank >> 5); // Set bits 5 & 6 (01100000) of ROM bank + writeByte_GB(0x2000, bank & 0x1F); // Set bits 0 & 4 (00011111) of ROM bank + } + + // Switch data pins to intput + dataIn_GB(); + + if (bank > 1) { + romAddress = 0x4000; + } + // Blink led + blinkLED(); + + // Read up to 7FFF per bank + while (romAddress <= 0x7FFF) { + // Fill sdBuffer + myFile.read(sdBuffer, 512); + // Compare + for (int i = 0; i < 512; i++) { + if (readByte_GB(romAddress + i) != sdBuffer[i]) { + writeErrors++; + } + } + romAddress += 512; + } + } + // Close the file: + myFile.close(); + + if (writeErrors == 0) { + println_Msg(F("OK")); + display_Update(); + } + else { + print_Msg(F("Error: ")); + print_Msg(writeErrors); + println_Msg(F(" bytes ")); + print_Error(F("did not verify."), false); + } + } + else { + println_Msg(F("Can't open file")); + display_Update(); + } +} + +/****************************************** + CFU flashrom functions +*****************************************/ + +/* + Flash chips can either be in x8 mode or x16 mode and sometimes the two + least significant bits on flash cartridges' data lines are swapped. + This function reads a byte and compensates for the differences. + This is only necessary for commands to the flash, not for data read from the flash, the MBC or SRAM. + + address needs to be the x8 mode address of the flash register that should be read. +*/ +byte readByteCompensated(int address) { + byte data = readByte_GB(address >> (flashX16Mode ? 1 : 0)); + if (flashSwitchLastBits) { + return (data & 0b11111100) | ((data << 1) & 0b10) | ((data >> 1) & 0b01); + } + return data; +} + +/* + Flash chips can either be in x8 mode or x16 mode and sometimes the two + least significant bits on flash cartridges' data lines are swapped. + This function writes a byte and compensates for the differences. + This is only necessary for commands to the flash, not for data written to the flash, the MBC or SRAM. + . + address needs to be the x8 mode address of the flash register that should be read. +*/ +byte writeByteCompensated(int address, byte data) { + if (flashSwitchLastBits) { + data = (data & 0b11111100) | ((data << 1) & 0b10) | ((data >> 1) & 0b01); + } + writeByte_GB(address >> (flashX16Mode ? 1 : 0), data); +} + +void startCFIMode(boolean x16Mode) { + if (x16Mode) { + writeByte_GB(0x555, 0xf0); //x16 mode reset command + delay(500); + writeByte_GB(0x555, 0xf0); //Double reset to get out of possible Autoselect + CFI mode + delay(500); + writeByte_GB(0x55, 0x98); //x16 CFI Query command + } else { + writeByte_GB(0xAAA, 0xf0); //x8 mode reset command + delay(100); + writeByte_GB(0xAAA, 0xf0); //Double reset to get out of possible Autoselect + CFI mode + delay(100); + writeByte_GB(0xAA, 0x98); //x8 CFI Query command + } +} + +/* Identify the different flash chips. + Sets the global variables flashBanks, flashX16Mode and flashSwitchLastBits +*/ +void identifyCFI_GB() { + // Reset flash + display_Clear(); + dataOut(); + writeByte_GB(0x6000, 0); // Set ROM Mode + writeByte_GB(0x2000, 0); // Set Bank to 0 + writeByte_GB(0x3000, 0); + + startCFIMode(false); // Trying x8 mode first + + dataIn_GB(); + display_Clear(); + // Try x8 mode first + char cfiQRYx8[7]; + char cfiQRYx16[7]; + sprintf(cfiQRYx8, "%02X%02X%02X", readByte_GB(0x20), readByte_GB(0x22), readByte_GB(0x24)); + sprintf(cfiQRYx16, "%02X%02X%02X", readByte_GB(0x10), readByte_GB(0x11), readByte_GB(0x12)); // some devices use x8-style CFI Query command even though they are in x16 command mode + if (strcmp(cfiQRYx8, "515259") == 0) { // QRY in x8 mode + println_Msg(F("Normal CFI x8 Mode")); + flashX16Mode = false; + flashSwitchLastBits = false; + } else if (strcmp(cfiQRYx8, "52515A") == 0) { // QRY in x8 mode with switched last bit + println_Msg(F("Switched CFI x8 Mode")); + flashX16Mode = false; + flashSwitchLastBits = true; + } else if (strcmp(cfiQRYx16, "515259") == 0) { // QRY in x16 mode + println_Msg(F("Normal CFI x16 Mode")); + flashX16Mode = true; + flashSwitchLastBits = false; + } else if (strcmp(cfiQRYx16, "52515A") == 0) { // QRY in x16 mode with switched last bit + println_Msg(F("Switched CFI x16 Mode")); + flashX16Mode = true; + flashSwitchLastBits = true; + } else { + startCFIMode(true); // Try x16 mode next + sprintf(cfiQRYx16, "%02X%02X%02X", readByte_GB(0x10), readByte_GB(0x11), readByte_GB(0x12)); + if (strcmp(cfiQRYx16, "515259") == 0) { // QRY in x16 mode + println_Msg(F("Normal CFI x16 Mode")); + flashX16Mode = true; + flashSwitchLastBits = false; + } else if (strcmp(cfiQRYx16, "52515A") == 0) { // QRY in x16 mode with switched last bit + println_Msg(F("Switched CFI x16 Mode")); + flashX16Mode = true; + flashSwitchLastBits = true; + } else { + println_Msg(F("CFI Query failed!")); + display_Update(); + wait(); + return; + } + } + dataIn_GB(); + flashBanks = 1 << (readByteCompensated(0x4E) - 14); // - flashX16Mode); + dataOut(); + + // Reset flash + writeByteCompensated(0xAAA, 0xf0); + delay(100); +} + +// Write 29F032 flashrom +// A0-A13 directly connected to cart edge -> 16384(0x0-0x3FFF) bytes per bank -> 256(0x0-0xFF) banks +// A14-A21 connected to MBC5 +// identifyFlash_GB() needs to be run before this! +bool writeCFI_GB() { + // Create filepath + sprintf(filePath, "%s/%s", filePath, fileName); + + // Open file on sd card + if (myFile.open(filePath, O_READ)) { + // Get rom size from file + myFile.seekCur(0x147); + romType = myFile.read(); + romSize = myFile.read(); + // Go back to file beginning + myFile.seekSet(0); + + // ROM banks + switch (romSize) { + case 0x00: + romBanks = 2; + break; + case 0x01: + romBanks = 4; + break; + case 0x02: + romBanks = 8; + break; + case 0x03: + romBanks = 16; + break; + case 0x04: + romBanks = 32; + break; + case 0x05: + romBanks = 64; + break; + case 0x06: + romBanks = 128; + break; + case 0x07: + romBanks = 256; + break; + default: + romBanks = 2; + } + + if (romBanks <= flashBanks) { + print_Msg(F("Using ")); + print_Msg(romBanks); + print_Msg(F("/")); + print_Msg(flashBanks); + println_Msg(F(" Banks")); + display_Update(); + } else { + println_Msg(F("Error: Flash has too few banks!")); + print_Msg(F("Has ")); + print_Msg(flashBanks); + println_Msg(F(" banks,")); + print_Msg(F("but needs ")); + print_Msg(romBanks); + println_Msg(F(".")); + println_Msg(F("Press button...")); + display_Update(); + wait(); + resetArduino(); + } + + // Set data pins to output + dataOut(); + + // Set ROM bank hi 0 + writeByte_GB(0x3000, 0); + // Set ROM bank low 0 + writeByte_GB(0x2000, 0); + delay(100); + + // Reset flash + writeByteCompensated(0xAAA, 0xf0); + delay(100); + dataOut(); + + // Reset flash + writeByte_GB(0x555, 0xf0); + + delay(100); + println_Msg(F("Erasing flash")); + display_Update(); + + // Erase flash + writeByteCompensated(0xAAA, 0xaa); + writeByteCompensated(0x555, 0x55); + writeByteCompensated(0xAAA, 0x80); + writeByteCompensated(0xAAA, 0xaa); + writeByteCompensated(0x555, 0x55); + writeByteCompensated(0xAAA, 0x10); + + dataIn_GB(); + + // Read the status register + byte statusReg = readByte_GB(0); + + // After a completed erase D7 will output 1 + while ((statusReg & 0x80) != 0x80) { + // Blink led + blinkLED(); + delay(100); + // Update Status + statusReg = readByte_GB(0); + } + + // Blankcheck + println_Msg(F("Blankcheck")); + display_Update(); + + // Read x number of banks + for (int currBank = 0; currBank < romBanks; currBank++) { + // Blink led + blinkLED(); + + dataOut(); + + // Set ROM bank + writeByte_GB(0x2000, currBank); + dataIn(); + + for (unsigned int currAddr = 0x4000; currAddr < 0x7FFF; currAddr += 512) { + for (int currByte = 0; currByte < 512; currByte++) { + sdBuffer[currByte] = readByte_GB(currAddr + currByte); + } + for (int j = 0; j < 512; j++) { + if (sdBuffer[j] != 0xFF) { + println_Msg(F("Not empty")); + print_Error(F("Erase failed"), true); + } + } + } + } + + println_Msg(F("Writing flash MBC3/5")); + display_Update(); + + // Write flash + dataOut(); + + word currAddr = 0; + word endAddr = 0x3FFF; + + for (int currBank = 0; currBank < romBanks; currBank++) { + // Blink led + blinkLED(); + + // Set ROM bank + writeByte_GB(0x2100, currBank); + // 0x2A8000 fix + writeByte_GB(0x4000, 0x0); + + if (currBank > 0) { + currAddr = 0x4000; + endAddr = 0x7FFF; + } + + while (currAddr <= endAddr) { + myFile.read(sdBuffer, 512); + + for (int currByte = 0; currByte < 512; currByte++) { + // Write command sequence + writeByteCompensated(0xAAA, 0xaa); + writeByteCompensated(0x555, 0x55); + writeByteCompensated(0xAAA, 0xa0); + + // Write current byte + writeByte_GB(currAddr + currByte, sdBuffer[currByte]); + + // Set data pins to input + dataIn(); + + // Setting CS(PH3) and OE/RD(PH6) LOW + PORTH &= ~((1 << 3) | (1 << 6)); + + // Busy check + short i = 0; + while ((PINC & 0x80) != (sdBuffer[currByte] & 0x80)) { + i++; + if (i > 500) { + if (currAddr < 0x4000) { // This happens when trying to flash an MBC5 as if it was an MBC3. Retry to flash as MBC5, starting from last successfull byte. + currByte--; + currAddr += 0x4000; + endAddr = 0x7FFF; + break; + } else { // If a timeout happens while trying to flash MBC5-style, flashing failed. + return false; + } + } + } + + // Switch CS(PH3) and OE/RD(PH6) to HIGH + PORTH |= (1 << 3) | (1 << 6); + __asm__("nop\n\tnop\n\tnop\n\t"); // Waste a few CPU cycles to remove write errors + + // Set data pins to output + dataOut(); + } + currAddr += 512; + } + } + + // Set data pins to input again + dataIn_GB(); + + display_Clear(); + println_Msg(F("Verifying")); + display_Update(); + + // Go back to file beginning + myFile.seekSet(0); + //unsigned int addr = 0; // unused + writeErrors = 0; + + // Verify flashrom + word romAddress = 0; + + // Read number of banks and switch banks + for (word bank = 1; bank < romBanks; bank++) { + // Switch data pins to output + dataOut(); + + if (romType >= 5) { // MBC2 and above + writeByte_GB(0x2100, bank); // Set ROM bank + } + else { // MBC1 + writeByte_GB(0x6000, 0); // Set ROM Mode + writeByte_GB(0x4000, bank >> 5); // Set bits 5 & 6 (01100000) of ROM bank + writeByte_GB(0x2000, bank & 0x1F); // Set bits 0 & 4 (00011111) of ROM bank + } + + // Switch data pins to intput + dataIn_GB(); + + if (bank > 1) { + romAddress = 0x4000; + } + // Blink led + blinkLED(); + + // Read up to 7FFF per bank + while (romAddress <= 0x7FFF) { + // Fill sdBuffer + myFile.read(sdBuffer, 512); + // Compare + for (int i = 0; i < 512; i++) { + if (readByte_GB(romAddress + i) != sdBuffer[i]) { + writeErrors++; + } + } + romAddress += 512; + } + } + // Close the file: + myFile.close(); + + if (writeErrors == 0) { + println_Msg(F("OK")); + display_Update(); + } + else { + print_Msg(F("Error: ")); + print_Msg(writeErrors); + println_Msg(F(" bytes ")); + print_Error(F("did not verify."), false); + } + } + else { + println_Msg(F("Can't open file")); + display_Update(); + } + return true; +} + +#endif + +//****************************************** +// End of File +//****************************************** diff --git a/Cart_Reader/NES.ino b/Cart_Reader/NES.ino index 7262831..94e3957 100644 --- a/Cart_Reader/NES.ino +++ b/Cart_Reader/NES.ino @@ -851,7 +851,7 @@ unsigned char* getNESHeaderForFileInfo(uint32_t prg_size, uint32_t chr_size, uin } char* temp_line; - char* nes20_header; + unsigned char* nes20_header; int i; if (!sdFile.open("/nes20db.txt", FILE_READ)) { @@ -862,7 +862,7 @@ unsigned char* getNESHeaderForFileInfo(uint32_t prg_size, uint32_t chr_size, uin display_Update(); } - temp_line = malloc(256 * sizeof(char)); + temp_line = (char*)malloc(256 * sizeof(char)); while (sdFile.available()) { // We're reading fixed-length lines // padded with null characters diff --git a/Cart_Reader/PCE.ino b/Cart_Reader/PCE.ino index 825bd4f..8147df7 100644 --- a/Cart_Reader/PCE.ino +++ b/Cart_Reader/PCE.ino @@ -1,955 +1,955 @@ -//****************************************** -// PC Engine & TurboGrafx dump code by tamanegi_taro -// April 18th 2018 Revision 1.0.1 Initial version -// August 12th 2019 Revision 1.0.2 Added Tennokoe Bank support -// -// Special thanks -// sanni - Arduino cart reader -// skaman - ROM size detection -// NO-INTRO - CRC list for game name detection -// Chris Covell - Tennokoe bank support -// -//****************************************** - -#include "options.h" -#ifdef enable_PCE - -/****************************************** - Defines - *****************************************/ -#define HUCARD 0 -#define TURBOCHIP 1 -#define HUCARD_NOSWAP 2 - -#define DETECTION_SIZE 64 -#define CHKSUM_SKIP 0 -#define CHKSUM_OK 1 -#define CHKSUM_ERROR 2 - -/****************************************** - Prototype Declarations - *****************************************/ -/* Several PCE dedicated functions */ -void pin_read_write_PCE(void); -void pin_init_PCE(void); -void setup_cart_PCE(void); -void reset_cart_PCE(void); -uint8_t read_byte_PCE(uint32_t address); -void write_byte_PCE(uint32_t address, uint8_t data); -uint32_t detect_rom_size_PCE(void); -void read_bank_PCE_ROM(uint32_t address_start, uint32_t address_end, uint32_t *processed_size, uint32_t total_size); -void read_bank_PCE_RAM(uint32_t address_start); -void read_rom_PCE(void); - -/****************************************** - Variables - *****************************************/ -uint8_t pce_internal_mode; //0 - HuCARD, 1 - TurboChip - -uint16_t pce_force_rom_size = 0; -uint8_t tennokoe_bank_index = 0; - -/****************************************** - Menu -*****************************************/ -// PCE start menu -static const char pceMenuItem1[] PROGMEM = "HuCARD"; -static const char pceMenuItem2[] PROGMEM = "Turbochip"; -static const char pceMenuItem3[] PROGMEM = "HuCARD Not Swapped"; -static const char pceMenuItem4[] PROGMEM = "Reset"; -static const char* const menuOptionspce[] PROGMEM = {pceMenuItem1, pceMenuItem2, pceMenuItem3, pceMenuItem4}; - -// PCE card menu items -static const char pceCartMenuItem1[] = "Read ROM"; -static char pceCartMenuItem2[20]; -static char pceCartMenuItem3[20]; -static const char pceCartMenuItem4[] = "Reset"; -static const char pceCartMenuItem5[] = "Inc Bank Number"; -static const char pceCartMenuItem6[] = "Dec Bank Number"; -static char pceCartMenuItem7[20]; -static const char menuOptionspceCart[7][20]; - -// Turbochip menu items -static const char pceTCMenuItem1[] PROGMEM = "Read ROM"; -static const char pceTCMenuItem2[] PROGMEM = "Reset"; -static const char* const menuOptionspceTC[] PROGMEM = {pceTCMenuItem1, pceTCMenuItem2}; - -// PCE start menu -void pcsMenu(void) { - // create menu with title and 3 options to choose from - unsigned char pceDev; - // Copy menuOptions out of progmem - convertPgm(menuOptionspce, 3); - pceDev = question_box(F("Select device"), menuOptions, 3, 0); - - // wait for user choice to come back from the question box menu - switch (pceDev) - { - case 0: - //Hucard - display_Clear(); - display_Update(); - pce_internal_mode = HUCARD; - setup_cart_PCE(); - mode = mode_PCE; - break; - - case 1: - //Turbografx - display_Clear(); - display_Update(); - pce_internal_mode = TURBOCHIP; - setup_cart_PCE(); - mode = mode_PCE; - break; - - case 2: - //Hucard not swapped - display_Clear(); - display_Update(); - pce_internal_mode = HUCARD_NOSWAP; - setup_cart_PCE(); - mode = mode_PCE; - break; - - case 3: - resetArduino(); - break; - } -} - -void pin_read_write_PCE(void) -{ - // Set Address Pins to Output - //A0-A7 - DDRF = 0xFF; - //A8-A15 - DDRK = 0xFF; - //A16-A19 - DDRL = (DDRL & 0xF0) | 0x0F; - - //Set Control Pin to Output CS(PL4) - DDRL |= (1 << 4); - - //Set CS(PL4) to HIGH - PORTL |= (1 << 4); - - // Set Control Pins to Output RST(PH0) RD(PH3) WR(PH5) - DDRH |= (1 << 0) | (1 << 3) | (1 << 5); - // Switch all of above to HIGH - PORTH |= (1 << 0) | (1 << 3) | (1 << 5); - - // Set IRQ(PH4) to Input - DDRH &= ~(1 << 4); - // Activate Internal Pullup Resistors - PORTH |= (1 << 4); - - // Set Data Pins (D0-D7) to Input - DDRC = 0x00; - - // Enable Internal Pullups - PORTC = 0xFF; - - set_cs_rd_low_PCE(); - - reset_cart_PCE(); -} - -void pin_init_PCE(void) -{ - - //Set Address Pins to input and pull up - DDRF = 0x00; - PORTF = 0xFF; - DDRK = 0x00; - PORTK = 0xFF; - DDRL = 0x00; - PORTL = 0xFF; - DDRH &= ~((1 << 0) | (1 << 3) | (1 << 5) | (1 << 6)); - PORTH = (1 << 0) | (1 << 3) | (1 << 5) | (1 << 6); - - // Set IRQ(PH4) to Input - DDRH &= ~(1 << 4); - // Activate Internal Pullup Resistors - PORTH |= (1 << 4); - - // Set Data Pins (D0-D7) to Input - DDRC = 0x00; - // Enable Internal Pullups - PORTC = 0xFF; - -} - -void setup_cart_PCE(void) -{ - // Set cicrstPin(PG1) to Output - DDRG |= (1 << 1); - // Output a high to disable CIC - PORTG |= (1 << 1); - - pin_init_PCE(); - -} - -void reset_cart_PCE(void) -{ - //Set RESET as Low - PORTH &= ~(1 << 0); - delay(200); - //Set RESET as High - PORTH |= (1 << 0); - delay(200); - -} - -void set_address_PCE(uint32_t address) -{ - //Set address - PORTF = address & 0xFF; - PORTK = (address >> 8) & 0xFF; - PORTL = (PORTL & 0xF0) | ((address >> 16) & 0x0F); -} - -void set_cs_rd_low_PCE () -{ - // Set CS(PL4) and RD(PH3) as LOW - PORTL &= ~(1 << 4); - PORTH &= ~(1 << 3); -} - -uint8_t read_byte_PCE(uint32_t address) -{ - uint8_t ret; - - set_address_PCE(address); - - // Arduino running at 16Mhz -> one nop = 62.5ns -> 1000ns total - __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"); - - //read byte - ret = PINC; - - //Swap bit order for PC Engine HuCARD - if (pce_internal_mode == HUCARD) - { - ret = ((ret & 0x01) << 7) | ((ret & 0x02) << 5) | ((ret & 0x04) << 3) | ((ret & 0x08) << 1) | ((ret & 0x10) >> 1) | ((ret & 0x20) >> 3) | ((ret & 0x40) >> 5) | ((ret & 0x80) >> 7); - } - - //return read data - return ret; -} - -void data_output_PCE () { - // Set Data Pins (D0-D7) to Output - DDRC = 0xFF; -} - -void data_input_PCE () { - // Set Data Pins (D0-D7) to Input - DDRC = 0x00; - // Enable Internal Pullups - PORTC = 0xFF; - - set_cs_rd_low_PCE(); -} - -void write_byte_PCE(uint32_t address, uint8_t data) -{ - //PORTH |= (1 << 3); // RD HIGH - set_address_PCE(address); - - // Arduino running at 16Mhz -> one nop = 62.5ns -> 1000ns total - __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"); - - //Swap bit order for PC Engine HuCARD - if (pce_internal_mode == HUCARD) - { - data = ((data & 0x01) << 7) | ((data & 0x02) << 5) | ((data & 0x04) << 3) | ((data & 0x08) << 1) | ((data & 0x10) >> 1) | ((data & 0x20) >> 3) | ((data & 0x40) >> 5) | ((data & 0x80) >> 7); - } - - //write byte - PORTC = data; - - // Set CS(PL4) and WR(PH5) as LOW - PORTL &= ~(1 << 4); - PORTH &= ~(1 << 5); - - // Arduino running at 16Mhz -> one nop = 62.5ns -> 1000ns total - __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"); - - // Set CS(PL4) and WR(PH5) as HIGH - PORTL |= (1 << 4); - PORTH |= (1 << 5); -} - -//Confirm the size of ROM - 128Kb, 256Kb, 384Kb, 512Kb, 768Kb or 1024Kb -uint32_t detect_rom_size_PCE(void) -{ - uint32_t rom_size; - uint8_t read_byte; - uint8_t current_byte; - uint8_t detect_128, detect_256, detect_512, detect_768; - - //Initialize variables - detect_128 = 0; - detect_256 = 0; - detect_512 = 0; - detect_768 = 0; - - //Set pins to read PC Engine cart - pin_read_write_PCE(); - - //Confirm where mirror address start from(128KB, 256KB, 512KB, 768, or 1024KB) - for (current_byte = 0; current_byte < DETECTION_SIZE; current_byte++) { - if ((current_byte != detect_128) && (current_byte != detect_256) && (current_byte != detect_512) && (current_byte != detect_768)) - { - //If none matched, it is 1024KB - break; - } - - //read byte for 128KB, 256KB, 512KB detection - read_byte = read_byte_PCE(current_byte); - - //128KB detection - if (current_byte == detect_128) - { - if (read_byte_PCE(current_byte + 128UL * 1024UL) == read_byte) - { - detect_128++; - } - } - - //256KB detection - if (current_byte == detect_256) - { - if (read_byte_PCE(current_byte + 256UL * 1024UL) == read_byte) - { - detect_256++; - } - } - - //512KB detection - if (current_byte == detect_512) - { - if (read_byte_PCE(current_byte + 512UL * 1024UL) == read_byte) - { - detect_512++; - } - } - - //768KB detection - read_byte = read_byte_PCE(current_byte + 512UL * 1024UL); - if (current_byte == detect_768) - { - if (read_byte_PCE(current_byte + 768UL * 1024UL) == read_byte) - { - detect_768++; - } - } - } - - //debug - //sprintf(fileName, "%d %d %d %d", detect_128, detect_256, detect_512, detect_768); //using filename global variable as string. Initialzed in below anyways. - //println_Msg(fileName); - - //ROM size detection by result - if (detect_128 == DETECTION_SIZE) - { - rom_size = 128; - } - else if (detect_256 == DETECTION_SIZE) - { - if (detect_512 == DETECTION_SIZE) - { - rom_size = 256; - } - else - { - //rom_size = 1024; - //Another confirmation for 384KB because 384KB hucard has data in 0x0--0x40000 and 0x80000--0xA0000(0x40000 is mirror of 0x00000) - rom_size = 384; - } - } - else if (detect_512 == DETECTION_SIZE) - { - rom_size = 512; - } - else if (detect_768 == DETECTION_SIZE) - { - rom_size = 768; - } - else - { - rom_size = 1024; - } - - //If rom size is more than or equal to 512KB, detect Street fighter II' - if (rom_size >= 512) - { - //Look for "NEC HE " - if (read_byte_PCE(0x7FFF9) == 'N' && read_byte_PCE(0x7FFFA) == 'E' && read_byte_PCE(0x7FFFB) == 'C' - && read_byte_PCE(0x7FFFC) == ' ' && read_byte_PCE(0x7FFFD) == 'H' && read_byte_PCE(0x7FFFE) == 'E') - { - rom_size = 2560; - } - } - - return rom_size; -} - -/* Must be address_start and address_end should be 512 byte aligned */ -void read_bank_PCE_ROM(uint32_t address_start, uint32_t address_end, uint32_t *processed_size, uint32_t total_size, uint32_t *crcp) -{ - uint32_t currByte; - uint16_t c; - - for (currByte = address_start; currByte < address_end; currByte += 512) { - for (c = 0; c < 512; c++) { - sdBuffer[c] = read_byte_PCE(currByte + c); - } - if (crcp != NULL) { - *crcp = calculate_crc32(512, sdBuffer, *crcp); - } - myFile.write(sdBuffer, 512); - *processed_size += 512; - draw_progressbar(*processed_size, total_size); - } -} - -void read_bank_PCE_RAM(uint32_t address_start, int block_index) -{ - uint32_t start = address_start + block_index * 512; - for (uint16_t c = 0; c < 512; c++) { - sdBuffer[c] = read_byte_PCE(start + c); - } -} - -//Get line from file and convert upper case to lower case -void skip_line(FsFile* readfile) -{ - int i = 0; - char str_buf; - - while (readfile->available()) - { - //Read 1 byte from file - str_buf = readfile->read(); - - //if end of file or newline found, execute command - if (str_buf == '\r') - { - readfile->read(); //dispose \n because \r\n - break; - } - i++; - }//End while -} - -//Get line from file and convert upper case to lower case -void get_line(char* str_buf, FsFile* readfile, uint8_t maxi) -{ - int i = 0; - - while (readfile->available()) - { - //If line size is more than maximum array, limit it. - if (i >= maxi) - { - i = maxi - 1; - } - - //Read 1 byte from file - str_buf[i] = readfile->read(); - - //if end of file or newline found, execute command - if (str_buf[i] == '\r') - { - str_buf[i] = '\0'; - readfile->read(); //dispose \n because \r\n - break; - } - i++; - }//End while -} - -uint32_t calculate_crc32(int n, unsigned char c[], uint32_t r) -{ - int i, j; - - for (i = 0; i < n; i++) { - r ^= c[i]; - for (j = 0; j < 8; j++) - if (r & 1) r = (r >> 1) ^ 0xEDB88320UL; - else r >>= 1; - } - return r; -} - -void crc_search(char *file_p, char *folder_p, uint32_t rom_size, uint32_t crc) -{ - FsFile rom, script; - uint32_t r, processedsize; - char gamename[100]; - char crc_file[9], crc_search[9]; - uint8_t flag; - flag = CHKSUM_SKIP; - - //Open list file. If no list file found, just skip - sd.chdir("/"); //Set read directry to root - if (script.open("PCE_CRC_LIST.txt", O_READ)) - { - //Calculate CRC of ROM file - sd.chdir(folder_p); - if (rom.open(file_p, O_READ)) - { - //Initialize flag as error - flag = CHKSUM_ERROR; - crc = crc ^ 0xFFFFFFFFUL; //Finish CRC calculation and progress bar - //Display calculated CRC - sprintf(crc_file, "%08lX", crc); - - //Search for same CRC in list - while (script.available()) { - //Read 2 lines (game name and CRC) - get_line(gamename, &script, 96); - get_line(crc_search, &script, 9); - skip_line(&script); //Skip every 3rd line - - //if checksum search successful, rename the file and end search - if (strcmp(crc_search, crc_file) == 0) - { - print_Msg(F("Chksum OK ")); - println_Msg(crc_file); - print_Msg(F("Saved to ")); - print_Msg(folder_p); - print_Msg(F("/")); - print_Msg(gamename); - print_Msg(F(".pce")); - flag = CHKSUM_OK; - strcat(gamename, ".pce"); - - // Open filepath directory - if (!myDir.open(folder_p)) { - display_Clear(); - print_Error(F("SD Error"), true); - } - rom.rename(&myDir, gamename); - myDir.close(); - break; - } - } - rom.close(); - } - } - - - if (flag == CHKSUM_SKIP) - { - print_Msg(F("Saved to ")); - print_Msg(folder_p); - print_Msg(F("/")); - print_Msg(file_p); - } - else if (flag == CHKSUM_ERROR) - { - print_Msg(F("Chksum Error ")); - println_Msg(crc_file); - print_Msg(F("Saved to ")); - print_Msg(folder_p); - print_Msg(F("/")); - print_Msg(file_p); - } - - script.close(); - -} - -void unlock_tennokoe_bank_RAM() -{ - write_byte_PCE(0x0D0000, 0x68); //Unlock RAM sequence 1 Bank 68 - write_byte_PCE(0x0F0000, 0x00); //Unlock RAM sequence 2 Bank 78 - write_byte_PCE(0x0F0000, 0x73); //Unlock RAM sequence 3 Bank 78 - write_byte_PCE(0x0F0000, 0x73); //Unlock RAM sequence 4 Bank 78 - write_byte_PCE(0x0F0000, 0x73); //Unlock RAM sequence 5 Bank 78 -} - -void lock_tennokoe_bank_RAM() -{ - write_byte_PCE(0x0D0000, 0x68); //Lock RAM sequence 1 Bank 68 - write_byte_PCE(0x0F0001, 0x00); //Lock RAM sequence 2 Bank 78 - write_byte_PCE(0x0C0001, 0x60); //Lock RAM sequence 3 Bank 60 -} - -void read_tennokoe_bank_PCE(int bank_index) -{ - uint32_t processed_size = 0; - uint32_t verify_loop; - uint8_t verify_flag = 1; - - //clear the screen - display_Clear(); - - 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); - - // create a new folder for the save file - EEPROM_readAnything(0, foldern); - sd.chdir("/"); - sprintf(folder, "PCE/ROM/%d", foldern); - sd.mkdir(folder, true); - sd.chdir(folder); - - print_Msg(F("Saving RAM to ")); - print_Msg(folder); - print_Msg(F("/")); - println_Msg(fileName); - display_Update(); - - // 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); - } - - pin_read_write_PCE(); - - for (int block_index = 0; block_index < 4; block_index++) { - //Unlock Tennokoe Bank RAM - //Disable interrupts - noInterrupts(); - data_output_PCE(); - unlock_tennokoe_bank_RAM(); - data_input_PCE(); - - //Read Tennokoe bank RAM - read_bank_PCE_RAM(0x080000 + 2048UL * bank_index, block_index); - - //Lock Tennokoe Bank RAM - data_output_PCE(); - lock_tennokoe_bank_RAM(); - data_input_PCE(); - //Enable interrupts - interrupts(); - - // hexdump: - // for (int c = 0; c < 512; c += 16) { - // for (int i = 0; i < 16; i++) { - // uint8_t b = sdBuffer[c + i]; - // print_Msg_PaddedHexByte(b); - // //print_Msg(F(" ")); - // } - // println_Msg(F("")); - // } - - if (block_index == 0) { - print_Msg(F("header: ")); - for (int i = 0; i < 4; i++) { - uint8_t b = sdBuffer[i]; - print_Msg_PaddedHexByte(b); - } - println_Msg(F("")); - } - if (block_index == 0 && sdBuffer[2] == 0x42 && sdBuffer[3] == 0x4D) { - if (sdBuffer[0] != 0x48 || sdBuffer[1] != 0x55) { - sdBuffer[0] = 0x48; // H - sdBuffer[1] = 0x55; // U - println_Msg(F("Corrected header")); - } else { - println_Msg(F("Header is correct")); - } - } - myFile.write(sdBuffer, 512); - } - - pin_init_PCE(); - - //Close the file: - myFile.close(); - -} - -void write_tennokoe_bank_PCE(int bank_index) -{ - //Display file Browser and wait user to select a file. Size must be 2KB. - filePath[0] = '\0'; - sd.chdir("/"); - fileBrowser(F("Select RAM 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 != 2 * 1024UL) { - println_Msg(F("File must be 2KB")); - display_Update(); - myFile.close(); - wait(); - return; - } - - pin_read_write_PCE(); - - for (int block_index = 0; block_index < 4; block_index++) { - for (uint16_t c = 0; c < 512; c++) { - sdBuffer[c] = myFile.read(); - } - //Unlock Tennokoe Bank RAM - //Disable interrupts - noInterrupts(); - data_output_PCE(); - unlock_tennokoe_bank_RAM(); - data_input_PCE(); - - //Write file to Tennokoe BANK RAM - data_output_PCE(); - uint32_t offset = 0x080000 + (bank_index * 2048UL) + (block_index * 512UL); - for (uint16_t c = 0; c < 512; c++) { - write_byte_PCE(offset + c, sdBuffer[c]); - } - - //Lock Tennokoe Bank RAM - lock_tennokoe_bank_RAM(); - data_input_PCE(); - //Enable interrupts - interrupts(); - } - - // verify - int diffcnt = 0; - myFile.seekSet(0); - for (int block_index = 0; block_index < 4; block_index++) { - //Unlock Tennokoe Bank RAM - //Disable interrupts - noInterrupts(); - data_output_PCE(); - unlock_tennokoe_bank_RAM(); - data_input_PCE(); - //Read Tennokoe bank RAM - read_bank_PCE_RAM(0x080000 + 2048UL * bank_index, block_index); - //Lock Tennokoe Bank RAM - data_output_PCE(); - lock_tennokoe_bank_RAM(); - data_input_PCE(); - //Enable interrupts - interrupts(); - int diffcnt = 0; - for (int c = 0; c < 512; c += 16) { - uint8_t ram_b = sdBuffer[c]; - uint8_t file_b = myFile.read(); - if (ram_b != file_b) { - diffcnt++; - } - } - } - if (diffcnt == 0) { - println_Msg(F("Verify OK...")); - } else { - println_Msg(F("Verify failed...")); - print_Msg(diffcnt); - println_Msg(F(" bytes ")); - print_Error(F("did not verify."), false); - } - - pin_init_PCE(); - - // Close the file: - myFile.close(); - println_Msg(F("Finished")); - display_Update(); - wait(); - } - else { - print_Error(F("File doesn't exist"), false); - } -} - -void read_rom_PCE(void) -{ - uint32_t rom_size; - uint32_t processed_size = 0; - - //clear the screen - display_Clear(); - rom_size = detect_rom_size_PCE(); - if (pce_force_rom_size > 0) { - rom_size = pce_force_rom_size; - print_Msg(F("Forced size: ")); - } else { - print_Msg(F("Detected size: ")); - } - print_Msg(rom_size); - println_Msg(F("KB")); - - // Get name, add extension and convert to char array for sd lib - strcpy(fileName, "PCEROM"); - strcat(fileName, ".pce"); - - // create a new folder for the save file - EEPROM_readAnything(0, foldern); - sd.chdir("/"); - sprintf(folder, "PCE/ROM/%d", foldern); - sd.mkdir(folder, true); - sd.chdir(folder); - - print_Msg(F("Saving ROM to ")); - print_Msg(folder); - print_Msg(F("/")); - println_Msg(fileName); - display_Update(); - - // 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); - } - - pin_read_write_PCE(); - - //Initialize progress bar by setting processed size as 0 - draw_progressbar(0, rom_size * 1024UL); - - uint32_t crc = 0xFFFFFFFFUL; //Initialize CRC - if (rom_size == 384) - { - //Read two sections. 0x000000--0x040000 and 0x080000--0x0A0000 for 384KB - read_bank_PCE_ROM(0, 0x40000, &processed_size, rom_size * 1024UL, &crc); - read_bank_PCE_ROM(0x80000, 0xA0000, &processed_size, rom_size * 1024UL, &crc); - } - else if (rom_size == 2560) - { - //Dump Street fighter II' Champion Edition - read_bank_PCE_ROM(0, 0x80000, &processed_size, rom_size * 1024UL, &crc); //Read first bank - data_output_PCE(); - write_byte_PCE(0x1FF0, 0xFF); //Display second bank - data_input_PCE(); - read_bank_PCE_ROM(0x80000, 0x100000, &processed_size, rom_size * 1024UL, &crc); //Read second bank - data_output_PCE(); - write_byte_PCE(0x1FF1, 0xFF); //Display third bank - data_input_PCE(); - read_bank_PCE_ROM(0x80000, 0x100000, &processed_size, rom_size * 1024UL, &crc); //Read third bank - data_output_PCE(); - write_byte_PCE(0x1FF2, 0xFF); //Display forth bank - data_input_PCE(); - read_bank_PCE_ROM(0x80000, 0x100000, &processed_size, rom_size * 1024UL, &crc); //Read forth bank - data_output_PCE(); - write_byte_PCE(0x1FF3, 0xFF); //Display fifth bank - data_input_PCE(); - read_bank_PCE_ROM(0x80000, 0x100000, &processed_size, rom_size * 1024UL, &crc); //Read fifth bank - } - else - { - //Read start form 0x000000 and keep reading until end of ROM - read_bank_PCE_ROM(0, rom_size * 1024UL, &processed_size, rom_size * 1024UL, &crc); - } - - pin_init_PCE(); - - //Close the file: - myFile.close(); - - //CRC search and rename ROM - crc_search(fileName, folder, rom_size, crc); -} - -// PC Engine Menu -void pceMenu() { - // create menu with title and 7 options to choose from - unsigned char mainMenu; - - 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); - strcpy(menuOptionspceCart[0], pceCartMenuItem1); - strcpy(menuOptionspceCart[1], pceCartMenuItem2); - strcpy(menuOptionspceCart[2], pceCartMenuItem3); - strcpy(menuOptionspceCart[3], pceCartMenuItem4); - strcpy(menuOptionspceCart[4], pceCartMenuItem5); - strcpy(menuOptionspceCart[5], pceCartMenuItem6); - if (pce_force_rom_size > 0) { - sprintf(pceCartMenuItem7, "ROM size now %dK", pce_force_rom_size); - } else { - sprintf(pceCartMenuItem7, "Force ROM size"); - } - strcpy(menuOptionspceCart[6], pceCartMenuItem7); - mainMenu = question_box(F("PCE HuCARD menu"), menuOptionspceCart, 7, 0); - - // wait for user choice to come back from the question box menu - switch (mainMenu) - { - case 0: - display_Clear(); - // Change working dir to root - sd.chdir("/"); - read_rom_PCE(); - break; - case 1: - display_Clear(); - read_tennokoe_bank_PCE(tennokoe_bank_index); - break; - case 2: - display_Clear(); - write_tennokoe_bank_PCE(tennokoe_bank_index); - break; - case 3: - resetArduino(); - break; - case 4: - if (tennokoe_bank_index < 3) { - tennokoe_bank_index++; - } - break; - case 5: - if (tennokoe_bank_index > 0) { - tennokoe_bank_index--; - } - break; - case 6: - pce_force_rom_size = 1024; - break; - } - } - else - { - // Copy menuOptions out of progmem - convertPgm(menuOptionspceTC, 2); - mainMenu = question_box(F("TG TurboChip menu"), menuOptions, 2, 0); - - // wait for user choice to come back from the question box menu - switch (mainMenu) - { - case 0: - display_Clear(); - // Change working dir to root - sd.chdir("/"); - read_rom_PCE(); - break; - - case 1: - resetArduino(); - break; - } - } - - println_Msg(F("")); - println_Msg(F("Press Button...")); - display_Update(); - wait(); -} - -#endif - -//****************************************** -// End of File -//****************************************** +//****************************************** +// PC Engine & TurboGrafx dump code by tamanegi_taro +// April 18th 2018 Revision 1.0.1 Initial version +// August 12th 2019 Revision 1.0.2 Added Tennokoe Bank support +// +// Special thanks +// sanni - Arduino cart reader +// skaman - ROM size detection +// NO-INTRO - CRC list for game name detection +// Chris Covell - Tennokoe bank support +// +//****************************************** + +#include "options.h" +#ifdef enable_PCE + +/****************************************** + Defines + *****************************************/ +#define HUCARD 0 +#define TURBOCHIP 1 +#define HUCARD_NOSWAP 2 + +#define DETECTION_SIZE 64 +#define CHKSUM_SKIP 0 +#define CHKSUM_OK 1 +#define CHKSUM_ERROR 2 + +/****************************************** + Prototype Declarations + *****************************************/ +/* Several PCE dedicated functions */ +void pin_read_write_PCE(void); +void pin_init_PCE(void); +void setup_cart_PCE(void); +void reset_cart_PCE(void); +uint8_t read_byte_PCE(uint32_t address); +void write_byte_PCE(uint32_t address, uint8_t data); +uint32_t detect_rom_size_PCE(void); +void read_bank_PCE_ROM(uint32_t address_start, uint32_t address_end, uint32_t *processed_size, uint32_t total_size); +void read_bank_PCE_RAM(uint32_t address_start); +void read_rom_PCE(void); + +/****************************************** + Variables + *****************************************/ +uint8_t pce_internal_mode; //0 - HuCARD, 1 - TurboChip + +uint16_t pce_force_rom_size = 0; +uint8_t tennokoe_bank_index = 0; + +/****************************************** + Menu +*****************************************/ +// PCE start menu +static const char pceMenuItem1[] PROGMEM = "HuCARD"; +static const char pceMenuItem2[] PROGMEM = "Turbochip"; +static const char pceMenuItem3[] PROGMEM = "HuCARD Not Swapped"; +static const char pceMenuItem4[] PROGMEM = "Reset"; +static const char* const menuOptionspce[] PROGMEM = {pceMenuItem1, pceMenuItem2, pceMenuItem3, pceMenuItem4}; + +// PCE card menu items +static const char pceCartMenuItem1[] = "Read ROM"; +static char pceCartMenuItem2[20]; +static char pceCartMenuItem3[20]; +static const char pceCartMenuItem4[] = "Reset"; +static const char pceCartMenuItem5[] = "Inc Bank Number"; +static const char pceCartMenuItem6[] = "Dec Bank Number"; +static char pceCartMenuItem7[20]; +static char menuOptionspceCart[7][20]; + +// Turbochip menu items +static const char pceTCMenuItem1[] PROGMEM = "Read ROM"; +static const char pceTCMenuItem2[] PROGMEM = "Reset"; +static const char* const menuOptionspceTC[] PROGMEM = {pceTCMenuItem1, pceTCMenuItem2}; + +// PCE start menu +void pcsMenu(void) { + // create menu with title and 3 options to choose from + unsigned char pceDev; + // Copy menuOptions out of progmem + convertPgm(menuOptionspce, 3); + pceDev = question_box(F("Select device"), menuOptions, 3, 0); + + // wait for user choice to come back from the question box menu + switch (pceDev) + { + case 0: + //Hucard + display_Clear(); + display_Update(); + pce_internal_mode = HUCARD; + setup_cart_PCE(); + mode = mode_PCE; + break; + + case 1: + //Turbografx + display_Clear(); + display_Update(); + pce_internal_mode = TURBOCHIP; + setup_cart_PCE(); + mode = mode_PCE; + break; + + case 2: + //Hucard not swapped + display_Clear(); + display_Update(); + pce_internal_mode = HUCARD_NOSWAP; + setup_cart_PCE(); + mode = mode_PCE; + break; + + case 3: + resetArduino(); + break; + } +} + +void pin_read_write_PCE(void) +{ + // Set Address Pins to Output + //A0-A7 + DDRF = 0xFF; + //A8-A15 + DDRK = 0xFF; + //A16-A19 + DDRL = (DDRL & 0xF0) | 0x0F; + + //Set Control Pin to Output CS(PL4) + DDRL |= (1 << 4); + + //Set CS(PL4) to HIGH + PORTL |= (1 << 4); + + // Set Control Pins to Output RST(PH0) RD(PH3) WR(PH5) + DDRH |= (1 << 0) | (1 << 3) | (1 << 5); + // Switch all of above to HIGH + PORTH |= (1 << 0) | (1 << 3) | (1 << 5); + + // Set IRQ(PH4) to Input + DDRH &= ~(1 << 4); + // Activate Internal Pullup Resistors + PORTH |= (1 << 4); + + // Set Data Pins (D0-D7) to Input + DDRC = 0x00; + + // Enable Internal Pullups + PORTC = 0xFF; + + set_cs_rd_low_PCE(); + + reset_cart_PCE(); +} + +void pin_init_PCE(void) +{ + + //Set Address Pins to input and pull up + DDRF = 0x00; + PORTF = 0xFF; + DDRK = 0x00; + PORTK = 0xFF; + DDRL = 0x00; + PORTL = 0xFF; + DDRH &= ~((1 << 0) | (1 << 3) | (1 << 5) | (1 << 6)); + PORTH = (1 << 0) | (1 << 3) | (1 << 5) | (1 << 6); + + // Set IRQ(PH4) to Input + DDRH &= ~(1 << 4); + // Activate Internal Pullup Resistors + PORTH |= (1 << 4); + + // Set Data Pins (D0-D7) to Input + DDRC = 0x00; + // Enable Internal Pullups + PORTC = 0xFF; + +} + +void setup_cart_PCE(void) +{ + // Set cicrstPin(PG1) to Output + DDRG |= (1 << 1); + // Output a high to disable CIC + PORTG |= (1 << 1); + + pin_init_PCE(); + +} + +void reset_cart_PCE(void) +{ + //Set RESET as Low + PORTH &= ~(1 << 0); + delay(200); + //Set RESET as High + PORTH |= (1 << 0); + delay(200); + +} + +void set_address_PCE(uint32_t address) +{ + //Set address + PORTF = address & 0xFF; + PORTK = (address >> 8) & 0xFF; + PORTL = (PORTL & 0xF0) | ((address >> 16) & 0x0F); +} + +void set_cs_rd_low_PCE () +{ + // Set CS(PL4) and RD(PH3) as LOW + PORTL &= ~(1 << 4); + PORTH &= ~(1 << 3); +} + +uint8_t read_byte_PCE(uint32_t address) +{ + uint8_t ret; + + set_address_PCE(address); + + // Arduino running at 16Mhz -> one nop = 62.5ns -> 1000ns total + __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"); + + //read byte + ret = PINC; + + //Swap bit order for PC Engine HuCARD + if (pce_internal_mode == HUCARD) + { + ret = ((ret & 0x01) << 7) | ((ret & 0x02) << 5) | ((ret & 0x04) << 3) | ((ret & 0x08) << 1) | ((ret & 0x10) >> 1) | ((ret & 0x20) >> 3) | ((ret & 0x40) >> 5) | ((ret & 0x80) >> 7); + } + + //return read data + return ret; +} + +void data_output_PCE () { + // Set Data Pins (D0-D7) to Output + DDRC = 0xFF; +} + +void data_input_PCE () { + // Set Data Pins (D0-D7) to Input + DDRC = 0x00; + // Enable Internal Pullups + PORTC = 0xFF; + + set_cs_rd_low_PCE(); +} + +void write_byte_PCE(uint32_t address, uint8_t data) +{ + //PORTH |= (1 << 3); // RD HIGH + set_address_PCE(address); + + // Arduino running at 16Mhz -> one nop = 62.5ns -> 1000ns total + __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"); + + //Swap bit order for PC Engine HuCARD + if (pce_internal_mode == HUCARD) + { + data = ((data & 0x01) << 7) | ((data & 0x02) << 5) | ((data & 0x04) << 3) | ((data & 0x08) << 1) | ((data & 0x10) >> 1) | ((data & 0x20) >> 3) | ((data & 0x40) >> 5) | ((data & 0x80) >> 7); + } + + //write byte + PORTC = data; + + // Set CS(PL4) and WR(PH5) as LOW + PORTL &= ~(1 << 4); + PORTH &= ~(1 << 5); + + // Arduino running at 16Mhz -> one nop = 62.5ns -> 1000ns total + __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"); + + // Set CS(PL4) and WR(PH5) as HIGH + PORTL |= (1 << 4); + PORTH |= (1 << 5); +} + +//Confirm the size of ROM - 128Kb, 256Kb, 384Kb, 512Kb, 768Kb or 1024Kb +uint32_t detect_rom_size_PCE(void) +{ + uint32_t rom_size; + uint8_t read_byte; + uint8_t current_byte; + uint8_t detect_128, detect_256, detect_512, detect_768; + + //Initialize variables + detect_128 = 0; + detect_256 = 0; + detect_512 = 0; + detect_768 = 0; + + //Set pins to read PC Engine cart + pin_read_write_PCE(); + + //Confirm where mirror address start from(128KB, 256KB, 512KB, 768, or 1024KB) + for (current_byte = 0; current_byte < DETECTION_SIZE; current_byte++) { + if ((current_byte != detect_128) && (current_byte != detect_256) && (current_byte != detect_512) && (current_byte != detect_768)) + { + //If none matched, it is 1024KB + break; + } + + //read byte for 128KB, 256KB, 512KB detection + read_byte = read_byte_PCE(current_byte); + + //128KB detection + if (current_byte == detect_128) + { + if (read_byte_PCE(current_byte + 128UL * 1024UL) == read_byte) + { + detect_128++; + } + } + + //256KB detection + if (current_byte == detect_256) + { + if (read_byte_PCE(current_byte + 256UL * 1024UL) == read_byte) + { + detect_256++; + } + } + + //512KB detection + if (current_byte == detect_512) + { + if (read_byte_PCE(current_byte + 512UL * 1024UL) == read_byte) + { + detect_512++; + } + } + + //768KB detection + read_byte = read_byte_PCE(current_byte + 512UL * 1024UL); + if (current_byte == detect_768) + { + if (read_byte_PCE(current_byte + 768UL * 1024UL) == read_byte) + { + detect_768++; + } + } + } + + //debug + //sprintf(fileName, "%d %d %d %d", detect_128, detect_256, detect_512, detect_768); //using filename global variable as string. Initialzed in below anyways. + //println_Msg(fileName); + + //ROM size detection by result + if (detect_128 == DETECTION_SIZE) + { + rom_size = 128; + } + else if (detect_256 == DETECTION_SIZE) + { + if (detect_512 == DETECTION_SIZE) + { + rom_size = 256; + } + else + { + //rom_size = 1024; + //Another confirmation for 384KB because 384KB hucard has data in 0x0--0x40000 and 0x80000--0xA0000(0x40000 is mirror of 0x00000) + rom_size = 384; + } + } + else if (detect_512 == DETECTION_SIZE) + { + rom_size = 512; + } + else if (detect_768 == DETECTION_SIZE) + { + rom_size = 768; + } + else + { + rom_size = 1024; + } + + //If rom size is more than or equal to 512KB, detect Street fighter II' + if (rom_size >= 512) + { + //Look for "NEC HE " + if (read_byte_PCE(0x7FFF9) == 'N' && read_byte_PCE(0x7FFFA) == 'E' && read_byte_PCE(0x7FFFB) == 'C' + && read_byte_PCE(0x7FFFC) == ' ' && read_byte_PCE(0x7FFFD) == 'H' && read_byte_PCE(0x7FFFE) == 'E') + { + rom_size = 2560; + } + } + + return rom_size; +} + +/* Must be address_start and address_end should be 512 byte aligned */ +void read_bank_PCE_ROM(uint32_t address_start, uint32_t address_end, uint32_t *processed_size, uint32_t total_size, uint32_t *crcp) +{ + uint32_t currByte; + uint16_t c; + + for (currByte = address_start; currByte < address_end; currByte += 512) { + for (c = 0; c < 512; c++) { + sdBuffer[c] = read_byte_PCE(currByte + c); + } + if (crcp != NULL) { + *crcp = calculate_crc32(512, sdBuffer, *crcp); + } + myFile.write(sdBuffer, 512); + *processed_size += 512; + draw_progressbar(*processed_size, total_size); + } +} + +void read_bank_PCE_RAM(uint32_t address_start, int block_index) +{ + uint32_t start = address_start + block_index * 512; + for (uint16_t c = 0; c < 512; c++) { + sdBuffer[c] = read_byte_PCE(start + c); + } +} + +//Get line from file and convert upper case to lower case +void skip_line(FsFile* readfile) +{ + int i = 0; + char str_buf; + + while (readfile->available()) + { + //Read 1 byte from file + str_buf = readfile->read(); + + //if end of file or newline found, execute command + if (str_buf == '\r') + { + readfile->read(); //dispose \n because \r\n + break; + } + i++; + }//End while +} + +//Get line from file and convert upper case to lower case +void get_line(char* str_buf, FsFile* readfile, uint8_t maxi) +{ + int i = 0; + + while (readfile->available()) + { + //If line size is more than maximum array, limit it. + if (i >= maxi) + { + i = maxi - 1; + } + + //Read 1 byte from file + str_buf[i] = readfile->read(); + + //if end of file or newline found, execute command + if (str_buf[i] == '\r') + { + str_buf[i] = '\0'; + readfile->read(); //dispose \n because \r\n + break; + } + i++; + }//End while +} + +uint32_t calculate_crc32(int n, unsigned char c[], uint32_t r) +{ + int i, j; + + for (i = 0; i < n; i++) { + r ^= c[i]; + for (j = 0; j < 8; j++) + if (r & 1) r = (r >> 1) ^ 0xEDB88320UL; + else r >>= 1; + } + return r; +} + +void crc_search(char *file_p, char *folder_p, uint32_t rom_size, uint32_t crc) +{ + FsFile rom, script; + uint32_t r, processedsize; + char gamename[100]; + char crc_file[9], crc_search[9]; + uint8_t flag; + flag = CHKSUM_SKIP; + + //Open list file. If no list file found, just skip + sd.chdir("/"); //Set read directry to root + if (script.open("PCE_CRC_LIST.txt", O_READ)) + { + //Calculate CRC of ROM file + sd.chdir(folder_p); + if (rom.open(file_p, O_READ)) + { + //Initialize flag as error + flag = CHKSUM_ERROR; + crc = crc ^ 0xFFFFFFFFUL; //Finish CRC calculation and progress bar + //Display calculated CRC + sprintf(crc_file, "%08lX", crc); + + //Search for same CRC in list + while (script.available()) { + //Read 2 lines (game name and CRC) + get_line(gamename, &script, 96); + get_line(crc_search, &script, 9); + skip_line(&script); //Skip every 3rd line + + //if checksum search successful, rename the file and end search + if (strcmp(crc_search, crc_file) == 0) + { + print_Msg(F("Chksum OK ")); + println_Msg(crc_file); + print_Msg(F("Saved to ")); + print_Msg(folder_p); + print_Msg(F("/")); + print_Msg(gamename); + print_Msg(F(".pce")); + flag = CHKSUM_OK; + strcat(gamename, ".pce"); + + // Open filepath directory + if (!myDir.open(folder_p)) { + display_Clear(); + print_Error(F("SD Error"), true); + } + rom.rename(&myDir, gamename); + myDir.close(); + break; + } + } + rom.close(); + } + } + + + if (flag == CHKSUM_SKIP) + { + print_Msg(F("Saved to ")); + print_Msg(folder_p); + print_Msg(F("/")); + print_Msg(file_p); + } + else if (flag == CHKSUM_ERROR) + { + print_Msg(F("Chksum Error ")); + println_Msg(crc_file); + print_Msg(F("Saved to ")); + print_Msg(folder_p); + print_Msg(F("/")); + print_Msg(file_p); + } + + script.close(); + +} + +void unlock_tennokoe_bank_RAM() +{ + write_byte_PCE(0x0D0000, 0x68); //Unlock RAM sequence 1 Bank 68 + write_byte_PCE(0x0F0000, 0x00); //Unlock RAM sequence 2 Bank 78 + write_byte_PCE(0x0F0000, 0x73); //Unlock RAM sequence 3 Bank 78 + write_byte_PCE(0x0F0000, 0x73); //Unlock RAM sequence 4 Bank 78 + write_byte_PCE(0x0F0000, 0x73); //Unlock RAM sequence 5 Bank 78 +} + +void lock_tennokoe_bank_RAM() +{ + write_byte_PCE(0x0D0000, 0x68); //Lock RAM sequence 1 Bank 68 + write_byte_PCE(0x0F0001, 0x00); //Lock RAM sequence 2 Bank 78 + write_byte_PCE(0x0C0001, 0x60); //Lock RAM sequence 3 Bank 60 +} + +void read_tennokoe_bank_PCE(int bank_index) +{ + uint32_t processed_size = 0; + uint32_t verify_loop; + uint8_t verify_flag = 1; + + //clear the screen + display_Clear(); + + 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); + + // create a new folder for the save file + EEPROM_readAnything(0, foldern); + sd.chdir("/"); + sprintf(folder, "PCE/ROM/%d", foldern); + sd.mkdir(folder, true); + sd.chdir(folder); + + print_Msg(F("Saving RAM to ")); + print_Msg(folder); + print_Msg(F("/")); + println_Msg(fileName); + display_Update(); + + // 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); + } + + pin_read_write_PCE(); + + for (int block_index = 0; block_index < 4; block_index++) { + //Unlock Tennokoe Bank RAM + //Disable interrupts + noInterrupts(); + data_output_PCE(); + unlock_tennokoe_bank_RAM(); + data_input_PCE(); + + //Read Tennokoe bank RAM + read_bank_PCE_RAM(0x080000 + 2048UL * bank_index, block_index); + + //Lock Tennokoe Bank RAM + data_output_PCE(); + lock_tennokoe_bank_RAM(); + data_input_PCE(); + //Enable interrupts + interrupts(); + + // hexdump: + // for (int c = 0; c < 512; c += 16) { + // for (int i = 0; i < 16; i++) { + // uint8_t b = sdBuffer[c + i]; + // print_Msg_PaddedHexByte(b); + // //print_Msg(F(" ")); + // } + // println_Msg(F("")); + // } + + if (block_index == 0) { + print_Msg(F("header: ")); + for (int i = 0; i < 4; i++) { + uint8_t b = sdBuffer[i]; + print_Msg_PaddedHexByte(b); + } + println_Msg(F("")); + } + if (block_index == 0 && sdBuffer[2] == 0x42 && sdBuffer[3] == 0x4D) { + if (sdBuffer[0] != 0x48 || sdBuffer[1] != 0x55) { + sdBuffer[0] = 0x48; // H + sdBuffer[1] = 0x55; // U + println_Msg(F("Corrected header")); + } else { + println_Msg(F("Header is correct")); + } + } + myFile.write(sdBuffer, 512); + } + + pin_init_PCE(); + + //Close the file: + myFile.close(); + +} + +void write_tennokoe_bank_PCE(int bank_index) +{ + //Display file Browser and wait user to select a file. Size must be 2KB. + filePath[0] = '\0'; + sd.chdir("/"); + fileBrowser(F("Select RAM 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 != 2 * 1024UL) { + println_Msg(F("File must be 2KB")); + display_Update(); + myFile.close(); + wait(); + return; + } + + pin_read_write_PCE(); + + for (int block_index = 0; block_index < 4; block_index++) { + for (uint16_t c = 0; c < 512; c++) { + sdBuffer[c] = myFile.read(); + } + //Unlock Tennokoe Bank RAM + //Disable interrupts + noInterrupts(); + data_output_PCE(); + unlock_tennokoe_bank_RAM(); + data_input_PCE(); + + //Write file to Tennokoe BANK RAM + data_output_PCE(); + uint32_t offset = 0x080000 + (bank_index * 2048UL) + (block_index * 512UL); + for (uint16_t c = 0; c < 512; c++) { + write_byte_PCE(offset + c, sdBuffer[c]); + } + + //Lock Tennokoe Bank RAM + lock_tennokoe_bank_RAM(); + data_input_PCE(); + //Enable interrupts + interrupts(); + } + + // verify + int diffcnt = 0; + myFile.seekSet(0); + for (int block_index = 0; block_index < 4; block_index++) { + //Unlock Tennokoe Bank RAM + //Disable interrupts + noInterrupts(); + data_output_PCE(); + unlock_tennokoe_bank_RAM(); + data_input_PCE(); + //Read Tennokoe bank RAM + read_bank_PCE_RAM(0x080000 + 2048UL * bank_index, block_index); + //Lock Tennokoe Bank RAM + data_output_PCE(); + lock_tennokoe_bank_RAM(); + data_input_PCE(); + //Enable interrupts + interrupts(); + int diffcnt = 0; + for (int c = 0; c < 512; c += 16) { + uint8_t ram_b = sdBuffer[c]; + uint8_t file_b = myFile.read(); + if (ram_b != file_b) { + diffcnt++; + } + } + } + if (diffcnt == 0) { + println_Msg(F("Verify OK...")); + } else { + println_Msg(F("Verify failed...")); + print_Msg(diffcnt); + println_Msg(F(" bytes ")); + print_Error(F("did not verify."), false); + } + + pin_init_PCE(); + + // Close the file: + myFile.close(); + println_Msg(F("Finished")); + display_Update(); + wait(); + } + else { + print_Error(F("File doesn't exist"), false); + } +} + +void read_rom_PCE(void) +{ + uint32_t rom_size; + uint32_t processed_size = 0; + + //clear the screen + display_Clear(); + rom_size = detect_rom_size_PCE(); + if (pce_force_rom_size > 0) { + rom_size = pce_force_rom_size; + print_Msg(F("Forced size: ")); + } else { + print_Msg(F("Detected size: ")); + } + print_Msg(rom_size); + println_Msg(F("KB")); + + // Get name, add extension and convert to char array for sd lib + strcpy(fileName, "PCEROM"); + strcat(fileName, ".pce"); + + // create a new folder for the save file + EEPROM_readAnything(0, foldern); + sd.chdir("/"); + sprintf(folder, "PCE/ROM/%d", foldern); + sd.mkdir(folder, true); + sd.chdir(folder); + + print_Msg(F("Saving ROM to ")); + print_Msg(folder); + print_Msg(F("/")); + println_Msg(fileName); + display_Update(); + + // 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); + } + + pin_read_write_PCE(); + + //Initialize progress bar by setting processed size as 0 + draw_progressbar(0, rom_size * 1024UL); + + uint32_t crc = 0xFFFFFFFFUL; //Initialize CRC + if (rom_size == 384) + { + //Read two sections. 0x000000--0x040000 and 0x080000--0x0A0000 for 384KB + read_bank_PCE_ROM(0, 0x40000, &processed_size, rom_size * 1024UL, &crc); + read_bank_PCE_ROM(0x80000, 0xA0000, &processed_size, rom_size * 1024UL, &crc); + } + else if (rom_size == 2560) + { + //Dump Street fighter II' Champion Edition + read_bank_PCE_ROM(0, 0x80000, &processed_size, rom_size * 1024UL, &crc); //Read first bank + data_output_PCE(); + write_byte_PCE(0x1FF0, 0xFF); //Display second bank + data_input_PCE(); + read_bank_PCE_ROM(0x80000, 0x100000, &processed_size, rom_size * 1024UL, &crc); //Read second bank + data_output_PCE(); + write_byte_PCE(0x1FF1, 0xFF); //Display third bank + data_input_PCE(); + read_bank_PCE_ROM(0x80000, 0x100000, &processed_size, rom_size * 1024UL, &crc); //Read third bank + data_output_PCE(); + write_byte_PCE(0x1FF2, 0xFF); //Display forth bank + data_input_PCE(); + read_bank_PCE_ROM(0x80000, 0x100000, &processed_size, rom_size * 1024UL, &crc); //Read forth bank + data_output_PCE(); + write_byte_PCE(0x1FF3, 0xFF); //Display fifth bank + data_input_PCE(); + read_bank_PCE_ROM(0x80000, 0x100000, &processed_size, rom_size * 1024UL, &crc); //Read fifth bank + } + else + { + //Read start form 0x000000 and keep reading until end of ROM + read_bank_PCE_ROM(0, rom_size * 1024UL, &processed_size, rom_size * 1024UL, &crc); + } + + pin_init_PCE(); + + //Close the file: + myFile.close(); + + //CRC search and rename ROM + crc_search(fileName, folder, rom_size, crc); +} + +// PC Engine Menu +void pceMenu() { + // create menu with title and 7 options to choose from + unsigned char mainMenu; + + 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); + strcpy(menuOptionspceCart[0], pceCartMenuItem1); + strcpy(menuOptionspceCart[1], pceCartMenuItem2); + strcpy(menuOptionspceCart[2], pceCartMenuItem3); + strcpy(menuOptionspceCart[3], pceCartMenuItem4); + strcpy(menuOptionspceCart[4], pceCartMenuItem5); + strcpy(menuOptionspceCart[5], pceCartMenuItem6); + if (pce_force_rom_size > 0) { + sprintf(pceCartMenuItem7, "ROM size now %dK", pce_force_rom_size); + } else { + sprintf(pceCartMenuItem7, "Force ROM size"); + } + strcpy(menuOptionspceCart[6], pceCartMenuItem7); + mainMenu = question_box(F("PCE HuCARD menu"), menuOptionspceCart, 7, 0); + + // wait for user choice to come back from the question box menu + switch (mainMenu) + { + case 0: + display_Clear(); + // Change working dir to root + sd.chdir("/"); + read_rom_PCE(); + break; + case 1: + display_Clear(); + read_tennokoe_bank_PCE(tennokoe_bank_index); + break; + case 2: + display_Clear(); + write_tennokoe_bank_PCE(tennokoe_bank_index); + break; + case 3: + resetArduino(); + break; + case 4: + if (tennokoe_bank_index < 3) { + tennokoe_bank_index++; + } + break; + case 5: + if (tennokoe_bank_index > 0) { + tennokoe_bank_index--; + } + break; + case 6: + pce_force_rom_size = 1024; + break; + } + } + else + { + // Copy menuOptions out of progmem + convertPgm(menuOptionspceTC, 2); + mainMenu = question_box(F("TG TurboChip menu"), menuOptions, 2, 0); + + // wait for user choice to come back from the question box menu + switch (mainMenu) + { + case 0: + display_Clear(); + // Change working dir to root + sd.chdir("/"); + read_rom_PCE(); + break; + + case 1: + resetArduino(); + break; + } + } + + println_Msg(F("")); + println_Msg(F("Press Button...")); + display_Update(); + wait(); +} + +#endif + +//****************************************** +// End of File +//****************************************** diff --git a/Cart_Reader/SMS.ino b/Cart_Reader/SMS.ino index 551cee1..fc2aab2 100644 --- a/Cart_Reader/SMS.ino +++ b/Cart_Reader/SMS.ino @@ -528,8 +528,8 @@ void writeSRAM_SMS() { if (myFile.open(filePath, O_READ)) { // Get SRAM size from file, with a maximum of 32KB uint32_t sramSize = myFile.fileSize(); - if (sramSize > (32 * 1024)) { - sramSize = 32 * 1024; + if (sramSize > ((uint32_t)32 * (uint32_t)1024)) { + sramSize = (uint32_t)32 * (uint32_t)1024; } print_Msg(F("sramSize: ")); print_Msg(sramSize); diff --git a/Cart_Reader/snes_clk.cpp b/Cart_Reader/snes_clk.cpp index f3a2481..758c00e 100644 --- a/Cart_Reader/snes_clk.cpp +++ b/Cart_Reader/snes_clk.cpp @@ -4,7 +4,7 @@ int32_t readClockOffset() { FsFile clock_file; - unsigned char* clock_buf; + char* clock_buf; int16_t i; int32_t clock_offset; @@ -12,7 +12,7 @@ int32_t readClockOffset() { return INT32_MIN; } - clock_buf = malloc(12 * sizeof(char)); + clock_buf = (char*)malloc(12 * sizeof(char)); i = clock_file.read(clock_buf, 11); clock_file.close(); if (i == -1) {