diff options
author | Kreeblah <[email protected]> | 2022-02-24 15:59:25 -0800 |
---|---|---|
committer | Kreeblah <[email protected]> | 2022-02-24 15:59:25 -0800 |
commit | 8e155cf97b1a4d30a2cdeb80eed72e7bb082654f (patch) | |
tree | 136ddb0ec2f46073cef6af1332b0e228f2d9c902 /Cart_Reader/PCE.ino | |
parent | 9eb7ba5d7cbb05f307147a60c8db14deabc92cf8 (diff) | |
download | cartreader-8e155cf97b1a4d30a2cdeb80eed72e7bb082654f.tar.gz cartreader-8e155cf97b1a4d30a2cdeb80eed72e7bb082654f.zip |
Fixed build warnings
Diffstat (limited to 'Cart_Reader/PCE.ino')
-rw-r--r-- | Cart_Reader/PCE.ino | 1910 |
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 +//****************************************** |