V27: Add basic Mega Drive Support

Just dumping of roms right now, no save games. Not sure if all games will dump or if there are some special ones.
This commit is contained in:
sanni 2017-06-26 23:48:07 +02:00 committed by GitHub
parent 0c0e08bc2f
commit 80e0e12c82
2 changed files with 305 additions and 11 deletions

View File

@ -2,8 +2,8 @@
Cartridge Reader for Arduino Mega2560 Cartridge Reader for Arduino Mega2560
Author: sanni Author: sanni
Date: 2017-06-25 Date: 2017-06-26
Version: V26 Version: V27
SD lib: https://github.com/greiman/SdFat SD lib: https://github.com/greiman/SdFat
LCD lib: https://github.com/adafruit/Adafruit_SSD1306 LCD lib: https://github.com/adafruit/Adafruit_SSD1306
@ -34,7 +34,7 @@
YamaArashi - GBA flashrom bank switch command YamaArashi - GBA flashrom bank switch command
**********************************************************************************/ **********************************************************************************/
char ver[5] = "V26"; char ver[5] = "V27";
/****************************************** /******************************************
Define Output Define Output
@ -124,6 +124,7 @@ SdFile myFile;
#define mode_FLASH16 8 #define mode_FLASH16 8
#define mode_GBA 9 #define mode_GBA 9
#define mode_GBM 10 #define mode_GBM 10
#define mode_MD 11
/****************************************** /******************************************
Variables Variables
@ -179,10 +180,10 @@ char fileOptions[30][20];
// Common // Common
char romName[17]; char romName[17];
int sramSize = 0; unsigned long sramSize = 0;
int romType = 0; int romType = 0;
byte saveType; byte saveType;
int romSize = 0; word romSize = 0;
byte numBanks = 128; byte numBanks = 128;
char checksumStr[5]; char checksumStr[5];
bool errorLvl = 0; bool errorLvl = 0;
@ -324,9 +325,10 @@ static const char modeItem1[] PROGMEM = "Nintendo 64";
static const char modeItem2[] PROGMEM = "Super Nintendo"; static const char modeItem2[] PROGMEM = "Super Nintendo";
static const char modeItem3[] PROGMEM = "Nintendo Power"; static const char modeItem3[] PROGMEM = "Nintendo Power";
static const char modeItem4[] PROGMEM = "Game Boy"; static const char modeItem4[] PROGMEM = "Game Boy";
static const char modeItem5[] PROGMEM = "Flashrom Programmer"; static const char modeItem5[] PROGMEM = "Mega Drive";
static const char modeItem6[] PROGMEM = "About"; static const char modeItem6[] PROGMEM = "Flashrom Programmer";
static const char* const modeOptions[] PROGMEM = {modeItem1, modeItem2, modeItem3, modeItem4, modeItem5, modeItem6}; static const char modeItem7[] PROGMEM = "About";
static const char* const modeOptions[] PROGMEM = {modeItem1, modeItem2, modeItem3, modeItem4, modeItem5, modeItem6, modeItem7};
// N64 Submenu // N64 Submenu
static const char n64MenuItem1[] PROGMEM = "Cart Slot"; static const char n64MenuItem1[] PROGMEM = "Cart Slot";
@ -353,8 +355,8 @@ void mainMenu() {
// create menu with title and 6 options to choose from // create menu with title and 6 options to choose from
unsigned char modeMenu; unsigned char modeMenu;
// Copy menuOptions out of progmem // Copy menuOptions out of progmem
convertPgm(modeOptions, 6); convertPgm(modeOptions, 7);
modeMenu = question_box("Cartridge Reader", menuOptions, 6, 0); modeMenu = question_box("Cartridge Reader", menuOptions, 7, 0);
// wait for user choice to come back from the question box menu // wait for user choice to come back from the question box menu
switch (modeMenu) switch (modeMenu)
@ -456,6 +458,13 @@ void mainMenu() {
break; break;
case 4: case 4:
display_Clear();
display_Update();
setup_MD();
mode = mode_MD;
break;
case 5:
// create menu with title and 2 options to choose from // create menu with title and 2 options to choose from
unsigned char flashSlot; unsigned char flashSlot;
// Copy menuOptions out of progmem // Copy menuOptions out of progmem
@ -481,7 +490,7 @@ void mainMenu() {
} }
break; break;
case 5: case 6:
display_Clear(); display_Clear();
// Draw the Logo // Draw the Logo
display.drawBitmap(0, 0, sig, 128, 64, 1); display.drawBitmap(0, 0, sig, 128, 64, 1);
@ -1308,6 +1317,9 @@ void loop() {
else if (mode == mode_GBM) { else if (mode == mode_GBM) {
gbmMenu(); gbmMenu();
} }
else if (mode == mode_MD) {
mdMenu();
}
else { else {
display_Clear(); display_Clear();
println_Msg(F("Menu Error")); println_Msg(F("Menu Error"));

282
Cart_Reader/MD.ino Normal file
View File

@ -0,0 +1,282 @@
//******************************************
// SEGA MEGA DRIVE
//******************************************
/******************************************
Menu
*****************************************/
// MD menu items
static const char MDMenuItem1[] PROGMEM = "Read Rom";
static const char MDMenuItem2[] PROGMEM = "Read Save";
static const char MDMenuItem3[] PROGMEM = "Write Save";
static const char MDMenuItem4[] PROGMEM = "Write Flashcart";
static const char MDMenuItem5[] PROGMEM = "Reset";
static const char* const menuOptionsMD[] PROGMEM = {MDMenuItem1, MDMenuItem2, MDMenuItem3, MDMenuItem4, MDMenuItem5};
void mdMenu() {
// create menu with title and 5 options to choose from
unsigned char mainMenu;
// Copy menuOptions out of progmem
convertPgm(menuOptionsMD, 5);
mainMenu = question_box("MEGA DRIVE Reader", menuOptions, 1, 0);
// wait for user choice to come back from the question box menu
switch (mainMenu)
{
case 0:
display_Clear();
// Change working dir to root
sd.chdir("/");
readROM_MD();
//compare_checksum_MD();
break;
/*case 1:
display_Clear();
// Does cartridge have SRAM
if () {
// Change working dir to root
sd.chdir("/");
readSRAM_MD();
}
else {
print_Error(F("Cart has no Sram"), false);
}
break;
case 2:
display_Clear();
// Does cartridge have SRAM
if () {
// Change working dir to root
sd.chdir("/");
writeSRAM_MD();
unsigned long wrErrors;
wrErrors = verifySRAM_MD();
if (wrErrors == 0) {
println_Msg(F("Verified OK"));
display_Update();
}
else {
print_Msg(F("Error: "));
print_Msg(wrErrors);
println_Msg(F(" bytes "));
print_Error(F("did not verify."), false);
}
}
else {
print_Error(F("Cart has no Sram"), false);
}
break;
case 3:
// Change working dir to root
sd.chdir("/");
writeFlash_MD();
// Reset
wait();
asm volatile (" jmp 0");
break;
case 4:
asm volatile (" jmp 0");
break;*/
}
println_Msg(F(""));
println_Msg(F("Press Button..."));
display_Update();
wait();
}
/******************************************
Setup
*****************************************/
void setup_MD() {
// Set Address Pins to Output
//A0-A7
DDRF = 0xFF;
//A8-A15
DDRK = 0xFF;
//A16-A23
DDRL = 0xFF;
// Set Control Pins to Output CS(PH3) WR(PH5) OE(PH6)
DDRH |= (1 << 3) | (1 << 5) | (1 << 6);
// Set Data Pins (D0-D15) to Input
DDRC = 0x00;
DDRA = 0x00;
// Setting WR(PH5) OE(PH6) HIGH
PORTH |= (1 << 5) | (1 << 6);
// Setting CS(PH3) LOW
PORTH &= ~(1 << 3);
delay(200);
// Print all the info
getCartInfo_MD();
}
/******************************************
I/O Functions
*****************************************/
/******************************************
Low level functions
*****************************************/
void writeWord_MD(unsigned long myAddress, word myData) {
PORTF = myAddress & 0xFF;
PORTK = (myAddress >> 8) & 0xFF;
PORTL = (myAddress >> 16) & 0xFF;
PORTC = myData;
PORTA = (myData >> 8) & 0xFF;
// Arduino running at 16Mhz -> one nop = 62.5ns
// Wait till output is stable
__asm__("nop\n\t");
// Switch WR(PH5) to LOW
PORTH &= ~(1 << 5);
// Leave WR low for at least 60ns
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
// Switch WR(PH5) to HIGH
PORTH |= (1 << 5);
// Leave WR high for at least 50ns
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
}
word readWord_MD(unsigned long myAddress) {
PORTF = myAddress & 0xFF;
PORTK = (myAddress >> 8) & 0xFF;
PORTL = (myAddress >> 16) & 0xFF;
// Arduino running at 16Mhz -> one nop = 62.5ns
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
// Setting OE(PH6) LOW
PORTH &= ~(1 << 6);
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
// Read
word tempWord = ( ( PINA & 0xFF ) << 8 ) | ( PINC & 0xFF );
// Setting OE(PH6) HIGH
PORTH |= (1 << 6);
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
return tempWord;
}
// Switch data pins to write
void dataOut_MD() {
DDRC = 0xFF;
DDRA = 0xFF;
}
// Switch data pins to read
void dataIn_MD() {
DDRC = 0x00;
DDRA = 0x00;
}
/******************************************
MEGA DRIVE functions
*****************************************/
void getCartInfo_MD() {
cartSize = ((long(readWord_MD(0xD2)) << 16) | readWord_MD(0xD3)) + 1;
sramSize = ((long(readWord_MD(0xDC)) << 16) | readWord_MD(0xDD)) - ((long(readWord_MD(0xDA)) << 16) | readWord_MD(0xDB)) + 2;
// Get name
for (byte c = 0; c < 48; c += 2) {
// split word
word myWord = readWord_MD((0x150 + c) / 2);
byte loByte = myWord & 0xFF;
byte hiByte = myWord >> 8;
// write to buffer
sdBuffer[c] = hiByte;
sdBuffer[c + 1] = loByte;
}
byte myLength = 0;
for (unsigned int i = 0; i < 48; i++) {
if (((char(sdBuffer[i]) >= 48 && char(sdBuffer[i]) <= 57) || (char(sdBuffer[i]) >= 65 && char(sdBuffer[i]) <= 122)) && myLength < 15) {
romName[myLength] = char(sdBuffer[i]);
myLength++;
}
}
display_Clear();
println_Msg(F("Cart Info"));
println_Msg(F(" "));
print_Msg(F("Name: "));
println_Msg(romName);
print_Msg(F("Size: "));
print_Msg(cartSize / 1024 / 1024);
println_Msg(F("MB"));
print_Msg(F("Sram: "));
print_Msg(sramSize / 1024);
println_Msg(F("KB"));
// Wait for user input
if (enable_OLED) {
println_Msg(F(" "));
println_Msg(F("Press Button..."));
display_Update();
wait();
}
}
// Read rom and save to the SD card
void readROM_MD() {
// Get name, add extension and convert to char array for sd lib
strcpy(fileName, romName);
strcat(fileName, ".MD");
// create a new folder
EEPROM_readAnything(10, foldern);
sprintf(folder, "MD/ROM/%s/%d", romName, foldern);
sd.mkdir(folder, true);
sd.chdir(folder);
display_Clear();
print_Msg(F("Saving to "));
print_Msg(folder);
println_Msg(F("/..."));
display_Update();
// write new folder number back to eeprom
foldern = foldern + 1;
EEPROM_writeAnything(10, foldern);
// Open file on sd card
if (!myFile.open(fileName, O_RDWR | O_CREAT)) {
print_Error(F("SD Error"), true);
}
word d = 0;
for (unsigned long currBuffer = 0; currBuffer < cartSize / 2; currBuffer += 256) {
// Blink led
if (currBuffer % 16384 == 0)
PORTB ^= (1 << 4);
for (int currWord = 0; currWord < 256; currWord++) {
word myWord = readWord_MD(currBuffer + currWord);
// Split word into two bytes
// Left
sdBuffer[d] = (( myWord >> 8 ) & 0xFF);
// Right
sdBuffer[d + 1] = (myWord & 0xFF);
d += 2;
}
myFile.write(sdBuffer, 512);
d = 0;
}
// Close the file:
myFile.close();
}