mirror of
https://github.com/sanni/cartreader.git
synced 2024-11-15 09:25:06 +01:00
1468 lines
38 KiB
Arduino
1468 lines
38 KiB
Arduino
|
//******************************************************************************
|
||
|
//* 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
|
||
|
//******************************************
|