mirror of
https://github.com/sanni/cartreader.git
synced 2024-11-30 16:34:14 +01:00
V27A: Add Mega Drive SRAM read/write
Only tested with the game STRIKER. There are probably multiple types of SRAM games so not all will work yet.
This commit is contained in:
parent
80e0e12c82
commit
9335e1d2aa
@ -2,8 +2,8 @@
|
|||||||
Cartridge Reader for Arduino Mega2560
|
Cartridge Reader for Arduino Mega2560
|
||||||
|
|
||||||
Author: sanni
|
Author: sanni
|
||||||
Date: 2017-06-26
|
Date: 2017-06-27
|
||||||
Version: V27
|
Version: V27A
|
||||||
|
|
||||||
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] = "V27";
|
char ver[5] = "V27A";
|
||||||
|
|
||||||
/******************************************
|
/******************************************
|
||||||
Define Output
|
Define Output
|
||||||
@ -192,6 +192,7 @@ char cartID[5];
|
|||||||
unsigned long cartSize;
|
unsigned long cartSize;
|
||||||
char flashid[5];
|
char flashid[5];
|
||||||
unsigned long fileSize;
|
unsigned long fileSize;
|
||||||
|
unsigned long sramBase;
|
||||||
|
|
||||||
// Variable to count errors
|
// Variable to count errors
|
||||||
unsigned long writeErrors;
|
unsigned long writeErrors;
|
||||||
|
@ -2,6 +2,11 @@
|
|||||||
// SEGA MEGA DRIVE
|
// SEGA MEGA DRIVE
|
||||||
//******************************************
|
//******************************************
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
Variables
|
||||||
|
*****************************************/
|
||||||
|
unsigned long sramEnd;
|
||||||
|
|
||||||
/******************************************
|
/******************************************
|
||||||
Menu
|
Menu
|
||||||
*****************************************/
|
*****************************************/
|
||||||
@ -18,7 +23,7 @@ void mdMenu() {
|
|||||||
unsigned char mainMenu;
|
unsigned char mainMenu;
|
||||||
// Copy menuOptions out of progmem
|
// Copy menuOptions out of progmem
|
||||||
convertPgm(menuOptionsMD, 5);
|
convertPgm(menuOptionsMD, 5);
|
||||||
mainMenu = question_box("MEGA DRIVE Reader", menuOptions, 1, 0);
|
mainMenu = question_box("MEGA DRIVE Reader", menuOptions, 3, 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 (mainMenu)
|
switch (mainMenu)
|
||||||
@ -31,13 +36,15 @@ void mdMenu() {
|
|||||||
//compare_checksum_MD();
|
//compare_checksum_MD();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*case 1:
|
case 1:
|
||||||
display_Clear();
|
display_Clear();
|
||||||
// Does cartridge have SRAM
|
// Does cartridge have SRAM
|
||||||
if () {
|
if ((saveType == 1) || (saveType == 2)) {
|
||||||
// Change working dir to root
|
// Change working dir to root
|
||||||
sd.chdir("/");
|
sd.chdir("/");
|
||||||
readSRAM_MD();
|
println_Msg(F("Reading Sram..."));
|
||||||
|
display_Update();
|
||||||
|
readSram_MD();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
print_Error(F("Cart has no Sram"), false);
|
print_Error(F("Cart has no Sram"), false);
|
||||||
@ -47,19 +54,22 @@ void mdMenu() {
|
|||||||
case 2:
|
case 2:
|
||||||
display_Clear();
|
display_Clear();
|
||||||
// Does cartridge have SRAM
|
// Does cartridge have SRAM
|
||||||
if () {
|
if ((saveType == 1) || (saveType == 2)) {
|
||||||
// Change working dir to root
|
// Change working dir to root
|
||||||
sd.chdir("/");
|
sd.chdir("/");
|
||||||
writeSRAM_MD();
|
// Launch file browser
|
||||||
unsigned long wrErrors;
|
fileBrowser("Select srm file");
|
||||||
wrErrors = verifySRAM_MD();
|
display_Clear();
|
||||||
if (wrErrors == 0) {
|
|
||||||
println_Msg(F("Verified OK"));
|
writeSram_MD();
|
||||||
|
writeErrors = verifySram_MD();
|
||||||
|
if (writeErrors == 0) {
|
||||||
|
println_Msg(F("Sram verified OK"));
|
||||||
display_Update();
|
display_Update();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
print_Msg(F("Error: "));
|
print_Msg(F("Error: "));
|
||||||
print_Msg(wrErrors);
|
print_Msg(writeErrors);
|
||||||
println_Msg(F(" bytes "));
|
println_Msg(F(" bytes "));
|
||||||
print_Error(F("did not verify."), false);
|
print_Error(F("did not verify."), false);
|
||||||
}
|
}
|
||||||
@ -69,7 +79,7 @@ void mdMenu() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
/*case 3:
|
||||||
// Change working dir to root
|
// Change working dir to root
|
||||||
sd.chdir("/");
|
sd.chdir("/");
|
||||||
writeFlash_MD();
|
writeFlash_MD();
|
||||||
@ -134,7 +144,7 @@ void writeWord_MD(unsigned long myAddress, word myData) {
|
|||||||
|
|
||||||
// Arduino running at 16Mhz -> one nop = 62.5ns
|
// Arduino running at 16Mhz -> one nop = 62.5ns
|
||||||
// Wait till output is stable
|
// Wait till output is stable
|
||||||
__asm__("nop\n\t");
|
__asm__("nop\n\t""nop\n\t");
|
||||||
|
|
||||||
// Switch WR(PH5) to LOW
|
// Switch WR(PH5) to LOW
|
||||||
PORTH &= ~(1 << 5);
|
PORTH &= ~(1 << 5);
|
||||||
@ -155,7 +165,7 @@ word readWord_MD(unsigned long myAddress) {
|
|||||||
PORTL = (myAddress >> 16) & 0xFF;
|
PORTL = (myAddress >> 16) & 0xFF;
|
||||||
|
|
||||||
// Arduino running at 16Mhz -> one nop = 62.5ns
|
// 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");
|
__asm__("nop\n\t""nop\n\t");
|
||||||
|
|
||||||
// Setting OE(PH6) LOW
|
// Setting OE(PH6) LOW
|
||||||
PORTH &= ~(1 << 6);
|
PORTH &= ~(1 << 6);
|
||||||
@ -188,8 +198,40 @@ void dataIn_MD() {
|
|||||||
MEGA DRIVE functions
|
MEGA DRIVE functions
|
||||||
*****************************************/
|
*****************************************/
|
||||||
void getCartInfo_MD() {
|
void getCartInfo_MD() {
|
||||||
|
// Set control
|
||||||
|
dataIn_MD();
|
||||||
|
|
||||||
cartSize = ((long(readWord_MD(0xD2)) << 16) | readWord_MD(0xD3)) + 1;
|
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;
|
|
||||||
|
// Check if cart has sram
|
||||||
|
if ((readWord_MD(0xD8) == 0x5241) && (readWord_MD(0xD9) == 0xF820)) {
|
||||||
|
// Get sram start and end
|
||||||
|
sramBase = ((long(readWord_MD(0xDA)) << 16) | readWord_MD(0xDB));
|
||||||
|
sramEnd = ((long(readWord_MD(0xDC)) << 16) | readWord_MD(0xDD));
|
||||||
|
|
||||||
|
// Check alignment of sram
|
||||||
|
if (sramBase == 0x200001) {
|
||||||
|
// low byte
|
||||||
|
saveType = 1;
|
||||||
|
sramSize = (sramEnd - sramBase + 2) / 2;
|
||||||
|
// Right shift sram base address so [A21] is set to high 0x200000 = 0b001[0]00000000000000000000
|
||||||
|
sramBase = sramBase >> 1;
|
||||||
|
}
|
||||||
|
else if (sramBase == 0x200000) {
|
||||||
|
// high byte
|
||||||
|
saveType = 2;
|
||||||
|
sramSize = (sramEnd - sramBase + 1) / 2;
|
||||||
|
// Right shift sram base address so [A21] is set to high 0x200000 = 0b001[0]00000000000000000000
|
||||||
|
sramBase = sramBase / 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
print_Error(F("Unknown Sram Base"), true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Either no save or eeprom save
|
||||||
|
saveType = 0;
|
||||||
|
sramSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Get name
|
// Get name
|
||||||
for (byte c = 0; c < 48; c += 2) {
|
for (byte c = 0; c < 48; c += 2) {
|
||||||
@ -219,12 +261,16 @@ void getCartInfo_MD() {
|
|||||||
print_Msg(cartSize / 1024 / 1024);
|
print_Msg(cartSize / 1024 / 1024);
|
||||||
println_Msg(F("MB"));
|
println_Msg(F("MB"));
|
||||||
print_Msg(F("Sram: "));
|
print_Msg(F("Sram: "));
|
||||||
|
if (sramSize > 0) {
|
||||||
print_Msg(sramSize / 1024);
|
print_Msg(sramSize / 1024);
|
||||||
println_Msg(F("KB"));
|
println_Msg(F("KB"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
println_Msg(F("None"));
|
||||||
|
println_Msg(F(" "));
|
||||||
|
|
||||||
// Wait for user input
|
// Wait for user input
|
||||||
if (enable_OLED) {
|
if (enable_OLED) {
|
||||||
println_Msg(F(" "));
|
|
||||||
println_Msg(F("Press Button..."));
|
println_Msg(F("Press Button..."));
|
||||||
display_Update();
|
display_Update();
|
||||||
wait();
|
wait();
|
||||||
@ -233,6 +279,9 @@ void getCartInfo_MD() {
|
|||||||
|
|
||||||
// Read rom and save to the SD card
|
// Read rom and save to the SD card
|
||||||
void readROM_MD() {
|
void readROM_MD() {
|
||||||
|
// Set control
|
||||||
|
dataIn_MD();
|
||||||
|
|
||||||
// Get name, add extension and convert to char array for sd lib
|
// Get name, add extension and convert to char array for sd lib
|
||||||
strcpy(fileName, romName);
|
strcpy(fileName, romName);
|
||||||
strcat(fileName, ".MD");
|
strcat(fileName, ".MD");
|
||||||
@ -280,3 +329,126 @@ void readROM_MD() {
|
|||||||
myFile.close();
|
myFile.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
SRAM functions
|
||||||
|
*****************************************/
|
||||||
|
// Write sram to cartridge
|
||||||
|
void writeSram_MD() {
|
||||||
|
dataOut_MD();
|
||||||
|
|
||||||
|
// Create filepath
|
||||||
|
sprintf(filePath, "%s/%s", filePath, fileName);
|
||||||
|
println_Msg(F("Writing..."));
|
||||||
|
println_Msg(filePath);
|
||||||
|
display_Update();
|
||||||
|
|
||||||
|
// Open file on sd card
|
||||||
|
if (myFile.open(filePath, O_READ)) {
|
||||||
|
// Write to the lower byte
|
||||||
|
if (saveType == 1) {
|
||||||
|
for (unsigned long currByte = sramBase; currByte < sramBase + sramSize; currByte++) {
|
||||||
|
writeWord_MD(currByte, (myFile.read() & 0xFF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Write to the upper byte
|
||||||
|
else if (saveType == 2) {
|
||||||
|
for (unsigned long currByte = sramBase; currByte < sramBase + sramSize; currByte++) {
|
||||||
|
writeWord_MD(currByte, ((myFile.read() << 8 ) & 0xFF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
print_Error(F("Unknown save type"), false);
|
||||||
|
|
||||||
|
// Close the file:
|
||||||
|
myFile.close();
|
||||||
|
println_Msg(F("Done"));
|
||||||
|
display_Update();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print_Error(F("SD Error"), true);
|
||||||
|
}
|
||||||
|
dataIn_MD();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read sram and save to the SD card
|
||||||
|
void readSram_MD() {
|
||||||
|
dataIn_MD();
|
||||||
|
|
||||||
|
// Get name, add extension and convert to char array for sd lib
|
||||||
|
strcpy(fileName, romName);
|
||||||
|
strcat(fileName, ".srm");
|
||||||
|
|
||||||
|
// create a new folder for the save file
|
||||||
|
EEPROM_readAnything(10, foldern);
|
||||||
|
sprintf(folder, "MD/SAVE/%s/%d", romName, foldern);
|
||||||
|
sd.mkdir(folder, true);
|
||||||
|
sd.chdir(folder);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned long currBuffer = sramBase; currBuffer < sramBase + sramSize; currBuffer += 512) {
|
||||||
|
for (int currWord = 0; currWord < 512; currWord++) {
|
||||||
|
word myWord = readWord_MD(currBuffer + currWord);
|
||||||
|
|
||||||
|
if (saveType == 2) {
|
||||||
|
// Only use the upper byte
|
||||||
|
sdBuffer[currWord] = (( myWord >> 8 ) & 0xFF);
|
||||||
|
}
|
||||||
|
else if (saveType == 1) {
|
||||||
|
// Only use the lower byte
|
||||||
|
sdBuffer[currWord] = (myWord & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
myFile.write(sdBuffer, 512);
|
||||||
|
}
|
||||||
|
// Close the file:
|
||||||
|
myFile.close();
|
||||||
|
print_Msg(F("Saved to "));
|
||||||
|
print_Msg(folder);
|
||||||
|
println_Msg(F("/"));
|
||||||
|
display_Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long verifySram_MD() {
|
||||||
|
dataIn_MD();
|
||||||
|
writeErrors = 0;
|
||||||
|
|
||||||
|
// Open file on sd card
|
||||||
|
if (myFile.open(filePath, O_READ)) {
|
||||||
|
for (unsigned long currBuffer = sramBase; currBuffer < sramBase + sramSize; currBuffer += 512) {
|
||||||
|
for (int currWord = 0; currWord < 512; currWord++) {
|
||||||
|
word myWord = readWord_MD(currBuffer + currWord);
|
||||||
|
|
||||||
|
if (saveType == 2) {
|
||||||
|
// Only use the upper byte
|
||||||
|
sdBuffer[currWord] = (( myWord >> 8 ) & 0xFF);
|
||||||
|
}
|
||||||
|
else if (saveType == 1) {
|
||||||
|
// Only use the lower byte
|
||||||
|
sdBuffer[currWord] = (myWord & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check sdBuffer content against file on sd card
|
||||||
|
for (int i = 0; i < 512; i++) {
|
||||||
|
if (myFile.read() != sdBuffer[i]) {
|
||||||
|
writeErrors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the file:
|
||||||
|
myFile.close();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print_Error(F("SD Error"), true);
|
||||||
|
}
|
||||||
|
// Return 0 if verified ok, or number of errors
|
||||||
|
return writeErrors;
|
||||||
|
}
|
||||||
|
@ -37,7 +37,6 @@ String lastbutton = "N/A";
|
|||||||
|
|
||||||
// Rom base address
|
// Rom base address
|
||||||
unsigned long romBase = 0x10000000;
|
unsigned long romBase = 0x10000000;
|
||||||
unsigned long sramBase = 0x08000000;
|
|
||||||
|
|
||||||
// Flashram type
|
// Flashram type
|
||||||
byte flashramType = 1;
|
byte flashramType = 1;
|
||||||
@ -277,6 +276,9 @@ void setup_N64_Cart() {
|
|||||||
// Activate Internal Pullup Resistors
|
// Activate Internal Pullup Resistors
|
||||||
//PORTH |= (1 << 4);
|
//PORTH |= (1 << 4);
|
||||||
|
|
||||||
|
// Set sram base address
|
||||||
|
sramBase = 0x08000000;
|
||||||
|
|
||||||
// Wait until all is stable
|
// Wait until all is stable
|
||||||
delay(300);
|
delay(300);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user