aboutsummaryrefslogtreecommitdiffhomepage
path: root/Cart_Reader/PCE.ino
diff options
context:
space:
mode:
authorKreeblah <[email protected]>2022-02-24 15:59:25 -0800
committerKreeblah <[email protected]>2022-02-24 15:59:25 -0800
commit8e155cf97b1a4d30a2cdeb80eed72e7bb082654f (patch)
tree136ddb0ec2f46073cef6af1332b0e228f2d9c902 /Cart_Reader/PCE.ino
parent9eb7ba5d7cbb05f307147a60c8db14deabc92cf8 (diff)
downloadcartreader-8e155cf97b1a4d30a2cdeb80eed72e7bb082654f.tar.gz
cartreader-8e155cf97b1a4d30a2cdeb80eed72e7bb082654f.zip
Fixed build warnings
Diffstat (limited to 'Cart_Reader/PCE.ino')
-rw-r--r--Cart_Reader/PCE.ino1910
1 files changed, 955 insertions, 955 deletions
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
+//******************************************