mirror of
https://github.com/sanni/cartreader.git
synced 2024-12-25 12:31:54 +01:00
Merge branch 'master' into patch-1
This commit is contained in:
commit
4f6f79b3b1
@ -1,20 +1,20 @@
|
||||
#include <EEPROM.h>
|
||||
#include <Arduino.h> // for type definitions
|
||||
|
||||
template <class T> int EEPROM_writeAnything(int ee, const T& value)
|
||||
{
|
||||
const byte* p = (const byte*)(const void*)&value;
|
||||
unsigned int i;
|
||||
for (i = 0; i < sizeof(value); i++)
|
||||
EEPROM.write(ee++, *p++);
|
||||
return i;
|
||||
}
|
||||
|
||||
template <class T> int EEPROM_readAnything(int ee, T& value)
|
||||
{
|
||||
byte* p = (byte*)(void*)&value;
|
||||
unsigned int i;
|
||||
for (i = 0; i < sizeof(value); i++)
|
||||
*p++ = EEPROM.read(ee++);
|
||||
return i;
|
||||
#include <EEPROM.h>
|
||||
#include <Arduino.h> // for type definitions
|
||||
|
||||
template <class T> int EEPROM_writeAnything(int ee, const T& value)
|
||||
{
|
||||
const byte* p = (const byte*)(const void*)&value;
|
||||
unsigned int i;
|
||||
for (i = 0; i < sizeof(value); i++)
|
||||
EEPROM.write(ee++, *p++);
|
||||
return i;
|
||||
}
|
||||
|
||||
template <class T> int EEPROM_readAnything(int ee, T& value)
|
||||
{
|
||||
byte* p = (byte*)(void*)&value;
|
||||
unsigned int i;
|
||||
for (i = 0; i < sizeof(value); i++)
|
||||
*p++ = EEPROM.read(ee++);
|
||||
return i;
|
||||
}
|
||||
|
2070
Cart_Reader/GB.ino
2070
Cart_Reader/GB.ino
File diff suppressed because it is too large
Load Diff
5266
Cart_Reader/GBA.ino
5266
Cart_Reader/GBA.ino
File diff suppressed because it is too large
Load Diff
@ -1,499 +1,499 @@
|
||||
//******************************************
|
||||
// SEGA MEGA DRIVE MODULE
|
||||
//******************************************
|
||||
|
||||
/******************************************
|
||||
Variables
|
||||
*****************************************/
|
||||
unsigned long sramEnd;
|
||||
|
||||
/******************************************
|
||||
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};
|
||||
|
||||
// Sega start menu
|
||||
void segaMenu() {
|
||||
display_Clear();
|
||||
display_Update();
|
||||
setup_MD();
|
||||
mode = mode_MD;
|
||||
}
|
||||
|
||||
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, 3, 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 ((saveType == 1) || (saveType == 2)) {
|
||||
// Change working dir to root
|
||||
sd.chdir("/");
|
||||
println_Msg(F("Reading Sram..."));
|
||||
display_Update();
|
||||
enableSram_MD(1);
|
||||
readSram_MD();
|
||||
enableSram_MD(0);
|
||||
}
|
||||
else {
|
||||
print_Error(F("Cart has no Sram"), false);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
display_Clear();
|
||||
// Does cartridge have SRAM
|
||||
if ((saveType == 1) || (saveType == 2)) {
|
||||
// Change working dir to root
|
||||
sd.chdir("/");
|
||||
// Launch file browser
|
||||
fileBrowser("Select srm file");
|
||||
display_Clear();
|
||||
enableSram_MD(1);
|
||||
writeSram_MD();
|
||||
writeErrors = verifySram_MD();
|
||||
enableSram_MD(0);
|
||||
if (writeErrors == 0) {
|
||||
println_Msg(F("Sram verified OK"));
|
||||
display_Update();
|
||||
}
|
||||
else {
|
||||
print_Msg(F("Error: "));
|
||||
print_Msg(writeErrors);
|
||||
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 RST(PH0) CS(PH3) WRH(PH4) WRL(PH5) OE(PH6)
|
||||
DDRH |= (1 << 0) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
||||
|
||||
// Set TIME(PJ0) to Output
|
||||
DDRJ |= (1 << 0);
|
||||
|
||||
// Set Data Pins (D0-D15) to Input
|
||||
DDRC = 0x00;
|
||||
DDRA = 0x00;
|
||||
|
||||
// Setting RST(PH0) CS(PH3) WRH(PH4) WRL(PH5) OE(PH6) HIGH
|
||||
PORTH |= (1 << 0) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
||||
|
||||
// Setting TIME(PJ0) HIGH
|
||||
PORTJ |= (1 << 0);
|
||||
|
||||
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""nop\n\t");
|
||||
|
||||
// Switch WR(PH5) to LOW
|
||||
PORTH &= ~(1 << 5);
|
||||
// Setting CS(PH3) LOW
|
||||
PORTH &= ~(1 << 3);
|
||||
|
||||
// Leave WR low for at least 200ns
|
||||
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
|
||||
|
||||
// Setting CS(PH3) HIGH
|
||||
PORTH |= (1 << 3);
|
||||
// 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");
|
||||
|
||||
// Setting CS(PH3) LOW
|
||||
PORTH &= ~(1 << 3);
|
||||
// Setting OE(PH6) LOW
|
||||
PORTH &= ~(1 << 6);
|
||||
|
||||
// Long delay here or there will be read errors
|
||||
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""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 CS(PH3) HIGH
|
||||
PORTH |= (1 << 3);
|
||||
// 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() {
|
||||
// Set control
|
||||
dataIn_MD();
|
||||
|
||||
cartSize = ((long(readWord_MD(0xD2)) << 16) | readWord_MD(0xD3)) + 1;
|
||||
|
||||
// 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
|
||||
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 * 8 / 1024 / 1024 );
|
||||
println_Msg(F(" MBit"));
|
||||
print_Msg(F("Sram: "));
|
||||
if (sramSize > 0) {
|
||||
print_Msg(sramSize * 8 / 1024);
|
||||
println_Msg(F(" KBit"));
|
||||
}
|
||||
else
|
||||
println_Msg(F("None"));
|
||||
println_Msg(F(" "));
|
||||
|
||||
// Wait for user input
|
||||
if (enable_OLED) {
|
||||
println_Msg(F("Press Button..."));
|
||||
display_Update();
|
||||
wait();
|
||||
}
|
||||
}
|
||||
|
||||
// Read rom and save to the SD card
|
||||
void readROM_MD() {
|
||||
// Set control
|
||||
dataIn_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();
|
||||
}
|
||||
|
||||
/******************************************
|
||||
SRAM functions
|
||||
*****************************************/
|
||||
// Sonic 3 sram enable
|
||||
void enableSram_MD(boolean enableSram) {
|
||||
dataOut_MD();
|
||||
|
||||
// Set D0 to either 1(enable SRAM) or 0(enable ROM)
|
||||
PORTC = enableSram;
|
||||
|
||||
// Strobe TIME(PJ0) LOW to latch the data
|
||||
PORTJ &= ~(1 << 0);
|
||||
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
|
||||
// Set TIME(PJ0) HIGH
|
||||
PORTJ |= (1 << 0);
|
||||
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
|
||||
|
||||
dataIn_MD();
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
//******************************************
|
||||
// End of File
|
||||
//******************************************
|
||||
// SEGA MEGA DRIVE MODULE
|
||||
//******************************************
|
||||
|
||||
/******************************************
|
||||
Variables
|
||||
*****************************************/
|
||||
unsigned long sramEnd;
|
||||
|
||||
/******************************************
|
||||
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};
|
||||
|
||||
// Sega start menu
|
||||
void segaMenu() {
|
||||
display_Clear();
|
||||
display_Update();
|
||||
setup_MD();
|
||||
mode = mode_MD;
|
||||
}
|
||||
|
||||
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, 3, 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 ((saveType == 1) || (saveType == 2)) {
|
||||
// Change working dir to root
|
||||
sd.chdir("/");
|
||||
println_Msg(F("Reading Sram..."));
|
||||
display_Update();
|
||||
enableSram_MD(1);
|
||||
readSram_MD();
|
||||
enableSram_MD(0);
|
||||
}
|
||||
else {
|
||||
print_Error(F("Cart has no Sram"), false);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
display_Clear();
|
||||
// Does cartridge have SRAM
|
||||
if ((saveType == 1) || (saveType == 2)) {
|
||||
// Change working dir to root
|
||||
sd.chdir("/");
|
||||
// Launch file browser
|
||||
fileBrowser("Select srm file");
|
||||
display_Clear();
|
||||
enableSram_MD(1);
|
||||
writeSram_MD();
|
||||
writeErrors = verifySram_MD();
|
||||
enableSram_MD(0);
|
||||
if (writeErrors == 0) {
|
||||
println_Msg(F("Sram verified OK"));
|
||||
display_Update();
|
||||
}
|
||||
else {
|
||||
print_Msg(F("Error: "));
|
||||
print_Msg(writeErrors);
|
||||
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 RST(PH0) CS(PH3) WRH(PH4) WRL(PH5) OE(PH6)
|
||||
DDRH |= (1 << 0) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
||||
|
||||
// Set TIME(PJ0) to Output
|
||||
DDRJ |= (1 << 0);
|
||||
|
||||
// Set Data Pins (D0-D15) to Input
|
||||
DDRC = 0x00;
|
||||
DDRA = 0x00;
|
||||
|
||||
// Setting RST(PH0) CS(PH3) WRH(PH4) WRL(PH5) OE(PH6) HIGH
|
||||
PORTH |= (1 << 0) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
||||
|
||||
// Setting TIME(PJ0) HIGH
|
||||
PORTJ |= (1 << 0);
|
||||
|
||||
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""nop\n\t");
|
||||
|
||||
// Switch WR(PH5) to LOW
|
||||
PORTH &= ~(1 << 5);
|
||||
// Setting CS(PH3) LOW
|
||||
PORTH &= ~(1 << 3);
|
||||
|
||||
// Leave WR low for at least 200ns
|
||||
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
|
||||
|
||||
// Setting CS(PH3) HIGH
|
||||
PORTH |= (1 << 3);
|
||||
// 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");
|
||||
|
||||
// Setting CS(PH3) LOW
|
||||
PORTH &= ~(1 << 3);
|
||||
// Setting OE(PH6) LOW
|
||||
PORTH &= ~(1 << 6);
|
||||
|
||||
// Long delay here or there will be read errors
|
||||
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""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 CS(PH3) HIGH
|
||||
PORTH |= (1 << 3);
|
||||
// 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() {
|
||||
// Set control
|
||||
dataIn_MD();
|
||||
|
||||
cartSize = ((long(readWord_MD(0xD2)) << 16) | readWord_MD(0xD3)) + 1;
|
||||
|
||||
// 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
|
||||
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 * 8 / 1024 / 1024 );
|
||||
println_Msg(F(" MBit"));
|
||||
print_Msg(F("Sram: "));
|
||||
if (sramSize > 0) {
|
||||
print_Msg(sramSize * 8 / 1024);
|
||||
println_Msg(F(" KBit"));
|
||||
}
|
||||
else
|
||||
println_Msg(F("None"));
|
||||
println_Msg(F(" "));
|
||||
|
||||
// Wait for user input
|
||||
if (enable_OLED) {
|
||||
println_Msg(F("Press Button..."));
|
||||
display_Update();
|
||||
wait();
|
||||
}
|
||||
}
|
||||
|
||||
// Read rom and save to the SD card
|
||||
void readROM_MD() {
|
||||
// Set control
|
||||
dataIn_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();
|
||||
}
|
||||
|
||||
/******************************************
|
||||
SRAM functions
|
||||
*****************************************/
|
||||
// Sonic 3 sram enable
|
||||
void enableSram_MD(boolean enableSram) {
|
||||
dataOut_MD();
|
||||
|
||||
// Set D0 to either 1(enable SRAM) or 0(enable ROM)
|
||||
PORTC = enableSram;
|
||||
|
||||
// Strobe TIME(PJ0) LOW to latch the data
|
||||
PORTJ &= ~(1 << 0);
|
||||
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
|
||||
// Set TIME(PJ0) HIGH
|
||||
PORTJ |= (1 << 0);
|
||||
__asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
|
||||
|
||||
dataIn_MD();
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
//******************************************
|
||||
// End of File
|
||||
//******************************************
|
||||
|
6063
Cart_Reader/N64.ino
6063
Cart_Reader/N64.ino
File diff suppressed because it is too large
Load Diff
4672
Cart_Reader/NP.ino
4672
Cart_Reader/NP.ino
File diff suppressed because it is too large
Load Diff
1416
Cart_Reader/PCE.ino
1416
Cart_Reader/PCE.ino
File diff suppressed because it is too large
Load Diff
3852
Cart_Reader/SNES.ino
3852
Cart_Reader/SNES.ino
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user