From 8e155cf97b1a4d30a2cdeb80eed72e7bb082654f Mon Sep 17 00:00:00 2001 From: Kreeblah Date: Thu, 24 Feb 2022 15:59:25 -0800 Subject: Fixed build warnings --- Cart_Reader/PCE.ino | 1910 +++++++++++++++++++++++++-------------------------- 1 file changed, 955 insertions(+), 955 deletions(-) (limited to 'Cart_Reader/PCE.ino') 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 +//****************************************** -- cgit v1.2.3