cartreader/Cart_Reader/SMS.ino
2019-09-10 17:38:56 +02:00

255 lines
5.9 KiB
C++

//******************************************
// SEGA MASTER SYSTEM MODULE
//******************************************
// unfinished and untested
/******************************************
Variables
*****************************************/
/******************************************
Menu
*****************************************/
// MD menu items
static const char SMSMenuItem1[] PROGMEM = "Read Rom";
static const char SMSMenuItem2[] PROGMEM = "Reset";
static const char* const menuOptionsSMS[] PROGMEM = {SMSMenuItem1, SMSMenuItem2};
void smsMenu() {
// create menu with title and 2 options to choose from
unsigned char mainMenu;
// Copy menuOptions out of progmem
convertPgm(menuOptionsSMS, 2);
mainMenu = question_box(F("Sega Master System"), menuOptions, 2, 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_SMS();
break;
case 1:
// Reset
asm volatile (" jmp 0");
break;
}
println_Msg(F(""));
println_Msg(F("Press Button..."));
display_Update();
wait();
}
/******************************************
Setup
*****************************************/
void setup_SMS() {
// Set Address Pins to Output
//A0-A7
DDRF = 0xFF;
//A8-A15
DDRK = 0xFF;
// Set Control Pins to Output RST(PH0) CS(PH3) WR(PH5) OE(PH6)
DDRH |= (1 << 0) | (1 << 3) | (1 << 5) | (1 << 6);
// Set Data Pins (D0-D15) to Input
DDRC = 0x00;
// Setting RST(PH0) CS(PH3) WR(PH5) OE(PH6) HIGH
PORTH |= (1 << 0) | (1 << 3) | (1 << 5) | (1 << 6);
delay(200);
// Print all the info
getCartInfo_SMS();
}
/******************************************
Low level functions
*****************************************/
void writeByte_SMS(unsigned long myAddress, word myData) {
PORTF = myAddress & 0xFF;
PORTK = (myAddress >> 8) & 0xFF;
PORTC = myData;
// 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");
}
byte readByte_SMS(unsigned long myAddress) {
PORTF = myAddress & 0xFF;
PORTK = (myAddress >> 8) & 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
byte tempByte = (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 tempByte;
}
// Switch data pins to write
void dataOut_SMS() {
DDRC = 0xFF;
}
// Switch data pins to read
void dataIn_SMS() {
DDRC = 0x00;
}
unsigned char hex2bcd (unsigned char x) {
unsigned char y;
y = (x / 10) << 4;
y = y | (x % 10);
return (y);
}
/******************************************
MASTER SYSTEM functions
*****************************************/
void getCartInfo_SMS() {
// Set control
dataIn_SMS();
// Rom size
switch (readByte_SMS(0x7fff) & 0xFF) {
case 0xa:
// Adding UL gets rid of integer overflow compiler warning
cartSize = 8 * 1024UL;
break;
case 0xb:
cartSize = 16 * 1024UL;
break;
case 0xc:
cartSize = 32 * 1024UL;
break;
case 0xd:
cartSize = 48 * 1024UL;
break;
case 0xe:
cartSize = 64 * 1024UL;
break;
case 0xf:
cartSize = 128 * 1024UL;
break;
case 0x0:
cartSize = 256 * 1024UL;
break;
case 0x1:
cartSize = 512 * 1024UL;
break;
case 0x2:
cartSize = 512 * 1024UL;
break;
}
// Get product code
romName[0] = (readByte_SMS(0x7ffe) >> 4);
romName[1] = hex2bcd(readByte_SMS(0x7ffd));
romName[2] = hex2bcd(readByte_SMS(0x7ffc));
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 );
println_Msg(F(" KBit"));
println_Msg(F(" "));
// Wait for user input
#ifdef enable_OLED
println_Msg(F("Press Button..."));
display_Update();
wait();
#endif
}
// Read rom and save to the SD card
void readROM_SMS() {
// Set control
dataIn_SMS();
// Get name, add extension and convert to char array for sd lib
strcpy(fileName, romName);
strcat(fileName, ".SMS");
// create a new folder
EEPROM_readAnything(10, foldern);
sprintf(folder, "SMS/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);
}
for (unsigned long currBuffer = 0; currBuffer < cartSize; currBuffer += 512) {
// Blink led
if (currBuffer % 16384 == 0)
PORTB ^= (1 << 4);
for (int currByte = 0; currByte < 512; currByte++) {
sdBuffer[currByte] = readByte_SMS(currBuffer + currByte);
}
myFile.write(sdBuffer, 512);
}
// Close the file:
myFile.close();
}
//******************************************
// End of File
//******************************************