mirror of
https://github.com/sanni/cartreader.git
synced 2024-11-13 08:25:05 +01:00
80e0e12c82
Just dumping of roms right now, no save games. Not sure if all games will dump or if there are some special ones.
283 lines
6.9 KiB
C++
283 lines
6.9 KiB
C++
//******************************************
|
|
// 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();
|
|
}
|
|
|