mirror of
https://github.com/sanni/cartreader.git
synced 2024-11-14 00:45:07 +01:00
V12.0: Add Atari 2600, Emerson Arcadia 2001, Fairchild Channel F, Magnavox Odyssey 2 modules (thx to skaman)
This commit is contained in:
parent
0ba515adcf
commit
248a1d9af5
534
Cart_Reader/ARC.ino
Normal file
534
Cart_Reader/ARC.ino
Normal file
@ -0,0 +1,534 @@
|
|||||||
|
//******************************************
|
||||||
|
// EMERSON ARCADIA 2001 MODULE
|
||||||
|
//******************************************
|
||||||
|
#if defined(enable_ARC)
|
||||||
|
// Emerson Arcadia 2001
|
||||||
|
// Cartridge Pinout
|
||||||
|
// 30P 2.54mm pitch connector
|
||||||
|
//
|
||||||
|
// FRONT BACK
|
||||||
|
// SIDE SIDE
|
||||||
|
// +-------+
|
||||||
|
// GND -| 2 1 |- A13 (A12)
|
||||||
|
// VCC (+5V) -| 4 3 |- D3
|
||||||
|
// A0 -| 6 5 |- D4
|
||||||
|
// A1 -| 8 7 |- D5
|
||||||
|
// A2 -| 10 9 |- D6
|
||||||
|
// A3 -| 12 11 |- D7
|
||||||
|
// A4 -| 14 13 |- D0
|
||||||
|
// A5 -| 16 15 |- D2
|
||||||
|
// A6 -| 18 17 |- D1
|
||||||
|
// A7 -| 20 19 |- NC
|
||||||
|
// A8 -| 22 21 |- NC
|
||||||
|
// A9 -| 24 23 |- NC
|
||||||
|
// A10 -| 26 25 |- GND
|
||||||
|
// A11 -| 28 27 |- GND
|
||||||
|
// A12 (/EN) -| 30 29 |- NC
|
||||||
|
// +-------+
|
||||||
|
//
|
||||||
|
// BACK
|
||||||
|
// +------------------------------------------------------------+
|
||||||
|
// | 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 |
|
||||||
|
// LEFT | | RIGHT
|
||||||
|
// | 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 |
|
||||||
|
// +------------------------------------------------------------+
|
||||||
|
// FRONT
|
||||||
|
//
|
||||||
|
|
||||||
|
byte ARC[] = { 2, 4, 6, 8 };
|
||||||
|
byte arclo = 0; // Lowest Entry
|
||||||
|
byte archi = 3; // Highest Entry
|
||||||
|
|
||||||
|
byte arcsize;
|
||||||
|
byte newarcsize;
|
||||||
|
|
||||||
|
// EEPROM MAPPING
|
||||||
|
// 08 ROM SIZE
|
||||||
|
|
||||||
|
//******************************************
|
||||||
|
// Menu
|
||||||
|
//******************************************
|
||||||
|
// Base Menu
|
||||||
|
static const char arcMenuItem1[] PROGMEM = "Select Cart";
|
||||||
|
static const char arcMenuItem2[] PROGMEM = "Read ROM";
|
||||||
|
static const char arcMenuItem3[] PROGMEM = "Set Size";
|
||||||
|
static const char arcMenuItem4[] PROGMEM = "Reset";
|
||||||
|
static const char* const menuOptionsARC[] PROGMEM = { arcMenuItem1, arcMenuItem2, arcMenuItem3, arcMenuItem4 };
|
||||||
|
|
||||||
|
void setup_ARC() {
|
||||||
|
// Set Address Pins to Output
|
||||||
|
// Arcadia 2001 uses A0-A13 [A14-A23 UNUSED]
|
||||||
|
//A0-A7
|
||||||
|
DDRF = 0xFF;
|
||||||
|
//A8-A15
|
||||||
|
DDRK = 0xFF;
|
||||||
|
//A16-A23
|
||||||
|
DDRL = 0xFF;
|
||||||
|
|
||||||
|
// Set Control Pins to Output
|
||||||
|
// ---(PH0) ---(PH1) ---(PH3) ---(PH4) ---(PH5) ---(PH6)
|
||||||
|
DDRH |= (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
||||||
|
|
||||||
|
// Set TIME(PJ0) to Output (UNUSED)
|
||||||
|
DDRJ |= (1 << 0);
|
||||||
|
|
||||||
|
// Set Pins (D0-D7) to Input
|
||||||
|
DDRC = 0x00;
|
||||||
|
|
||||||
|
// Setting Unused Control Pins to HIGH
|
||||||
|
// ---(PH0) ---(PH1) ---(PH3) ---(PH4) ---(PH5) ---(PH6)
|
||||||
|
PORTH |= (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
||||||
|
|
||||||
|
// Set Unused Data Pins (PA0-PA7) to Output
|
||||||
|
DDRA = 0xFF;
|
||||||
|
|
||||||
|
// Set Unused Pins HIGH
|
||||||
|
PORTA = 0xFF;
|
||||||
|
PORTL = 0xFF; // A16-A23
|
||||||
|
PORTJ |= (1 << 0); // TIME(PJ0)
|
||||||
|
|
||||||
|
checkStatus_ARC();
|
||||||
|
strcpy(romName, "ARCADIA");
|
||||||
|
|
||||||
|
mode = mode_ARC;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arcMenu() {
|
||||||
|
convertPgm(menuOptionsARC, 4);
|
||||||
|
uint8_t mainMenu = question_box(F("ARCADIA 2001 MENU"), menuOptions, 4, 0);
|
||||||
|
|
||||||
|
switch (mainMenu) {
|
||||||
|
case 0:
|
||||||
|
// Select Cart
|
||||||
|
setCart_ARC();
|
||||||
|
wait();
|
||||||
|
setup_ARC();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
// Read ROM
|
||||||
|
sd.chdir("/");
|
||||||
|
readROM_ARC();
|
||||||
|
sd.chdir("/");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// Set Size
|
||||||
|
setROMSize_ARC();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
// reset
|
||||||
|
resetArduino();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************
|
||||||
|
// READ CODE
|
||||||
|
//******************************************
|
||||||
|
|
||||||
|
uint8_t readData_ARC(uint16_t addr) {
|
||||||
|
PORTF = addr & 0xFF; // A0-A7
|
||||||
|
PORTK = (addr >> 8) & 0xFF; // A8-A13
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
uint8_t ret = PINC;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void readSegment_ARC(uint16_t startaddr, uint16_t endaddr) {
|
||||||
|
for (uint16_t addr = startaddr; addr < endaddr; addr += 512) {
|
||||||
|
for (int w = 0; w < 512; w++) {
|
||||||
|
uint8_t temp = readData_ARC(addr + w);
|
||||||
|
sdBuffer[w] = temp;
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 512);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void readROM_ARC() {
|
||||||
|
strcpy(fileName, romName);
|
||||||
|
strcat(fileName, ".bin");
|
||||||
|
|
||||||
|
// create a new folder for storing rom file
|
||||||
|
EEPROM_readAnything(0, foldern);
|
||||||
|
sprintf(folder, "ARC/ROM/%d", foldern);
|
||||||
|
sd.mkdir(folder, true);
|
||||||
|
sd.chdir(folder);
|
||||||
|
|
||||||
|
display_Clear();
|
||||||
|
print_Msg(F("Saving to "));
|
||||||
|
print_Msg(folder);
|
||||||
|
println_Msg(F("/..."));
|
||||||
|
display_Update();
|
||||||
|
|
||||||
|
// open file on sdcard
|
||||||
|
if (!myFile.open(fileName, O_RDWR | O_CREAT)) {
|
||||||
|
print_FatalError(create_file_STR);
|
||||||
|
}
|
||||||
|
// write new folder number back to EEPROM
|
||||||
|
foldern++;
|
||||||
|
EEPROM_writeAnything(0, foldern);
|
||||||
|
|
||||||
|
readSegment_ARC(0x0000, 0x0800); // 2K
|
||||||
|
if (arcsize > 0) {
|
||||||
|
readSegment_ARC(0x0800, 0x1000); // +2K = 4K
|
||||||
|
if (arcsize > 1) {
|
||||||
|
readSegment_ARC(0x2000, 0x2800); // +2K = 6K
|
||||||
|
if (arcsize > 2) {
|
||||||
|
readSegment_ARC(0x2800, 0x3000); // +2K = 8K
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
myFile.close();
|
||||||
|
|
||||||
|
unsigned long crcsize = ARC[arcsize] * 0x400;
|
||||||
|
calcCRC(fileName, crcsize, NULL, 0);
|
||||||
|
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F("Press Button..."));
|
||||||
|
display_Update();
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************
|
||||||
|
// ROM SIZE
|
||||||
|
//******************************************
|
||||||
|
|
||||||
|
void setROMSize_ARC() {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
if (arclo == archi)
|
||||||
|
newarcsize = arclo;
|
||||||
|
else {
|
||||||
|
int b = 0;
|
||||||
|
int i = arclo;
|
||||||
|
while (1) {
|
||||||
|
display_Clear();
|
||||||
|
print_Msg(F("ROM Size: "));
|
||||||
|
println_Msg(ARC[i]);
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F("Press to Change"));
|
||||||
|
println_Msg(F("Hold to Select"));
|
||||||
|
display_Update();
|
||||||
|
b = checkButton();
|
||||||
|
if (b == 2) { // Previous (doubleclick)
|
||||||
|
if (i == arclo)
|
||||||
|
i = archi;
|
||||||
|
else
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
if (b == 1) { // Next (press)
|
||||||
|
if (i == archi)
|
||||||
|
i = arclo;
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (b == 3) { // Long Press - Execute (hold)
|
||||||
|
newarcsize = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
display.setCursor(0, 56); // Display selection at bottom
|
||||||
|
}
|
||||||
|
print_Msg(F("ROM SIZE "));
|
||||||
|
print_Msg(ARC[newarcsize]);
|
||||||
|
println_Msg(F("K"));
|
||||||
|
display_Update();
|
||||||
|
delay(1000);
|
||||||
|
#else
|
||||||
|
if (arclo == archi)
|
||||||
|
newarcsize = arclo;
|
||||||
|
else {
|
||||||
|
setrom:
|
||||||
|
String sizeROM;
|
||||||
|
for (int i = 0; i < (archi - arclo + 1); i++) {
|
||||||
|
Serial.print(F("Select ROM Size: "));
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.print(F(" = "));
|
||||||
|
Serial.print(ARC[i + arclo]);
|
||||||
|
Serial.println(F("K"));
|
||||||
|
}
|
||||||
|
Serial.print(F("Enter ROM Size: "));
|
||||||
|
while (Serial.available() == 0) {}
|
||||||
|
sizeROM = Serial.readStringUntil('\n');
|
||||||
|
Serial.println(sizeROM);
|
||||||
|
newarcsize = sizeROM.toInt() + arclo;
|
||||||
|
if (newarcsize > archi) {
|
||||||
|
Serial.println(F("SIZE NOT SUPPORTED"));
|
||||||
|
Serial.println(F(""));
|
||||||
|
goto setrom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.print(F("ROM Size = "));
|
||||||
|
Serial.print(ARC[newarcsize]);
|
||||||
|
Serial.println(F("K"));
|
||||||
|
#endif
|
||||||
|
EEPROM_writeAnything(8, newarcsize);
|
||||||
|
arcsize = newarcsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkStatus_ARC() {
|
||||||
|
EEPROM_readAnything(8, arcsize);
|
||||||
|
if (arcsize > 3) {
|
||||||
|
arcsize = 0;
|
||||||
|
EEPROM_writeAnything(8, arcsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("ARCADIA 2001 READER"));
|
||||||
|
println_Msg(F("CURRENT SETTINGS"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
print_Msg(F("ROM SIZE: "));
|
||||||
|
print_Msg(ARC[arcsize]);
|
||||||
|
println_Msg(F("K"));
|
||||||
|
display_Update();
|
||||||
|
wait();
|
||||||
|
#else
|
||||||
|
Serial.print(F("CURRENT ROM SIZE: "));
|
||||||
|
Serial.print(ARC[arcsize]);
|
||||||
|
Serial.println(F("K"));
|
||||||
|
Serial.println(F(""));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************
|
||||||
|
// CART SELECT CODE
|
||||||
|
//******************************************
|
||||||
|
|
||||||
|
FsFile arccsvFile;
|
||||||
|
char arcgame[20]; // title
|
||||||
|
char arcrr[3]; // romsize
|
||||||
|
char arcll[4]; // linelength (previous line)
|
||||||
|
unsigned long arccsvpos; // CSV File Position
|
||||||
|
char arccartCSV[] = "arccart.txt"; // CSV List
|
||||||
|
char arccsvEND[] = "EOF"; // CSV End Marker for scrolling
|
||||||
|
|
||||||
|
bool readLine_ARC(FsFile& f, char* line, size_t maxLen) {
|
||||||
|
for (size_t n = 0; n < maxLen; n++) {
|
||||||
|
int c = f.read();
|
||||||
|
if (c < 0 && n == 0) return false; // EOF
|
||||||
|
if (c < 0 || c == '\n') {
|
||||||
|
line[n] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
line[n] = c;
|
||||||
|
}
|
||||||
|
return false; // line too long
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readVals_ARC(char* arcgame, char* arcrr, char* arcll) {
|
||||||
|
char line[26];
|
||||||
|
arccsvpos = arccsvFile.position();
|
||||||
|
if (!readLine_ARC(arccsvFile, line, sizeof(line))) {
|
||||||
|
return false; // EOF or too long
|
||||||
|
}
|
||||||
|
char* comma = strtok(line, ",");
|
||||||
|
int x = 0;
|
||||||
|
while (comma != NULL) {
|
||||||
|
if (x == 0)
|
||||||
|
strcpy(arcgame, comma);
|
||||||
|
else if (x == 1)
|
||||||
|
strcpy(arcrr, comma);
|
||||||
|
else if (x == 2)
|
||||||
|
strcpy(arcll, comma);
|
||||||
|
comma = strtok(NULL, ",");
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getCartListInfo_ARC() {
|
||||||
|
bool buttonreleased = 0;
|
||||||
|
bool cartselected = 0;
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F(" HOLD TO FAST CYCLE"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("HOLD BUTTON TO FAST CYCLE"));
|
||||||
|
#endif
|
||||||
|
delay(2000);
|
||||||
|
#if defined(enable_OLED)
|
||||||
|
buttonVal1 = (PIND & (1 << 7)); // PD7
|
||||||
|
#elif defined(enable_LCD)
|
||||||
|
boolean buttonVal1 = (PING & (1 << 2)); //PG2
|
||||||
|
#endif
|
||||||
|
if (buttonVal1 == LOW) { // Button Held - Fast Cycle
|
||||||
|
while (1) { // Scroll Game List
|
||||||
|
while (readVals_ARC(arcgame, arcrr, arcll)) {
|
||||||
|
if (strcmp(arccsvEND, arcgame) == 0) {
|
||||||
|
arccsvFile.seek(0); // Restart
|
||||||
|
} else {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("CART TITLE:"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(arcgame);
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.print(F("CART TITLE:"));
|
||||||
|
Serial.println(arcgame);
|
||||||
|
#endif
|
||||||
|
#if defined(enable_OLED)
|
||||||
|
buttonVal1 = (PIND & (1 << 7)); // PD7
|
||||||
|
#elif defined(enable_LCD)
|
||||||
|
buttonVal1 = (PING & (1 << 2)); //PG2
|
||||||
|
#endif
|
||||||
|
if (buttonVal1 == HIGH) { // Button Released
|
||||||
|
buttonreleased = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (buttonreleased) {
|
||||||
|
buttonreleased = 0; // Reset Flag
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if defined(enable_OLED)
|
||||||
|
buttonVal1 = (PIND & (1 << 7)); // PD7
|
||||||
|
#elif defined(enable_LCD)
|
||||||
|
buttonVal1 = (PING & (1 << 2)); //PG2
|
||||||
|
#endif
|
||||||
|
if (buttonVal1 == HIGH) // Button Released
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display.setCursor(0, 56);
|
||||||
|
println_Msg(F("FAST CYCLE OFF"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F(""));
|
||||||
|
Serial.println(F("FAST CYCLE OFF"));
|
||||||
|
Serial.println(F("PRESS BUTTON TO STEP FORWARD"));
|
||||||
|
Serial.println(F("DOUBLE CLICK TO STEP BACK"));
|
||||||
|
Serial.println(F("HOLD TO SELECT"));
|
||||||
|
Serial.println(F(""));
|
||||||
|
#endif
|
||||||
|
while (readVals_ARC(arcgame, arcrr, arcll)) {
|
||||||
|
if (strcmp(arccsvEND, arcgame) == 0) {
|
||||||
|
arccsvFile.seek(0); // Restart
|
||||||
|
} else {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("CART TITLE:"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(arcgame);
|
||||||
|
display.setCursor(0, 48);
|
||||||
|
println_Msg(F("Press to Change"));
|
||||||
|
println_Msg(F("Hold to Select"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.print(F("CART TITLE:"));
|
||||||
|
Serial.println(arcgame);
|
||||||
|
#endif
|
||||||
|
while (1) { // Single Step
|
||||||
|
int b = checkButton();
|
||||||
|
if (b == 1) { // Continue (press)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (b == 2) { // Reset to Start of List (doubleclick)
|
||||||
|
byte prevline = strtol(arcll, NULL, 10);
|
||||||
|
arccsvpos -= prevline;
|
||||||
|
arccsvFile.seek(arccsvpos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (b == 3) { // Long Press - Select Cart (hold)
|
||||||
|
newarcsize = strtol(arcrr, NULL, 10);
|
||||||
|
EEPROM_writeAnything(8, newarcsize);
|
||||||
|
cartselected = 1; // SELECTION MADE
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
println_Msg(F("SELECTION MADE"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("SELECTION MADE"));
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cartselected) {
|
||||||
|
cartselected = 0; // Reset Flag
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F("END OF FILE"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("END OF FILE"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkCSV_ARC() {
|
||||||
|
if (getCartListInfo_ARC()) {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("CART SELECTED"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(arcgame);
|
||||||
|
display_Update();
|
||||||
|
// Display Settings
|
||||||
|
display.setCursor(0, 56);
|
||||||
|
print_Msg(F("CODE: R"));
|
||||||
|
println_Msg(newarcsize);
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F(""));
|
||||||
|
Serial.println(F("CART SELECTED"));
|
||||||
|
Serial.println(arcgame);
|
||||||
|
// Display Settings
|
||||||
|
Serial.print(F("CODE: R"));
|
||||||
|
Serial.println(newarcsize);
|
||||||
|
Serial.println(F(""));
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#ifdef enable_OLED
|
||||||
|
display.setCursor(0, 56);
|
||||||
|
println_Msg(F("NO SELECTION"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("NO SELECTION"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCart_ARC() {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(arccartCSV);
|
||||||
|
display_Update();
|
||||||
|
#endif
|
||||||
|
sd.chdir();
|
||||||
|
sprintf(folder, "ARC/CSV");
|
||||||
|
sd.chdir(folder); // Switch Folder
|
||||||
|
arccsvFile = sd.open(arccartCSV, O_READ);
|
||||||
|
if (!arccsvFile) {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("CSV FILE NOT FOUND!"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("CSV FILE NOT FOUND!"));
|
||||||
|
#endif
|
||||||
|
while (1) {
|
||||||
|
if (checkButton() != 0)
|
||||||
|
setup_ARC();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkCSV_ARC();
|
||||||
|
|
||||||
|
arccsvFile.close();
|
||||||
|
}
|
||||||
|
#endif
|
912
Cart_Reader/ATARI.ino
Normal file
912
Cart_Reader/ATARI.ino
Normal file
@ -0,0 +1,912 @@
|
|||||||
|
//******************************************
|
||||||
|
// ATARI 2600 MODULE
|
||||||
|
//******************************************
|
||||||
|
#if defined(enable_ATARI)
|
||||||
|
// Atari 2600
|
||||||
|
// Cartridge Pinout
|
||||||
|
// 24P 2.54mm pitch connector
|
||||||
|
//
|
||||||
|
// LABEL SIDE
|
||||||
|
//
|
||||||
|
// GND +5V A8 A9 A11 A10 A12 D7 D6 D5 D4 D3
|
||||||
|
// +--------------------------------------------------+
|
||||||
|
// | 24 23 22 21 20 19 18 17 16 15 14 13 |
|
||||||
|
// LEFT | | RIGHT
|
||||||
|
// | 1 2 3 4 5 6 7 8 9 10 11 12 |
|
||||||
|
// +--------------------------------------------------+
|
||||||
|
// A7 A6 A5 A4 A3 A2 A1 A0 D0 D1 D2 GND
|
||||||
|
//
|
||||||
|
// BOTTOM SIDE
|
||||||
|
|
||||||
|
// Cart Configurations
|
||||||
|
// Format = {mapper,romsize}
|
||||||
|
static const byte PROGMEM atarimapsize[] = {
|
||||||
|
0x20, 0, // 2K
|
||||||
|
0x3F, 2, // Tigervision 8K
|
||||||
|
0x40, 1, // 4K [DEFAULT]
|
||||||
|
0xC0, 0, // "CV" Commavid 2K
|
||||||
|
0xD0, 2, // "DPC" Pitfall II 10K
|
||||||
|
0xE0, 2, // Parker Bros 8K
|
||||||
|
0xE7, 4, // M-Network 16K
|
||||||
|
0xF0, 6, // Megaboy 64K
|
||||||
|
0xF4, 5, // Atari 32K
|
||||||
|
0xF6, 4, // Atari 16K
|
||||||
|
0xF8, 2, // Atari 8K
|
||||||
|
0xFA, 3, // CBS RAM Plus 12K
|
||||||
|
0xFE, 2, // Activision 8K
|
||||||
|
0x0A, 2, // "UA" UA Ltd 8K
|
||||||
|
};
|
||||||
|
|
||||||
|
//byte atarimapcount = 14;
|
||||||
|
byte atarimapcount = (sizeof(atarimapsize) / sizeof(atarimapsize[0])) / 2;
|
||||||
|
|
||||||
|
byte atarimapselect;
|
||||||
|
int atariindex;
|
||||||
|
|
||||||
|
byte ATARI[] = { 2, 4, 8, 12, 16, 32, 64 };
|
||||||
|
byte atarimapper = 0;
|
||||||
|
byte newatarimapper;
|
||||||
|
byte atarisize;
|
||||||
|
|
||||||
|
// EEPROM MAPPING
|
||||||
|
// 07 MAPPER
|
||||||
|
// 08 ROM SIZE
|
||||||
|
|
||||||
|
//******************************************
|
||||||
|
// Menu
|
||||||
|
//******************************************
|
||||||
|
// Base Menu
|
||||||
|
static const char atariMenuItem1[] PROGMEM = "Select Cart";
|
||||||
|
static const char atariMenuItem2[] PROGMEM = "Read ROM";
|
||||||
|
static const char atariMenuItem3[] PROGMEM = "Set Mapper";
|
||||||
|
static const char atariMenuItem4[] PROGMEM = "Reset";
|
||||||
|
static const char* const menuOptionsATARI[] PROGMEM = { atariMenuItem1, atariMenuItem2, atariMenuItem3, atariMenuItem4 };
|
||||||
|
|
||||||
|
void setup_ATARI() {
|
||||||
|
// Set Address Pins to Output
|
||||||
|
// Atari 2600 uses A0-A12 [A13-A23 UNUSED]
|
||||||
|
//A0-A7
|
||||||
|
DDRF = 0xFF;
|
||||||
|
//A8-A15
|
||||||
|
DDRK = 0xFF;
|
||||||
|
//A16-A23
|
||||||
|
DDRL = 0xFF;
|
||||||
|
|
||||||
|
// Set Control Pins to Output [UNUSED]
|
||||||
|
// ---(PH0) ---(PH1) ---(PH3) ---(PH4) ---(PH5) ---(PH6)
|
||||||
|
DDRH |= (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
||||||
|
|
||||||
|
// Set TIME(PJ0) to Output (UNUSED)
|
||||||
|
DDRJ |= (1 << 0);
|
||||||
|
|
||||||
|
// Set Pins (D0-D7) to Input
|
||||||
|
DDRC = 0x00;
|
||||||
|
|
||||||
|
// Setting Control Pins to HIGH [UNUSED]
|
||||||
|
// ---(PH0) ---(PH1) ---(PH3) ---(PH4) ---(PH5) ---(PH6)
|
||||||
|
PORTH |= (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
||||||
|
|
||||||
|
// Set Unused Data Pins (PA0-PA7) to Output
|
||||||
|
DDRA = 0xFF;
|
||||||
|
|
||||||
|
// Set Unused Pins HIGH
|
||||||
|
PORTA = 0xFF;
|
||||||
|
PORTL = 0xFF; // A16-A23
|
||||||
|
PORTJ |= (1 << 0); // TIME(PJ0)
|
||||||
|
|
||||||
|
checkStatus_ATARI();
|
||||||
|
strcpy(romName, "ATARI");
|
||||||
|
|
||||||
|
mode = mode_ATARI;
|
||||||
|
}
|
||||||
|
|
||||||
|
void atariMenu() {
|
||||||
|
convertPgm(menuOptionsATARI, 4);
|
||||||
|
uint8_t mainMenu = question_box(F("ATARI 2600 MENU"), menuOptions, 4, 0);
|
||||||
|
|
||||||
|
switch (mainMenu) {
|
||||||
|
case 0:
|
||||||
|
// Select Cart
|
||||||
|
setCart_ATARI();
|
||||||
|
wait();
|
||||||
|
setup_ATARI();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
// Read ROM
|
||||||
|
sd.chdir("/");
|
||||||
|
readROM_ATARI();
|
||||||
|
sd.chdir("/");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// Set Mapper
|
||||||
|
setMapper_ATARI();
|
||||||
|
checkStatus_ATARI();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
// reset
|
||||||
|
resetArduino();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************
|
||||||
|
// READ CODE
|
||||||
|
//******************************************
|
||||||
|
|
||||||
|
uint8_t readData_ATARI(uint16_t addr) // Add Input Pullup
|
||||||
|
{
|
||||||
|
PORTF = addr & 0xFF; // A0-A7
|
||||||
|
PORTK = (addr >> 8) & 0xFF; // A8-A12
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
DDRC = 0x00; // Set to Input
|
||||||
|
PORTC = 0xFF; // Input Pullup
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
uint8_t ret = PINC;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void readSegment_ATARI(uint16_t startaddr, uint16_t endaddr) {
|
||||||
|
for (uint16_t addr = startaddr; addr < endaddr; addr += 512) {
|
||||||
|
for (int w = 0; w < 512; w++) {
|
||||||
|
uint8_t temp = readData_ATARI(addr + w);
|
||||||
|
sdBuffer[w] = temp;
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 512);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void readSegmentF8_ATARI(uint16_t startaddr, uint16_t endaddr, uint16_t bankaddr) {
|
||||||
|
for (uint16_t addr = startaddr; addr < endaddr; addr += 512) {
|
||||||
|
for (int w = 0; w < 512; w++) {
|
||||||
|
if (addr > 0x1FF9) // SET BANK ADDRESS FOR 0x1FFA-0x1FFF
|
||||||
|
readData_ATARI(bankaddr);
|
||||||
|
uint8_t temp = readData_ATARI(addr + w);
|
||||||
|
sdBuffer[w] = temp;
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 512);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeData_ATARI(uint16_t addr, uint8_t data) {
|
||||||
|
PORTF = addr & 0xFF; // A0-A7
|
||||||
|
PORTK = (addr >> 8) & 0xFF; // A8-A12
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
DDRC = 0xFF; // Set to Output
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PORTC = data;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
DDRC = 0x00; // Reset to Input
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeData3F_ATARI(uint16_t addr, uint8_t data) {
|
||||||
|
PORTF = addr & 0xFF; // A0-A7
|
||||||
|
PORTK = (addr >> 8) & 0xFF; // A8-A12
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
DDRC = 0xFF; // Set to Output
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PORTC = data;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
// Address (0x1000);
|
||||||
|
PORTF = 0x00; // A0-A7
|
||||||
|
PORTK = 0x10; // A8-A12
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
DDRC = 0x00; // Reset to Input
|
||||||
|
}
|
||||||
|
|
||||||
|
void readROM_ATARI() {
|
||||||
|
strcpy(fileName, romName);
|
||||||
|
strcat(fileName, ".a26");
|
||||||
|
|
||||||
|
// create a new folder for storing rom file
|
||||||
|
EEPROM_readAnything(0, foldern);
|
||||||
|
sprintf(folder, "ATARI/ROM/%d", foldern);
|
||||||
|
sd.mkdir(folder, true);
|
||||||
|
sd.chdir(folder);
|
||||||
|
|
||||||
|
display_Clear();
|
||||||
|
print_Msg(F("Saving to "));
|
||||||
|
print_Msg(folder);
|
||||||
|
println_Msg(F("/..."));
|
||||||
|
display_Update();
|
||||||
|
|
||||||
|
// open file on sdcard
|
||||||
|
if (!myFile.open(fileName, O_RDWR | O_CREAT))
|
||||||
|
print_FatalError(create_file_STR);
|
||||||
|
|
||||||
|
// write new folder number back to EEPROM
|
||||||
|
foldern++;
|
||||||
|
EEPROM_writeAnything(0, foldern);
|
||||||
|
|
||||||
|
// ROM Start 0xF000
|
||||||
|
// Address A12-A0 = 0x1000 = 1 0000 0000 0000 = 4KB
|
||||||
|
// Read Start 0x1000
|
||||||
|
|
||||||
|
switch (atarimapper) {
|
||||||
|
case 0x20: // 2K Standard 2KB
|
||||||
|
readSegment_ATARI(0x1000, 0x1800);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x3F: // 3F Mapper 8KB
|
||||||
|
for (int x = 0; x < 0x3; x++) {
|
||||||
|
writeData3F_ATARI(0x3F, x);
|
||||||
|
readSegment_ATARI(0x1000, 0x1800);
|
||||||
|
}
|
||||||
|
readSegment_ATARI(0x1800, 0x2000);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x40: // 4K Default 4KB
|
||||||
|
readSegment_ATARI(0x1000, 0x2000);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xC0: // CV Mapper 2KB
|
||||||
|
readSegment_ATARI(0x1800, 0x2000);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xD0: // DPC Mapper 10KB
|
||||||
|
// 8K ROM
|
||||||
|
for (int x = 0; x < 0x2; x++) {
|
||||||
|
readData_ATARI(0x1FF8 + x);
|
||||||
|
// Split Read of 1st 0x200 bytes
|
||||||
|
// 0x0000-0x0080 are DPC Registers (Random on boot)
|
||||||
|
for (int y = 0; y < 0x80; y++) {
|
||||||
|
sdBuffer[y] = 0xFF; // Output 0xFFs for Registers
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 128);
|
||||||
|
for (int z = 0; z < 0x180; z++) {
|
||||||
|
sdBuffer[z] = readData_ATARI(0x1080 + z);
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 384);
|
||||||
|
// Read Segment
|
||||||
|
readSegment_ATARI(0x1200, 0x1800);
|
||||||
|
// 0x1000-0x1080 are DPC Registers (Random on boot)
|
||||||
|
for (int y = 0; y < 0x80; y++) {
|
||||||
|
sdBuffer[y] = 0xFF; // Output 0xFFs for Registers
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 128);
|
||||||
|
for (int z = 0; z < 0x180; z++) {
|
||||||
|
sdBuffer[z] = readData_ATARI(0x1880 + z);
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 384);
|
||||||
|
// Read Segment
|
||||||
|
readSegment_ATARI(0x1A00, 0x1E00);
|
||||||
|
// Split Read of Last 0x200 bytes
|
||||||
|
for (int y = 0; y < 0x1F8; y++) {
|
||||||
|
sdBuffer[y] = readData_ATARI(0x1E00 + y);
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 504);
|
||||||
|
for (int z = 0; z < 8; z++) {
|
||||||
|
// Set Bank to ensure 0x1FFA-0x1FFF is correct
|
||||||
|
readData_ATARI(0x1FF8 + x);
|
||||||
|
sdBuffer[z] = readData_ATARI(0x1FF8 + z);
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2K DPC Internal Graphics ROM
|
||||||
|
// Read Registers 0x1008-0x100F (Graphics 0x1008-0x100C)
|
||||||
|
// Write Registers LSB 0x1050-0x1057 AND MSB 0x1058-0x105F
|
||||||
|
|
||||||
|
// Set Data Fetcher 0 Limits
|
||||||
|
writeData_ATARI(0x1040, 0xFF); // MAX for Data Fetcher 0
|
||||||
|
writeData_ATARI(0x1048, 0x00); // MIN for Data Fetcher 0
|
||||||
|
// Set Data Fetcher 0 Counter (0x7FF)
|
||||||
|
writeData_ATARI(0x1050, 0xFF); // LSB for Data Fetcher 0
|
||||||
|
writeData_ATARI(0x1058, 0x07); // MSB for Data Fetcher 0
|
||||||
|
// Set Data Fetcher 1 Counter (0x7FF)
|
||||||
|
writeData_ATARI(0x1051, 0xFF); // LSB for Data Fetcher 1
|
||||||
|
writeData_ATARI(0x1059, 0x07); // MSB for Data Fetcher 1
|
||||||
|
for (int x = 0; x < 0x800; x += 512) {
|
||||||
|
for (int y = 0; y < 512; y++) {
|
||||||
|
sdBuffer[y] = readData_ATARI(0x1008); // Data Fetcher 0
|
||||||
|
readData_ATARI(0x1009); // Data Fetcher 1
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 512);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xE0: // E0 Mapper 8KB
|
||||||
|
for (int x = 0; x < 0x7; x++) {
|
||||||
|
readData_ATARI(0x1FE0 + x);
|
||||||
|
readSegment_ATARI(0x1000, 0x1400);
|
||||||
|
}
|
||||||
|
readSegment_ATARI(0x1C00, 0x2000);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xE7: // E7 Mapper 16KB
|
||||||
|
writeData_ATARI(0x1800, 0xFF);
|
||||||
|
for (int x = 0; x < 0x7; x++) {
|
||||||
|
readData_ATARI(0x1FE0 + x);
|
||||||
|
readSegment_ATARI(0x1000, 0x1800);
|
||||||
|
}
|
||||||
|
readSegment_ATARI(0x1800, 0x2000);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xF0: // F0 Mapper 64KB
|
||||||
|
for (int x = 0; x < 0x10; x++) {
|
||||||
|
readData_ATARI(0x1FF0);
|
||||||
|
readSegment_ATARI(0x1000, 0x2000);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xF4: // F4 Mapper 32KB
|
||||||
|
for (int x = 0; x < 0x8; x++) {
|
||||||
|
readData_ATARI(0x1FF4 + x);
|
||||||
|
readSegment_ATARI(0x1000, 0x2000);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xF6: // F6 Mapper 16KB
|
||||||
|
for (int x = 0; x < 0x4; x++) {
|
||||||
|
readData_ATARI(0x1FF6 + x);
|
||||||
|
readSegment_ATARI(0x1000, 0x2000);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xF8: // F8 Mapper 8KB
|
||||||
|
for (int x = 0; x < 0x2; x++) {
|
||||||
|
readData_ATARI(0x1FF8 + x);
|
||||||
|
readSegment_ATARI(0x1000, 0x1E00);
|
||||||
|
// Split Read of Last 0x200 bytes
|
||||||
|
for (int y = 0; y < 0x1F8; y++) {
|
||||||
|
sdBuffer[y] = readData_ATARI(0x1E00 + y);
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 504);
|
||||||
|
for (int z = 0; z < 8; z++) {
|
||||||
|
// Set Bank to ensure 0x1FFA-0x1FFF is correct
|
||||||
|
readData_ATARI(0x1FF8 + x);
|
||||||
|
sdBuffer[z] = readData_ATARI(0x1FF8 + z);
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 8);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xFA: // FA Mapper 12KB
|
||||||
|
for (int x = 0; x < 0x3; x++) {
|
||||||
|
writeData_ATARI(0x1FF8 + x, 0x1); // Set Bank with D0 HIGH
|
||||||
|
readSegment_ATARI(0x1000, 0x1E00);
|
||||||
|
// Split Read of Last 0x200 bytes
|
||||||
|
for (int y = 0; y < 0x1F8; y++) {
|
||||||
|
sdBuffer[y] = readData_ATARI(0x1E00 + y);
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 504);
|
||||||
|
for (int z = 0; z < 8; z++) {
|
||||||
|
// Set Bank to ensure 0x1FFB-0x1FFF is correct
|
||||||
|
writeData_ATARI(0x1FF8 + x, 0x1); // Set Bank with D0 HIGH
|
||||||
|
sdBuffer[z] = readData_ATARI(0x1FF8 + z);
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 8);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xFE: // FE Mapper 8KB
|
||||||
|
for (int x = 0; x < 0x2; x++) {
|
||||||
|
writeData_ATARI(0x01FE, 0xF0 ^ (x << 5));
|
||||||
|
writeData_ATARI(0x01FF, 0xF0 ^ (x << 5));
|
||||||
|
readSegment_ATARI(0x1000, 0x2000);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0A: // UA Mapper 8KB
|
||||||
|
readData_ATARI(0x220);
|
||||||
|
readSegment_ATARI(0x1000, 0x2000);
|
||||||
|
readData_ATARI(0x240);
|
||||||
|
readSegment_ATARI(0x1000, 0x2000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
myFile.close();
|
||||||
|
|
||||||
|
unsigned long crcsize = ATARI[atarisize] * 0x400;
|
||||||
|
calcCRC(fileName, crcsize, NULL, 0);
|
||||||
|
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F("Press Button..."));
|
||||||
|
display_Update();
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************
|
||||||
|
// ROM SIZE
|
||||||
|
//******************************************
|
||||||
|
|
||||||
|
void checkStatus_ATARI() {
|
||||||
|
EEPROM_readAnything(7, atarimapper);
|
||||||
|
EEPROM_readAnything(8, atarisize);
|
||||||
|
if (atarisize > 6) {
|
||||||
|
atarisize = 1; // default 4KB
|
||||||
|
EEPROM_writeAnything(8, atarisize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("ATARI 2600 READER"));
|
||||||
|
println_Msg(F("CURRENT SETTINGS"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
print_Msg(F("MAPPER: "));
|
||||||
|
if (atarimapper == 0x20)
|
||||||
|
println_Msg(F("2K"));
|
||||||
|
else if (atarimapper == 0x40)
|
||||||
|
println_Msg(F("4K"));
|
||||||
|
else if (atarimapper == 0x0A)
|
||||||
|
println_Msg(F("UA"));
|
||||||
|
else if (atarimapper == 0xC0)
|
||||||
|
println_Msg(F("CV"));
|
||||||
|
else if (atarimapper == 0xD0)
|
||||||
|
println_Msg(F("DPC"));
|
||||||
|
else
|
||||||
|
println_Msg(atarimapper, HEX);
|
||||||
|
print_Msg(F("ROM SIZE: "));
|
||||||
|
if (atarimapper == 0xD0)
|
||||||
|
print_Msg(F("10"));
|
||||||
|
else
|
||||||
|
print_Msg(ATARI[atarisize]);
|
||||||
|
println_Msg(F("K"));
|
||||||
|
display_Update();
|
||||||
|
wait();
|
||||||
|
#else
|
||||||
|
Serial.print(F("MAPPER: "));
|
||||||
|
if (atarimapper == 0x20)
|
||||||
|
Serial.println(F("2K"));
|
||||||
|
else if (atarimapper == 0x40)
|
||||||
|
Serial.println(F("4K"));
|
||||||
|
else if (atarimapper == 0x0A)
|
||||||
|
Serial.println(F("UA"));
|
||||||
|
else if (atarimapper == 0xC0)
|
||||||
|
Serial.println(F("CV"));
|
||||||
|
else if (atarimapper == 0xD0)
|
||||||
|
Serial.println(F("DPC"));
|
||||||
|
else
|
||||||
|
Serial.println(atarimapper, HEX);
|
||||||
|
Serial.print(F("ROM SIZE: "));
|
||||||
|
if (atarimapper == 0xD0)
|
||||||
|
Serial.print(F("10"));
|
||||||
|
else
|
||||||
|
Serial.print(ATARI[atarisize]);
|
||||||
|
Serial.println(F("K"));
|
||||||
|
Serial.println(F(""));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************
|
||||||
|
// SET MAPPER
|
||||||
|
//******************************************
|
||||||
|
|
||||||
|
void setMapper_ATARI() {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
int b = 0;
|
||||||
|
int i = 0;
|
||||||
|
// Check Button Status
|
||||||
|
#if defined(enable_OLED)
|
||||||
|
buttonVal1 = (PIND & (1 << 7)); // PD7
|
||||||
|
#elif defined(enable_LCD)
|
||||||
|
boolean buttonVal1 = (PING & (1 << 2)); //PG2
|
||||||
|
#endif
|
||||||
|
if (buttonVal1 == LOW) { // Button Pressed
|
||||||
|
while (1) { // Scroll Mapper List
|
||||||
|
#if defined(enable_OLED)
|
||||||
|
buttonVal1 = (PIND & (1 << 7)); // PD7
|
||||||
|
#elif defined(enable_LCD)
|
||||||
|
buttonVal1 = (PING & (1 << 2)); //PG2
|
||||||
|
#endif
|
||||||
|
if (buttonVal1 == HIGH) { // Button Released
|
||||||
|
// Correct Overshoot
|
||||||
|
if (i == 0)
|
||||||
|
i = atarimapcount - 1;
|
||||||
|
else
|
||||||
|
i--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
display_Clear();
|
||||||
|
print_Msg(F("Mapper: "));
|
||||||
|
atariindex = i * 2;
|
||||||
|
atarimapselect = pgm_read_byte(atarimapsize + atariindex);
|
||||||
|
if (atarimapselect == 0x20)
|
||||||
|
println_Msg(F("2K"));
|
||||||
|
else if (atarimapselect == 0x40)
|
||||||
|
println_Msg(F("4K"));
|
||||||
|
else if (atarimapselect == 0x0A)
|
||||||
|
println_Msg(F("UA"));
|
||||||
|
else if (atarimapselect == 0xC0)
|
||||||
|
println_Msg(F("CV"));
|
||||||
|
else if (atarimapselect == 0xD0)
|
||||||
|
println_Msg(F("DPC"));
|
||||||
|
else
|
||||||
|
println_Msg(atarimapselect, HEX);
|
||||||
|
display_Update();
|
||||||
|
if (i == (atarimapcount - 1))
|
||||||
|
i = 0;
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
delay(250);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (1) {
|
||||||
|
display_Clear();
|
||||||
|
print_Msg(F("Mapper: "));
|
||||||
|
atariindex = i * 2;
|
||||||
|
atarimapselect = pgm_read_byte(atarimapsize + atariindex);
|
||||||
|
if (atarimapselect == 0x20)
|
||||||
|
println_Msg(F("2K"));
|
||||||
|
else if (atarimapselect == 0x40)
|
||||||
|
println_Msg(F("4K"));
|
||||||
|
else if (atarimapselect == 0x0A)
|
||||||
|
println_Msg(F("UA"));
|
||||||
|
else if (atarimapselect == 0xC0)
|
||||||
|
println_Msg(F("CV"));
|
||||||
|
else if (atarimapselect == 0xD0)
|
||||||
|
println_Msg(F("DPC"));
|
||||||
|
else
|
||||||
|
println_Msg(atarimapselect, HEX);
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F("Press to Change"));
|
||||||
|
println_Msg(F("Hold to Select"));
|
||||||
|
display_Update();
|
||||||
|
b = checkButton();
|
||||||
|
if (b == 2) { // Previous Mapper (doubleclick)
|
||||||
|
if (i == 0)
|
||||||
|
i = atarimapcount - 1;
|
||||||
|
else
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
if (b == 1) { // Next Mapper (press)
|
||||||
|
if (i == (atarimapcount - 1))
|
||||||
|
i = 0;
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (b == 3) { // Long Press - Execute (hold)
|
||||||
|
newatarimapper = atarimapselect;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
display.setCursor(0, 56);
|
||||||
|
print_Msg(F("MAPPER "));
|
||||||
|
if (newatarimapper == 0x20)
|
||||||
|
println_Msg(F("2K"));
|
||||||
|
else if (newatarimapper == 0x40)
|
||||||
|
println_Msg(F("4K"));
|
||||||
|
if (newatarimapper == 0x0A)
|
||||||
|
print_Msg(F("UA"));
|
||||||
|
else if (newatarimapper == 0xC0)
|
||||||
|
print_Msg(F("CV"));
|
||||||
|
else if (newatarimapper == 0xD0)
|
||||||
|
println_Msg(F("DPC"));
|
||||||
|
else
|
||||||
|
print_Msg(newatarimapper, HEX);
|
||||||
|
println_Msg(F(" SELECTED"));
|
||||||
|
display_Update();
|
||||||
|
delay(1000);
|
||||||
|
#else
|
||||||
|
setmapper:
|
||||||
|
String newmap;
|
||||||
|
Serial.println(F("SUPPORTED MAPPERS:"));
|
||||||
|
Serial.println(F("0 = 2K [Standard 2K]"));
|
||||||
|
Serial.println(F("1 = 3F [Tigervision]"));
|
||||||
|
Serial.println(F("2 = 4K [Standard 4K]"));
|
||||||
|
Serial.println(F("3 = CV [Commavid]"));
|
||||||
|
Serial.println(F("4 = DPC [Pitfall II]"));
|
||||||
|
Serial.println(F("5 = E0 [Parker Bros]"));
|
||||||
|
Serial.println(F("6 = E7 [M-Network]"));
|
||||||
|
Serial.println(F("7 = F0 [Megaboy]"));
|
||||||
|
Serial.println(F("8 = F4 [Atari 32K]"));
|
||||||
|
Serial.println(F("9 = F6 [Atari 16K]"));
|
||||||
|
Serial.println(F("10 = F8 [Atari 8K]"));
|
||||||
|
Serial.println(F("11 = FA [CBS RAM Plus]"));
|
||||||
|
Serial.println(F("12 = FE [Activision]"));
|
||||||
|
Serial.println(F("13 = UA [UA Ltd]"));
|
||||||
|
Serial.print(F("Enter Mapper [0-13]: "));
|
||||||
|
while (Serial.available() == 0) {}
|
||||||
|
newmap = Serial.readStringUntil('\n');
|
||||||
|
Serial.println(newmap);
|
||||||
|
atariindex = newmap.toInt() * 2;
|
||||||
|
newatarimapper = pgm_read_byte(atarimapsize + atariindex);
|
||||||
|
#endif
|
||||||
|
EEPROM_writeAnything(7, newatarimapper);
|
||||||
|
atarimapper = newatarimapper;
|
||||||
|
|
||||||
|
atarisize = pgm_read_byte(atarimapsize + atariindex + 1);
|
||||||
|
EEPROM_writeAnything(8, atarisize);
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************
|
||||||
|
// CART SELECT CODE
|
||||||
|
//******************************************
|
||||||
|
|
||||||
|
FsFile ataricsvFile;
|
||||||
|
char atarigame[36]; // title
|
||||||
|
char atarimm[4]; // mapper
|
||||||
|
char atarill[4]; // linelength (previous line)
|
||||||
|
unsigned long ataricsvpos; // CSV File Position
|
||||||
|
char ataricartCSV[] = "ataricart.txt"; // CSV List
|
||||||
|
char ataricsvEND[] = "EOF"; // CSV End Marker for scrolling
|
||||||
|
|
||||||
|
bool readLine_ATARI(FsFile& f, char* line, size_t maxLen) {
|
||||||
|
for (size_t n = 0; n < maxLen; n++) {
|
||||||
|
int c = f.read();
|
||||||
|
if (c < 0 && n == 0) return false; // EOF
|
||||||
|
if (c < 0 || c == '\n') {
|
||||||
|
line[n] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
line[n] = c;
|
||||||
|
}
|
||||||
|
return false; // line too long
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readVals_ATARI(char* atarigame, char* atarimm, char* atarill) {
|
||||||
|
char line[42];
|
||||||
|
ataricsvpos = ataricsvFile.position();
|
||||||
|
if (!readLine_ATARI(ataricsvFile, line, sizeof(line))) {
|
||||||
|
return false; // EOF or too long
|
||||||
|
}
|
||||||
|
char* comma = strtok(line, ",");
|
||||||
|
int x = 0;
|
||||||
|
while (comma != NULL) {
|
||||||
|
if (x == 0)
|
||||||
|
strcpy(atarigame, comma);
|
||||||
|
else if (x == 1)
|
||||||
|
strcpy(atarimm, comma);
|
||||||
|
else if (x == 2)
|
||||||
|
strcpy(atarill, comma);
|
||||||
|
comma = strtok(NULL, ",");
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getCartListInfo_ATARI() {
|
||||||
|
bool buttonreleased = 0;
|
||||||
|
bool cartselected = 0;
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F(" HOLD TO FAST CYCLE"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("HOLD BUTTON TO FAST CYCLE"));
|
||||||
|
#endif
|
||||||
|
delay(2000);
|
||||||
|
#if defined(enable_OLED)
|
||||||
|
buttonVal1 = (PIND & (1 << 7)); // PD7
|
||||||
|
#elif defined(enable_LCD)
|
||||||
|
boolean buttonVal1 = (PING & (1 << 2)); //PG2
|
||||||
|
#endif
|
||||||
|
if (buttonVal1 == LOW) { // Button Held - Fast Cycle
|
||||||
|
while (1) { // Scroll Game List
|
||||||
|
while (readVals_ATARI(atarigame, atarimm, atarill)) {
|
||||||
|
if (strcmp(ataricsvEND, atarigame) == 0) {
|
||||||
|
ataricsvFile.seek(0); // Restart
|
||||||
|
} else {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("CART TITLE:"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(atarigame);
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.print(F("CART TITLE:"));
|
||||||
|
Serial.println(atarigame);
|
||||||
|
#endif
|
||||||
|
#if defined(enable_OLED)
|
||||||
|
buttonVal1 = (PIND & (1 << 7)); // PD7
|
||||||
|
#elif defined(enable_LCD)
|
||||||
|
buttonVal1 = (PING & (1 << 2)); //PG2
|
||||||
|
#endif
|
||||||
|
if (buttonVal1 == HIGH) { // Button Released
|
||||||
|
buttonreleased = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (buttonreleased) {
|
||||||
|
buttonreleased = 0; // Reset Flag
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if defined(enable_OLED)
|
||||||
|
buttonVal1 = (PIND & (1 << 7)); // PD7
|
||||||
|
#elif defined(enable_LCD)
|
||||||
|
buttonVal1 = (PING & (1 << 2)); //PG2
|
||||||
|
#endif
|
||||||
|
if (buttonVal1 == HIGH) // Button Released
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display.setCursor(0, 56);
|
||||||
|
println_Msg(F("FAST CYCLE OFF"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F(""));
|
||||||
|
Serial.println(F("FAST CYCLE OFF"));
|
||||||
|
Serial.println(F("PRESS BUTTON TO STEP FORWARD"));
|
||||||
|
Serial.println(F("DOUBLE CLICK TO STEP BACK"));
|
||||||
|
Serial.println(F("HOLD TO SELECT"));
|
||||||
|
Serial.println(F(""));
|
||||||
|
#endif
|
||||||
|
while (readVals_ATARI(atarigame, atarimm, atarill)) {
|
||||||
|
if (strcmp(ataricsvEND, atarigame) == 0) {
|
||||||
|
ataricsvFile.seek(0); // Restart
|
||||||
|
} else {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("CART TITLE:"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(atarigame);
|
||||||
|
display.setCursor(0, 48);
|
||||||
|
println_Msg(F("Press to Change"));
|
||||||
|
println_Msg(F("Hold to Select"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.print(F("CART TITLE:"));
|
||||||
|
Serial.println(atarigame);
|
||||||
|
#endif
|
||||||
|
while (1) { // Single Step
|
||||||
|
int b = checkButton();
|
||||||
|
if (b == 1) { // Continue (press)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (b == 2) { // Reset to Start of List (doubleclick)
|
||||||
|
byte prevline = strtol(atarill, NULL, 10);
|
||||||
|
ataricsvpos -= prevline;
|
||||||
|
ataricsvFile.seek(ataricsvpos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (b == 3) { // Long Press - Select Cart (hold)
|
||||||
|
newatarimapper = strtol(atarimm, NULL, 10);
|
||||||
|
EEPROM_writeAnything(7, newatarimapper);
|
||||||
|
cartselected = 1; // SELECTION MADE
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
println_Msg(F("SELECTION MADE"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("SELECTION MADE"));
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cartselected) {
|
||||||
|
cartselected = 0; // Reset Flag
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F("END OF FILE"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("END OF FILE"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkCSV_ATARI() {
|
||||||
|
if (getCartListInfo_ATARI()) {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("CART SELECTED"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(atarigame);
|
||||||
|
display_Update();
|
||||||
|
// Display Settings
|
||||||
|
display.setCursor(0, 56);
|
||||||
|
print_Msg(F("CODE: "));
|
||||||
|
println_Msg(newatarimapper, HEX);
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F(""));
|
||||||
|
Serial.println(F("CART SELECTED"));
|
||||||
|
Serial.println(atarigame);
|
||||||
|
// Display Settings
|
||||||
|
Serial.print(F("CODE: "));
|
||||||
|
Serial.println(newatarimapper, HEX);
|
||||||
|
Serial.println(F(""));
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display.setCursor(0, 56);
|
||||||
|
println_Msg(F("NO SELECTION"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("NO SELECTION"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkSize_ATARI() {
|
||||||
|
EEPROM_readAnything(7, atarimapper);
|
||||||
|
for (int i = 0; i < atarimapcount; i++) {
|
||||||
|
atariindex = i * 2;
|
||||||
|
if (atarimapper == pgm_read_byte(atarimapsize + atariindex)) {
|
||||||
|
atarisize = pgm_read_byte(atarimapsize + atariindex + 1);
|
||||||
|
EEPROM_writeAnything(8, atarisize);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCart_ATARI() {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(ataricartCSV);
|
||||||
|
display_Update();
|
||||||
|
#endif
|
||||||
|
sd.chdir();
|
||||||
|
sprintf(folder, "ATARI/CSV");
|
||||||
|
sd.chdir(folder); // Switch Folder
|
||||||
|
ataricsvFile = sd.open(ataricartCSV, O_READ);
|
||||||
|
if (!ataricsvFile) {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("CSV FILE NOT FOUND!"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("CSV FILE NOT FOUND!"));
|
||||||
|
#endif
|
||||||
|
while (1) {
|
||||||
|
if (checkButton() != 0)
|
||||||
|
setup_ATARI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkCSV_ATARI();
|
||||||
|
ataricsvFile.close();
|
||||||
|
|
||||||
|
checkSize_ATARI();
|
||||||
|
}
|
||||||
|
#endif
|
@ -4,8 +4,8 @@
|
|||||||
This project represents a community-driven effort to provide
|
This project represents a community-driven effort to provide
|
||||||
an easy to build and easy to modify cartridge dumper.
|
an easy to build and easy to modify cartridge dumper.
|
||||||
|
|
||||||
Date: 20.12.2022
|
Date: 03.01.2023
|
||||||
Version: 11.5
|
Version: 12.0
|
||||||
|
|
||||||
SD lib: https://github.com/greiman/SdFat
|
SD lib: https://github.com/greiman/SdFat
|
||||||
LCD lib: https://github.com/olikraus/u8g2
|
LCD lib: https://github.com/olikraus/u8g2
|
||||||
@ -21,7 +21,7 @@
|
|||||||
MichlK - ROM Reader for Super Nintendo
|
MichlK - ROM Reader for Super Nintendo
|
||||||
Jeff Saltzman - 4-Way Button
|
Jeff Saltzman - 4-Way Button
|
||||||
Wayne and Layne - Video Game Shield menu
|
Wayne and Layne - Video Game Shield menu
|
||||||
skaman - Cart ROM READER SNES ENHANCED, Famicom Cart Dumper, Coleco-, Intellivision, Virtual Boy, WSV, PCW modules
|
skaman - Cart ROM READER SNES ENHANCED, Famicom Cart Dumper, Coleco-, Intellivision, Virtual Boy, WSV, PCW, ARC, Atari, ODY2, Fairchild modules
|
||||||
Tamanegi_taro - PCE and Satellaview modules
|
Tamanegi_taro - PCE and Satellaview modules
|
||||||
splash5 - GBSmart, Wonderswan and NGP modules
|
splash5 - GBSmart, Wonderswan and NGP modules
|
||||||
hkz & themanbehindthecurtain - N64 flashram commands
|
hkz & themanbehindthecurtain - N64 flashram commands
|
||||||
@ -38,7 +38,7 @@
|
|||||||
jiyunomegami, splash5, Kreeblah, ramapcsx2, PsyK0p4T, Dakkaron, majorpbx, Pickle, sdhizumi,
|
jiyunomegami, splash5, Kreeblah, ramapcsx2, PsyK0p4T, Dakkaron, majorpbx, Pickle, sdhizumi,
|
||||||
Uzlopak, sakman55, Tombo89, scrap-a, borti4938, vogelfreiheit, CaitSith2, Modman,
|
Uzlopak, sakman55, Tombo89, scrap-a, borti4938, vogelfreiheit, CaitSith2, Modman,
|
||||||
philenotfound, karimhadjsalem, nsx0r, ducky92, niklasweber, Lesserkuma, BacteriaMage,
|
philenotfound, karimhadjsalem, nsx0r, ducky92, niklasweber, Lesserkuma, BacteriaMage,
|
||||||
vpelletier, Ancyker
|
vpelletier, Ancyker, mattiacci, RWeick
|
||||||
|
|
||||||
And to nocash for figuring out the secrets of the SFC Nintendo Power cartridge.
|
And to nocash for figuring out the secrets of the SFC Nintendo Power cartridge.
|
||||||
|
|
||||||
@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
**********************************************************************************/
|
**********************************************************************************/
|
||||||
|
|
||||||
char ver[5] = "11.5";
|
char ver[5] = "12.0";
|
||||||
|
|
||||||
//******************************************
|
//******************************************
|
||||||
// !!! CHOOSE HARDWARE VERSION !!!
|
// !!! CHOOSE HARDWARE VERSION !!!
|
||||||
@ -79,10 +79,24 @@ char ver[5] = "11.5";
|
|||||||
//******************************************
|
//******************************************
|
||||||
// add/remove // before #define to disable/enable modules you
|
// add/remove // before #define to disable/enable modules you
|
||||||
// don't need/need to save programm storage space and dynamic memory
|
// don't need/need to save programm storage space and dynamic memory
|
||||||
|
// If you only get an empty or "Press Button" screen after flashing
|
||||||
|
// you have enabled too many modules
|
||||||
|
|
||||||
|
// Atari 2600
|
||||||
|
//#define enable_ATARI
|
||||||
|
|
||||||
|
// Benesse Pocket Challenge W
|
||||||
|
//#define enable_PCW
|
||||||
|
|
||||||
// ColecoVision
|
// ColecoVision
|
||||||
#define enable_COLV
|
#define enable_COLV
|
||||||
|
|
||||||
|
// Emerson Arcadia 2001
|
||||||
|
//#define enable_ARC
|
||||||
|
|
||||||
|
// Fairchild Channel F
|
||||||
|
//#define enable_FAIRCHILD
|
||||||
|
|
||||||
// Flashrom Programmer for SNES repros
|
// Flashrom Programmer for SNES repros
|
||||||
#define enable_FLASH
|
#define enable_FLASH
|
||||||
//#define enable_FLASH16
|
//#define enable_FLASH16
|
||||||
@ -93,8 +107,8 @@ char ver[5] = "11.5";
|
|||||||
// Intellivision
|
// Intellivision
|
||||||
#define enable_INTV
|
#define enable_INTV
|
||||||
|
|
||||||
// Sega Mega Drive/Genesis
|
// Neo Geo Pocket
|
||||||
#define enable_MD
|
#define enable_NGP
|
||||||
|
|
||||||
// Nintendo 64
|
// Nintendo 64
|
||||||
#define enable_N64
|
#define enable_N64
|
||||||
@ -102,20 +116,17 @@ char ver[5] = "11.5";
|
|||||||
// Nintendo Entertainment System/Family Computer
|
// Nintendo Entertainment System/Family Computer
|
||||||
#define enable_NES
|
#define enable_NES
|
||||||
|
|
||||||
// Neo Geo Pocket
|
// Magnavox Odyssey 2
|
||||||
#define enable_NGP
|
//#define enable_ODY2
|
||||||
|
|
||||||
// PC Engine/TurboGrafx 16
|
// PC Engine/TurboGrafx 16
|
||||||
#define enable_PCE
|
#define enable_PCE
|
||||||
|
|
||||||
// Benesse Pocket Challenge W
|
|
||||||
#define enable_PCW
|
|
||||||
|
|
||||||
// Sega Master System
|
// Sega Master System
|
||||||
#define enable_SMS
|
#define enable_SMS
|
||||||
|
|
||||||
// Super Nintendo
|
// Sega Mega Drive/Genesis
|
||||||
#define enable_SNES
|
#define enable_MD
|
||||||
|
|
||||||
// Super Famicom SF Memory Cassette
|
// Super Famicom SF Memory Cassette
|
||||||
#define enable_SFM
|
#define enable_SFM
|
||||||
@ -123,15 +134,18 @@ char ver[5] = "11.5";
|
|||||||
// Super Famicom Satellaview
|
// Super Famicom Satellaview
|
||||||
#define enable_SV
|
#define enable_SV
|
||||||
|
|
||||||
|
// Super Nintendo
|
||||||
|
#define enable_SNES
|
||||||
|
|
||||||
// Virtual Boy
|
// Virtual Boy
|
||||||
#define enable_VBOY
|
#define enable_VBOY
|
||||||
|
|
||||||
|
// Watara Supervision
|
||||||
|
//#define enable_WSV
|
||||||
|
|
||||||
// WonderSwan
|
// WonderSwan
|
||||||
#define enable_WS
|
#define enable_WS
|
||||||
|
|
||||||
// Watara Supervision
|
|
||||||
#define enable_WSV
|
|
||||||
|
|
||||||
//******************************************
|
//******************************************
|
||||||
// HW CONFIGS
|
// HW CONFIGS
|
||||||
//******************************************
|
//******************************************
|
||||||
@ -390,6 +404,10 @@ void print_STR(byte string_number, boolean newline) {
|
|||||||
#define mode_VBOY 25
|
#define mode_VBOY 25
|
||||||
#define mode_WSV 26
|
#define mode_WSV 26
|
||||||
#define mode_PCW 27
|
#define mode_PCW 27
|
||||||
|
#define mode_ATARI 28
|
||||||
|
#define mode_ODY2 29
|
||||||
|
#define mode_ARC 30
|
||||||
|
#define mode_FAIRCHILD 31
|
||||||
|
|
||||||
// optimization-safe nop delay
|
// optimization-safe nop delay
|
||||||
#define NOP __asm__ __volatile__("nop\n\t")
|
#define NOP __asm__ __volatile__("nop\n\t")
|
||||||
@ -630,6 +648,52 @@ uint32_t calculateCRC(char* fileName, char* folder, int offset) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
CRC Functions for Atari, Fairchild, Ody2, Arc modules
|
||||||
|
*****************************************/
|
||||||
|
#if (defined(enable_ATARI) || defined(enable_ODY2) || defined(enable_ARC) || defined(enable_FAIRCHILD))
|
||||||
|
|
||||||
|
inline uint32_t updateCRC(uint8_t ch, uint32_t crc) {
|
||||||
|
uint32_t idx = ((crc) ^ (ch)) & 0xff;
|
||||||
|
uint32_t tab_value = pgm_read_dword(crc_32_tab + idx);
|
||||||
|
return tab_value ^ ((crc) >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
FsFile crcFile;
|
||||||
|
char tempCRC[9];
|
||||||
|
|
||||||
|
uint32_t crc32(FsFile& file, uint32_t& charcnt) {
|
||||||
|
uint32_t oldcrc32 = 0xFFFFFFFF;
|
||||||
|
charcnt = 0;
|
||||||
|
while (file.available()) {
|
||||||
|
crcFile.read(sdBuffer, 512);
|
||||||
|
for (int x = 0; x < 512; x++) {
|
||||||
|
uint8_t c = sdBuffer[x];
|
||||||
|
charcnt++;
|
||||||
|
oldcrc32 = updateCRC(c, oldcrc32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ~oldcrc32;
|
||||||
|
}
|
||||||
|
|
||||||
|
void calcCRC(char* checkFile, unsigned long filesize, uint32_t* crcCopy, unsigned long offset) {
|
||||||
|
uint32_t crc;
|
||||||
|
crcFile = sd.open(checkFile);
|
||||||
|
crcFile.seek(offset);
|
||||||
|
crc = crc32(crcFile, filesize);
|
||||||
|
crcFile.close();
|
||||||
|
sprintf(tempCRC, "%08lX", crc);
|
||||||
|
|
||||||
|
if (crcCopy != NULL) {
|
||||||
|
*crcCopy = crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_Msg(F("CRC: "));
|
||||||
|
println_Msg(tempCRC);
|
||||||
|
display_Update();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//******************************************
|
//******************************************
|
||||||
// Functions for CRC32 database
|
// Functions for CRC32 database
|
||||||
//******************************************
|
//******************************************
|
||||||
@ -932,18 +996,22 @@ static const char modeItem11[] PROGMEM = "Colecovision";
|
|||||||
static const char modeItem12[] PROGMEM = "Virtual Boy";
|
static const char modeItem12[] PROGMEM = "Virtual Boy";
|
||||||
static const char modeItem13[] PROGMEM = "Watara Supervision";
|
static const char modeItem13[] PROGMEM = "Watara Supervision";
|
||||||
static const char modeItem14[] PROGMEM = "Pocket Challenge W";
|
static const char modeItem14[] PROGMEM = "Pocket Challenge W";
|
||||||
static const char modeItem15[] PROGMEM = "Flashrom Programmer";
|
static const char modeItem15[] PROGMEM = "Atari 2600";
|
||||||
static const char modeItem16[] PROGMEM = "About";
|
static const char modeItem16[] PROGMEM = "Magnavox Odyssey 2";
|
||||||
static const char* const modeOptions[] PROGMEM = { modeItem1, modeItem2, modeItem3, modeItem4, modeItem5, modeItem6, modeItem7, modeItem8, modeItem9, modeItem10, modeItem11, modeItem12, modeItem13, modeItem14, modeItem15, modeItem16 };
|
static const char modeItem17[] PROGMEM = "Arcadia 2001";
|
||||||
|
static const char modeItem18[] PROGMEM = "Fairchild Channel F";
|
||||||
|
static const char modeItem19[] PROGMEM = "Flashrom Programmer";
|
||||||
|
static const char modeItem20[] PROGMEM = "About";
|
||||||
|
static const char* const modeOptions[] PROGMEM = { modeItem1, modeItem2, modeItem3, modeItem4, modeItem5, modeItem6, modeItem7, modeItem8, modeItem9, modeItem10, modeItem11, modeItem12, modeItem13, modeItem14, modeItem15, modeItem16, modeItem17, modeItem18, modeItem19, modeItem20 };
|
||||||
|
|
||||||
// All included slots
|
// All included slots
|
||||||
void mainMenu() {
|
void mainMenu() {
|
||||||
// create menu with title and 15 options to choose from
|
// create menu with title and 20 options to choose from
|
||||||
unsigned char modeMenu;
|
unsigned char modeMenu;
|
||||||
byte num_answers;
|
byte num_answers;
|
||||||
byte option_offset;
|
byte option_offset;
|
||||||
|
|
||||||
// Main menu spans across two pages
|
// Main menu spans across three pages
|
||||||
currPage = 1;
|
currPage = 1;
|
||||||
lastPage = 1;
|
lastPage = 1;
|
||||||
numPages = 3;
|
numPages = 3;
|
||||||
@ -957,7 +1025,7 @@ void mainMenu() {
|
|||||||
num_answers = 7;
|
num_answers = 7;
|
||||||
} else { // currPage == 3
|
} else { // currPage == 3
|
||||||
option_offset = 14;
|
option_offset = 14;
|
||||||
num_answers = 2;
|
num_answers = 6;
|
||||||
}
|
}
|
||||||
// Copy menuOptions out of progmem
|
// Copy menuOptions out of progmem
|
||||||
convertPgm(modeOptions + option_offset, num_answers);
|
convertPgm(modeOptions + option_offset, num_answers);
|
||||||
@ -1077,8 +1145,36 @@ void mainMenu() {
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef enable_FLASH
|
#ifdef enable_ATARI
|
||||||
case 14:
|
case 14:
|
||||||
|
setup_ATARI();
|
||||||
|
atariMenu();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef enable_ODY2
|
||||||
|
case 15:
|
||||||
|
setup_ODY2();
|
||||||
|
ody2Menu();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef enable_ARC
|
||||||
|
case 16:
|
||||||
|
setup_ARC();
|
||||||
|
arcMenu();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef enable_FAIRCHILD
|
||||||
|
case 17:
|
||||||
|
setup_FAIRCHILD();
|
||||||
|
fairchildMenu();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef enable_FLASH
|
||||||
|
case 18:
|
||||||
#ifdef enable_FLASH16
|
#ifdef enable_FLASH16
|
||||||
flashMenu();
|
flashMenu();
|
||||||
#else
|
#else
|
||||||
@ -1087,7 +1183,7 @@ void mainMenu() {
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case 15:
|
case 19:
|
||||||
aboutScreen();
|
aboutScreen();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1115,20 +1211,29 @@ static const char modeItem6[] PROGMEM = "About";
|
|||||||
static const char* const modeOptions[] PROGMEM = { modeItem1, modeItem2, modeItem3, modeItem4, modeItem5, modeItem6, string_reset2 };
|
static const char* const modeOptions[] PROGMEM = { modeItem1, modeItem2, modeItem3, modeItem4, modeItem5, modeItem6, string_reset2 };
|
||||||
|
|
||||||
// Add-ons submenu
|
// Add-ons submenu
|
||||||
static const char addonsItem1[] PROGMEM = "Consoles";
|
static const char addonsItem1[] PROGMEM = "70s Consoles";
|
||||||
static const char addonsItem2[] PROGMEM = "Handhelds";
|
static const char addonsItem2[] PROGMEM = "80s Consoles";
|
||||||
static const char addonsItem3[] PROGMEM = "Flashrom Programmer";
|
static const char addonsItem3[] PROGMEM = "Handhelds";
|
||||||
//static const char addonsItem4[] PROGMEM = "Reset"; (stored in common strings array)
|
static const char addonsItem4[] PROGMEM = "Flashrom Programmer";
|
||||||
static const char* const addonsOptions[] PROGMEM = { addonsItem1, addonsItem2, addonsItem3, string_reset2 };
|
//static const char addonsItem5[] PROGMEM = "Reset"; (stored in common strings array)
|
||||||
|
static const char* const addonsOptions[] PROGMEM = { addonsItem1, addonsItem2, addonsItem3, addonsItem4, string_reset2 };
|
||||||
|
|
||||||
// Consoles submenu
|
// 70s Consoles submenu
|
||||||
static const char consolesItem1[] PROGMEM = "NES/Famicom";
|
static const char consoles70Item1[] PROGMEM = "Atari 2600";
|
||||||
static const char consolesItem2[] PROGMEM = "PC Engine/TG16";
|
static const char consoles70Item2[] PROGMEM = "Magnavox Odyssey 2";
|
||||||
static const char consolesItem3[] PROGMEM = "SMS/GG/MIII/SG-1000";
|
static const char consoles70Item3[] PROGMEM = "Arcadia 2001";
|
||||||
static const char consolesItem4[] PROGMEM = "Intellivision";
|
static const char consoles70Item4[] PROGMEM = "Fairchild Channel F";
|
||||||
static const char consolesItem5[] PROGMEM = "Colecovision";
|
static const char consoles70Item5[] PROGMEM = "Intellivision";
|
||||||
//static const char consolesItem6[] PROGMEM = "Reset"; (stored in common strings array)
|
static const char consoles70Item6[] PROGMEM = "Colecovision";
|
||||||
static const char* const consolesOptions[] PROGMEM = { consolesItem1, consolesItem2, consolesItem3, consolesItem4, consolesItem5, string_reset2 };
|
//static const char consoles70Item7[] PROGMEM = "Reset"; (stored in common strings array)
|
||||||
|
static const char* const consoles70Options[] PROGMEM = { consoles70Item1, consoles70Item2, consoles70Item3, consoles70Item4, consoles70Item5, consoles70Item6, string_reset2 };
|
||||||
|
|
||||||
|
// 80s Consoles submenu
|
||||||
|
static const char consoles80Item1[] PROGMEM = "NES/Famicom";
|
||||||
|
static const char consoles80Item2[] PROGMEM = "PC Engine/TG16";
|
||||||
|
static const char consoles80Item3[] PROGMEM = "SMS/GG/MIII/SG-1000";
|
||||||
|
//static const char consoles80Item4[] PROGMEM = "Reset"; (stored in common strings array)
|
||||||
|
static const char* const consoles80Options[] PROGMEM = { consoles80Item1, consoles80Item2, consoles80Item3, string_reset2 };
|
||||||
|
|
||||||
// Handhelds submenu
|
// Handhelds submenu
|
||||||
static const char handheldsItem1[] PROGMEM = "Virtual Boy";
|
static const char handheldsItem1[] PROGMEM = "Virtual Boy";
|
||||||
@ -1192,26 +1297,31 @@ void mainMenu() {
|
|||||||
|
|
||||||
// Everything that needs an adapter
|
// Everything that needs an adapter
|
||||||
void addonMenu() {
|
void addonMenu() {
|
||||||
// create menu with title and 4 options to choose from
|
// create menu with title and 5 options to choose from
|
||||||
unsigned char addonsMenu;
|
unsigned char addonsMenu;
|
||||||
// Copy menuOptions out of progmem
|
// Copy menuOptions out of progmem
|
||||||
convertPgm(addonsOptions, 4);
|
convertPgm(addonsOptions, 5);
|
||||||
addonsMenu = question_box(F("Type"), menuOptions, 4, 0);
|
addonsMenu = question_box(F("Type"), menuOptions, 5, 0);
|
||||||
|
|
||||||
// wait for user choice to come back from the question box menu
|
// wait for user choice to come back from the question box menu
|
||||||
switch (addonsMenu) {
|
switch (addonsMenu) {
|
||||||
// Consoles
|
// 70s Consoles
|
||||||
case 0:
|
case 0:
|
||||||
consoleMenu();
|
consoles70Menu();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 80s Consoles
|
||||||
|
case 1:
|
||||||
|
consoles80Menu();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Handhelds
|
// Handhelds
|
||||||
case 1:
|
case 2:
|
||||||
handheldMenu();
|
handheldMenu();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef enable_FLASH
|
#ifdef enable_FLASH
|
||||||
case 2:
|
case 3:
|
||||||
#ifdef enable_FLASH16
|
#ifdef enable_FLASH16
|
||||||
flashMenu();
|
flashMenu();
|
||||||
#else
|
#else
|
||||||
@ -1220,7 +1330,7 @@ void addonMenu() {
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case 3:
|
case 4:
|
||||||
resetArduino();
|
resetArduino();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1230,15 +1340,76 @@ void addonMenu() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Everything that needs an adapter
|
// Everything that needs an adapter
|
||||||
void consoleMenu() {
|
void consoles70Menu() {
|
||||||
// create menu with title and 6 options to choose from
|
// create menu with title and 7 options to choose from
|
||||||
unsigned char consolesMenu;
|
unsigned char consoles70Menu;
|
||||||
// Copy menuOptions out of progmem
|
// Copy menuOptions out of progmem
|
||||||
convertPgm(consolesOptions, 6);
|
convertPgm(consoles70Options, 7);
|
||||||
consolesMenu = question_box(F("Choose Adapter"), menuOptions, 6, 0);
|
consoles70Menu = question_box(F("Choose Adapter"), menuOptions, 7, 0);
|
||||||
|
|
||||||
// wait for user choice to come back from the question box menu
|
// wait for user choice to come back from the question box menu
|
||||||
switch (consolesMenu) {
|
switch (consoles70Menu) {
|
||||||
|
#ifdef enable_ATARI
|
||||||
|
case 0:
|
||||||
|
setup_ATARI();
|
||||||
|
atariMenu();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef enable_ODY2
|
||||||
|
case 1:
|
||||||
|
setup_ODY2();
|
||||||
|
ody2Menu();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef enable_ARC
|
||||||
|
case 2:
|
||||||
|
setup_ARC();
|
||||||
|
arcMenu();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef enable_FAIRCHILD
|
||||||
|
case 3:
|
||||||
|
setup_FAIRCHILD();
|
||||||
|
fairchildMenu();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef enable_INTV
|
||||||
|
case 4:
|
||||||
|
setup_INTV();
|
||||||
|
intvMenu();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef enable_COLV
|
||||||
|
case 5:
|
||||||
|
setup_COL();
|
||||||
|
colMenu();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
resetArduino();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
print_MissingModule(); // does not return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything that needs an adapter
|
||||||
|
void consoles80Menu() {
|
||||||
|
// create menu with title and 6 options to choose from
|
||||||
|
unsigned char consoles80Menu;
|
||||||
|
// Copy menuOptions out of progmem
|
||||||
|
convertPgm(consoles80Options, 4);
|
||||||
|
consoles80Menu = question_box(F("Choose Adapter"), menuOptions, 4, 0);
|
||||||
|
|
||||||
|
// wait for user choice to come back from the question box menu
|
||||||
|
switch (consoles80Menu) {
|
||||||
#ifdef enable_NES
|
#ifdef enable_NES
|
||||||
case 0:
|
case 0:
|
||||||
mode = mode_NES;
|
mode = mode_NES;
|
||||||
@ -1265,21 +1436,7 @@ void consoleMenu() {
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef enable_INTV
|
|
||||||
case 3:
|
case 3:
|
||||||
setup_INTV();
|
|
||||||
intvMenu();
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef enable_COLV
|
|
||||||
case 4:
|
|
||||||
setup_COL();
|
|
||||||
colMenu();
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case 5:
|
|
||||||
resetArduino();
|
resetArduino();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -3332,6 +3489,26 @@ void loop() {
|
|||||||
else if (mode == mode_PCW) {
|
else if (mode == mode_PCW) {
|
||||||
pcwMenu();
|
pcwMenu();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef enable_ATARI
|
||||||
|
else if (mode == mode_ATARI) {
|
||||||
|
atariMenu();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef enable_ODY2
|
||||||
|
else if (mode == mode_ODY2) {
|
||||||
|
ody2Menu();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef enable_ARC
|
||||||
|
else if (mode == mode_ARC) {
|
||||||
|
arcMenu();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef enable_FAIRCHILD
|
||||||
|
else if (mode == mode_FAIRCHILD) {
|
||||||
|
fairchildMenu();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
else {
|
else {
|
||||||
display_Clear();
|
display_Clear();
|
||||||
|
865
Cart_Reader/FAIRCHILD.ino
Normal file
865
Cart_Reader/FAIRCHILD.ino
Normal file
@ -0,0 +1,865 @@
|
|||||||
|
//******************************************
|
||||||
|
// FAIRCHILD CHANNEL F MODULE
|
||||||
|
//******************************************
|
||||||
|
#if defined(enable_FAIRCHILD)
|
||||||
|
// Fairchild Channel F
|
||||||
|
// Cartridge Pinout
|
||||||
|
// 22P (27P Width) 2.54mm pitch connector
|
||||||
|
//
|
||||||
|
// TOP BOTTOM
|
||||||
|
// SIDE SIDE
|
||||||
|
// +-------+
|
||||||
|
// | == |
|
||||||
|
// | 1 |- GND
|
||||||
|
// | 2 |- GND
|
||||||
|
// | 3 |- D0
|
||||||
|
// | 4 |- D1
|
||||||
|
// | 5 |- /INTREQ
|
||||||
|
// | 6 |- ROMC0
|
||||||
|
// | 7 |- ROMC1
|
||||||
|
// | 8 |- ROMC2
|
||||||
|
// | 9 |- D2
|
||||||
|
// | 10 |- ROMC3
|
||||||
|
// | 11 |- D3
|
||||||
|
// | == |
|
||||||
|
// | == |
|
||||||
|
// | == |
|
||||||
|
// | 12 |- ROMC4
|
||||||
|
// | 13 |- PHI
|
||||||
|
// | 14 |- D4
|
||||||
|
// | 15 |- WRITE
|
||||||
|
// | 16 |- D5
|
||||||
|
// | 17 |- D6
|
||||||
|
// | 18 |- D7
|
||||||
|
// | 19 |- VDD(+5V)
|
||||||
|
// | 20 |- VDD(+5V)
|
||||||
|
// | 21 |- NC
|
||||||
|
// | 22 |- VGG(+12V)
|
||||||
|
// | == |
|
||||||
|
// +-------+
|
||||||
|
//
|
||||||
|
// TOP
|
||||||
|
// +----------------------------------------------------------------------------------+
|
||||||
|
// | |
|
||||||
|
// LEFT | | RIGHT
|
||||||
|
// | == 22 21 20 19 18 17 16 15 14 13 12 == == == 11 10 9 8 7 6 5 4 3 2 1 == |
|
||||||
|
// +----------------------------------------------------------------------------------+
|
||||||
|
// BOTTOM
|
||||||
|
//
|
||||||
|
|
||||||
|
// CONTROL PINS:
|
||||||
|
// PHI(PH3) - SNES /CS
|
||||||
|
// /INTREQ(PH4) - SNES /IRQ
|
||||||
|
// WRITE(PH5) - SNES /WR
|
||||||
|
// ROMC0(PF0) - SNES A0
|
||||||
|
// ROMC1(PF1) - SNES A1
|
||||||
|
// ROMC2(PF2) - SNES A2
|
||||||
|
// ROMC3(PF3) - SNES A3
|
||||||
|
// ROMC4(PF4) - SNES A4
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
Defines
|
||||||
|
*****************************************/
|
||||||
|
#define PHI_HI PORTH |= (1 << 3)
|
||||||
|
#define PHI_LOW PORTH &= ~(1 << 3)
|
||||||
|
#define WRITE_HI PORTH |= (1 << 5)
|
||||||
|
#define WRITE_LOW PORTH &= ~(1 << 5)
|
||||||
|
|
||||||
|
byte FAIRCHILD[] = { 2, 3, 4, 6 };
|
||||||
|
byte fairchildlo = 0; // Lowest Entry
|
||||||
|
byte fairchildhi = 3; // Highest Entry
|
||||||
|
|
||||||
|
byte fairchildsize;
|
||||||
|
byte newfairchildsize;
|
||||||
|
|
||||||
|
// EEPROM MAPPING
|
||||||
|
// 08 ROM SIZE
|
||||||
|
|
||||||
|
//******************************************
|
||||||
|
// Menu
|
||||||
|
//******************************************
|
||||||
|
// Base Menu
|
||||||
|
static const char fairchildMenuItem1[] PROGMEM = "Select Cart";
|
||||||
|
static const char fairchildMenuItem2[] PROGMEM = "Read ROM";
|
||||||
|
static const char fairchildMenuItem3[] PROGMEM = "Set Size";
|
||||||
|
static const char fairchildMenuItem4[] PROGMEM = "Read 16K";
|
||||||
|
static const char fairchildMenuItem5[] PROGMEM = "Reset";
|
||||||
|
static const char* const menuOptionsFAIRCHILD[] PROGMEM = { fairchildMenuItem1, fairchildMenuItem2, fairchildMenuItem3, fairchildMenuItem4, fairchildMenuItem5 };
|
||||||
|
|
||||||
|
void setup_FAIRCHILD() {
|
||||||
|
// Set Address Pins to Output
|
||||||
|
// Channel F uses A0-A4 [A5-A23 UNUSED]
|
||||||
|
//A0-A7
|
||||||
|
DDRF = 0xFF;
|
||||||
|
//A8-A15
|
||||||
|
DDRK = 0xFF;
|
||||||
|
//A16-A23
|
||||||
|
DDRL = 0xFF;
|
||||||
|
|
||||||
|
// Set Control Pins to Output
|
||||||
|
// ---(PH0) ---(PH1) PHI(PH3) /INTREQ(PH4) WRITE(PH5) ---(PH6)
|
||||||
|
DDRH |= (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
||||||
|
|
||||||
|
// Set TIME(PJ0) to Output (UNUSED)
|
||||||
|
DDRJ |= (1 << 0);
|
||||||
|
|
||||||
|
// Set Pins (D0-D7) to Input
|
||||||
|
DDRC = 0x00;
|
||||||
|
|
||||||
|
// Setting Unused Control Pins to HIGH
|
||||||
|
// ---(PH0) ---(PH1) PHI(PH3) /INTREQ(PH4) WRITE(PH5) ---(PH6)
|
||||||
|
PORTH |= (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
||||||
|
|
||||||
|
// Set Unused Data Pins (PA0-PA7) to Output
|
||||||
|
DDRA = 0xFF;
|
||||||
|
|
||||||
|
// Set Unused Pins HIGH
|
||||||
|
PORTA = 0xFF;
|
||||||
|
PORTK = 0xFF; // A8-A15
|
||||||
|
PORTL = 0xFF; // A16-A23
|
||||||
|
PORTJ |= (1 << 0); // TIME(PJ0)
|
||||||
|
|
||||||
|
checkStatus_FAIRCHILD();
|
||||||
|
strcpy(romName, "FAIRCHILD");
|
||||||
|
|
||||||
|
mode = mode_FAIRCHILD;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fairchildMenu() {
|
||||||
|
convertPgm(menuOptionsFAIRCHILD, 5);
|
||||||
|
uint8_t mainMenu = question_box(F("CHANNEL F MENU"), menuOptions, 5, 0);
|
||||||
|
|
||||||
|
switch (mainMenu) {
|
||||||
|
case 0:
|
||||||
|
// Select Cart
|
||||||
|
setCart_FAIRCHILD();
|
||||||
|
wait();
|
||||||
|
setup_FAIRCHILD();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
// Read ROM
|
||||||
|
sd.chdir("/");
|
||||||
|
readROM_FAIRCHILD();
|
||||||
|
sd.chdir("/");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// Set Size
|
||||||
|
setROMSize_FAIRCHILD();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
// Read 16K
|
||||||
|
sd.chdir("/");
|
||||||
|
read16K_FAIRCHILD();
|
||||||
|
sd.chdir("/");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
// reset
|
||||||
|
resetArduino();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************
|
||||||
|
// READ CODE
|
||||||
|
//******************************************
|
||||||
|
|
||||||
|
// Sean Riddle Dumper Routine
|
||||||
|
// clear PC0 with ROMC state 8
|
||||||
|
// loop 256 times
|
||||||
|
// fetch 16 bytes into buffer with ROMC state 0
|
||||||
|
// dump buffer to serial port
|
||||||
|
// clear PC0
|
||||||
|
|
||||||
|
// Clear PC0
|
||||||
|
void clearRegister_FAIRCHILD() {
|
||||||
|
PHI_LOW;
|
||||||
|
WRITE_LOW;
|
||||||
|
PORTF = 0; // ROMC3 LOW
|
||||||
|
|
||||||
|
delay(2000);
|
||||||
|
|
||||||
|
PHI_HI;
|
||||||
|
WRITE_HI;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
WRITE_LOW;
|
||||||
|
PHI_HI;
|
||||||
|
PORTF = 0; // ROMC3 LOW
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PORTF = 0; // ROMC3 LOW
|
||||||
|
PHI_HI;
|
||||||
|
PORTF = 0x8; // this puts us in ROMC state 8 - clear PC0
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PORTF = 0x08; // ROMC3 HIGH
|
||||||
|
PHI_HI;
|
||||||
|
PORTF = 0x08; // ROMC3 HIGH
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PHI_HI;
|
||||||
|
WRITE_HI;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
WRITE_LOW;
|
||||||
|
PHI_HI;
|
||||||
|
PORTF = 0; // ROMC3 LOW
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
WRITE_LOW;
|
||||||
|
PHI_HI;
|
||||||
|
PORTF = 0; // ROMC3 LOW
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
WRITE_LOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setROMC_FAIRCHILD(uint8_t command) {
|
||||||
|
PHI_LOW;
|
||||||
|
WRITE_LOW;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
WRITE_HI;
|
||||||
|
PHI_HI;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
WRITE_LOW;
|
||||||
|
PHI_HI;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
// PWs = 4 PHI Cycles
|
||||||
|
// PWl = 6 PHI Cycles
|
||||||
|
for (int x = 0; x < 2; x++) { // 2 PHI
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
PHI_HI;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
}
|
||||||
|
PORTF = command; // ROMC3 = command
|
||||||
|
|
||||||
|
for (int x = 0; x < 3; x++) { // 4 PHI
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
PHI_HI;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PHI_HI;
|
||||||
|
WRITE_HI;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PHI_HI;
|
||||||
|
WRITE_LOW;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setREAD_FAIRCHILD() {
|
||||||
|
PHI_LOW;
|
||||||
|
WRITE_LOW;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
WRITE_HI;
|
||||||
|
PHI_HI;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
WRITE_LOW;
|
||||||
|
PHI_HI;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
// PWs = 4 PHI Cycles
|
||||||
|
// PWl = 6 PHI Cycles
|
||||||
|
for (int x = 0; x < 2; x++) { // 2 PHI
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
PHI_HI;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
}
|
||||||
|
PORTF = 0; // ROMC3 = 0 = Fetch Data
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t readData_FAIRCHILD() {
|
||||||
|
for (int x = 0; x < 3; x++) { // 4 PHI
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
PHI_HI;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PHI_HI;
|
||||||
|
WRITE_HI;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PHI_HI;
|
||||||
|
WRITE_LOW;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
uint8_t ret = PINC; // read databus into buffer
|
||||||
|
|
||||||
|
PHI_LOW;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void readROM_FAIRCHILD() {
|
||||||
|
strcpy(fileName, romName);
|
||||||
|
strcat(fileName, ".bin");
|
||||||
|
|
||||||
|
// create a new folder for storing rom file
|
||||||
|
EEPROM_readAnything(0, foldern);
|
||||||
|
sprintf(folder, "FAIRCHILD/ROM/%d", foldern);
|
||||||
|
sd.mkdir(folder, true);
|
||||||
|
sd.chdir(folder);
|
||||||
|
|
||||||
|
display_Clear();
|
||||||
|
print_Msg(F("Saving to "));
|
||||||
|
print_Msg(folder);
|
||||||
|
println_Msg(F("/..."));
|
||||||
|
display_Update();
|
||||||
|
|
||||||
|
// open file on sdcard
|
||||||
|
if (!myFile.open(fileName, O_RDWR | O_CREAT)) {
|
||||||
|
print_FatalError(create_file_STR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write new folder number back to EEPROM
|
||||||
|
foldern++;
|
||||||
|
EEPROM_writeAnything(0, foldern);
|
||||||
|
|
||||||
|
unsigned long cartsize = FAIRCHILD[fairchildsize] * 0x400;
|
||||||
|
uint8_t blocks = cartsize / 0x200;
|
||||||
|
setROMC_FAIRCHILD(0x8); // Clear PC0
|
||||||
|
setREAD_FAIRCHILD();
|
||||||
|
|
||||||
|
// ROM Start Bytes
|
||||||
|
// 0x55,0x08 - desert fox, muehle, space war, tic-tac-toe (all 2K)
|
||||||
|
// 0x55,0x2B - most carts
|
||||||
|
// 0x55,0xAA - alien invasion (4K)
|
||||||
|
// 0x55,0xBB - video whizball (3K)
|
||||||
|
for (int y = 0; y < 0x4800; y++) {
|
||||||
|
uint8_t startbyte = readData_FAIRCHILD();
|
||||||
|
if (startbyte == 0x55) { // Start Byte
|
||||||
|
sdBuffer[0] = startbyte;
|
||||||
|
startbyte = readData_FAIRCHILD();
|
||||||
|
if ((startbyte == 0x08) || (startbyte == 0x2B) || (startbyte == 0xAA) || (startbyte == 0xBB)) {
|
||||||
|
sdBuffer[1] = startbyte;
|
||||||
|
for (int w = 2; w < 512; w++) {
|
||||||
|
startbyte = readData_FAIRCHILD();
|
||||||
|
sdBuffer[w] = startbyte;
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 512);
|
||||||
|
delay(1); // Added delay
|
||||||
|
for (int z = 1; z < blocks; z++) {
|
||||||
|
// Skip BIOS/Blocks Code for 4K Cart
|
||||||
|
if (cartsize == 0x1000) { // Pro Football 4K
|
||||||
|
setROMC_FAIRCHILD(0x8); // Clear PC0
|
||||||
|
setREAD_FAIRCHILD();
|
||||||
|
uint16_t offset = z * 0x200;
|
||||||
|
for (int x = 0; x < 0x800 + offset; x++) { // Skip BIOS/Previous Blocks
|
||||||
|
readData_FAIRCHILD();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int w = 0; w < 512; w++) {
|
||||||
|
uint8_t temp = readData_FAIRCHILD();
|
||||||
|
sdBuffer[w] = temp;
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 512);
|
||||||
|
delay(1); // Added delay
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
myFile.close();
|
||||||
|
|
||||||
|
calcCRC(fileName, cartsize, NULL, 0);
|
||||||
|
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F("Press Button..."));
|
||||||
|
display_Update();
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
void read16K_FAIRCHILD() // Read 16K Bytes
|
||||||
|
{
|
||||||
|
strcpy(fileName, romName);
|
||||||
|
strcat(fileName, ".bin");
|
||||||
|
|
||||||
|
// create a new folder for storing rom file
|
||||||
|
EEPROM_readAnything(0, foldern);
|
||||||
|
sprintf(folder, "FAIRCHILD/ROM/%d", foldern);
|
||||||
|
sd.mkdir(folder, true);
|
||||||
|
sd.chdir(folder);
|
||||||
|
|
||||||
|
display_Clear();
|
||||||
|
print_Msg(F("Saving to "));
|
||||||
|
print_Msg(folder);
|
||||||
|
println_Msg(F("/..."));
|
||||||
|
display_Update();
|
||||||
|
|
||||||
|
// open file on sdcard
|
||||||
|
if (!myFile.open(fileName, O_RDWR | O_CREAT)) {
|
||||||
|
print_FatalError(create_file_STR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write new folder number back to EEPROM
|
||||||
|
foldern++;
|
||||||
|
EEPROM_writeAnything(0, foldern);
|
||||||
|
|
||||||
|
unsigned long cartsize = FAIRCHILD[fairchildsize] * 0x400;
|
||||||
|
for (int y = 0; y < 0x20; y++) {
|
||||||
|
// Skip BIOS/Blocks Code for 4K Cart
|
||||||
|
// 3K/6K CARTS MAY NEED THE SKIP BIOS/BLOCKS ROUTINE USED FOR THE 4K CART
|
||||||
|
// TEST 3K/6K CARTS BY SETTING ROM SIZE TO 2K/4K AND COMPARE 16K DUMPS
|
||||||
|
if (cartsize == 0x1000) { // Pro Football 4K
|
||||||
|
setROMC_FAIRCHILD(0x8); // Clear PC0
|
||||||
|
setREAD_FAIRCHILD();
|
||||||
|
uint16_t offset = y * 0x200;
|
||||||
|
for (int x = 0; x < 0x800 + offset; x++) { // Skip BIOS/Previous Blocks
|
||||||
|
readData_FAIRCHILD();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int w = 0; w < 512; w++) {
|
||||||
|
uint8_t temp = readData_FAIRCHILD();
|
||||||
|
sdBuffer[w] = temp;
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 512);
|
||||||
|
delay(1); // Added delay
|
||||||
|
}
|
||||||
|
myFile.close();
|
||||||
|
|
||||||
|
calcCRC(fileName, 0x4000, NULL, 0);
|
||||||
|
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F("Press Button..."));
|
||||||
|
display_Update();
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************
|
||||||
|
// ROM SIZE
|
||||||
|
//******************************************
|
||||||
|
|
||||||
|
void setROMSize_FAIRCHILD() {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
if (fairchildlo == fairchildhi)
|
||||||
|
newfairchildsize = fairchildlo;
|
||||||
|
else {
|
||||||
|
int b = 0;
|
||||||
|
int i = fairchildlo;
|
||||||
|
while (1) {
|
||||||
|
display_Clear();
|
||||||
|
print_Msg(F("ROM Size: "));
|
||||||
|
println_Msg(FAIRCHILD[i]);
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F("Press to Change"));
|
||||||
|
println_Msg(F("Hold to Select"));
|
||||||
|
display_Update();
|
||||||
|
b = checkButton();
|
||||||
|
if (b == 2) { // Previous (doubleclick)
|
||||||
|
if (i == fairchildlo)
|
||||||
|
i = fairchildhi;
|
||||||
|
else
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
if (b == 1) { // Next (press)
|
||||||
|
if (i == fairchildhi)
|
||||||
|
i = fairchildlo;
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (b == 3) { // Long Press - Execute (hold)
|
||||||
|
newfairchildsize = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
display.setCursor(0, 56); // Display selection at bottom
|
||||||
|
}
|
||||||
|
print_Msg(F("ROM SIZE "));
|
||||||
|
print_Msg(FAIRCHILD[newfairchildsize]);
|
||||||
|
println_Msg(F("K"));
|
||||||
|
display_Update();
|
||||||
|
delay(1000);
|
||||||
|
#else
|
||||||
|
if (fairchildlo == fairchildhi)
|
||||||
|
newfairchildsize = fairchildlo;
|
||||||
|
else {
|
||||||
|
setrom:
|
||||||
|
String sizeROM;
|
||||||
|
for (int i = 0; i < (fairchildhi - fairchildlo + 1); i++) {
|
||||||
|
Serial.print(F("Select ROM Size: "));
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.print(F(" = "));
|
||||||
|
Serial.print(FAIRCHILD[i + fairchildlo]);
|
||||||
|
Serial.println(F("K"));
|
||||||
|
}
|
||||||
|
Serial.print(F("Enter ROM Size: "));
|
||||||
|
while (Serial.available() == 0) {}
|
||||||
|
sizeROM = Serial.readStringUntil('\n');
|
||||||
|
Serial.println(sizeROM);
|
||||||
|
newfairchildsize = sizeROM.toInt() + fairchildlo;
|
||||||
|
if (newfairchildsize > fairchildhi) {
|
||||||
|
Serial.println(F("SIZE NOT SUPPORTED"));
|
||||||
|
Serial.println(F(""));
|
||||||
|
goto setrom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.print(F("ROM Size = "));
|
||||||
|
Serial.print(FAIRCHILD[newfairchildsize]);
|
||||||
|
Serial.println(F("K"));
|
||||||
|
#endif
|
||||||
|
EEPROM_writeAnything(8, newfairchildsize);
|
||||||
|
fairchildsize = newfairchildsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkStatus_FAIRCHILD() {
|
||||||
|
EEPROM_readAnything(8, fairchildsize);
|
||||||
|
if (fairchildsize > 3) {
|
||||||
|
fairchildsize = 0;
|
||||||
|
EEPROM_writeAnything(8, fairchildsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("CHANNEL F READER"));
|
||||||
|
println_Msg(F("CURRENT SETTINGS"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
print_Msg(F("ROM SIZE: "));
|
||||||
|
print_Msg(FAIRCHILD[fairchildsize]);
|
||||||
|
println_Msg(F("K"));
|
||||||
|
display_Update();
|
||||||
|
wait();
|
||||||
|
#else
|
||||||
|
Serial.print(F("CURRENT ROM SIZE: "));
|
||||||
|
Serial.print(FAIRCHILD[fairchildsize]);
|
||||||
|
Serial.println(F("K"));
|
||||||
|
Serial.println(F(""));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************
|
||||||
|
// CART SELECT CODE
|
||||||
|
//******************************************
|
||||||
|
|
||||||
|
FsFile fairchildcsvFile;
|
||||||
|
char fairchildgame[33]; // title
|
||||||
|
char fairchildrr[3]; // romsize
|
||||||
|
char fairchildll[4]; // linelength (previous line)
|
||||||
|
unsigned long fairchildcsvpos; // CSV File Position
|
||||||
|
char fairchildcartCSV[] = "fairchildcart.txt"; // CSV List
|
||||||
|
char fairchildcsvEND[] = "EOF"; // CSV End Marker for scrolling
|
||||||
|
|
||||||
|
bool readLine_FAIRCHILD(FsFile& f, char* line, size_t maxLen) {
|
||||||
|
for (size_t n = 0; n < maxLen; n++) {
|
||||||
|
int c = f.read();
|
||||||
|
if (c < 0 && n == 0) return false; // EOF
|
||||||
|
if (c < 0 || c == '\n') {
|
||||||
|
line[n] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
line[n] = c;
|
||||||
|
}
|
||||||
|
return false; // line too long
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readVals_FAIRCHILD(char* fairchildgame, char* fairchildrr, char* fairchildll) {
|
||||||
|
char line[39];
|
||||||
|
fairchildcsvpos = fairchildcsvFile.position();
|
||||||
|
if (!readLine_FAIRCHILD(fairchildcsvFile, line, sizeof(line))) {
|
||||||
|
return false; // EOF or too long
|
||||||
|
}
|
||||||
|
char* comma = strtok(line, ",");
|
||||||
|
int x = 0;
|
||||||
|
while (comma != NULL) {
|
||||||
|
if (x == 0)
|
||||||
|
strcpy(fairchildgame, comma);
|
||||||
|
else if (x == 1)
|
||||||
|
strcpy(fairchildrr, comma);
|
||||||
|
else if (x == 2)
|
||||||
|
strcpy(fairchildll, comma);
|
||||||
|
comma = strtok(NULL, ",");
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getCartListInfo_FAIRCHILD() {
|
||||||
|
bool buttonreleased = 0;
|
||||||
|
bool cartselected = 0;
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F(" HOLD TO FAST CYCLE"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("HOLD BUTTON TO FAST CYCLE"));
|
||||||
|
#endif
|
||||||
|
delay(2000);
|
||||||
|
#if defined(enable_OLED)
|
||||||
|
buttonVal1 = (PIND & (1 << 7)); // PD7
|
||||||
|
#elif defined(enable_LCD)
|
||||||
|
boolean buttonVal1 = (PING & (1 << 2)); //PG2
|
||||||
|
#endif
|
||||||
|
if (buttonVal1 == LOW) { // Button Held - Fast Cycle
|
||||||
|
while (1) { // Scroll Game List
|
||||||
|
while (readVals_FAIRCHILD(fairchildgame, fairchildrr, fairchildll)) {
|
||||||
|
if (strcmp(fairchildcsvEND, fairchildgame) == 0) {
|
||||||
|
fairchildcsvFile.seek(0); // Restart
|
||||||
|
} else {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("CART TITLE:"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(fairchildgame);
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.print(F("CART TITLE:"));
|
||||||
|
Serial.println(fairchildgame);
|
||||||
|
#endif
|
||||||
|
#if defined(enable_OLED)
|
||||||
|
buttonVal1 = (PIND & (1 << 7)); // PD7
|
||||||
|
#elif defined(enable_LCD)
|
||||||
|
buttonVal1 = (PING & (1 << 2)); //PG2
|
||||||
|
#endif
|
||||||
|
if (buttonVal1 == HIGH) { // Button Released
|
||||||
|
buttonreleased = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (buttonreleased) {
|
||||||
|
buttonreleased = 0; // Reset Flag
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if defined(enable_OLED)
|
||||||
|
buttonVal1 = (PIND & (1 << 7)); // PD7
|
||||||
|
#elif defined(enable_LCD)
|
||||||
|
buttonVal1 = (PING & (1 << 2)); //PG2
|
||||||
|
#endif
|
||||||
|
if (buttonVal1 == HIGH) // Button Released
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display.setCursor(0, 56);
|
||||||
|
println_Msg(F("FAST CYCLE OFF"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F(""));
|
||||||
|
Serial.println(F("FAST CYCLE OFF"));
|
||||||
|
Serial.println(F("PRESS BUTTON TO STEP FORWARD"));
|
||||||
|
Serial.println(F("DOUBLE CLICK TO STEP BACK"));
|
||||||
|
Serial.println(F("HOLD TO SELECT"));
|
||||||
|
Serial.println(F(""));
|
||||||
|
#endif
|
||||||
|
while (readVals_FAIRCHILD(fairchildgame, fairchildrr, fairchildll)) {
|
||||||
|
if (strcmp(fairchildcsvEND, fairchildgame) == 0) {
|
||||||
|
fairchildcsvFile.seek(0); // Restart
|
||||||
|
} else {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("CART TITLE:"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(fairchildgame);
|
||||||
|
display.setCursor(0, 48);
|
||||||
|
println_Msg(F("Press to Change"));
|
||||||
|
println_Msg(F("Hold to Select"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.print(F("CART TITLE:"));
|
||||||
|
Serial.println(fairchildgame);
|
||||||
|
#endif
|
||||||
|
while (1) { // Single Step
|
||||||
|
int b = checkButton();
|
||||||
|
if (b == 1) { // Continue (press)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (b == 2) { // Reset to Start of List (doubleclick)
|
||||||
|
byte prevline = strtol(fairchildll, NULL, 10);
|
||||||
|
fairchildcsvpos -= prevline;
|
||||||
|
fairchildcsvFile.seek(fairchildcsvpos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (b == 3) { // Long Press - Select Cart (hold)
|
||||||
|
newfairchildsize = strtol(fairchildrr, NULL, 10);
|
||||||
|
EEPROM_writeAnything(8, newfairchildsize);
|
||||||
|
cartselected = 1; // SELECTION MADE
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
println_Msg(F("SELECTION MADE"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("SELECTION MADE"));
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cartselected) {
|
||||||
|
cartselected = 0; // Reset Flag
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F("END OF FILE"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("END OF FILE"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkCSV_FAIRCHILD() {
|
||||||
|
if (getCartListInfo_FAIRCHILD()) {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("CART SELECTED"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(fairchildgame);
|
||||||
|
display_Update();
|
||||||
|
// Display Settings
|
||||||
|
display.setCursor(0, 56);
|
||||||
|
print_Msg(F("CODE: R"));
|
||||||
|
println_Msg(newfairchildsize);
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F(""));
|
||||||
|
Serial.println(F("CART SELECTED"));
|
||||||
|
Serial.println(fairchildgame);
|
||||||
|
// Display Settings
|
||||||
|
Serial.print(F("CODE: R"));
|
||||||
|
Serial.println(newfairchildsize);
|
||||||
|
Serial.println(F(""));
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display.setCursor(0, 56);
|
||||||
|
println_Msg(F("NO SELECTION"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("NO SELECTION"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCart_FAIRCHILD() {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(fairchildcartCSV);
|
||||||
|
display_Update();
|
||||||
|
#endif
|
||||||
|
sd.chdir();
|
||||||
|
sprintf(folder, "FAIRCHILD/CSV");
|
||||||
|
sd.chdir(folder); // Switch Folder
|
||||||
|
fairchildcsvFile = sd.open(fairchildcartCSV, O_READ);
|
||||||
|
if (!fairchildcsvFile) {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("CSV FILE NOT FOUND!"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("CSV FILE NOT FOUND!"));
|
||||||
|
#endif
|
||||||
|
while (1) {
|
||||||
|
if (checkButton() != 0)
|
||||||
|
setup_FAIRCHILD();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkCSV_FAIRCHILD();
|
||||||
|
|
||||||
|
fairchildcsvFile.close();
|
||||||
|
}
|
||||||
|
#endif
|
632
Cart_Reader/ODY2.ino
Normal file
632
Cart_Reader/ODY2.ino
Normal file
@ -0,0 +1,632 @@
|
|||||||
|
//******************************************
|
||||||
|
// MAGNAVOX ODYSSEY 2 MODULE
|
||||||
|
//******************************************
|
||||||
|
#if defined(enable_ODY2)
|
||||||
|
// Magnavox Odyssey 2
|
||||||
|
// Philips Videopac/Videopac+
|
||||||
|
// Cartridge Pinout
|
||||||
|
// 30P 3.96mm pitch connector
|
||||||
|
//
|
||||||
|
// FRONT BACK
|
||||||
|
// SIDE SIDE
|
||||||
|
// +------+
|
||||||
|
// T0 -| 1 A |- /WR
|
||||||
|
// D0 -| 2 B |- GND
|
||||||
|
// D1 -| 3 C |- GND
|
||||||
|
// D2 -| 4 D |- VCC (+5V)
|
||||||
|
// D3 -| 5 E |- CS3
|
||||||
|
// D4 -| 6 F |- /PSEN (/CE)
|
||||||
|
// D5 -| 7 G |- A0
|
||||||
|
// D6 -| 8 H |- A1
|
||||||
|
// D7 -| 9 J |- A2
|
||||||
|
// A10 (P22) -| 10 K |- A3
|
||||||
|
// /CS1 (P14) -| 11 L |- A4
|
||||||
|
// P11 -| 12 M |- A5
|
||||||
|
// P10 -| 13 N |- A7
|
||||||
|
// A11 (P23) -| 14 P |- A6
|
||||||
|
// A9 (P21) -| 15 R |- A8 (P20)
|
||||||
|
// +------+
|
||||||
|
//
|
||||||
|
// NOTE: ADDRESS A7/A6 PIN ORDER ON PINS N & P.
|
||||||
|
// NOTE: MOST CARTS DO NOT CONNECT A10 ON PIN 10.
|
||||||
|
//
|
||||||
|
// BACK
|
||||||
|
// +---------------------------------------------+
|
||||||
|
// | A B C D E F G H J K L M N P R |
|
||||||
|
// LEFT | | RIGHT
|
||||||
|
// | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
||||||
|
// +---------------------------------------------+
|
||||||
|
// FRONT
|
||||||
|
//
|
||||||
|
// CONTROL PINS:
|
||||||
|
// T0(PH0) - SNES RESET
|
||||||
|
// CS3(PH3) - SNES /CS
|
||||||
|
// /CS1(PH4) - SNES /IRQ
|
||||||
|
// /WR(PH5) - SNES /WR
|
||||||
|
// /PSEN(PH6) - SNES /RD
|
||||||
|
|
||||||
|
byte ODY2[] = { 2, 4, 8, 12, 16 };
|
||||||
|
byte ody2lo = 0; // Lowest Entry
|
||||||
|
byte ody2hi = 4; // Highest Entry
|
||||||
|
|
||||||
|
byte ody2mapper;
|
||||||
|
byte newody2mapper;
|
||||||
|
byte ody2size;
|
||||||
|
byte newody2size;
|
||||||
|
|
||||||
|
// EEPROM MAPPING
|
||||||
|
// 07 MAPPER
|
||||||
|
// 08 ROM SIZE
|
||||||
|
|
||||||
|
//******************************************
|
||||||
|
// Menu
|
||||||
|
//******************************************
|
||||||
|
// Base Menu
|
||||||
|
static const char ody2MenuItem1[] PROGMEM = "Select Cart";
|
||||||
|
static const char ody2MenuItem2[] PROGMEM = "Read ROM";
|
||||||
|
static const char ody2MenuItem3[] PROGMEM = "Set Size";
|
||||||
|
static const char ody2MenuItem4[] PROGMEM = "Reset";
|
||||||
|
static const char* const menuOptionsODY2[] PROGMEM = { ody2MenuItem1, ody2MenuItem2, ody2MenuItem3, ody2MenuItem4 };
|
||||||
|
|
||||||
|
void setup_ODY2() {
|
||||||
|
// Set Address Pins to Output
|
||||||
|
// Odyssey 2 uses A0-A13 [A14-A23 UNUSED]
|
||||||
|
//A0-A7
|
||||||
|
DDRF = 0xFF;
|
||||||
|
//A8-A15
|
||||||
|
DDRK = 0xFF;
|
||||||
|
//A16-A23
|
||||||
|
DDRL = 0xFF;
|
||||||
|
|
||||||
|
// Set Control Pins to Output
|
||||||
|
// T0(PH0) ---(PH1) CS3(PH3) /CS1(PH4) /WR(PH5) /RD(PH6)
|
||||||
|
DDRH |= (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
||||||
|
|
||||||
|
// Set TIME(PJ0) to Output (UNUSED)
|
||||||
|
DDRJ |= (1 << 0);
|
||||||
|
|
||||||
|
// Set Pins (D0-D7) to Input
|
||||||
|
DDRC = 0x00;
|
||||||
|
|
||||||
|
// Setting Control Pins to HIGH
|
||||||
|
// T0(PH0) ---(PH1) /CS1(PH4) /WR(PH5) /RD(PH6)
|
||||||
|
PORTH |= (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 6);
|
||||||
|
|
||||||
|
// Set CS3(PH3) to LOW
|
||||||
|
PORTH &= ~(1 << 3);
|
||||||
|
|
||||||
|
// Set Unused Data Pins (PA0-PA7) to Output
|
||||||
|
DDRA = 0xFF;
|
||||||
|
|
||||||
|
// Set Unused Pins HIGH
|
||||||
|
PORTA = 0xFF;
|
||||||
|
PORTL = 0xFF; // A16-A23
|
||||||
|
PORTJ |= (1 << 0); // TIME(PJ0)
|
||||||
|
|
||||||
|
checkStatus_ODY2();
|
||||||
|
strcpy(romName, "ODYSSEY2");
|
||||||
|
|
||||||
|
mode = mode_ODY2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ody2Menu() {
|
||||||
|
convertPgm(menuOptionsODY2, 4);
|
||||||
|
uint8_t mainMenu = question_box(F("ODYSSEY 2 MENU"), menuOptions, 4, 0);
|
||||||
|
|
||||||
|
switch (mainMenu) {
|
||||||
|
case 0:
|
||||||
|
// Select Cart
|
||||||
|
setCart_ODY2();
|
||||||
|
wait();
|
||||||
|
setup_ODY2();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
// Read ROM
|
||||||
|
sd.chdir("/");
|
||||||
|
readROM_ODY2();
|
||||||
|
sd.chdir("/");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// Set Size
|
||||||
|
setROMSize_ODY2();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
// reset
|
||||||
|
resetArduino();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************
|
||||||
|
// READ CODE
|
||||||
|
//******************************************
|
||||||
|
|
||||||
|
uint8_t readData_ODY2(uint16_t addr) {
|
||||||
|
PORTF = addr & 0xFF; // A0-A7
|
||||||
|
PORTK = (addr >> 8) & 0xFF; // A8-A13
|
||||||
|
|
||||||
|
// Set /PSEN (/CE) to LOW
|
||||||
|
PORTH &= ~(1 << 6); // /PSEN LOW (ENABLE)
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
uint8_t ret = PINC;
|
||||||
|
|
||||||
|
// Pull /PSEN (/CE) to HIGH
|
||||||
|
PORTH |= (1 << 6); // /PSEN HIGH (DISABLE)
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void readSegment_ODY2(uint16_t startaddr, uint16_t endaddr) {
|
||||||
|
for (uint16_t addr = startaddr; addr < endaddr; addr += 512) {
|
||||||
|
for (int w = 0; w < 512; w++) {
|
||||||
|
uint8_t temp = readData_ODY2(addr + w);
|
||||||
|
sdBuffer[w] = temp;
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 512);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bankSwitch_ODY2(uint16_t addr, uint8_t data) {
|
||||||
|
PORTF = addr & 0xFF; // A0-A7
|
||||||
|
PORTK = (addr >> 8) & 0xFF; // A8-A13
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
// Set /CS1(PH4) to LOW
|
||||||
|
PORTH &= ~(1 << 4);
|
||||||
|
// Set /WR(PH5) to LOW
|
||||||
|
PORTH &= ~(1 << 5);
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
DDRC = 0xFF; // Set to Output
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
PORTC = data;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
NOP;
|
||||||
|
|
||||||
|
// Set /WR(PH5) to HIGH
|
||||||
|
PORTH |= (1 << 5);
|
||||||
|
// Set /CS1(PH4) to HIGH
|
||||||
|
PORTH |= (1 << 4);
|
||||||
|
|
||||||
|
DDRC = 0x00; // Reset to Input
|
||||||
|
}
|
||||||
|
|
||||||
|
void readROM_ODY2() {
|
||||||
|
strcpy(fileName, romName);
|
||||||
|
strcat(fileName, ".bin");
|
||||||
|
|
||||||
|
// create a new folder for storing rom file
|
||||||
|
EEPROM_readAnything(0, foldern);
|
||||||
|
sprintf(folder, "ODY2/ROM/%d", foldern);
|
||||||
|
sd.mkdir(folder, true);
|
||||||
|
sd.chdir(folder);
|
||||||
|
|
||||||
|
display_Clear();
|
||||||
|
print_Msg(F("Saving to "));
|
||||||
|
print_Msg(folder);
|
||||||
|
println_Msg(F("/..."));
|
||||||
|
display_Update();
|
||||||
|
|
||||||
|
// open file on sdcard
|
||||||
|
if (!myFile.open(fileName, O_RDWR | O_CREAT)) {
|
||||||
|
print_FatalError(create_file_STR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write new folder number back to EEPROM
|
||||||
|
foldern++;
|
||||||
|
EEPROM_writeAnything(0, foldern);
|
||||||
|
|
||||||
|
if (ody2mapper == 1) { // A10 CONNECTED
|
||||||
|
// Videopac 31: Musician
|
||||||
|
// Videopac 40: 4 in 1 Row/4 en 1 Ligne
|
||||||
|
readSegment_ODY2(0x0000, 0x1000); // 4K
|
||||||
|
}
|
||||||
|
// A10 NOT CONNECTED
|
||||||
|
else if (ody2size > 2) { // 12K/16K (BANKSWITCH)
|
||||||
|
// Videopac+ 55: Neutron Star 12K = 2K x 6 Banks
|
||||||
|
// Videopac+ 58: Norseman 12K = 2K x 6 Banks
|
||||||
|
// Videopac+ 59: Helicopter Rescue 16K = 2K x 8 Banks
|
||||||
|
// Videopac+ 60: Trans American Rally 16K = 2K x 8 Banks
|
||||||
|
uint8_t ody2banks = (ody2size * 4) / 2;
|
||||||
|
for (int x = (ody2banks - 1); x >= 0; x--) {
|
||||||
|
bankSwitch_ODY2(0x80, ~x);
|
||||||
|
readSegment_ODY2(0x0400, 0x0C00); // 2K x 6/8 = 12K/16K
|
||||||
|
}
|
||||||
|
} else { // STANDARD SIZES
|
||||||
|
readSegment_ODY2(0x0400, 0x0C00); // 2K
|
||||||
|
if (ody2size > 0) {
|
||||||
|
readSegment_ODY2(0x1400, 0x1C00); // +2K = 4K
|
||||||
|
if (ody2size > 1) {
|
||||||
|
readSegment_ODY2(0x2400, 0x2C00); // +2K = 6K
|
||||||
|
readSegment_ODY2(0x3400, 0x3C00); // +2K = 8K
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
myFile.close();
|
||||||
|
|
||||||
|
unsigned long crcsize = ODY2[ody2size] * 0x400;
|
||||||
|
calcCRC(fileName, crcsize, NULL, 0);
|
||||||
|
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F("Press Button..."));
|
||||||
|
display_Update();
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************
|
||||||
|
// ROM SIZE
|
||||||
|
//******************************************
|
||||||
|
|
||||||
|
void setROMSize_ODY2() {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
if (ody2lo == ody2hi)
|
||||||
|
newody2size = ody2lo;
|
||||||
|
else {
|
||||||
|
int b = 0;
|
||||||
|
int i = ody2lo;
|
||||||
|
while (1) {
|
||||||
|
display_Clear();
|
||||||
|
print_Msg(F("ROM Size: "));
|
||||||
|
println_Msg(ODY2[i]);
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F("Press to Change"));
|
||||||
|
println_Msg(F("Hold to Select"));
|
||||||
|
display_Update();
|
||||||
|
b = checkButton();
|
||||||
|
if (b == 2) { // Previous (doubleclick)
|
||||||
|
if (i == ody2lo)
|
||||||
|
i = ody2hi;
|
||||||
|
else
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
if (b == 1) { // Next (press)
|
||||||
|
if (i == ody2hi)
|
||||||
|
i = ody2lo;
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (b == 3) { // Long Press - Execute (hold)
|
||||||
|
newody2size = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
display.setCursor(0, 56); // Display selection at bottom
|
||||||
|
}
|
||||||
|
print_Msg(F("ROM SIZE "));
|
||||||
|
print_Msg(ODY2[newody2size]);
|
||||||
|
println_Msg(F("K"));
|
||||||
|
display_Update();
|
||||||
|
delay(1000);
|
||||||
|
#else
|
||||||
|
if (ody2lo == ody2hi)
|
||||||
|
newody2size = ody2lo;
|
||||||
|
else {
|
||||||
|
setrom:
|
||||||
|
String sizeROM;
|
||||||
|
for (int i = 0; i < (ody2hi - ody2lo + 1); i++) {
|
||||||
|
Serial.print(F("Select ROM Size: "));
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.print(F(" = "));
|
||||||
|
Serial.print(ODY2[i + ody2lo]);
|
||||||
|
Serial.println(F("K"));
|
||||||
|
}
|
||||||
|
Serial.print(F("Enter ROM Size: "));
|
||||||
|
while (Serial.available() == 0) {}
|
||||||
|
sizeROM = Serial.readStringUntil('\n');
|
||||||
|
Serial.println(sizeROM);
|
||||||
|
newody2size = sizeROM.toInt() + ody2lo;
|
||||||
|
if (newody2size > ody2hi) {
|
||||||
|
Serial.println(F("SIZE NOT SUPPORTED"));
|
||||||
|
Serial.println(F(""));
|
||||||
|
goto setrom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.print(F("ROM Size = "));
|
||||||
|
Serial.print(ODY2[newody2size]);
|
||||||
|
Serial.println(F("K"));
|
||||||
|
#endif
|
||||||
|
EEPROM_writeAnything(8, newody2size);
|
||||||
|
ody2size = newody2size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkStatus_ODY2() {
|
||||||
|
EEPROM_readAnything(7, ody2mapper);
|
||||||
|
EEPROM_readAnything(8, ody2size);
|
||||||
|
if (ody2mapper > 1) {
|
||||||
|
ody2mapper = 0;
|
||||||
|
EEPROM_writeAnything(7, ody2mapper);
|
||||||
|
}
|
||||||
|
if (ody2size > 4) {
|
||||||
|
ody2size = 0;
|
||||||
|
EEPROM_writeAnything(8, ody2size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("ODYSSEY 2 READER"));
|
||||||
|
println_Msg(F("CURRENT SETTINGS"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
print_Msg(F("MAPPER: "));
|
||||||
|
println_Msg(ody2mapper);
|
||||||
|
print_Msg(F("ROM SIZE: "));
|
||||||
|
print_Msg(ODY2[ody2size]);
|
||||||
|
println_Msg(F("K"));
|
||||||
|
display_Update();
|
||||||
|
wait();
|
||||||
|
#else
|
||||||
|
Serial.print(F("CURRENT MAPPER: "));
|
||||||
|
Serial.println(ody2mapper);
|
||||||
|
Serial.print(F("CURRENT ROM SIZE: "));
|
||||||
|
Serial.print(ODY2[ody2size]);
|
||||||
|
Serial.println(F("K"));
|
||||||
|
Serial.println(F(""));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************
|
||||||
|
// CART SELECT CODE
|
||||||
|
//******************************************
|
||||||
|
|
||||||
|
FsFile ody2csvFile;
|
||||||
|
char ody2game[51]; // title
|
||||||
|
char ody2mm[3]; // mapper (A10)
|
||||||
|
char ody2rr[3]; // romsize
|
||||||
|
char ody2ll[4]; // linelength (previous line)
|
||||||
|
unsigned long ody2csvpos; // CSV File Position
|
||||||
|
char ody2cartCSV[] = "ody2cart.txt"; // CSV List
|
||||||
|
char ody2csvEND[] = "EOF"; // CSV End Marker for scrolling
|
||||||
|
|
||||||
|
bool readLine_ODY2(FsFile& f, char* line, size_t maxLen) {
|
||||||
|
for (size_t n = 0; n < maxLen; n++) {
|
||||||
|
int c = f.read();
|
||||||
|
if (c < 0 && n == 0) return false; // EOF
|
||||||
|
if (c < 0 || c == '\n') {
|
||||||
|
line[n] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
line[n] = c;
|
||||||
|
}
|
||||||
|
return false; // line too long
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readVals_ODY2(char* ody2game, char* ody2mm, char* ody2rr, char* ody2ll) {
|
||||||
|
char line[59];
|
||||||
|
ody2csvpos = ody2csvFile.position();
|
||||||
|
if (!readLine_ODY2(ody2csvFile, line, sizeof(line))) {
|
||||||
|
return false; // EOF or too long
|
||||||
|
}
|
||||||
|
char* comma = strtok(line, ",");
|
||||||
|
int x = 0;
|
||||||
|
while (comma != NULL) {
|
||||||
|
if (x == 0)
|
||||||
|
strcpy(ody2game, comma);
|
||||||
|
else if (x == 1)
|
||||||
|
strcpy(ody2mm, comma);
|
||||||
|
else if (x == 2)
|
||||||
|
strcpy(ody2rr, comma);
|
||||||
|
else if (x == 3)
|
||||||
|
strcpy(ody2ll, comma);
|
||||||
|
comma = strtok(NULL, ",");
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getCartListInfo_ODY2() {
|
||||||
|
bool buttonreleased = 0;
|
||||||
|
bool cartselected = 0;
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F(" HOLD TO FAST CYCLE"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("HOLD BUTTON TO FAST CYCLE"));
|
||||||
|
#endif
|
||||||
|
delay(2000);
|
||||||
|
#if defined(enable_OLED)
|
||||||
|
buttonVal1 = (PIND & (1 << 7)); // PD7
|
||||||
|
#elif defined(enable_LCD)
|
||||||
|
boolean buttonVal1 = (PING & (1 << 2)); //PG2
|
||||||
|
#endif
|
||||||
|
if (buttonVal1 == LOW) { // Button Held - Fast Cycle
|
||||||
|
while (1) { // Scroll Game List
|
||||||
|
while (readVals_ODY2(ody2game, ody2mm, ody2rr, ody2ll)) {
|
||||||
|
if (strcmp(ody2csvEND, ody2game) == 0) {
|
||||||
|
ody2csvFile.seek(0); // Restart
|
||||||
|
} else {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("CART TITLE:"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(ody2game);
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.print(F("CART TITLE:"));
|
||||||
|
Serial.println(ody2game);
|
||||||
|
#endif
|
||||||
|
#if defined(enable_OLED)
|
||||||
|
buttonVal1 = (PIND & (1 << 7)); // PD7
|
||||||
|
#elif defined(enable_LCD)
|
||||||
|
buttonVal1 = (PING & (1 << 2)); //PG2
|
||||||
|
#endif
|
||||||
|
if (buttonVal1 == HIGH) { // Button Released
|
||||||
|
buttonreleased = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (buttonreleased) {
|
||||||
|
buttonreleased = 0; // Reset Flag
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if defined(enable_OLED)
|
||||||
|
buttonVal1 = (PIND & (1 << 7)); // PD7
|
||||||
|
#elif defined(enable_LCD)
|
||||||
|
buttonVal1 = (PING & (1 << 2)); //PG2
|
||||||
|
#endif
|
||||||
|
if (buttonVal1 == HIGH) // Button Released
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display.setCursor(0, 56);
|
||||||
|
println_Msg(F("FAST CYCLE OFF"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F(""));
|
||||||
|
Serial.println(F("FAST CYCLE OFF"));
|
||||||
|
Serial.println(F("PRESS BUTTON TO STEP FORWARD"));
|
||||||
|
Serial.println(F("DOUBLE CLICK TO STEP BACK"));
|
||||||
|
Serial.println(F("HOLD TO SELECT"));
|
||||||
|
Serial.println(F(""));
|
||||||
|
#endif
|
||||||
|
while (readVals_ODY2(ody2game, ody2mm, ody2rr, ody2ll)) {
|
||||||
|
if (strcmp(ody2csvEND, ody2game) == 0) {
|
||||||
|
ody2csvFile.seek(0); // Restart
|
||||||
|
} else {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("CART TITLE:"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(ody2game);
|
||||||
|
display.setCursor(0, 48);
|
||||||
|
println_Msg(F("Press to Change"));
|
||||||
|
println_Msg(F("Hold to Select"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.print(F("CART TITLE:"));
|
||||||
|
Serial.println(ody2game);
|
||||||
|
#endif
|
||||||
|
while (1) { // Single Step
|
||||||
|
int b = checkButton();
|
||||||
|
if (b == 1) { // Continue (press)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (b == 2) { // Reset to Start of List (doubleclick)
|
||||||
|
byte prevline = strtol(ody2ll, NULL, 10);
|
||||||
|
ody2csvpos -= prevline;
|
||||||
|
ody2csvFile.seek(ody2csvpos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (b == 3) { // Long Press - Select Cart (hold)
|
||||||
|
newody2mapper = strtol(ody2mm, NULL, 10);
|
||||||
|
newody2size = strtol(ody2rr, NULL, 10);
|
||||||
|
EEPROM_writeAnything(7, newody2mapper);
|
||||||
|
EEPROM_writeAnything(8, newody2size);
|
||||||
|
cartselected = 1; // SELECTION MADE
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
println_Msg(F("SELECTION MADE"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("SELECTION MADE"));
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cartselected) {
|
||||||
|
cartselected = 0; // Reset Flag
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(F("END OF FILE"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("END OF FILE"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkCSV_ODY2() {
|
||||||
|
if (getCartListInfo_ODY2()) {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("CART SELECTED"));
|
||||||
|
println_Msg(F(""));
|
||||||
|
println_Msg(ody2game);
|
||||||
|
display_Update();
|
||||||
|
// Display Settings
|
||||||
|
display.setCursor(0, 56);
|
||||||
|
print_Msg(F("CODE: M"));
|
||||||
|
print_Msg(newody2mapper);
|
||||||
|
print_Msg(F("/R"));
|
||||||
|
println_Msg(newody2size);
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F(""));
|
||||||
|
Serial.println(F("CART SELECTED"));
|
||||||
|
Serial.println(ody2game);
|
||||||
|
// Display Settings
|
||||||
|
Serial.print(F("CODE: M"));
|
||||||
|
Serial.print(newody2mapper);
|
||||||
|
Serial.print(F("/R"));
|
||||||
|
Serial.println(newody2size);
|
||||||
|
Serial.println(F(""));
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display.setCursor(0, 56);
|
||||||
|
println_Msg(F("NO SELECTION"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("NO SELECTION"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCart_ODY2() {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(ody2cartCSV);
|
||||||
|
display_Update();
|
||||||
|
#endif
|
||||||
|
sd.chdir();
|
||||||
|
sprintf(folder, "ODY2/CSV");
|
||||||
|
sd.chdir(folder); // Switch Folder
|
||||||
|
ody2csvFile = sd.open(ody2cartCSV, O_READ);
|
||||||
|
if (!ody2csvFile) {
|
||||||
|
#if (defined(enable_OLED) || defined(enable_LCD))
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F("CSV FILE NOT FOUND!"));
|
||||||
|
display_Update();
|
||||||
|
#else
|
||||||
|
Serial.println(F("CSV FILE NOT FOUND!"));
|
||||||
|
#endif
|
||||||
|
while (1) {
|
||||||
|
if (checkButton() != 0)
|
||||||
|
setup_ODY2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkCSV_ODY2();
|
||||||
|
|
||||||
|
ody2csvFile.close();
|
||||||
|
}
|
||||||
|
#endif
|
49
sd/arccart.txt
Normal file
49
sd/arccart.txt
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
3D Bowling,1,0
|
||||||
|
3D Soccer,3,16
|
||||||
|
Alien Invaders,1,16
|
||||||
|
American Football,2,21
|
||||||
|
Astro Invader,3,24
|
||||||
|
Autorace,3,20
|
||||||
|
Baseball,1,15
|
||||||
|
Basketball,1,15
|
||||||
|
Blackjack and Poker,1,17
|
||||||
|
Boxing,1,26
|
||||||
|
Brain Quiz,1,13
|
||||||
|
Breakaway,1,17
|
||||||
|
Capture,0,16
|
||||||
|
Cat Trax,1,14
|
||||||
|
Circus,1,15
|
||||||
|
Combat,3,13
|
||||||
|
Crazy Climber,1,13
|
||||||
|
Crazy Gobbler,0,20
|
||||||
|
Escape,1,20
|
||||||
|
Funky Fish,3,13
|
||||||
|
Golf,3,17
|
||||||
|
Grand Slam Tennis,3,11
|
||||||
|
Hobo,3,24
|
||||||
|
Horse Racing,1,11
|
||||||
|
Jump Bug,3,19
|
||||||
|
Jungler,3,15
|
||||||
|
Missile War,1,14
|
||||||
|
Monaco Grand Prix,1,18
|
||||||
|
Nibblemen,1,24
|
||||||
|
Ocean Battle,1,16
|
||||||
|
Parashooter,1,19
|
||||||
|
Pleiades,3,18
|
||||||
|
R2D Tank,1,15
|
||||||
|
Red Clash,3,15
|
||||||
|
Robot Killer,1,16
|
||||||
|
Route 16,3,19
|
||||||
|
Soccer,3,15
|
||||||
|
Space Attack,1,13
|
||||||
|
Space Mission,1,19
|
||||||
|
Space Raiders,1,20
|
||||||
|
Space Squadron,1,20
|
||||||
|
Space Vultures,2,21
|
||||||
|
Spiders,3,21
|
||||||
|
Star Chess,1,14
|
||||||
|
Super Gobbler,1,17
|
||||||
|
Tanks a Lot,1,20
|
||||||
|
The End,1,18
|
||||||
|
Turtles,3,14
|
||||||
|
EOF,0,0
|
494
sd/ataricart.txt
Normal file
494
sd/ataricart.txt
Normal file
@ -0,0 +1,494 @@
|
|||||||
|
32 in 1,240,0
|
||||||
|
3-D Tic-Tac-Toe,32,15
|
||||||
|
Acid Drop,246,23
|
||||||
|
Action Force,64,18
|
||||||
|
Adventure,64,20
|
||||||
|
Adventures of TRON,64,17
|
||||||
|
Air Raid,64,26
|
||||||
|
Air Raiders,64,16
|
||||||
|
Airlock,64,19
|
||||||
|
Air-Sea Battle,32,15
|
||||||
|
AKA Space Adventure,64,22
|
||||||
|
Alien,64,27
|
||||||
|
Alpha Beam with Ernie,248,13
|
||||||
|
Amidar,64,30
|
||||||
|
Armor Ambush,64,14
|
||||||
|
Artillery Duel,248,20
|
||||||
|
Assault,64,23
|
||||||
|
Asterix,248,15
|
||||||
|
Asteroids,248,16
|
||||||
|
Astroblast,64,18
|
||||||
|
Atari Video Cube,64,18
|
||||||
|
Atlantis,64,24
|
||||||
|
Atlantis II,64,16
|
||||||
|
Bachelor Party,64,19
|
||||||
|
Bachelorette Party,64,22
|
||||||
|
Backgammon,64,26
|
||||||
|
Bank Heist,64,18
|
||||||
|
Barnstorming,64,18
|
||||||
|
Base Attack,64,20
|
||||||
|
Basic Math,32,19
|
||||||
|
BASIC Programming,64,18
|
||||||
|
Basketball,32,25
|
||||||
|
Battlezone,248,18
|
||||||
|
Beamrider,248,19
|
||||||
|
Beany Bopper,64,18
|
||||||
|
Beat 'Em & Eat 'Em,64,20
|
||||||
|
Berenstain Bears,248,26
|
||||||
|
Bermuda,64,25
|
||||||
|
Bermuda Triangle,64,15
|
||||||
|
Berzerk,64,24
|
||||||
|
Big Bird's Egg Catch,248,15
|
||||||
|
Blackjack,32,29
|
||||||
|
Blueprint,248,17
|
||||||
|
BMX Air Master,246,18
|
||||||
|
Bobby Is Going Home,64,23
|
||||||
|
Boing!,64,27
|
||||||
|
Bowling,32,14
|
||||||
|
Boxing,32,15
|
||||||
|
Brain Games,32,14
|
||||||
|
Breakout,32,19
|
||||||
|
Bridge,64,16
|
||||||
|
Buck Rogers - Planet of Zoom,248,14
|
||||||
|
Bugs,64,37
|
||||||
|
Bump 'n' Jump,231,12
|
||||||
|
Bumper Bash,64,22
|
||||||
|
BurgerTime,231,19
|
||||||
|
Burning Desire,64,19
|
||||||
|
Cakewalk,64,22
|
||||||
|
California Games,246,16
|
||||||
|
Canyon Bomber,32,25
|
||||||
|
Carnival,64,21
|
||||||
|
Casino,64,16
|
||||||
|
Cat Trax,64,14
|
||||||
|
Cathouse Blues,64,16
|
||||||
|
Centipede,248,22
|
||||||
|
Challenge,248,18
|
||||||
|
Challenge of.... Nexar,64,18
|
||||||
|
Chase the Chuckwagon,64,30
|
||||||
|
Checkers,32,28
|
||||||
|
China Syndrome,64,16
|
||||||
|
Chopper Command,64,22
|
||||||
|
Chuck Norris Superkicks,248,23
|
||||||
|
Circus Atari,64,32
|
||||||
|
Coco Nuts,64,20
|
||||||
|
Codebreaker,32,17
|
||||||
|
Combat,32,19
|
||||||
|
Commando,246,14
|
||||||
|
Commando Raid,64,17
|
||||||
|
Condor Attack,64,21
|
||||||
|
Confrontation,64,21
|
||||||
|
Congo Bongo,248,21
|
||||||
|
Cookie Monster Munch,248,20
|
||||||
|
Cosmic Ark,64,29
|
||||||
|
Cosmic Commuter,64,18
|
||||||
|
Cosmic Corridor,64,23
|
||||||
|
Cosmic Creeps,64,23
|
||||||
|
Cosmic Swarm,32,21
|
||||||
|
Crackpots,64,20
|
||||||
|
Crash Dive,64,17
|
||||||
|
Crazy Climber,248,18
|
||||||
|
Cross Force,64,22
|
||||||
|
Crossbow,246,19
|
||||||
|
Crypts of Chaos,64,17
|
||||||
|
Crystal Castles,246,23
|
||||||
|
Cubicolor,64,24
|
||||||
|
Cubo Magico,64,17
|
||||||
|
Custer's Revenge,64,19
|
||||||
|
Dancing Plate,64,24
|
||||||
|
Dark Cavern,64,21
|
||||||
|
Dark Chambers,246,19
|
||||||
|
Dark Mage,248,22
|
||||||
|
Deadly Duck,64,18
|
||||||
|
Death Trap,64,19
|
||||||
|
Decathlon,254,18
|
||||||
|
Defender,64,18
|
||||||
|
Defender II,248,16
|
||||||
|
Demolition Herby,64,20
|
||||||
|
Demon Attack,64,24
|
||||||
|
Demons to Diamonds,64,20
|
||||||
|
Desert Falcon,246,26
|
||||||
|
Dice Puzzle,64,22
|
||||||
|
Dig Dug,246,19
|
||||||
|
Dishaster,64,16
|
||||||
|
Dodge 'Em,64,17
|
||||||
|
Dolphin,64,17
|
||||||
|
Donald Duck's Speedboat,248,15
|
||||||
|
Donkey Kong,64,32
|
||||||
|
Donkey Kong Jr,248,19
|
||||||
|
Double Dragon,246,23
|
||||||
|
Double Dunk,246,22
|
||||||
|
Dragon Defender,64,20
|
||||||
|
Dragonfire,64,23
|
||||||
|
Dragster,32,18
|
||||||
|
Dukes of Hazzard,246,16
|
||||||
|
E.T.,248,25
|
||||||
|
Earth Dies Screaming,64,13
|
||||||
|
Eggomania,64,28
|
||||||
|
Elevator Action,248,17
|
||||||
|
Eli's Ladder,64,24
|
||||||
|
Encounter at L-5,64,20
|
||||||
|
Enduro,64,24
|
||||||
|
Entombed,64,14
|
||||||
|
Espial,63,16
|
||||||
|
Exocet,64,14
|
||||||
|
Extra Terrestrials,64,14
|
||||||
|
Fantastic Voyage,64,26
|
||||||
|
Farmyard Fun,64,24
|
||||||
|
Fast Eddie,64,20
|
||||||
|
Fast Food,64,18
|
||||||
|
Fatal Run,244,17
|
||||||
|
Fathom,248,18
|
||||||
|
Fighter Pilot,246,15
|
||||||
|
Final Approach,64,22
|
||||||
|
Fire Fighter,64,22
|
||||||
|
Fire Fly,64,20
|
||||||
|
Fishing Derby,32,16
|
||||||
|
Flag Capture,32,21
|
||||||
|
Flash Gordon,64,20
|
||||||
|
Football,32,20
|
||||||
|
Forest,64,16
|
||||||
|
Frankenstein's Monster,64,14
|
||||||
|
Freeway,32,30
|
||||||
|
Frisco,64,15
|
||||||
|
Frog Pond,248,14
|
||||||
|
Frogger,64,18
|
||||||
|
Frogger II,224,15
|
||||||
|
Frogs and Flies,64,19
|
||||||
|
Front Line,248,23
|
||||||
|
Frostbite,64,19
|
||||||
|
G.I. Joe,64,17
|
||||||
|
Galaxian,248,16
|
||||||
|
Gamma Attack,32,17
|
||||||
|
Gangster Alley,64,20
|
||||||
|
Gas Hog,64,22
|
||||||
|
Gauntlet,64,15
|
||||||
|
Ghost Manor,248,16
|
||||||
|
Ghostbusters,248,20
|
||||||
|
Ghostbusters II,246,21
|
||||||
|
Gigolo,64,24
|
||||||
|
Glacier Patrol,64,14
|
||||||
|
Glib,64,22
|
||||||
|
Golf,32,12
|
||||||
|
Gopher,64,12
|
||||||
|
Gorf,64,14
|
||||||
|
Grand Prix,246,12
|
||||||
|
Gravitar,248,19
|
||||||
|
Great Escape,64,17
|
||||||
|
Gremlins,248,20
|
||||||
|
Guardian,64,17
|
||||||
|
Gyruss,224,16
|
||||||
|
H.E.R.O.,248,15
|
||||||
|
Halloween,64,17
|
||||||
|
Hangman,64,17
|
||||||
|
Harbor Escape,64,15
|
||||||
|
Haunted House,64,21
|
||||||
|
Hole Hunter,64,21
|
||||||
|
Home Run,32,19
|
||||||
|
Human Cannonball,32,16
|
||||||
|
Hunt & Score,32,24
|
||||||
|
I Want My Mommy,64,20
|
||||||
|
Ice Hockey,64,23
|
||||||
|
Ikari Warriors,246,18
|
||||||
|
Indy 500,32,23
|
||||||
|
Infiltrate,64,16
|
||||||
|
International Soccer,64,18
|
||||||
|
IQ 180,64,28
|
||||||
|
James Bond 007,224,14
|
||||||
|
Jaw Breaker,64,23
|
||||||
|
Journey Escape,64,19
|
||||||
|
Joust,248,22
|
||||||
|
JoustPong,64,14
|
||||||
|
Jr. Pac-Man,246,17
|
||||||
|
Jungle Fever,64,20
|
||||||
|
Jungle Hunt,248,20
|
||||||
|
Kaboom!,32,20
|
||||||
|
Kangaroo,248,15
|
||||||
|
Karate,64,17
|
||||||
|
Keystone Kapers,64,14
|
||||||
|
King Kong,64,23
|
||||||
|
Klax,246,17
|
||||||
|
Knight on the Town,64,13
|
||||||
|
Kool-Aid Man,64,26
|
||||||
|
Krull,248,20
|
||||||
|
Kung Fu Superkicks,248,14
|
||||||
|
Kung-Fu Master,248,27
|
||||||
|
Lady in Wading,64,23
|
||||||
|
Laser Blast,32,22
|
||||||
|
Laser Gates,64,19
|
||||||
|
Lilly Advenure,64,19
|
||||||
|
Lochjaw,64,22
|
||||||
|
Lock 'n' Chase,64,15
|
||||||
|
London Blitz,64,22
|
||||||
|
Lost Luggage,64,20
|
||||||
|
M.A.D.,64,20
|
||||||
|
M.A.S.H,64,14
|
||||||
|
MagiCard,192,15
|
||||||
|
Malagai,64,17
|
||||||
|
Mangia',64,15
|
||||||
|
Marauder,64,15
|
||||||
|
Marine Wars,64,16
|
||||||
|
Mario Bros.,248,19
|
||||||
|
Master Builder,64,20
|
||||||
|
Masters of the Universe,231,22
|
||||||
|
Math Gran Prix,64,32
|
||||||
|
Maze Craze,64,22
|
||||||
|
Mega Force,64,18
|
||||||
|
MegaBoy,240,18
|
||||||
|
MegaMania,64,16
|
||||||
|
Midnight Magic,246,17
|
||||||
|
Millipede,246,23
|
||||||
|
Mind Maze,248,18
|
||||||
|
Miner 2049er,63,18
|
||||||
|
Miner 2049er Volume II,63,20
|
||||||
|
Mines of Minos,64,30
|
||||||
|
Miniature Golf,32,22
|
||||||
|
Miss Piggy's Wedding,248,22
|
||||||
|
Missile Command,64,29
|
||||||
|
Missile Control,64,23
|
||||||
|
Mission 3000 A.D.,64,23
|
||||||
|
Mission Survive,64,25
|
||||||
|
Mogul Maniac,64,23
|
||||||
|
Montezuma's Revenge,224,20
|
||||||
|
Moon Patrol,248,28
|
||||||
|
Moonsweeper,248,20
|
||||||
|
Motocross,64,20
|
||||||
|
Motocross Racer,248,17
|
||||||
|
MotoRodeo,246,24
|
||||||
|
Mountain King,250,18
|
||||||
|
Mouse Trap,64,22
|
||||||
|
Mr. Do!,248,18
|
||||||
|
Mr. Do!'s Castle,224,16
|
||||||
|
Mr. Postman,64,25
|
||||||
|
Ms. Pac-Man,248,19
|
||||||
|
Music Machine,64,20
|
||||||
|
My Golf,248,21
|
||||||
|
Name This Game,64,16
|
||||||
|
Night Driver,32,22
|
||||||
|
Night Stalker,64,20
|
||||||
|
Nightmare,64,21
|
||||||
|
No Escape!,64,17
|
||||||
|
Nuts,64,18
|
||||||
|
Obelix,248,12
|
||||||
|
Off the Wall,246,15
|
||||||
|
Oink!,64,21
|
||||||
|
Omega Race,250,13
|
||||||
|
Open Sesame,64,19
|
||||||
|
Oscar's Trash Race,248,19
|
||||||
|
Othello,32,27
|
||||||
|
Out of Control,64,15
|
||||||
|
Outlaw,32,22
|
||||||
|
Pac-Kong,64,14
|
||||||
|
Pac-Man,64,16
|
||||||
|
Panda Chase,64,15
|
||||||
|
Parachute,64,19
|
||||||
|
Pele's Soccer,64,17
|
||||||
|
Pengo,248,21
|
||||||
|
Pepsi Invaders,64,14
|
||||||
|
Pete Rose Baseball,246,22
|
||||||
|
Phantom Tank,64,27
|
||||||
|
Pharaoh's Curse,64,20
|
||||||
|
Philly Flasher,64,23
|
||||||
|
Phoenix,248,22
|
||||||
|
Pick 'n' Pile,246,16
|
||||||
|
Picnic,64,22
|
||||||
|
Piece o' Cake,64,14
|
||||||
|
Pigs in Space,248,21
|
||||||
|
Pitfall II,208,22
|
||||||
|
Pitfall!,64,19
|
||||||
|
Planet Patrol,64,16
|
||||||
|
Plaque Attack,64,21
|
||||||
|
Polaris,63,21
|
||||||
|
Pole Position,248,15
|
||||||
|
Polo,32,22
|
||||||
|
Pompeii,64,12
|
||||||
|
Pooyan,64,15
|
||||||
|
Popeye,224,14
|
||||||
|
Porky's,248,15
|
||||||
|
Pressure Cooker,248,16
|
||||||
|
Private Eye,248,24
|
||||||
|
Pyramid War,64,20
|
||||||
|
Q-bert,64,19
|
||||||
|
Q-bert's Qubes,224,14
|
||||||
|
Quadrun,248,23
|
||||||
|
Quest for Quintana Roo,248,16
|
||||||
|
Quick Step!,64,31
|
||||||
|
Rabbit Transit,248,19
|
||||||
|
Racing Car,64,23
|
||||||
|
Racquetball,64,18
|
||||||
|
Radar Lock,246,19
|
||||||
|
Raft Rider,64,19
|
||||||
|
Raiders of the Lost Ark,248,18
|
||||||
|
Ram It,64,32
|
||||||
|
Rampage!,246,14
|
||||||
|
Raumpatrouille,64,17
|
||||||
|
Reactor,64,22
|
||||||
|
RealSports Baseball,248,15
|
||||||
|
RealSports Boxing,246,28
|
||||||
|
RealSports Football,248,26
|
||||||
|
RealSports Soccer,248,28
|
||||||
|
RealSports Tennis,248,26
|
||||||
|
RealSports Volleyball,64,26
|
||||||
|
Rescue Terra I,64,29
|
||||||
|
Resgate Espacial,248,22
|
||||||
|
Revenge of the Beefsteak Tomatoes,64,25
|
||||||
|
Riddle of the Sphinx,64,41
|
||||||
|
River Patrol,63,28
|
||||||
|
River Raid,64,20
|
||||||
|
River Raid II,246,18
|
||||||
|
Road Runner,246,22
|
||||||
|
Robin Hood,248,20
|
||||||
|
Robot Tank,254,19
|
||||||
|
Roc 'n Rope,248,19
|
||||||
|
Room of Doom,64,20
|
||||||
|
Rubik's Cube,64,20
|
||||||
|
Save Our Ship,64,20
|
||||||
|
Scuba Diver,64,21
|
||||||
|
Sea Hawk,64,19
|
||||||
|
Sea Hunt,64,16
|
||||||
|
Sea Monster,64,16
|
||||||
|
Seaquest,64,19
|
||||||
|
Secret Quest,246,16
|
||||||
|
Sentinel,246,21
|
||||||
|
Shark Attack,64,17
|
||||||
|
Shootin' Gallery,64,20
|
||||||
|
Shuttle Orbiter,64,24
|
||||||
|
Sir Lancelot,248,23
|
||||||
|
Skate Boardin',248,21
|
||||||
|
Skeet Shoot,32,23
|
||||||
|
Ski Hunt,64,19
|
||||||
|
Ski Run,64,16
|
||||||
|
Skiing,32,15
|
||||||
|
Sky Diver,32,14
|
||||||
|
Sky Jinks,32,17
|
||||||
|
Sky Skipper,64,17
|
||||||
|
Slot Machine,32,19
|
||||||
|
Slot Racers,32,20
|
||||||
|
Smurf - Rescue in Gargamel's Castle,248,19
|
||||||
|
Smurfs Save the Day,248,44
|
||||||
|
Sneak 'n Peek,64,28
|
||||||
|
Snoopy and the Red Baron,248,21
|
||||||
|
Solar Fox,248,33
|
||||||
|
Solar Storm,64,18
|
||||||
|
Solaris,246,19
|
||||||
|
Sorcerer,64,16
|
||||||
|
Sorcerer's Apprentice,248,16
|
||||||
|
Space Attack,64,30
|
||||||
|
Space Canyon,64,20
|
||||||
|
Space Cavern,64,20
|
||||||
|
Space Invaders,64,20
|
||||||
|
Space Jockey,32,22
|
||||||
|
Space Shuttle,248,20
|
||||||
|
Space Tunnel,64,22
|
||||||
|
Space War,32,20
|
||||||
|
Spacechase,64,17
|
||||||
|
SpaceMaster X-7,64,18
|
||||||
|
Spider Fighter,64,23
|
||||||
|
Spider Maze,64,22
|
||||||
|
Spider-Man,64,19
|
||||||
|
Spike's Peak,248,18
|
||||||
|
Spitfire Attack,64,21
|
||||||
|
Springer,63,23
|
||||||
|
Sprint Master,246,16
|
||||||
|
Spy Hunter,248,22
|
||||||
|
Squeeze Box,64,19
|
||||||
|
Squirrel,64,19
|
||||||
|
Sssnake,64,16
|
||||||
|
Stampede,32,15
|
||||||
|
Star Fox,64,16
|
||||||
|
Star Raiders,248,16
|
||||||
|
Star Ship,32,21
|
||||||
|
Star Strike,64,17
|
||||||
|
Star Trek,248,19
|
||||||
|
Star Voyager,64,18
|
||||||
|
Star Wars - Arcade Game,224,20
|
||||||
|
Star Wars - Death Star Battle,224,32
|
||||||
|
Star Wars - Empire Strikes Back,64,38
|
||||||
|
Star Wars - Jedi Arena,64,39
|
||||||
|
Stargate,246,30
|
||||||
|
Stargunner,64,17
|
||||||
|
StarMaster,64,18
|
||||||
|
Steeplechase,32,18
|
||||||
|
Stellar Track,64,20
|
||||||
|
Strategy X,64,21
|
||||||
|
Strawberry Shortcake,64,18
|
||||||
|
Street Racer,32,28
|
||||||
|
Stronghold,64,20
|
||||||
|
Stunt Man,64,18
|
||||||
|
Submarine Commander,64,17
|
||||||
|
Sub-Scan,64,27
|
||||||
|
Subterranea,248,16
|
||||||
|
Summer Games,246,20
|
||||||
|
Super Baseball,246,21
|
||||||
|
Super Breakout,64,23
|
||||||
|
Super Challenge Baseball,64,22
|
||||||
|
Super Challenge Football,64,32
|
||||||
|
Super Cobra,224,32
|
||||||
|
Super Football,248,20
|
||||||
|
Superman,64,23
|
||||||
|
Surfer's Paradise,64,16
|
||||||
|
Surround,32,25
|
||||||
|
Survival Run,64,16
|
||||||
|
SwordQuest - EarthWorld,248,20
|
||||||
|
SwordQuest - FireWorld,248,32
|
||||||
|
SwordQuest - WaterWorld,248,31
|
||||||
|
Tac-Scan,64,32
|
||||||
|
Tanks But No Tanks,64,16
|
||||||
|
Tapeworm,64,26
|
||||||
|
Tapper,248,16
|
||||||
|
Tax Avoiders,248,15
|
||||||
|
Taz,248,21
|
||||||
|
Tempest,248,12
|
||||||
|
Tennis,32,16
|
||||||
|
Texas Chainsaw Massacre,64,14
|
||||||
|
Threshold,64,31
|
||||||
|
Thunderground,64,17
|
||||||
|
Time Pilot,248,21
|
||||||
|
Time Warp,64,19
|
||||||
|
Title Match Pro Wrestling,248,17
|
||||||
|
Tomarc the Barbarian,248,34
|
||||||
|
Tomcat,246,29
|
||||||
|
Tooth Protectors,224,15
|
||||||
|
Towering Inferno,64,25
|
||||||
|
Track and Field,246,24
|
||||||
|
Treasure Below,64,24
|
||||||
|
Treasure Island,64,22
|
||||||
|
Trick Shot,64,23
|
||||||
|
TRON - Deadly Discs,64,18
|
||||||
|
Tunnel Runner,250,27
|
||||||
|
Turmoil,64,22
|
||||||
|
Tutankham,224,15
|
||||||
|
Universal Chaos,64,18
|
||||||
|
Up 'n Down,248,23
|
||||||
|
Vanguard,248,19
|
||||||
|
Venture,64,17
|
||||||
|
Video Checkers,64,15
|
||||||
|
Video Chess,64,22
|
||||||
|
Video Jogger,64,19
|
||||||
|
Video Life,32,20
|
||||||
|
Video Olympics,32,18
|
||||||
|
Video Pinball,64,22
|
||||||
|
Video Reflex,64,21
|
||||||
|
Vogel Flieh,64,20
|
||||||
|
Vulture Attack,64,19
|
||||||
|
Wabbit,64,22
|
||||||
|
Walker,64,14
|
||||||
|
Wall Ball,64,14
|
||||||
|
Wall Break,64,17
|
||||||
|
Wall-Defender,64,18
|
||||||
|
Warlords,64,21
|
||||||
|
Warplock,64,16
|
||||||
|
Wing War,248,16
|
||||||
|
Wings,250,17
|
||||||
|
Winter Games,246,14
|
||||||
|
Wizard of Wor,64,21
|
||||||
|
Word Zapper,64,21
|
||||||
|
World End,64,19
|
||||||
|
Worm War I,64,17
|
||||||
|
Xenophobe,246,18
|
||||||
|
X-Man,64,18
|
||||||
|
Yars' Revenge,64,13
|
||||||
|
Zaxxon,248,21
|
||||||
|
Zoo Fun,64,15
|
||||||
|
Z-Tack,64,15
|
||||||
|
EOF,0,0
|
33
sd/fairchildcart.txt
Normal file
33
sd/fairchildcart.txt
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
Alien Invasion,2,0
|
||||||
|
Backgammon/Acey-Deucey,0,20
|
||||||
|
Baseball,0,29
|
||||||
|
Bowling,0,15
|
||||||
|
Casino Poker,2,14
|
||||||
|
Checkers,0,19
|
||||||
|
Demonstration Cartridge,0,15
|
||||||
|
Demonstration Cartridge 2,0,30
|
||||||
|
Desert Fox/Shooting Gallery,0,32
|
||||||
|
Dodge It,0,34
|
||||||
|
Drag Race,0,15
|
||||||
|
Galactic Space Wars/Lunar Lander,0,16
|
||||||
|
Hangman,1,39
|
||||||
|
Magic Numbers,0,14
|
||||||
|
Math Quiz I,0,20
|
||||||
|
Math Quiz II,0,18
|
||||||
|
Maze (Multi),0,19
|
||||||
|
Memory Match 1 & 2,0,19
|
||||||
|
Muehle (Multi),0,25
|
||||||
|
Ordtaevling,1,21
|
||||||
|
Pinball Challenge,0,18
|
||||||
|
Pro Football,2,24
|
||||||
|
Rat' Mal,1,19
|
||||||
|
Robot War/Torpedo Alley,0,15
|
||||||
|
Schach,3,30
|
||||||
|
Slot Machine,0,13
|
||||||
|
Sonar Search,0,19
|
||||||
|
Space War,0,19
|
||||||
|
Spitfire,0,16
|
||||||
|
Tic-Tac-Toe (Multi),0,15
|
||||||
|
Video Blackjack,0,26
|
||||||
|
Video Whizball,1,22
|
||||||
|
EOF,0,0
|
134
sd/ody2cart.txt
Normal file
134
sd/ody2cart.txt
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
4 en 1 Ligne,1,1,0
|
||||||
|
4 in 1 Row,1,1,20
|
||||||
|
Air Battle (V+),0,3,19
|
||||||
|
Alien Invaders - Plus,0,0,24
|
||||||
|
Alpine Skiing,0,0,30
|
||||||
|
Armored Encounter + Sub Chase,0,0,22
|
||||||
|
Atlantis,0,1,38
|
||||||
|
Attack of the Timelord,0,1,17
|
||||||
|
Baseball,0,0,31
|
||||||
|
Billard Americain,0,0,17
|
||||||
|
Billard Americain (V+),0,2,26
|
||||||
|
Billard Electrique,0,0,31
|
||||||
|
Billard Electrique (V+),0,2,27
|
||||||
|
Blackjack,0,0,32
|
||||||
|
Blobbers,0,2,18
|
||||||
|
Blockout + Breakdown,0,0,17
|
||||||
|
Bombardeio Submarino + Tiro ao Alvo,0,0,29
|
||||||
|
Bowling + Basketball,0,0,44
|
||||||
|
Buraco Negro,0,2,29
|
||||||
|
Casino Slot Machine,0,0,21
|
||||||
|
Catch the Ball + Noughts and Crosses,0,0,28
|
||||||
|
Chat et Souris,0,1,45
|
||||||
|
Chess,0,0,23
|
||||||
|
Chez Maxime (V+),0,1,14
|
||||||
|
Chinese Logic,0,0,25
|
||||||
|
Clay Pigeon,0,1,22
|
||||||
|
Comando Noturno,0,2,20
|
||||||
|
Computer Golf,0,0,24
|
||||||
|
Computer Intro,0,0,22
|
||||||
|
Computer Programmer,0,0,23
|
||||||
|
Conflit Cosmique,0,0,28
|
||||||
|
Conquest of the World,0,1,25
|
||||||
|
Cosmic Conflict,0,0,30
|
||||||
|
Cosmic Conflict (V+),0,2,24
|
||||||
|
Course de Voitures + Autodrome + Cryptogramme,0,0,29
|
||||||
|
Course de Voitures + Autodrome + Cryptogramme (V+),0,2,54
|
||||||
|
Demon Attack,0,1,59
|
||||||
|
Demon Attack (V+),0,2,21
|
||||||
|
Depth Charge + Marksman,0,0,26
|
||||||
|
Desafio Chines,0,0,32
|
||||||
|
Dynasty,0,0,23
|
||||||
|
Electronic Table Soccer,0,0,16
|
||||||
|
Exojet (V+),0,2,32
|
||||||
|
Football,0,0,20
|
||||||
|
Football Electronique + Hockey Electronique,0,0,17
|
||||||
|
Freedom Fighters,0,1,52
|
||||||
|
Freedom Fighters (V+),0,2,25
|
||||||
|
Frogger,0,2,30
|
||||||
|
Golf,0,0,16
|
||||||
|
Great Wall Street Fortune Hunt,0,1,13
|
||||||
|
Guerre de l'Espace (V+),0,2,39
|
||||||
|
Guerre Laser,0,0,32
|
||||||
|
Gunfighter,0,0,21
|
||||||
|
Helicopter Rescue (V+),0,4,19
|
||||||
|
Hockey + Soccer,0,0,31
|
||||||
|
I've Got Your Number,0,0,24
|
||||||
|
Invaders from Hyperspace,0,0,29
|
||||||
|
Jeu de Quilles + Basketball,0,0,33
|
||||||
|
Jeu de Quilles + Basketball (V+),0,2,36
|
||||||
|
Jumping Acrobats,0,0,41
|
||||||
|
K.C. Munchkin,0,1,25
|
||||||
|
K.C.'s Krazy Chase,0,1,22
|
||||||
|
Keyboard Creations,0,0,27
|
||||||
|
Killer Bees,0,2,27
|
||||||
|
Killer Bees (V+),0,2,20
|
||||||
|
Kinder im Verkehr 1,0,0,25
|
||||||
|
La Quete des Anneaux,0,1,28
|
||||||
|
La Ruche Infernale (V+),0,2,29
|
||||||
|
Labyrinth Game + Supermind,0,0,32
|
||||||
|
Las Vegas,0,0,35
|
||||||
|
Las Vegas Blackjack,0,0,18
|
||||||
|
Laser War,0,0,28
|
||||||
|
Le Mur Magique,0,0,18
|
||||||
|
Le Tresor Englouti (V+),0,2,23
|
||||||
|
Loony Balloon (V+),0,2,32
|
||||||
|
Matchmaker + Logix + Buzzword,0,0,27
|
||||||
|
Math-A-Magic + Echo,0,0,38
|
||||||
|
Mathematicien + Echo,0,0,28
|
||||||
|
Monkeyshines,0,1,29
|
||||||
|
Morse,0,0,21
|
||||||
|
Moto-Crash (V+),0,2,14
|
||||||
|
Mousing Cat,0,1,24
|
||||||
|
Munchkin,0,1,20
|
||||||
|
Musician,1,1,17
|
||||||
|
Neutron Star (V+),0,3,17
|
||||||
|
Newscaster,0,0,26
|
||||||
|
Nightmare,0,2,19
|
||||||
|
Nightmare (V+),0,2,18
|
||||||
|
Nimble Numbers Ned,0,1,23
|
||||||
|
Norseman (V+),0,2,27
|
||||||
|
O Malabarista + Jogo da Velha,0,0,22
|
||||||
|
O Segredo do Farao,0,1,38
|
||||||
|
Out of this World + Helicopter Rescue,0,0,27
|
||||||
|
P.T. Barnum's Acrobats,0,1,46
|
||||||
|
Pachinko,0,0,31
|
||||||
|
Pairs + Space Rendezvous + Logic,0,0,17
|
||||||
|
Pick Axe Pete,0,1,41
|
||||||
|
Pickaxe Pete (V+),0,2,22
|
||||||
|
Pocket Billiards,0,0,26
|
||||||
|
Popeye,0,2,25
|
||||||
|
Power Lords,0,1,15
|
||||||
|
Power Lords (Alt),0,2,20
|
||||||
|
Prendre l'Argent et Fuir,0,0,26
|
||||||
|
Q-Bert,0,2,33
|
||||||
|
Quest for the Rings,0,1,15
|
||||||
|
Race + Spin-out + Cryptogram (V+),0,2,28
|
||||||
|
Samurai,0,0,42
|
||||||
|
Satellite Attack,0,0,16
|
||||||
|
Satellite Attack (V+),0,2,25
|
||||||
|
Secret of the Pharaohs,0,0,30
|
||||||
|
Showdown in 2100 A.D.,0,0,31
|
||||||
|
Sid the Spellbinder,0,1,30
|
||||||
|
Skiing,0,0,28
|
||||||
|
Smithereens,0,1,15
|
||||||
|
Speedway + Spin-out + Crypto-logic,0,0,20
|
||||||
|
Stone Sling,0,0,43
|
||||||
|
Stone Sling (V+),0,2,20
|
||||||
|
Super Bee,0,1,25
|
||||||
|
Super Cobra,0,2,18
|
||||||
|
Syracuse (V+),0,1,20
|
||||||
|
Take the Money and Run,0,0,22
|
||||||
|
Terrahawks (V+),0,2,31
|
||||||
|
Thunderball,0,0,24
|
||||||
|
Trans American Rally (V+),0,4,20
|
||||||
|
Turtles,0,2,34
|
||||||
|
Type & Tell,0,1,16
|
||||||
|
UFO,0,0,20
|
||||||
|
Verkehrsspiele 1,0,0,12
|
||||||
|
Verkehrsspiele 2,0,0,25
|
||||||
|
Volleyball,0,0,25
|
||||||
|
Volleyball Electronique,0,0,19
|
||||||
|
Wall Street,0,1,32
|
||||||
|
War of Nerves,0,0,20
|
||||||
|
EOF,0,0,22
|
Loading…
Reference in New Issue
Block a user