cartreader/Cart_Reader/PCE.ino
Ancyker 2cf7f5dbe7 Cleanup voltage requests
The `setVoltage()` function should be called even when `ENABLE_VSELECT` is disabled because `ENABLE_3V3FIX` also uses it. There is no resource cost to do this as when both options are disabled the compiler will optimize this function out. This just "future proofs" the code so if that function ever does more it doesn't need updated everywhere. This applies to `setup_FlashVoltage()` as well.

The changes to OSCR.cpp are just for code formatting and additional comments to clarify this.
2023-06-26 15:25:54 -04:00

895 lines
24 KiB
C++

//******************************************
// 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
//
//******************************************
#ifdef enable_PCE
/******************************************
Defines
*****************************************/
#define HUCARD 0
#define TURBOCHIP 1
#define HUCARD_NOSWAP 2
#define DETECTION_SIZE 64
#define FORCED_SIZE 1024
#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 (swapped)";
static const char pceMenuItem2[] PROGMEM = "HuCARD(not swapped)";
static const char pceMenuItem3[] PROGMEM = "Turbochip";
static const char *const menuOptionspce[] PROGMEM = { pceMenuItem1, pceMenuItem2, pceMenuItem3, string_reset2 };
// PCE card menu items
static const char menuOptionspceCart_0[] PROGMEM = "Read ROM";
static const char menuOptionspceCart_1[] PROGMEM = "Read RAM Bank %d";
static const char menuOptionspceCart_2[] PROGMEM = "Write RAM Bank %d";
static const char menuOptionspceCart_3[] PROGMEM = "Inc Bank Number";
static const char menuOptionspceCart_4[] PROGMEM = "Dec Bank Number";
static const char menuOptionspceCart_5[] PROGMEM = "Set %dK ROM size";
static const char menuOptionspceCart_5_fmt[] PROGMEM = "ROM size now %dK";
// Turbochip menu items
static const char pceTCMenuItem1[] PROGMEM = "Read ROM";
static const char *const menuOptionspceTC[] PROGMEM = { pceTCMenuItem1, string_reset2 };
// 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:
//Hucard not swapped
display_Clear();
display_Update();
pce_internal_mode = HUCARD_NOSWAP;
setup_cart_PCE();
mode = mode_PCE;
break;
case 2:
//Turbografx
display_Clear();
display_Update();
pce_internal_mode = TURBOCHIP;
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) {
// Request 5V
setVoltage(VOLTS_SET_5V);
// 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
uint32_t detect_rom_size_PCE(void) {
uint32_t rom_size;
uint8_t read_byte;
uint8_t current_byte;
uint8_t detect_32, detect_128, detect_256, detect_512, detect_768;
//Initialize variables
detect_32 = 0;
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 (32KB, 128KB, 256KB, 512KB, 768KB, or 1024KB)
for (current_byte = 0; current_byte < DETECTION_SIZE; current_byte++) {
if ((current_byte != detect_32) && (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 32KB, 128KB, 256KB, 512KB detection
read_byte = read_byte_PCE(current_byte);
//32KB detection
if (current_byte == detect_32) {
if (read_byte_PCE(current_byte + 32UL * 1024UL) == read_byte) {
detect_32++;
}
}
//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 %d", detect_32, 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_32 == DETECTION_SIZE) {
rom_size = 32;
} else 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 special cards
if (rom_size >= 512) {
//Street Fighter II' - Champion Edition (Japan)
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;
}
//Populous (Japan)
if (read_byte_PCE(0x1F26) == 'P' && read_byte_PCE(0x1F27) == 'O' && read_byte_PCE(0x1F28) == 'P' && read_byte_PCE(0x1F29) == 'U' && read_byte_PCE(0x1F2A) == 'L' && read_byte_PCE(0x1F2B) == 'O' && read_byte_PCE(0x1F2C) == 'U' && read_byte_PCE(0x1F2D) == 'S') {
rom_size = 512;
}
//Dinoforce (World)
if (read_byte_PCE(0x15A) == 'D' && read_byte_PCE(0x15B) == 'I' && read_byte_PCE(0x15C) == 'N' && read_byte_PCE(0x15D) == 'O' && read_byte_PCE(0x15E) == '-' && read_byte_PCE(0x15F) == 'F' && read_byte_PCE(0x160) == 'O' && read_byte_PCE(0x161) == 'R' && read_byte_PCE(0x162) == 'C' && read_byte_PCE(0x163) == 'E') {
rom_size = 512;
}
}
if (rom_size == 384) {
//"CD-ROM² Super System Card (v3.0)(Japan)" or "Arcade Card Pro CD-ROM²"
if (read_byte_PCE(0x29D1) == 'V' && read_byte_PCE(0x29D2) == 'E' && read_byte_PCE(0x29D3) == 'R' && read_byte_PCE(0x29D4) == '.' && read_byte_PCE(0x29D5) == ' ' && read_byte_PCE(0x29D6) == '3' && read_byte_PCE(0x29D7) == '.' && read_byte_PCE(0x29D8) == '0' && read_byte_PCE(0x29D9) == '0') {
rom_size = 256;
}
}
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);
}
}
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 __attribute__((unused)), uint32_t crc) {
FsFile rom, script;
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.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);
flag = CHKSUM_OK;
rom.rename(gamename);
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) {
//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/RAM/%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_FatalError(create_file_STR);
}
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();
println_Msg(F(""));
print_STR(press_button_STR, 1);
display_Update();
wait();
}
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);
print_STR(_bytes_STR, 1);
print_Error(did_not_verify_STR);
}
pin_init_PCE();
// Close the file:
myFile.close();
println_Msg(F("Finished"));
} else {
print_Error(F("File doesn't exist"));
}
println_Msg(F(""));
print_STR(press_button_STR, 1);
display_Update();
wait();
}
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_FatalError(create_file_STR);
}
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);
println_Msg(F(""));
print_STR(press_button_STR, 1);
display_Update();
wait();
}
// 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) {
strcpy_P(menuOptions[0], menuOptionspceCart_0);
sprintf_P(menuOptions[1], menuOptionspceCart_1, tennokoe_bank_index + 1);
sprintf_P(menuOptions[2], menuOptionspceCart_2, tennokoe_bank_index + 1);
strcpy_P(menuOptions[3], menuOptionspceCart_3);
strcpy_P(menuOptions[4], menuOptionspceCart_4);
if (pce_force_rom_size > 0) {
sprintf_P(menuOptions[5], menuOptionspceCart_5_fmt, pce_force_rom_size);
} else {
sprintf_P(menuOptions[5], menuOptionspceCart_5, FORCED_SIZE);
}
strcpy_P(menuOptions[6], string_reset2);
mainMenu = question_box(F("PCE HuCARD menu"), menuOptions, 7, 0);
// wait for user choice to come back from the question box menu
switch (mainMenu) {
case 0:
read_rom_PCE();
break;
case 1:
read_tennokoe_bank_PCE(tennokoe_bank_index);
break;
case 2:
write_tennokoe_bank_PCE(tennokoe_bank_index);
break;
case 3:
if (tennokoe_bank_index < 3) {
tennokoe_bank_index++;
}
break;
case 4:
if (tennokoe_bank_index > 0) {
tennokoe_bank_index--;
}
break;
case 5:
pce_force_rom_size = FORCED_SIZE;
break;
case 6:
resetArduino();
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:
read_rom_PCE();
break;
case 1:
resetArduino();
break;
}
}
}
#endif
//******************************************
// End of File
//******************************************