diff --git a/.gitignore b/.gitignore index 3e196f5..64a151d 100644 --- a/.gitignore +++ b/.gitignore @@ -34,4 +34,5 @@ fp-info-cache ._* # ODS files -.~lock* \ No newline at end of file +.~lock* +/.vs diff --git a/Cart_Reader/Cart_Reader.ino b/Cart_Reader/Cart_Reader.ino index 6b80062..d93bfcf 100644 --- a/Cart_Reader/Cart_Reader.ino +++ b/Cart_Reader/Cart_Reader.ino @@ -659,7 +659,7 @@ boolean compareCRC(const char* database, uint32_t crc32sum, boolean renamerom, i //****************************************** // Math Functions //****************************************** -#if (defined(ENABLE_NES) || defined(ENABLE_MSX) || defined(ENABLE_GBX) || defined(ENABLE_TRS80)) +#if (defined(ENABLE_NES) || defined(ENABLE_MSX) || defined(ENABLE_GBX) || defined(ENABLE_TRS80) || defined(ENABLE_JAGUAR)) int int_pow(int base, int exp) { // Power for int int result = 1; while (exp) { @@ -751,7 +751,9 @@ void readDataLineSingleDigit(FsFile& database, void* byteData) { #endif #if ( \ - defined(ENABLE_ODY2) || defined(ENABLE_5200) || defined(ENABLE_7800) || defined(ENABLE_C64) || defined(ENABLE_VIC20) || defined(ENABLE_ATARI8)) + defined(ENABLE_ODY2) || defined(ENABLE_5200) || defined(ENABLE_7800) || defined(ENABLE_C64) || defined(ENABLE_JAGUAR) || \ + defined(ENABLE_VIC20)|| defined(ENABLE_ATARI8)\ + ) struct database_entry_mapper_size { byte gameMapper; byte gameSize; @@ -1100,23 +1102,24 @@ constexpr char modeItem22[] PROGMEM = "Casio Loopy"; constexpr char modeItem23[] PROGMEM = "Commodore 64"; constexpr char modeItem24[] PROGMEM = "Atari 5200"; constexpr char modeItem25[] PROGMEM = "Atari 7800"; -constexpr char modeItem26[] PROGMEM = "Atari Lynx"; -constexpr char modeItem27[] PROGMEM = "Vectrex"; -constexpr char modeItem28[] PROGMEM = "Atari 8-bit"; -constexpr char modeItem29[] PROGMEM = "Bally Astrocade"; -constexpr char modeItem30[] PROGMEM = "Bandai LJ"; -constexpr char modeItem31[] PROGMEM = "Bandai LJ Pro"; -constexpr char modeItem32[] PROGMEM = "Casio PV-1000"; -constexpr char modeItem33[] PROGMEM = "Commodore VIC-20"; -constexpr char modeItem34[] PROGMEM = "LF Leapster (3V)"; -constexpr char modeItem35[] PROGMEM = "RCA Studio II"; -constexpr char modeItem36[] PROGMEM = "TI-99"; -constexpr char modeItem37[] PROGMEM = "Tomy Pyuuta"; -constexpr char modeItem38[] PROGMEM = "TRS-80"; -constexpr char modeItem39[] PROGMEM = "Vtech V.Smile (3V)"; -constexpr char modeItem40[] PROGMEM = "Flashrom Programmer"; -constexpr char modeItem41[] PROGMEM = "Self Test (3V)"; -constexpr char modeItem42[] PROGMEM = "About"; +constexpr char modeItem26[] PROGMEM = "Atari Jaguar"; +constexpr char modeItem27[] PROGMEM = "Atari Lynx"; +constexpr char modeItem28[] PROGMEM = "Vectrex"; +constexpr char modeItem29[] PROGMEM = "Atari 8-bit"; +constexpr char modeItem30[] PROGMEM = "Bally Astrocade"; +constexpr char modeItem31[] PROGMEM = "Bandai LJ"; +constexpr char modeItem32[] PROGMEM = "Bandai LJ Pro"; +constexpr char modeItem33[] PROGMEM = "Casio PV-1000"; +constexpr char modeItem34[] PROGMEM = "Commodore VIC-20"; +constexpr char modeItem35[] PROGMEM = "LF Leapster (3V)"; +constexpr char modeItem36[] PROGMEM = "RCA Studio II"; +constexpr char modeItem37[] PROGMEM = "TI-99"; +constexpr char modeItem38[] PROGMEM = "Tomy Pyuuta"; +constexpr char modeItem39[] PROGMEM = "TRS-80"; +constexpr char modeItem40[] PROGMEM = "Vtech V.Smile (3V)"; +constexpr char modeItem41[] PROGMEM = "Flashrom Programmer"; +constexpr char modeItem42[] PROGMEM = "Self Test (3V)"; +constexpr char modeItem43[] PROGMEM = "About"; static const char* const modeOptions[] PROGMEM = { #ifdef ENABLE_GBX @@ -1194,55 +1197,59 @@ static const char* const modeOptions[] PROGMEM = { #ifdef ENABLE_7800 modeItem25, #endif -#ifdef ENABLE_LYNX +#ifdef ENABLE_JAGUAR modeItem26, #endif -#ifdef ENABLE_VECTREX +#ifdef ENABLE_LYNX modeItem27, #endif -#ifdef ENABLE_ATARI8 +#ifdef ENABLE_VECTREX modeItem28, #endif -#ifdef ENABLE_BALLY +#ifdef ENABLE_ATARI8 modeItem29, #endif -#ifdef ENABLE_LJ +#ifdef ENABLE_BALLY modeItem30, #endif -#ifdef ENABLE_LJPRO +#ifdef ENABLE_LJ modeItem31, #endif -#ifdef ENABLE_PV1000 +#ifdef ENABLE_LJPRO modeItem32, #endif -#ifdef ENABLE_VIC20 +#ifdef ENABLE_PV1000 modeItem33, #endif -#ifdef ENABLE_LEAP +#ifdef ENABLE_VIC20 modeItem34, #endif -#ifdef ENABLE_RCA +#ifdef ENABLE_LEAP modeItem35, #endif -#ifdef ENABLE_TI99 +#ifdef ENABLE_RCA modeItem36, #endif -#ifdef ENABLE_PYUUTA +#ifdef ENABLE_TI99 modeItem37, #endif -#ifdef ENABLE_TRS80 +#ifdef ENABLE_PYUUTA modeItem38, #endif -#ifdef ENABLE_VSMILE +#ifdef ENABLE_TRS80 modeItem39, #endif -#ifdef ENABLE_FLASH +#ifdef ENABLE_VSMILE modeItem40, #endif -#ifdef ENABLE_SELFTEST +#ifdef ENABLE_FLASH modeItem41, #endif - modeItem42, FSTRING_RESET +#ifdef ENABLE_SELFTEST + modeItem42, +#endif + modeItem43, FSTRING_RESET + }; uint8_t pageMenu(const __FlashStringHelper* question, const char* const* menuStrings, uint8_t entryCount, uint8_t default_choice = 0) { @@ -1445,6 +1452,12 @@ void mainMenu() { return a7800Menu(); break; #endif +#ifdef ENABLE_JAGUAR + case SYSTEM_MENU_JAGUAR: + setup_Jag(); + return jagMenu(); + break; +#endif #ifdef ENABLE_LYNX case SYSTEM_MENU_LYNX: @@ -3752,7 +3765,10 @@ void loop() { case CORE_LYNX: return lynxMenu(); #endif #ifdef ENABLE_VECTREX - case CORE_VECTREX: return vectrexMenu(); + case CORE_VECTREX: return vectrexMenu(); +#endif +#ifdef ENABLE_JAGUAR + case CORE_JAGUAR: return jagMenu(); #endif #ifdef ENABLE_ST case CORE_ST: return stMenu(); diff --git a/Cart_Reader/Config.h b/Cart_Reader/Config.h index 0fc64ce..1779812 100644 --- a/Cart_Reader/Config.h +++ b/Cart_Reader/Config.h @@ -89,6 +89,12 @@ /****/ +/* [ Atari Jaguar --------------------------------------------------- ] +*/ +//#define ENABLE_JAGUAR + +/****/ + /* [ Atari LYNX --------------------------------------------------- ] */ diff --git a/Cart_Reader/JAG.ino b/Cart_Reader/JAG.ino new file mode 100644 index 0000000..cd71ddc --- /dev/null +++ b/Cart_Reader/JAG.ino @@ -0,0 +1,1467 @@ +//****************************************************************************** +//* Atari Jaguar Module * +//* * +//* Author: skaman / cephiros * +//* Date: 2024-07-05 * +//* * +//****************************************************************************** +#ifdef ENABLE_JAGUAR +// HARDWARE PROFILE +// PIN ASSIGNMENTS +// DATA D0-D7 - PORTF +// DATA D8-D15 - PORTK +// DATA D16-D23 - PORTL +// DATA D24-D31 - PORTC +// 74HC595 (ADDR) PINS - PORTE: ADDR (PE3-PJ0), SRCLR (PE4), SRCLK (PE5) +// PORTG: RCLK (PG5) +// EEPROM PINS - EEPDO (PA5), EEPSK (PA6), EEPCS (PA7), [EEPDI = DATA D0 (PF0)] +// CONTROL PINS - PORTH: OEH (PH3), OEL (PH4), CE (PH5), WE (PH6) + +//****************************************** +// Defines +//****************************************** +uint16_t tempDataLO = 0; +uint16_t tempDataHI = 0; + +unsigned long jagCartSize; // (0x20000)/0x100000/0x200000/0x400000 +byte jagromSize = 0; // 0 = 1MB, 1 = 2MB, 2 = 4MB +// Variable to count errors +//unsigned long writeErrors; +// SAVE TYPE +// 0 = SERIAL EEPROM +// 1 = FLASH +byte jagSaveType = 0; // Serial EEPROM + +// SERIAL EEPROM 93CX6 +// CONTROL: EEPCS (PA7), EEPSK (PA6), EEPDI (PF0) [DATA D0] +// SERIAL DATA OUTPUT: EEPDO (PA5) +#define EEP_CS_SET PORTA |= (1<<7) +#define EEP_CS_CLEAR PORTA &= ~(1<<7) +#define EEP_SK_SET PORTA |= (1<<6) +#define EEP_SK_CLEAR PORTA &= ~(1<<6) +#define EEP_DI_SET PORTF |= (1<<0) +#define EEP_DI_CLEAR PORTF &= ~(1<<0) + +// SERIAL EEPROM SIZES +// 0 = 93C46 = 128 byte = Standard +// 1 = 93C56 = 256 byte = Aftermarket +// 2 = 93C66 = 512 byte = Aftermarket +// 3 = 93C76 = 1024 byte = Aftermarket +// 4 = 93C86 = 2048 byte = Aftermarket - Battlesphere Gold +int jagEepSize; +byte jagEepBuf[2]; +boolean jagEepBit[16]; + +// MEMORY TRACK CART +boolean jagMemorytrack = 0; +char jagFlashID[5]; // AT29C010 = "1FD5" +unsigned long jagflaSize = 0; // AT29C010 = 128K + +// JAGUAR EEPROM MAPPING +// 08 ROM SIZE +// 10 EEP SIZE + +//****************************************** +// MENU +//****************************************** +// Base Menu + +static const char jagMenuItem6[] PROGMEM = "Read MEMORY TRACK"; +static const char jagMenuItem7[] PROGMEM = "Write FLASH"; + +static const char* const menuOptionsJag[] PROGMEM = { FSTRING_SELECT_CART, FSTRING_READ_ROM, FSTRING_SET_SIZE, FSTRING_READ_SAVE, FSTRING_WRITE_SAVE, jagMenuItem6, jagMenuItem7 }; + +static const char jagRomItem1[] PROGMEM = "1MB ROM"; +static const char jagRomItem2[] PROGMEM = "2MB ROM"; +static const char jagRomItem3[] PROGMEM = "4MB ROM"; +static const char* const jagRomMenu[] PROGMEM = {jagRomItem1, jagRomItem2, jagRomItem3}; + +static const char jagEepItem1[] PROGMEM = "128B (93C46)"; +static const char jagEepItem2[] PROGMEM = "256B (93C56)"; +static const char jagEepItem3[] PROGMEM = "512B (93C66)"; +static const char jagEepItem4[] PROGMEM = "1024B (93C76)"; +static const char jagEepItem5[] PROGMEM = "2048B (93C86)"; +static const char* const jagSaveMenu[] PROGMEM = {jagEepItem1, jagEepItem2, jagEepItem3, jagEepItem4, jagEepItem5}; +static const char* const ConfirmMenu[] PROGMEM = {FSTRING_OK, FSTRING_RESET}; +void jagMenu() { + + convertPgm(menuOptionsJag, 7); + uint8_t mainMenu = question_box(F("Jaguar MENU"), menuOptions, 8, 0); + +// wait for user choice to come back from the question box menu + switch (mainMenu) { + // Select Cart + case 0: + setCart_Jag(); + break; + + // Read ROM + case 1: + display_Clear(); + // Change working dir to root + readJagROM(); + break; + + // Set ROM Size + case 2: + jagSizeMenu(); + jagEepMenu(); + setDefaultRomName(); + getJagCartInfo(); + break; + + // Read EEPROM + case 3: + display_Clear(); + if (jagSaveType == 0) + readJagEEP(); + else { + println_Msg(F("Cart has no EEPROM")); + display.display(); + } + break; + + // Write EEPROM + case 4: + if (jagSaveType == 0) { + // Launch file browser + sd.chdir("/"); + fileBrowser(FS(FSTRING_SELECT_FILE)); + display_Clear(); + writeJagEEP(); + } + else { + println_Msg(F("Cart has no EEPROM")); + display.display(); + } + break; + + // Read MEMORY TRACK + case 5: + readJagMEMORY(); + if (jagSaveType == 1) + readJagFLASH(); + else { + println_Msg(F("Cart has no FLASH")); + display.display(); + } + break; + + // Write FLASH + case 6: + display_Clear(); + if (jagSaveType == 1) { + // Launch file browser + sd.chdir("/"); + fileBrowser(FS(FSTRING_SELECT_FILE)); + display_Clear(); + writeJagFLASH(); + verifyJagFLASH(); + } + else { + println_Msg(F("Cart has no FLASH")); + display.display(); + } + break; + } +} + +//****************************************** +// CART SELECT CODE +//****************************************** +struct database_entry_Jag { + byte gameSize; + byte saveSize; +}; + +void readDataLine_Jag(FsFile& database, void* entry) { + struct database_entry_Jag* castEntry = (database_entry_Jag*)entry; + // Read CRC32 checksum + for (byte i = 0; i < 8; i++) { + checksumStr[i] = char(database.read()); + } + + // Skip over semicolon + database.seekCur(1); + + + // Read rom size + // Read the next ascii character and subtract 48 to convert to decimal + castEntry->gameSize = (database.read()-48); + + // Skip over semicolon + database.seekCur(1); + + // Read save size + // Read the next ascii character and subtract 48 to convert to decimal + castEntry->saveSize = (database.read()-48); + + // Skip rest of line + database.seekCur(2); +} + +void printDataLine_Jag(void* entry) { + struct database_entry_Jag* castEntry = (database_entry_Jag*)entry; + print_Msg(FS(FSTRING_SIZE)); + print_Msg(castEntry->gameSize); + println_Msg(F("MB")); + // 0 = 93C46 = 128 byte = Standard +// 1 = 93C56 = 256 byte = Aftermarket +// 2 = 93C66 = 512 byte = Aftermarket +// 3 = 93C76 = 1024 byte = Aftermarket +// 4 = 93C86 = 2048 byte = Aftermarket - Battlesphere Gold + switch (castEntry->saveSize) { + case 0: + println_Msg(F("Save: 128B")); + break; + + case 1: + println_Msg(F("Save: 256B")); + break; + + case 2: + println_Msg(F("Save: 512B")); + break; + case 3: + println_Msg(F("Save: 1KB")); + break; + case 4: + println_Msg(F("Save: 2KB")); + break; + } +} +#ifndef ENABLE_NES +void setDefaultRomName() { + romName[0] = 'C'; + romName[1] = 'A'; + romName[2] = 'R'; + romName[3] = 'T'; + romName[4] = '\0'; +} + +void setRomnameFromString(const char* input) { + uint8_t myLength = 0; + for (uint8_t i = 0; i < 20 && myLength < 15; i++) { + // Stop at first "(" to remove "(Country)" + if (input[i] == '(') { + break; + } + if ( + (input[i] >= '0' && input[i] <= '9') || (input[i] >= 'A' && input[i] <= 'Z') || (input[i] >= 'a' && input[i] <= 'z')) { + romName[myLength++] = input[i]; + } + } + + // If name consists out of all japanese characters use CART as name + if (myLength == 0) { + setDefaultRomName(); + } +} +#endif +void setCart_Jag() { + //go to root + sd.chdir(); + + struct database_entry_Jag entry; + + // Select starting letter + byte myLetter = starting_letter(); + + // Open database + if (myFile.open("jag.txt", O_READ)) { + seek_first_letter_in_database(myFile, myLetter); + + + if(checkCartSelection(myFile, &readDataLine_Jag, &entry, &printDataLine_Jag,&setRomnameFromString)) { + EEPROM_writeAnything(10, entry.saveSize); + jagEepSize = entry.saveSize; + switch (entry.gameSize) { + case 1: + jagromSize = 0; + EEPROM_writeAnything(8, jagromSize); + jagCartSize = 0x100000; + break; + + case 2: + jagromSize = 1; + EEPROM_writeAnything(8, jagromSize); + jagCartSize = 0x200000; + break; + + case 4: + jagromSize = 2; + EEPROM_writeAnything(8, jagromSize); + jagCartSize = 0x400000; + break; + } + } + } else { + print_FatalError(FS(FSTRING_DATABASE_FILE_NOT_FOUND)); + } +} + +//****************************************************************************** +// ROM SIZE MENU +//****************************************************************************** +void jagSizeMenu() { + + convertPgm(jagRomMenu, 3); + unsigned char subMenu = question_box(F("Select ROM Size"), menuOptions, 3, 0); + + switch (subMenu) { + case 0: + jagromSize = 0; + EEPROM_writeAnything(8, jagromSize); + jagCartSize = 0x100000; + break; + + case 1: + jagromSize = 1; + EEPROM_writeAnything(8, jagromSize); + jagCartSize = 0x200000; + break; + + case 2: + jagromSize = 2; + EEPROM_writeAnything(8, jagromSize); + jagCartSize = 0x400000; + break; + } +} + +//****************************************************************************** +// EEPROM SIZE MENU +//****************************************************************************** +void jagEepMenu() { + convertPgm(jagSaveMenu, 5); + unsigned char subMenu = question_box(F("Select EEPROM Size"), menuOptions, 5, 0); + + switch (subMenu) { + case 0: + jagEepSize = 0; // 128B + EEPROM_writeAnything(10, jagEepSize); + println_Msg(F("128B (93C46)")); + display.display(); + break; + + case 1: + jagEepSize = 1; // 256B + EEPROM_writeAnything(10, jagEepSize); + println_Msg(F("256B (93C56)")); + display.display(); + break; + + case 2: + jagEepSize = 2; // 512B + EEPROM_writeAnything(10, jagEepSize); + println_Msg(F("512B (93C66)")); + display.display(); + break; + + case 3: + jagEepSize = 3; // 1024B + EEPROM_writeAnything(10, jagEepSize); + println_Msg(F("1024B (93C76)")); + display.display(); + break; + + case 4: + jagEepSize = 4; // 2048B + EEPROM_writeAnything(10, jagEepSize); + println_Msg(F("2048B (93C86)")); + display.display(); + break; + } +} +//****************************************** +// SETUP +//****************************************** +void setup_Jag() { + // Request 5V + setVoltage(VOLTS_SET_5V); + + // Set Address Pins to Output ADDR(PE3)(PJ0), SRCLR(PE4), SRCLK(PE5), RCLK(PG5) + DDRE |= (1 << 3) | (1 << 4) | (1 << 5); + DDRG |= (1 << 5); + + // Set Control Pins to Output OEH(PH3), OEL(PH4), CE(PH5), WE(PH6) + DDRH |= (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6); + + // Set EEPROM Control Pins to Output EEPSK(PA6), EEPCS(PA7) + DDRA |= (1 << 6) | (1 << 7); + + // Set EEPROM Data to Input EEPDO(PA5) + DDRA &= ~(1 << 5); + + // Set Data Pins (D0-D31) to Input + DDRF = 0x00; + DDRK = 0x00; + DDRL = 0x00; + DDRC = 0x00; + + // Set Control Pins HIGH - OEH(PH3), OEL(PH4), CE(PH5), WE(PH6) + PORTH |= (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6); + + // Set 74HC595 (Address) Clear LOW - SRCLR (PE4) + PORTE &= ~(1 << 4); // Disable Address Shift Register + + EEPROM_readAnything(8, jagromSize); + EEPROM_readAnything(10, jagEepSize); + // Print all the info + if (jagromSize > 2) { + jagromSize = 1; // default 2MB + EEPROM_writeAnything(8, jagromSize); + } + jagCartSize = long(int_pow(2, jagromSize)) * 0x100000; + strcpy(romName, "JAG"); + if (jagEepSize > 4) { + jagEepSize = 0; // default 128B + EEPROM_writeAnything(10, jagEepSize); + } + readJagID(); + + if (strcmp(jagFlashID, "1FD5") == 0) { // AT29C010 128K FLASH + jagMemorytrack = 1; // Memory Track Found + jagSaveType = 1; // FLASH + strcpy(romName, "jagMemorytrack"); + jagCartSize = 0x20000; + jagflaSize = 0x20000; + } + else + setCart_Jag(); + getJagCartInfo(); + + mode = CORE_JAGUAR; +} + +//****************************************************************************** +// GET CART INFO +//****************************************************************************** +void getJagCartInfo() { + // Check for Memory Track NVRAM Cart + + display_Clear(); + println_Msg(F("CART INFO")); + print_Msg(F("Name: ")); + println_Msg(romName); + print_Msg(F("Size: ")); + if (jagMemorytrack) { + print_Msg(jagCartSize / 1024); + println_Msg(F(" KB")); + } + else { + + print_Msg(jagCartSize / 1024 / 1024 ); + println_Msg(F(" MB")); + } + if (jagSaveType == 0) { + print_Msg(F("EEPROM: ")); + print_Msg(int_pow(2, jagEepSize) * 128); // 128/256/512/1024/2048 BYTES + println_Msg(F(" B")); + } + else if (jagSaveType == 1) { + print_Msg(F("FLASH: ")); + print_Msg(jagflaSize / 1024); + println_Msg(F(" KB")); + } + display_Update(); + + println_Msg(F("Press Button...")); + + wait(); +} + +//****************************************************************************** +// SHIFT OUT +//****************************************************************************** +// SHIFT OUT ADDRESS CODE +// SN74HC595 (ADDR) PINS - PORTE: ADDR (PJ3-PE3), SRCLR (PE4), SRCLK (PE5) +// PORTG: RCLK (PG5) +// DATA (SER/DS) PIN 14 = PE3 PJ0 +// /OE (GND) PIN 13 +// LATCH (RCLK/STCP) PIN 12 - LO/HI TO OUTPUT ADDRESS = PG5 +// CLOCK (SRCLK/SHCP) PIN 11 - LO/HI TO READ ADDRESS = PE5 +// RESET (/SRCLR//MR) PIN 10 = PE4 + +#define SER_CLEAR PORTE &= ~(1 << 3); +#define SER_SET PORTE |= (1 << 3); +#define SRCLR_CLEAR PORTE &= ~(1 << 4); +#define SRCLR_SET PORTE |= (1 << 4); +#define CLOCK_CLEAR PORTE &= ~(1 << 5); +#define CLOCK_SET PORTE |= (1 << 5); +#define LATCH_CLEAR PORTG &= ~(1 << 5); +#define LATCH_SET PORTG |= (1 << 5); + +// INPUT ADDRESS BYTE IN MSB +// LATCH LO BEFORE FIRST SHIFTOUT +// LATCH HI AFTER LAST SHIFOUT +void shiftOutFAST(byte addr) { // + for (int i = 7; i >= 0; i--) { // MSB + CLOCK_CLEAR; + if (addr & (1 << i)) { + SER_SET; // 1 + } + else { + SER_CLEAR; // 0 + } + CLOCK_SET; // shift bit + SER_CLEAR; // reset 1 + } + CLOCK_CLEAR; +} + +//****************************************** +// READ DATA +//****************************************** +void readJagData(unsigned long myAddress) { + SRCLR_CLEAR; + SRCLR_SET; + LATCH_CLEAR; + + shiftOutFAST((myAddress >> 16) & 0xFF); + shiftOutFAST((myAddress >> 8) & 0xFF); + shiftOutFAST(myAddress); + LATCH_SET; + + // Arduino running at 16Mhz -> one nop = 62.5ns + __asm__("nop\n\t"); + + // Setting CE(PH5) LOW + PORTH &= ~(1 << 5); + // Setting OEH3(PH3) + OEL(PH4) LOW + PORTH &= ~(1 << 3) & ~(1 << 4); + + // Long delay here or there will be read errors + __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"); + + // Read + tempDataLO = (((PINK & 0xFF) << 8) | (PINF & 0xFF)); // D0-D15 [ROM U1] + tempDataHI = (((PINC & 0xFF) << 8) | (PINL & 0xFF)); // D16-D31 [ROM U2] + + // Setting OEH(PH3) + OEL(PH4) HIGH + PORTH |= (1 << 3) | (1 << 4); + // Setting CE(PH5) HIGH + PORTH |= (1 << 5); + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + SRCLR_CLEAR; +} +// Switch data pins to write +void dataOut_Jag() { + DDRF = 0xFF; + DDRK = 0xFF; + DDRL = 0xFF; + DDRC = 0xFF; +} + +// Switch data pins to read +void dataIn_Jag() { + DDRF = 0x00; + DDRK = 0x00; + DDRL = 0x00; + DDRC = 0x00; +} + + + +//****************************************************************************** +// READ ROM +//****************************************************************************** +// Read rom and save to the SD card +void readJagROM() { + // Set control + dataIn_Jag(); + + // Get name, add extension and convert to char array for sd lib + strcpy(fileName, romName); + strcat(fileName, ".J64"); + + // create a new folder + sd.chdir(); + EEPROM_readAnything(0, foldern); +// sprintf(folder, "JAG/ROM/%s/%d", romName, foldern); + sprintf(folder, "JAG/ROM/%d", foldern); + sd.mkdir(folder, true); + sd.chdir(folder); + + display_Clear(); + print_Msg(F("Saving ROM to ")); + print_Msg(folder); + println_Msg(F("/...")); + display_Update(); + + // write new folder number back to eeprom + foldern = foldern + 1; + EEPROM_writeAnything(0, foldern); + + // Open file on sd card + if (!myFile.open(fileName, O_RDWR | O_CREAT)) { + println_Msg(F("SD ERROR")); + println_Msg(F("Press Button to Reset")); + display_Update(); + wait(); + resetArduino(); + } + + //Initialize progress bar + uint32_t processedProgressBar = 0; + uint32_t totalProgressBar = (uint32_t)(jagCartSize); + draw_progressbar(0, totalProgressBar); + + int d = 0; + for (unsigned long currBuffer = 0; currBuffer < jagCartSize; currBuffer += 512) { + // Blink led + if (currBuffer % 16384 == 0) + blinkLED(); + // MaskROM does not use A0 + A1 - Shift Address *4 + for (int currWord = 0; currWord < 512; currWord += 4) { + readJagData(currBuffer + currWord); + // Move WORD into SD Buffer + sdBuffer[d] = (tempDataHI >> 8) & 0xFF; + sdBuffer[d + 1] = tempDataHI & 0xFF; + sdBuffer[d + 2] = (tempDataLO >> 8) & 0xFF; + sdBuffer[d + 3] = tempDataLO & 0xFF; + d += 4; + } + myFile.write(sdBuffer, 512); + d = 0; + processedProgressBar += 512; + draw_progressbar(processedProgressBar, totalProgressBar); + } + // Close the file: + myFile.close(); + + compareCRC("jag.txt", 0, 1, 0); + + println_Msg(F("Press Button...")); + display_Update(); + wait(); +} + + +//***************************************************************************** +// MICROCHIP EEPROM 93C56/66/76/86 CODE +// SERIAL DATA OUTPUT (DO): PIN PA5 +// +// ISSI 93C46-3P EEPROM ONLY USES WORD MODE +// EEPROM CODE IS WRITTEN IN WORD MODE (16bit) +// +// 93C46 (16bit): A5..A0, EWEN/ERAL/EWDS XXXX +// 93C56 (16bit): A6..A0, EWEN/ERAL/EWDS XXXXXX +// 93C66 (16bit): A7..A0, EWEN/ERAL/EWDS XXXXXX +// 93C76 (16bit): A8..A0, EWEN/ERAL/EWDS XXXXXXXX +// 93C86 (16bit): A9..A0, EWEN/ERAL/EWDS XXXXXXXX +// +// MICROCHIP EEPROM - TIE PIN 6 (ORG) TO VCC (ORG = 1) TO ENABLE 16bit MODE +// FOR 93C76 & 93C86, TIE PIN 7 (PE) TO VCC TO ENABLE PROGRAMMING +//***************************************************************************** +void Eepromdisplay_Clear() { + DDRF |= (1 << 0); // DATA PIN PF0 AS OUTPUT + DDRA &= ~(1 << 5); // DO INPUT + EEP_CS_CLEAR; + EEP_SK_CLEAR; + EEP_DI_CLEAR; +} + +void EepromresetArduino() { + DDRF &= ~(1 << 0); // DATA PIN PF0 AS INPUT + EEP_CS_CLEAR; + EEP_SK_CLEAR; + EEP_DI_CLEAR; +} + +void Eeprom0() { + EEP_DI_CLEAR; + EEP_SK_SET; + _delay_us(1); // minimum 250ns + EEP_DI_CLEAR; + EEP_SK_CLEAR; + _delay_us(1); // minimum 250ns +} + +void Eeprom1() { + EEP_DI_SET; + EEP_SK_SET; + _delay_us(1); // minimum 250ns + EEP_DI_CLEAR; + EEP_SK_CLEAR; + _delay_us(1); // minimum 250ns +} + +void EepromRead(uint16_t addr) { + Eepromdisplay_Clear(); + EEP_CS_SET; + Eeprom1(); // 1 + Eeprom1(); // 1 + Eeprom0(); // 0 + if ((jagEepSize == 1) || (jagEepSize == 3)) + Eeprom0(); // Dummy 0 for 56/76 + jagEepromSetAddress(addr); + _delay_us(12); // From Willem Timing + // DATA OUTPUT + EepromreadData(); + EEP_CS_CLEAR; + // OR 16 bits into two bytes + for (int j = 0; j < 16; j += 8) { + jagEepBuf[(j / 8)] = jagEepBit[0 + j] << 7 | jagEepBit[1 + j] << 6 | jagEepBit[2 + j] << 5 | jagEepBit[3 + j] << 4 | jagEepBit[4 + j] << 3 | jagEepBit[5 + j] << 2 | jagEepBit[6 + j] << 1 | jagEepBit[7 + j]; + } +} + +// Capture 2 bytes in 16 bits into bit array jagEepBit[] +void EepromreadData(void) { + for (int i = 0; i < 16; i++) { + EEP_SK_SET; + _delay_us(1); // minimum 250ns + jagEepBit[i] = ((PINA & 0x20) >> 5); // Read DO (PA5) - PINA with Mask 0x20 + EEP_SK_CLEAR; + _delay_us(1); // minimum 250ns + } +} + +void EepromWrite(uint16_t addr) { + Eepromdisplay_Clear(); + EEP_CS_SET; + Eeprom1(); // 1 + Eeprom0(); // 0 + Eeprom1(); // 1 + if ((jagEepSize == 1) || (jagEepSize == 3)) + Eeprom0(); // Dummy 0 for 56/76 + jagEepromSetAddress(addr); + // DATA OUTPUT + EepromWriteData(); + EEP_CS_CLEAR; + jagEepromStatus(); +} + +void EepromWriteData(void) { + byte UPPER = jagEepBuf[1]; + byte LOWER = jagEepBuf[0]; + for (int i = 0; i < 8; i++) { + if (((UPPER >> 7) & 0x1) == 1) { // Bit is HIGH + Eeprom1(); + } + else { // Bit is LOW + Eeprom0(); + } + // rotate to the next bit + UPPER <<= 1; + } + for (int j = 0; j < 8; j++) { + if (((LOWER >> 7) & 0x1) == 1) { // Bit is HIGH + Eeprom1(); + } + else { // Bit is LOW + Eeprom0(); + } + // rotate to the next bit + LOWER <<= 1; + } +} + +void jagEepromSetAddress(uint16_t addr) { // 16bit + uint8_t shiftaddr = jagEepSize + 6; // 93C46 = 0 + 6, 93C56 = 7, 93C66 = 8, 93C76 = 9, 93C86 = 10 + for (int i = 0; i < shiftaddr; i++) { + if (((addr >> shiftaddr) & 1) == 1) { // Bit is HIGH + Eeprom1(); + } + else { // Bit is LOW + Eeprom0(); + } + // rotate to the next bit + addr <<= 1; + } +} + +// EWEN/ERAL/EWDS +// 93C56/93C66 - 10000xxxxxx (6 PULSES) +// 93C76/93C86 - 10000xxxxxxxx (8 PULSES) +void EepromEWEN(void) { // EWEN 10011xxxx + Eepromdisplay_Clear(); + EEP_CS_SET; + Eeprom1(); // 1 + Eeprom0(); // 0 + Eeprom0(); // 0 + Eeprom1(); // 1 + Eeprom1(); // 1 + // 46 = 4x Trailing 0s for 16bit + Eeprom0(); // 0 + Eeprom0(); // 0 + Eeprom0(); // 0 + Eeprom0(); // 0 + // 56/66 = 6x Trailing 0s for 16bit + if (jagEepSize > 0) { + Eeprom0(); // 0 + Eeprom0(); // 0 + } + // 76/86 = 8x Trailing 0s for 16bit + if (jagEepSize > 2) { + Eeprom0(); // 0 + Eeprom0(); // 0 + } + EEP_CS_CLEAR; + _delay_us(2); + Serial.println(F("ERASE ENABLED")); +} + +void EepromERAL(void) { // ERASE ALL 10010xxxx + EEP_CS_SET; + Eeprom1(); // 1 + Eeprom0(); // 0 + Eeprom0(); // 0 + Eeprom1(); // 1 + Eeprom0(); // 0 + // 46 = 4x Trailing 0s for 16bit + Eeprom0(); // 0 + Eeprom0(); // 0 + Eeprom0(); // 0 + Eeprom0(); // 0 + // 56/66 = 6x Trailing 0s for 16bit + if (jagEepSize > 0) { + Eeprom0(); // 0 + Eeprom0(); // 0 + } + // 76/86 = 8x Trailing 0s for 16bit + if (jagEepSize > 2) { + Eeprom0(); // 0 + Eeprom0(); // 0 + } + EEP_CS_CLEAR; + jagEepromStatus(); + Serial.println(F("ERASED ALL")); +} + +void EepromEWDS(void) { // DISABLE 10000xxxx + Eepromdisplay_Clear(); + EEP_CS_SET; + Eeprom1(); // 1 + Eeprom0(); // 0 + Eeprom0(); // 0 + Eeprom0(); // 0 + Eeprom0(); // 0 + // 46 = 4x Trailing 0s for 16bit + Eeprom0(); // 0 + Eeprom0(); // 0 + Eeprom0(); // 0 + Eeprom0(); // 0 + // 56/66 = 6x Trailing 0s for 16bit + if (jagEepSize > 0) { + Eeprom0(); // 0 + Eeprom0(); // 0 + } + // 76/86 = 8x Trailing 0s for 16bit + if (jagEepSize > 2) { + Eeprom0(); // 0 + Eeprom0(); // 0 + } + EEP_CS_CLEAR; + _delay_us(2); + Serial.println(F("ERASE DISABLED")); +} + +void jagEepromStatus(void) {// CHECK READY/BUSY + __asm__("nop\n\t""nop\n\t"); // CS LOW for minimum 100ns + EEP_CS_SET; + boolean status = ((PINA & 0x20) >> 5); // Check DO + do { + _delay_ms(1); + status = ((PINA & 0x20) >> 5); + } + while (!status); // status == 0 = BUSY + EEP_CS_CLEAR; +} + +void EepromDisplay(){ // FOR SERIAL ONLY + word eepEnd = int_pow(2, jagEepSize) * 128; + for (word address = 0; address < eepEnd; address += 2) { + EepromRead(address); + if ((address % 16 == 0) && (address != 0)) + Serial.println(F("")); + if (jagEepBuf[1] < 0x10) + Serial.print(F("0")); + Serial.print(jagEepBuf[1], HEX); + Serial.print(F(" ")); + if (jagEepBuf[0] < 0x10) + Serial.print(F("0")); + Serial.print(jagEepBuf[0], HEX); + Serial.print(F(" ")); + } + Serial.println(F("")); + Serial.println(F("")); +} + +//***************************************************************************** +// EEPROM +// (0) 93C46 128B STANDARD +// (1) 93C56 256B AFTERMARKET +// (2) 93C66 512B AFTERMARKET +// (3) 93C76 1024B AFTERMARKET +// (4) 93C86 2048B AFTERMARKET - Battlesphere Gold +//***************************************************************************** +// Read EEPROM and save to the SD card +void readJagEEP() { + // Get name, add extension and convert to char array for sd lib + strcpy(fileName, romName); + strcat(fileName, ".eep"); + println_Msg(F("Reading...")); + + // create a new folder for the save file + EEPROM_readAnything(0, foldern); + sd.chdir(); +// sprintf(folder, "JAG/SAVE/%s/%d", romName, foldern); + sprintf(folder, "JAG/SAVE/%d", foldern); + sd.mkdir(folder, true); + sd.chdir(folder); + + // write new folder number back to eeprom + foldern = foldern + 1; + EEPROM_writeAnything(0, foldern); + + // Open file on sd card + if (!myFile.open(fileName, O_RDWR | O_CREAT)) { + println_Msg(F("SD ERROR")); + + println_Msg(F("Press Button to Reset")); + display_Update(); + wait(); + resetArduino(); + } + word eepEnd = int_pow(2, jagEepSize) * 64; // WORDS + if (jagEepSize > 1) { // 93C66/93C76/93C86 - 256/512/1024 WORDS + for (word currWord = 0; currWord < eepEnd; currWord += 256) { + for (int i = 0; i < 256; i++) { + EepromRead((currWord + i) * 2); + sdBuffer[(i * 2)] = jagEepBuf[1]; + sdBuffer[(i * 2) + 1] = jagEepBuf[0]; + } + myFile.write(sdBuffer, 512); + } + } + else { // 93C46/93C56 - 64/128 WORDS + for (word currWord = 0; currWord < eepEnd; currWord++) { + EepromRead(currWord * 2); + sdBuffer[(currWord * 2)] = jagEepBuf[1]; + sdBuffer[(currWord * 2) + 1] = jagEepBuf[0]; + } + myFile.write(sdBuffer, eepEnd * 2); + } + EepromresetArduino(); + // Close the file: + myFile.close(); + println_Msg(F("")); + print_Msg(F("Saved to ")); + println_Msg(folder); + display_Update(); + wait(); +} + +// NOTE: TO WRITE TO 93C76 & 93C86, MUST TIE PE (PROGRAM ENABLE) PIN 7 TO VCC +void writeJagEEP() { + // Create filepath + sprintf(filePath, "%s/%s", filePath, fileName); + println_Msg(F("Writing...")); + println_Msg(filePath); + display_Update(); + + // Open file on sd card + if (myFile.open(filePath, O_READ)) { + EepromEWEN(); // ERASE/WRITE ENABLE + EepromERAL(); // ERASE ALL + Serial.println(F("WRITING")); + word eepEnd = int_pow(2, jagEepSize) * 64; // WORDS + if (jagEepSize > 1) { // 93C66/93C76/93C86 + for (word currWord = 0; currWord < eepEnd; currWord += 256) { + myFile.read(sdBuffer, 512); + for (int i = 0; i < 256; i++) { + jagEepBuf[0] = sdBuffer[(i * 2)]; + jagEepBuf[1] = sdBuffer[(i * 2) + 1]; + EepromWrite((currWord + i) * 2); + } + } + } + else { // 93C46/93C56 + myFile.read(sdBuffer, eepEnd * 2); + for (word currWord = 0; currWord < eepEnd; currWord++) { + jagEepBuf[0] = sdBuffer[currWord * 2]; + jagEepBuf[1] = sdBuffer[(currWord * 2) + 1]; + EepromWrite(currWord * 2); + } + } + EepromEWDS(); // ERASE/WRITE DISABLE + EepromresetArduino(); + // Close the file: + myFile.close(); + println_Msg(F("")); + println_Msg(F("DONE")); + display_Update(); + } + else { + println_Msg(F("SD ERROR")); + println_Msg(F("Press Button to Reset")); + display_Update(); + wait(); + resetArduino(); + } +} + +//***************************************************************************** +// MEMORY TRACK NVRAM FLASH +//***************************************************************************** +void readJagID() { // AT29C010 Flash ID "1FD5" + // Switch to write + dataOut_Jag(); + + // ID command sequence + writeBYTE_FLASH(0x15554, 0xAA); // 0x5555 + writeBYTE_FLASH(0xAAA8, 0x55); // 0x2AAA + writeBYTE_FLASH(0x15554, 0x90); // 0x5555 + + // Switch to read + dataIn_Jag(); + + // Read the two id bytes into a string + sprintf(jagFlashID, "%02X%02X", readBYTE_FLASH(0x0000), readBYTE_FLASH(0x0004)); + + resetFLASH(); +} + +void eraseFLASH() { // Chip Erase (NOT NEEDED FOR WRITES) + // Switch to write + dataOut_Jag(); + + println_Msg(F("Erasing...")); + display_Update(); + + // Erase command sequence + writeBYTE_FLASH(0x15554, 0xAA); // 0x5555 + writeBYTE_FLASH(0xAAA8, 0x55); // 0x2AAA + writeBYTE_FLASH(0x15554, 0x80); // 0x5555 + writeBYTE_FLASH(0x15554, 0xAA); // 0x5555 + writeBYTE_FLASH(0xAAA8, 0x55); // 0x2AAA + writeBYTE_FLASH(0x15554, 0x10); // 0x5555 + + // Wait for command to complete + busyCheck(); + + // Switch to read + dataIn_Jag(); +} + +void resetFLASH() { + // Switch to write + dataOut_Jag(); + + // Reset command sequence + writeBYTE_FLASH(0x15554, 0xAA); // 0x5555 + writeBYTE_FLASH(0xAAA8, 0x55); // 0x2AAA + writeBYTE_FLASH(0x15554, 0xF0); // 0x5555 + + // Switch to read + dataIn_Jag(); + delayMicroseconds(10); +} + +void busyCheck() { + // Switch to read + dataIn_Jag(); + + // Read register + readBYTE_FLASH(0x0000); + + // CE or OE must be toggled with each subsequent status read or the + // completion of a program or erase operation will not be evident. + while (((PINL >> 6) & 0x1) == 0) { // IO6 = PORTL PL6 + // Setting CE(PH5) HIGH + PORTH |= (1 << 5); + + // Leave CE high for at least 60ns + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Setting CE(PH5) LOW + PORTH &= ~(1 << 5); + + // Leave CE low for at least 50ns + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Read register + readBYTE_FLASH(0x0000); + } + + // Switch to write + dataOut_Jag(); +} + +byte readBYTE_FLASH(unsigned long myAddress) { + SRCLR_CLEAR; + SRCLR_SET; + LATCH_CLEAR; + shiftOutFAST((myAddress >> 16) & 0xFF); + shiftOutFAST((myAddress >> 8) & 0xFF); + shiftOutFAST(myAddress); + LATCH_SET; + + // Arduino running at 16Mhz -> one nop = 62.5ns + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Setting CE(PH5) LOW + PORTH &= ~(1 << 5); + // Setting OEH(PH3) HIGH + PORTH |= (1 << 3); + // Setting OEL(PH4) LOW + PORTH &= ~(1 << 4); + + __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"); + + // Read + byte tempByte = PINL; // D16..D23 + + // Setting CE(PH5) HIGH + PORTH |= (1 << 5); + // Setting OEL(PH4) HIGH + PORTH |= (1 << 4); + + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + return tempByte; +} + +byte readBYTE_MEMROM(unsigned long myAddress) { + SRCLR_CLEAR; + SRCLR_SET; + LATCH_CLEAR; + shiftOutFAST((myAddress >> 16) & 0xFF); + shiftOutFAST((myAddress >> 8) & 0xFF); + shiftOutFAST(myAddress); + LATCH_SET; + + // Arduino running at 16Mhz -> one nop = 62.5ns + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Setting CE(PH5) LOW + PORTH &= ~(1 << 5); + // Setting OEH(PH3) LOW + PORTH &= ~(1 << 3); + + __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"); + + // Read + byte tempByte = PINF; // D0..D7 + + // Setting CE(PH5) HIGH + PORTH |= (1 << 5); + // Setting OEH(PH3) HIGH + PORTH |= (1 << 3); + + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + return tempByte; +} + +void writeBYTE_FLASH(unsigned long myAddress, byte myData) { + SRCLR_CLEAR; + SRCLR_SET; + LATCH_CLEAR; + shiftOutFAST((myAddress >> 16) & 0xFF); + shiftOutFAST((myAddress >> 8) & 0xFF); + shiftOutFAST(myAddress); + LATCH_SET; + + PORTL = myData; + + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Setting OEL(PH4) HIGH + PORTH |= (1 << 4); + // Setting CE(PH5) LOW + PORTH &= ~(1 << 5); + // Switch WE(PH6) LOW + PORTH &= ~(1 << 6); + delayMicroseconds(10); + + // Switch WE(PH6) HIGH + PORTH |= (1 << 6); + // Setting CE(PH5) HIGH + PORTH |= (1 << 5); + delayMicroseconds(10); +} + +void writeSECTOR_FLASH(unsigned long myAddress) { + dataOut_Jag(); + + // Enable command sequence + writeBYTE_FLASH(0x15554, 0xAA); // 0x5555 + writeBYTE_FLASH(0xAAA8, 0x55); // 0x2AAA + writeBYTE_FLASH(0x15554, 0xA0); // 0x5555 + + for (int i = 0; i < 128; i++) { + SRCLR_CLEAR; + SRCLR_SET; + LATCH_CLEAR; + shiftOutFAST((((myAddress + i) * 4) >> 16) & 0xFF); + shiftOutFAST((((myAddress + i) * 4) >> 8) & 0xFF); + shiftOutFAST((myAddress + i) * 4); // (myAddress + i) * 4 + LATCH_SET; + + PORTL = sdBuffer[i]; + __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t"); + + // Setting OEL(PH4) HIGH +// PORTH |= (1 << 4); + // Setting CE(PH5) LOW + PORTH &= ~(1 << 5); + // Switch WE(PH6) LOW + PORTH &= ~(1 << 6); + __asm__("nop\n\t""nop\n\t"); // Minimum 90ns + + // Switch WE(PH6) HIGH + PORTH |= (1 << 6); + // Setting CE(PH5) HIGH + PORTH |= (1 << 5); + + __asm__("nop\n\t""nop\n\t"); // Minimum 100ns + } + delay(30); +} + +//***************************************************************************** +// MEMORY TRACK ROM U1 +// U1 ADDR PINS A0..A18 [USES A0..A17 = 0x20000 BYTES] +// U1 DATA PINS D0..D7 +// /CE ON PIN 20A (CONTROLS BOTH U1 AND U2) +// /OEH ON PIN 23B (CONTROLS U1 ROM ONLY) +//***************************************************************************** +void readJagMEMORY() { + // Set control + dataIn_Jag(); + + strcpy(fileName, romName); + strcat(fileName, ".J64"); + + // create a new folder + sd.chdir(); + EEPROM_readAnything(0, foldern); +// sprintf(folder, "JAG/ROM/%s/%d", romName, foldern); + sprintf(folder, "JAG/ROM/%d", foldern); + sd.mkdir(folder, true); + sd.chdir(folder); + + display_Clear(); + print_Msg(F("Saving ROM to ")); + print_Msg(folder); + println_Msg(F("/...")); + display_Update(); + + // write new folder number back to eeprom + foldern = foldern + 1; + EEPROM_writeAnything(0, foldern); + + // Open file on sd card + if (!myFile.open(fileName, O_RDWR | O_CREAT)) { + println_Msg(F("SD ERROR")); + println_Msg(F("Press Button to Reset")); + display_Update(); + wait(); + resetArduino(); + } + // Memory Track ROM Size 0x20000 + //Initialize progress bar + uint32_t processedProgressBar = 0; + uint32_t totalProgressBar = (uint32_t)(jagCartSize); + draw_progressbar(0, totalProgressBar); + for (unsigned long currBuffer = 0; currBuffer < jagCartSize; currBuffer += 512) { + // Blink led + if (currBuffer % 16384 == 0) + blinkLED(); + for (int currByte = 0; currByte < 512; currByte++) { + sdBuffer[currByte] = readBYTE_MEMROM(currBuffer + currByte); + } + myFile.write(sdBuffer, 512); + processedProgressBar += 512; + draw_progressbar(processedProgressBar, totalProgressBar); + } + // Close the file: + myFile.close(); + + println_Msg(F("Press Button...")); + wait(); + +} + +//***************************************************************************** +// MEMORY TRACK FLASH U2 +// AT29C010 = 0x20000 BYTES = 128 KB +// U2 ADDR PINS A2..A18 +// U2 DATA PINS D16..D23 +// /CE ON PIN 20A (CONTROLS BOTH U1 AND U2) +// /OEL ON PIN 22B (CONTROLS U2 FLASH ONLY) +//***************************************************************************** +void readJagFLASH() { + dataIn_Jag(); + strcpy(fileName, romName); + strcat(fileName, ".fla"); + + // create a new folder for the save file + sd.chdir(); + EEPROM_readAnything(0, foldern); +// sprintf(folder, "JAG/SAVE/%s/%d", romName, foldern); + sprintf(folder, "JAG/SAVE/%d", foldern); + sd.mkdir(folder, true); + sd.chdir(folder); + + display_Clear(); + print_Msg(F("Saving FLASH to ")); + print_Msg(folder); + println_Msg(F("/...")); + display_Update(); + + // write new folder number back to eeprom + foldern = foldern + 1; + EEPROM_writeAnything(0, foldern); + + // Open file on sd card + if (!myFile.open(fileName, O_RDWR | O_CREAT)) { + println_Msg(F("SD ERROR")); + println_Msg(F("Press Button to Reset")); + display_Update(); + wait(); + resetArduino(); + } + //Initialize progress bar + uint32_t processedProgressBar = 0; + uint32_t totalProgressBar = (uint32_t)(jagflaSize); + draw_progressbar(0, totalProgressBar); + for (unsigned long currByte = 0; currByte < jagflaSize; currByte += 512) { + // Blink led + if (currByte % 16384 == 0) + blinkLED(); + for (int i = 0; i < 512; i++) { + sdBuffer[i] = readBYTE_FLASH((currByte + i) * 4); // Address Shift A2..A18 + } + myFile.write(sdBuffer, 512); + processedProgressBar += 512; + draw_progressbar(processedProgressBar, totalProgressBar); + } + // Close the file: + myFile.close(); + print_Msg(F("Saved to ")); + print_Msg(folder); + println_Msg(F("/")); + + println_Msg(F("Press Button...")); + display_Update(); + wait(); +} + +// AT29C010 - Write in 128 BYTE Secrors +// Write Enable then Write DATA +void writeJagFLASH() { + dataOut_Jag(); + + // Create filepath + sprintf(filePath, "%s/%s", filePath, fileName); + println_Msg(F("Writing...")); + println_Msg(filePath); + display_Update(); + + // Open file on sd card + if (myFile.open(filePath, O_READ)) { + //Initialize progress bar + uint32_t processedProgressBar = 0; + uint32_t totalProgressBar = (uint32_t)(jagflaSize); + draw_progressbar(0, totalProgressBar); + for (unsigned long currByte = 0; currByte < jagflaSize; currByte += 128) { + // Blink led + if (currByte % 16384 == 0) + blinkLED(); + // Load Data + for (int i = 0; i < 128; i++) { + sdBuffer[i] = myFile.read() & 0xFF; + } + writeSECTOR_FLASH(currByte); + processedProgressBar += 128; + draw_progressbar(processedProgressBar, totalProgressBar); + } + // Close the file: + myFile.close(); + println_Msg(F("WRITE COMPLETE")); + display_Update(); + } + else { + println_Msg(F("SD ERROR")); + println_Msg(F("Press Button to Reset")); + display_Update(); + wait(); + resetArduino(); + } + dataIn_Jag(); +} + +unsigned long verifyJagFLASH() { + dataIn_Jag(); + writeErrors = 0; + + println_Msg(F("")); + println_Msg(F("Verifying...")); + display_Update(); + + // Open file on sd card + if (myFile.open(filePath, O_READ)) { + for (unsigned long currByte = 0; currByte < jagflaSize; currByte += 512) { + for (int i = 0; i < 512; i++) { + sdBuffer[i] = readBYTE_FLASH((currByte + i) * 4); + } + // Check sdBuffer content against file on sd card + for (int j = 0; j < 512; j++) { + if (myFile.read() != sdBuffer[j]) { + writeErrors++; + } + } + } + // Close the file: + myFile.close(); + } + else { + println_Msg(F("SD ERROR")); + println_Msg(F("Press Button to Reset")); + display_Update(); + wait(); + resetArduino(); + } + if (!writeErrors) + println_Msg(F("WRITE VERIFIED")); + else + println_Msg(F("WRITE ERROR")); + display_Update(); + println_Msg(F("Press Button...")); + display_Update(); + wait(); + // Return 0 if verified ok, or number of errors + return writeErrors; +} +//****************************************************************************** +// WRITE CONFIRM +//****************************************************************************** +void writeConfirm() { + display_Clear(); + println_Msg(F("***** WARNING ******")); + println_Msg(F("* YOU ARE ABOUT TO *")); + println_Msg(F("* ERASE SAVE DATA! *")); + println_Msg(F("********************")); + wait(); + convertPgm(ConfirmMenu, 4); + uint8_t resetMenu = question_box(F("CONTINUE?"), menuOptions, 2, 0); + +// wait for user choice to come back from the question box menu + switch (resetMenu) { + case 0: + return; + case 1: + println_Msg(F("Press Button to Reset")); + wait(); + resetArduino(); + } + +} +#endif +//****************************************** +// End of File +//****************************************** diff --git a/Cart_Reader/OSCR.h b/Cart_Reader/OSCR.h index a6fdf9d..a64c975 100644 --- a/Cart_Reader/OSCR.h +++ b/Cart_Reader/OSCR.h @@ -216,6 +216,9 @@ enum CORES: uint8_t { # ifdef ENABLE_7800 CORE_7800, # endif +# ifdef ENABLE_JAGUAR + CORE_JAGUAR, +# endif # ifdef ENABLE_LYNX CORE_LYNX, # endif @@ -343,6 +346,9 @@ enum SYSTEM_MENU: uint8_t { # if defined(ENABLE_7800) SYSTEM_MENU_7800, # endif +# if defined(ENABLE_JAGUAR) + SYSTEM_MENU_JAGUAR, +# endif # if defined(ENABLE_LYNX) SYSTEM_MENU_LYNX, # endif diff --git a/sd/jag.txt b/sd/jag.txt new file mode 100644 index 0000000..b980575 --- /dev/null +++ b/sd/jag.txt @@ -0,0 +1,305 @@ +Aircars (USA) (Beta) (1994-11-14).j64 +53E35744,1,0 + +Alien vs Predator (World).j64 +DC187F82,4,0 + +Alien vs Predator (World) (Beta) (1993-08-18).j64 +3153D470,4,0 + +Alien vs Predator (World) (Beta) (1993-10-13).j64 +B4E7BC59,4,0 + +Alien vs Predator (World) (v0.93) (Beta) (1994-04-08).j64 +E65DA590,4,0 + +Atari Karts (World).j64 +E28756DE,4,0 + +Arena Football '95 (World).j64 +199B9D83,4,0 + +Atari Karts (World) (Beta).j64 +52C996E0,4,0 + +Attack of the Mutant Penguins (World).j64 +CD5BF827,2,0 + +Barkley Shut Up and Jam (USA) (Beta).j64 +3A3B1FD2,4,0 + +Battle Sphere (World).j64 +5F2C2774,4,3 + +Battle Sphere Gold (World).j64 +67F9AB3A,4,4 + +Breakout 2000 (USA, Europe).j64 +B5604D40,2,0 + +Breakout 2000 (USA, Europe) (Beta).j64 +20DBFF9F,2,0 + +Brutal Sports Football (World).j64 +BCB1A4BF,2,0 + +Bubsy in Fractured Furry Tales (World).j64 +2E17D5DA,2,0 + +Burn Out (World) (Demo 2) (WCES 1995).j64 +0F698FB3,2,0 + +Burn Out (World) (Demo 1).j64 +701E7BBE,2,0 + +Cannon Fodder (World).j64 +BDA405C6,2,0 + +Checkered Flag (World).j64 +FA7775AE,2,0 + +Checkered Flag (World) (Beta) (CES 1993).j64 +CE94C0D5,2,0 + +Club Drive (World).j64 +EEE8D61D,2,0 + +Club Drive (World) (Beta).j64 +0E320385,2,0 + +Cybermorph (World) (Rev A).j64 +BDE67498,1,0 + +Cybermorph (World) (Rev B).j64 +ECF854E7,1,0 + +Cybermorph (World) (Beta) (1993-08-23).j64 +9EB389F9,1,0 + +Defender 2000 (World).j64 +27594C6A,4,0 + +Defender 2000 (World) (Beta).j64 +952D07F0,4,0 + +Doom (World).j64 +5E2CDBC0,4,0 + +Double Dragon V - The Shadow Falls (World).j64 +348E6449,2,0 + +Dragon - The Bruce Lee Story (World).j64 +8FEA5AB0,2,0 + +Dragon - The Bruce Lee Story (World) (Beta) (1994-09-26).j64 +A14F94AB,2,0 + +Dragon - The Bruce Lee Story (World) (Beta) (1994-10-06).j64 +83C6ACC0,2,0 + +Evolution - Dino Dudes (World).j64 +0EC5369D,2,0 + +Fever Pitch Soccer (World) (En,Fr,De,Es,It).j64 +3615AF6A,2,0 + +Fight for Life (USA, Europe).j64 +B14C4753,4,0 + +Fight for Life (USA, Europe) (Beta) (1995-03-22).j64 +59458199,4,0 + +Fight for Life (USA, Europe) (Beta) (1995-09-07).j64 +036A25E6,4,0 + +Flashback - The Quest for Identity (World) (En,Fr).j64 +DE55DCC7,2,0 + +Flip Out! (World).j64 +892BC67C,2,0 + +High Voltage C Maze (USA) (Demo).j64 +25F79B1F,2,0 + +Hover Strike (World).j64 +4899628F,2,0 + +Hyper Force (World).j64 +F0360DB3,2,0 + +I-War (USA, Europe).j64 +97EB4651,2,0 + +I-War (USA, Europe) (Beta) (1995-10-20).j64 +5BFFA5AC,2,0 + +International Sensible Soccer (World).j64 +5A101212,2,0 + +Iron Soldier (World).j64 +08F15576,2,0 + +Iron Soldier 2 (World).j64 +D6C19E34,2,0 + +Jack Nicklaus Cyber Golf (USA) (v0.02) (Proto) (1994-07-04).j64 +7733F701,2,0 + +Jack Nicklaus Cyber Golf (USA) (v0.03) (Demo) (1995-01-13).j64 +E20F0EEF,1,0 + +Jack Nicklaus Cyber Golf (USA) (v0.04) (Demo) (1995-01-16).j64 +BE5E9EF1,1,0 + +Jaguar Hockey Legends 2013 (World) (Unl).j64 +7E90046E,4,0 + +Kasumi Ninja (World).j64 +0957A072,4,0 + +Kasumi Ninja (World) (v0.01) (Beta).j64 +EE9529EE,4,0 + +Kasumi Ninja (World) (v0.29) (Beta) (1994-05-24).j64 +3D6C5D44,4,0 + +Missile Command 3D (World).j64 +DA9C4162,2,0 + +Missile Command VR (World) (Beta) (1995-07-05).j64 +5810CADB,2,0 + +NBA Jam - Tournament Edition (USA, Europe).j64 +0AC83D77,4,0 + +Phase Zero (World).j64 +7168B143,2,0 + +Painter (World) (1995-12-29) (Unl).j64 +5F9EF174,1,0 + +Pinball Fantasies (World).j64 +5CFF14AB,2,0 + +Pitfall - The Mayan Adventure (USA, Europe).j64 +817A2273,4,0 + +Plucky Duck in Hollywood Hijinks (USA) (Proto) (1994-10-28).j64 +4E77A83C,2,0 + +Power Drive Rally (World).j64 +1660F070,2,0 + +Raiden (World).j64 +0509C85E,2,0 + +Raiden (World) (Rev A).j64 +31812799,2,0 + +Rayman (World).j64 +A9F8A00E,4,0 + +Rayman (World) (Beta 2).j64 +254DD949,4,0 + +Rayman (World) (Beta 1).j64 +92743C49,4,0 + +Ruiner Pinball (USA, Europe).j64 +5B6BB205,2,0 + +Skyhammer (World).j64 +3C044941,4,0 + +SkyCopter II (USA) (Proto).j64 +4F464FA5,2,0 + +Slam Racer (USA) (Proto).j64 +E25FEC7C,4,0 + +Soccer Kid (World).j64 +732FFAB6,2,0 + +Space War 2000 (World).j64 +D821F5EB,2,0 + +Speedster II (USA) (Proto).j64 +F7CFE6E6,2,0 + +Super Burnout (World).j64 +6F8B2547,2,0 + +Supercross 3D (USA, Europe).j64 +EC22F572,2,0 + +Syndicate (World).j64 +58272540,2,0 + +Tempest 2000 (World).j64 +6B2B95AD,2,0 + +Thea Realm Fighters (USA) (Proto 2).j64 +BB06D3C6,4,0 + +Thea Realm Fighters (USA) (Proto 1).j64 +85BE7E07,4,0 + +Theme Park (World).j64 +47EBC158,2,0 + +Tiny Toon Adventures (USA) (Proto).j64 +F4ACBB04,2,0 + +Total Carnage (USA) (Beta).j64 +8F80EDCF,4,0 + +Towers II - Plight of the Stargazer (USA, Europe).j64 +83A3FB5D,2,0 + +Trevor McFur in the Crescent Galaxy (World) (Rev A).j64 +1E451446,2,0 + +Trevor McFur in the Crescent Galaxy (World) (Beta).j64 +0A055EE0,2,0 + +Trevor McFur in the Crescent Galaxy (World).j64 +95143668,2,0 + +Troy Aikman NFL Football (World).j64 +38A130ED,2,0 + +Ultimate Brain Games (USA) (Proto).j64 +8FB54827,2,0 + +Ultra Vortek (World).j64 +0F6A1C2C,4,0 + +Ultra Vortex (World) (Beta) (1995-03-20).j64 +A27823D8,4,0 + +Val d'Isere Skiing and Snowboarding (World).j64 +C9608717,2,0 + +Virtual VCS (USA) (Proto).j64 +59A8863F,1,0 + +White Men Can't Jump (USA, Europe).j64 +14915F20,4,0 + +Wolfenstein 3D (World).j64 +E91BD644,2,0 + +Worms (USA, Europe).j64 +6EB774EB,2,0 + +Zero 5 (USA) (Beta).j64 +691B54BA,2,0 + +Zool 2 (World).j64 +8975F48B,2,0 + +Zoop (USA, Europe).j64 +C5562581,1,0 + +Zzyorxx II (USA) (Demo).j64 +C8C7E4C7,1,0