mirror of
https://github.com/sanni/cartreader.git
synced 2024-12-28 05:51:52 +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
|
||||
an easy to build and easy to modify cartridge dumper.
|
||||
|
||||
Date: 20.12.2022
|
||||
Version: 11.5
|
||||
Date: 03.01.2023
|
||||
Version: 12.0
|
||||
|
||||
SD lib: https://github.com/greiman/SdFat
|
||||
LCD lib: https://github.com/olikraus/u8g2
|
||||
@ -21,7 +21,7 @@
|
||||
MichlK - ROM Reader for Super Nintendo
|
||||
Jeff Saltzman - 4-Way Button
|
||||
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
|
||||
splash5 - GBSmart, Wonderswan and NGP modules
|
||||
hkz & themanbehindthecurtain - N64 flashram commands
|
||||
@ -38,7 +38,7 @@
|
||||
jiyunomegami, splash5, Kreeblah, ramapcsx2, PsyK0p4T, Dakkaron, majorpbx, Pickle, sdhizumi,
|
||||
Uzlopak, sakman55, Tombo89, scrap-a, borti4938, vogelfreiheit, CaitSith2, Modman,
|
||||
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.
|
||||
|
||||
@ -57,7 +57,7 @@
|
||||
|
||||
**********************************************************************************/
|
||||
|
||||
char ver[5] = "11.5";
|
||||
char ver[5] = "12.0";
|
||||
|
||||
//******************************************
|
||||
// !!! CHOOSE HARDWARE VERSION !!!
|
||||
@ -79,10 +79,24 @@ char ver[5] = "11.5";
|
||||
//******************************************
|
||||
// add/remove // before #define to disable/enable modules you
|
||||
// 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
|
||||
#define enable_COLV
|
||||
|
||||
// Emerson Arcadia 2001
|
||||
//#define enable_ARC
|
||||
|
||||
// Fairchild Channel F
|
||||
//#define enable_FAIRCHILD
|
||||
|
||||
// Flashrom Programmer for SNES repros
|
||||
#define enable_FLASH
|
||||
//#define enable_FLASH16
|
||||
@ -93,8 +107,8 @@ char ver[5] = "11.5";
|
||||
// Intellivision
|
||||
#define enable_INTV
|
||||
|
||||
// Sega Mega Drive/Genesis
|
||||
#define enable_MD
|
||||
// Neo Geo Pocket
|
||||
#define enable_NGP
|
||||
|
||||
// Nintendo 64
|
||||
#define enable_N64
|
||||
@ -102,20 +116,17 @@ char ver[5] = "11.5";
|
||||
// Nintendo Entertainment System/Family Computer
|
||||
#define enable_NES
|
||||
|
||||
// Neo Geo Pocket
|
||||
#define enable_NGP
|
||||
// Magnavox Odyssey 2
|
||||
//#define enable_ODY2
|
||||
|
||||
// PC Engine/TurboGrafx 16
|
||||
#define enable_PCE
|
||||
|
||||
// Benesse Pocket Challenge W
|
||||
#define enable_PCW
|
||||
|
||||
// Sega Master System
|
||||
#define enable_SMS
|
||||
|
||||
// Super Nintendo
|
||||
#define enable_SNES
|
||||
// Sega Mega Drive/Genesis
|
||||
#define enable_MD
|
||||
|
||||
// Super Famicom SF Memory Cassette
|
||||
#define enable_SFM
|
||||
@ -123,15 +134,18 @@ char ver[5] = "11.5";
|
||||
// Super Famicom Satellaview
|
||||
#define enable_SV
|
||||
|
||||
// Super Nintendo
|
||||
#define enable_SNES
|
||||
|
||||
// Virtual Boy
|
||||
#define enable_VBOY
|
||||
|
||||
// Watara Supervision
|
||||
//#define enable_WSV
|
||||
|
||||
// WonderSwan
|
||||
#define enable_WS
|
||||
|
||||
// Watara Supervision
|
||||
#define enable_WSV
|
||||
|
||||
//******************************************
|
||||
// HW CONFIGS
|
||||
//******************************************
|
||||
@ -390,6 +404,10 @@ void print_STR(byte string_number, boolean newline) {
|
||||
#define mode_VBOY 25
|
||||
#define mode_WSV 26
|
||||
#define mode_PCW 27
|
||||
#define mode_ATARI 28
|
||||
#define mode_ODY2 29
|
||||
#define mode_ARC 30
|
||||
#define mode_FAIRCHILD 31
|
||||
|
||||
// optimization-safe nop delay
|
||||
#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
|
||||
//******************************************
|
||||
@ -932,18 +996,22 @@ static const char modeItem11[] PROGMEM = "Colecovision";
|
||||
static const char modeItem12[] PROGMEM = "Virtual Boy";
|
||||
static const char modeItem13[] PROGMEM = "Watara Supervision";
|
||||
static const char modeItem14[] PROGMEM = "Pocket Challenge W";
|
||||
static const char modeItem15[] PROGMEM = "Flashrom Programmer";
|
||||
static const char modeItem16[] PROGMEM = "About";
|
||||
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 modeItem15[] PROGMEM = "Atari 2600";
|
||||
static const char modeItem16[] PROGMEM = "Magnavox Odyssey 2";
|
||||
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
|
||||
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;
|
||||
byte num_answers;
|
||||
byte option_offset;
|
||||
|
||||
// Main menu spans across two pages
|
||||
// Main menu spans across three pages
|
||||
currPage = 1;
|
||||
lastPage = 1;
|
||||
numPages = 3;
|
||||
@ -957,7 +1025,7 @@ void mainMenu() {
|
||||
num_answers = 7;
|
||||
} else { // currPage == 3
|
||||
option_offset = 14;
|
||||
num_answers = 2;
|
||||
num_answers = 6;
|
||||
}
|
||||
// Copy menuOptions out of progmem
|
||||
convertPgm(modeOptions + option_offset, num_answers);
|
||||
@ -1077,8 +1145,36 @@ void mainMenu() {
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef enable_FLASH
|
||||
#ifdef enable_ATARI
|
||||
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
|
||||
flashMenu();
|
||||
#else
|
||||
@ -1087,7 +1183,7 @@ void mainMenu() {
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 15:
|
||||
case 19:
|
||||
aboutScreen();
|
||||
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 };
|
||||
|
||||
// Add-ons submenu
|
||||
static const char addonsItem1[] PROGMEM = "Consoles";
|
||||
static const char addonsItem2[] PROGMEM = "Handhelds";
|
||||
static const char addonsItem3[] PROGMEM = "Flashrom Programmer";
|
||||
//static const char addonsItem4[] PROGMEM = "Reset"; (stored in common strings array)
|
||||
static const char* const addonsOptions[] PROGMEM = { addonsItem1, addonsItem2, addonsItem3, string_reset2 };
|
||||
static const char addonsItem1[] PROGMEM = "70s Consoles";
|
||||
static const char addonsItem2[] PROGMEM = "80s Consoles";
|
||||
static const char addonsItem3[] PROGMEM = "Handhelds";
|
||||
static const char addonsItem4[] PROGMEM = "Flashrom Programmer";
|
||||
//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
|
||||
static const char consolesItem1[] PROGMEM = "NES/Famicom";
|
||||
static const char consolesItem2[] PROGMEM = "PC Engine/TG16";
|
||||
static const char consolesItem3[] PROGMEM = "SMS/GG/MIII/SG-1000";
|
||||
static const char consolesItem4[] PROGMEM = "Intellivision";
|
||||
static const char consolesItem5[] PROGMEM = "Colecovision";
|
||||
//static const char consolesItem6[] PROGMEM = "Reset"; (stored in common strings array)
|
||||
static const char* const consolesOptions[] PROGMEM = { consolesItem1, consolesItem2, consolesItem3, consolesItem4, consolesItem5, string_reset2 };
|
||||
// 70s Consoles submenu
|
||||
static const char consoles70Item1[] PROGMEM = "Atari 2600";
|
||||
static const char consoles70Item2[] PROGMEM = "Magnavox Odyssey 2";
|
||||
static const char consoles70Item3[] PROGMEM = "Arcadia 2001";
|
||||
static const char consoles70Item4[] PROGMEM = "Fairchild Channel F";
|
||||
static const char consoles70Item5[] PROGMEM = "Intellivision";
|
||||
static const char consoles70Item6[] PROGMEM = "Colecovision";
|
||||
//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
|
||||
static const char handheldsItem1[] PROGMEM = "Virtual Boy";
|
||||
@ -1192,26 +1297,31 @@ void mainMenu() {
|
||||
|
||||
// Everything that needs an adapter
|
||||
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;
|
||||
// Copy menuOptions out of progmem
|
||||
convertPgm(addonsOptions, 4);
|
||||
addonsMenu = question_box(F("Type"), menuOptions, 4, 0);
|
||||
convertPgm(addonsOptions, 5);
|
||||
addonsMenu = question_box(F("Type"), menuOptions, 5, 0);
|
||||
|
||||
// wait for user choice to come back from the question box menu
|
||||
switch (addonsMenu) {
|
||||
// Consoles
|
||||
// 70s Consoles
|
||||
case 0:
|
||||
consoleMenu();
|
||||
consoles70Menu();
|
||||
break;
|
||||
|
||||
// 80s Consoles
|
||||
case 1:
|
||||
consoles80Menu();
|
||||
break;
|
||||
|
||||
// Handhelds
|
||||
case 1:
|
||||
case 2:
|
||||
handheldMenu();
|
||||
break;
|
||||
|
||||
#ifdef enable_FLASH
|
||||
case 2:
|
||||
case 3:
|
||||
#ifdef enable_FLASH16
|
||||
flashMenu();
|
||||
#else
|
||||
@ -1220,7 +1330,7 @@ void addonMenu() {
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 3:
|
||||
case 4:
|
||||
resetArduino();
|
||||
break;
|
||||
|
||||
@ -1230,15 +1340,76 @@ void addonMenu() {
|
||||
}
|
||||
|
||||
// Everything that needs an adapter
|
||||
void consoleMenu() {
|
||||
// create menu with title and 6 options to choose from
|
||||
unsigned char consolesMenu;
|
||||
void consoles70Menu() {
|
||||
// create menu with title and 7 options to choose from
|
||||
unsigned char consoles70Menu;
|
||||
// Copy menuOptions out of progmem
|
||||
convertPgm(consolesOptions, 6);
|
||||
consolesMenu = question_box(F("Choose Adapter"), menuOptions, 6, 0);
|
||||
convertPgm(consoles70Options, 7);
|
||||
consoles70Menu = question_box(F("Choose Adapter"), menuOptions, 7, 0);
|
||||
|
||||
// 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
|
||||
case 0:
|
||||
mode = mode_NES;
|
||||
@ -1265,21 +1436,7 @@ void consoleMenu() {
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef enable_INTV
|
||||
case 3:
|
||||
setup_INTV();
|
||||
intvMenu();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef enable_COLV
|
||||
case 4:
|
||||
setup_COL();
|
||||
colMenu();
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 5:
|
||||
resetArduino();
|
||||
break;
|
||||
|
||||
@ -3332,6 +3489,26 @@ void loop() {
|
||||
else if (mode == mode_PCW) {
|
||||
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
|
||||
else {
|
||||
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
|
@ -2797,7 +2797,7 @@ void readPRG(boolean readrom) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 31:
|
||||
banks = int_pow(2, prgsize) * 4;
|
||||
for (int i = 0; i < banks; i += 8) {
|
||||
@ -2960,7 +2960,7 @@ void readPRG(boolean readrom) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 56:
|
||||
banks = int_pow(2, prgsize) * 2;
|
||||
for (int i = 0; i < banks; i++) {
|
||||
@ -2971,7 +2971,7 @@ void readPRG(boolean readrom) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 57:
|
||||
banks = int_pow(2, prgsize);
|
||||
for (int i = 0; i < banks; i++) {
|
||||
@ -3060,7 +3060,7 @@ void readPRG(boolean readrom) {
|
||||
case 68:
|
||||
case 73: // 128K
|
||||
banks = int_pow(2, prgsize);
|
||||
for (int i = 0; i < banks; i++) { // 128K
|
||||
for (int i = 0; i < banks; i++) { // 128K
|
||||
write_prg_byte(0xF000, i);
|
||||
for (word address = 0x0; address < 0x4000; address += 512) { // 16K Banks ($8000-$BFFF)
|
||||
dumpPRG(base, address);
|
||||
@ -3230,7 +3230,7 @@ void readPRG(boolean readrom) {
|
||||
case 94: // bus conflicts - fixed last bank
|
||||
banks = int_pow(2, prgsize);
|
||||
busConflict = true;
|
||||
for (int i = 0; i < banks-1; i++) {
|
||||
for (int i = 0; i < banks - 1; i++) {
|
||||
for (int x = 0; x < 0x4000; x++) {
|
||||
if (read_prg_byte(0xC000 + x) == (i << 2)) {
|
||||
write_prg_byte(0xC000 + x, i << 2);
|
||||
@ -3250,13 +3250,13 @@ void readPRG(boolean readrom) {
|
||||
}
|
||||
break;
|
||||
|
||||
case 97: // fixed first bank
|
||||
case 97: // fixed first bank
|
||||
case 180: // bus conflicts - fixed fist bank
|
||||
banks = int_pow(2, prgsize);
|
||||
busConflict = true;
|
||||
for (word address = 0x0; address < 0x4000; address += 512) {
|
||||
dumpPRG(base, address);
|
||||
}
|
||||
dumpPRG(base, address);
|
||||
}
|
||||
for (int i = 1; i < banks; i++) {
|
||||
for (int x = 0; x < 0x4000; x++) {
|
||||
if (read_prg_byte(0x8000 + x) == i) {
|
||||
@ -3504,7 +3504,7 @@ void readPRG(boolean readrom) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 214:
|
||||
banks = int_pow(2, prgsize);
|
||||
for (int i = 0; i < banks; i++) {
|
||||
@ -3621,12 +3621,12 @@ void readPRG(boolean readrom) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 236:
|
||||
banks = int_pow(2, prgsize);
|
||||
for (int i = 0; i < banks; i++) {
|
||||
write_prg_byte(0x8000 | ((i & 0x38) >> 3), 0); // A19-A17
|
||||
write_prg_byte(0xC030 | (i & 0x0F), 0); // A17-A14
|
||||
write_prg_byte(0xC030 | (i & 0x0F), 0); // A17-A14
|
||||
for (word address = 0x0; address < 0x4000; address += 512) {
|
||||
dumpPRG(base, address);
|
||||
}
|
||||
@ -3920,8 +3920,8 @@ void readCHR(boolean readrom) {
|
||||
case 25: // 128K/256K
|
||||
banks = int_pow(2, chrsize) * 4;
|
||||
for (int i = 0; i < banks; i++) {
|
||||
write_prg_byte(0xB000, i & 0xF); // CHR Bank Lower 4 bits
|
||||
write_prg_byte(0xB00A, (i >> 4) & 0xF); // Combine VRC2c and VRC4b, VRC4d reg
|
||||
write_prg_byte(0xB000, i & 0xF); // CHR Bank Lower 4 bits
|
||||
write_prg_byte(0xB00A, (i >> 4) & 0xF); // Combine VRC2c and VRC4b, VRC4d reg
|
||||
for (word address = 0x0; address < 0x400; address += 512) {
|
||||
dumpCHR(address);
|
||||
}
|
||||
@ -4076,7 +4076,7 @@ void readCHR(boolean readrom) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 56:
|
||||
banks = int_pow(2, chrsize) * 4;
|
||||
for (int i = 0; i < banks; i++) {
|
||||
@ -4086,11 +4086,11 @@ void readCHR(boolean readrom) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 57:
|
||||
banks = int_pow(2, chrsize) / 2;
|
||||
for (int i = 0; i < banks; i++) {
|
||||
write_prg_byte(0x8800, i & 0x07); // A15-A13
|
||||
write_prg_byte(0x8800, i & 0x07); // A15-A13
|
||||
write_prg_byte(0x8000, 0x80 | ((i & 0x08) << 3)); // A16
|
||||
for (word address = 0x0; address < 0x2000; address += 512) {
|
||||
dumpCHR(address);
|
||||
@ -4530,7 +4530,7 @@ void readCHR(boolean readrom) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 214:
|
||||
banks = int_pow(2, chrsize) / 2;
|
||||
for (int i = 0; i < banks; i++) {
|
||||
@ -4570,7 +4570,7 @@ void readCHR(boolean readrom) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 236:
|
||||
banks = int_pow(2, chrsize) / 2;
|
||||
for (int i = 0; i < banks; i++) {
|
||||
|
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