V3.5 Change Menu and add Sega CD Ram Cart

Thanks to skaman for the Sega CD Ram Cart code.  Writes to the Sega CD Backup RAM Cart require an extra wire from MRES (B02) to VRES (B27).
This commit is contained in:
sanni 2019-09-01 14:36:53 +02:00
parent 61f5966a49
commit 0c75bf8aed
7 changed files with 711 additions and 209 deletions

View File

@ -2,8 +2,8 @@
Cartridge Reader for Arduino Mega2560
Author: sanni
Date: 30-08-2019
Version: 3.4
Date: 01-09-2019
Version: 3.5
SD lib: https://github.com/greiman/SdFat
LCD lib: https://github.com/adafruit/Adafruit_SSD1306
@ -16,7 +16,7 @@
MichlK - ROM-Reader for Super Nintendo
Jeff Saltzman - 4-Way Button
Wayne and Layne - Video-Game-Shield menu
skaman - SNES enhancements, SA1 sram support,GB flash fix and MD improvements
skaman - SNES enhancements, SA1 sram support, GB flash fix, MD improvements, Famicom dumper
nocash - Nintendo Power and GBA Eeprom commands and lots of other info
crazynation - N64 bus timing
hkz/themanbehindthecurtain - N64 flashram commands
@ -36,18 +36,18 @@
moldov - SF Memory Binary Maker
vogelfreiheit - N64 flashram fix
rama - code speedup & improvements
Megadrive checksum - Gens-gs
Gens-gs - Megadrive checksum
**********************************************************************************/
#include <SdFat.h>
char ver[5] = "3.4";
char ver[5] = "3.5";
/******************************************
Define Starting Point
******************************************/
// mainMenu, n64Menu, snsMenu, gbxMenu, segaMenu, flashMenu, pceMenu
// mainMenu, n64Menu, snsMenu, gbxMenu, nesMenu, mdMenu, flashMenu, pceMenu
#define startMenu mainMenu
/******************************************
@ -74,10 +74,10 @@ char ver[5] = "3.4";
/******************************************
Options
******************************************/
// If set to 1 then the crc32 checksum will be calculated after reading a N64 rom
boolean n64crc = 1;
// Enable 16bit flash adapter menu
//#define enable_flash16
// Disable splash screen
#define fast_start
/******************************************
Libraries
@ -90,7 +90,23 @@ boolean n64crc = 1;
// AVR Eeprom
#include <EEPROM.h>
#include "EEPROMAnything.h"
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;
}
// Graphic I2C LCD
#include <Adafruit_GFX.h>
@ -141,10 +157,13 @@ SdFile myFile;
#define mode_FLASH16 8
#define mode_GBA 9
#define mode_GBM 10
#define mode_MD 11
#define mode_MD_Cart 11
#define mode_EPROM 12
#define mode_PCE 13
#define mode_SV 14
#define mode_NES 15
#define mode_SMS 16
#define mode_SEGA_CD 17
/******************************************
optimization-safe nop delay
@ -349,23 +368,27 @@ static const unsigned char PROGMEM sig [] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
//For PC Engine
extern void pcsMenu(void);
extern void pceMenu(void);
/******************************************
Menu
*****************************************/
// Main menu
static const char modeItem1[] PROGMEM = "Nintendo 64";
static const char modeItem1[] PROGMEM = "Add-ons";
static const char modeItem2[] PROGMEM = "Super Nintendo";
static const char modeItem3[] PROGMEM = "Game Boy";
static const char modeItem4[] PROGMEM = "Mega Drive";
static const char modeItem5[] PROGMEM = "Flashrom Programmer";
static const char modeItem6[] PROGMEM = "PC Engine/TG16";
static const char modeItem7[] PROGMEM = "About";
static const char modeItem3[] PROGMEM = "Mega Drive";
static const char modeItem4[] PROGMEM = "Nintendo 64";
static const char modeItem5[] PROGMEM = "Game Boy";
static const char modeItem6[] PROGMEM = "About";
static const char modeItem7[] PROGMEM = "Reset";
static const char* const modeOptions[] PROGMEM = {modeItem1, modeItem2, modeItem3, modeItem4, modeItem5, modeItem6, modeItem7};
// Add-ons submenu
static const char addonsItem1[] PROGMEM = "PC Engine/TG16";
static const char addonsItem2[] PROGMEM = "Flashrom Programmer";
static const char addonsItem3[] PROGMEM = "NES/Famicom";
static const char addonsItem4[] PROGMEM = "Sega Master System";
static const char addonsItem5[] PROGMEM = "Reset";
static const char* const addonsOptions[] PROGMEM = {addonsItem1, addonsItem2, addonsItem3, addonsItem4, addonsItem5};
void aboutScreen() {
display_Clear();
// Draw the Logo
@ -416,47 +439,6 @@ void aboutScreen() {
}
}
void draw_progressbar(uint32_t processed, uint32_t total)
{
uint8_t current, i;
static uint8_t previous;
uint8_t steps = 20;
//Find progressbar length and draw if processed size is not 0
if (processed == 0)
{
previous = 0;
print_Msg(F("["));
display_Update();
return;
}
// Progress bar
current = (processed >= total) ? steps : processed / (total / steps);
//Draw "*" if needed
if (current > previous)
{
for (i = previous; i < current; i++)
{
// steps are 20, so 20 - 1 = 19.
if (i == (19))
{
//If end of progress bar, finish progress bar by drawing "]"
print_Msg(F("]"));
}
else
{
print_Msg(F("*"));
}
}
//update previous "*" status
previous = current;
//Update display
display_Update();
}
}
void mainMenu() {
// create menu with title and 6 options to choose from
unsigned char modeMenu;
@ -468,7 +450,7 @@ void mainMenu() {
switch (modeMenu)
{
case 0:
n64Menu();
addonsMenu();
break;
case 1:
@ -476,22 +458,94 @@ void mainMenu() {
break;
case 2:
gbxMenu();
mdMenu();
break;
case 3:
segaMenu();
n64Menu();
break;
case 4:
flashMenu();
gbxMenu();
break;
case 5:
pcsMenu();
break;
case 6:
aboutScreen();
break;
case 6:
resetArduino();
break;
}
}
void addonsMenu() {
// create menu with title and 5 options to choose from
unsigned char addonsMenu;
// Copy menuOptions out of progmem
convertPgm(addonsOptions, 2);
addonsMenu = question_box(F("Choose Adapter"), menuOptions, 2, 0);
// wait for user choice to come back from the question box menu
switch (addonsMenu)
{
case 0:
pcsMenu();
break;
case 1:
flashMenu();
break;
case 2:
nesMenu();
break;
case 3:
smsMenu();
break;
case 4:
resetArduino();
break;
}
}
/******************************************
Progressbar
*****************************************/
void draw_progressbar(uint32_t processed, uint32_t total) {
uint8_t current, i;
static uint8_t previous;
uint8_t steps = 20;
//Find progressbar length and draw if processed size is not 0
if (processed == 0) {
previous = 0;
print_Msg(F("["));
display_Update();
return;
}
// Progress bar
current = (processed >= total) ? steps : processed / (total / steps);
//Draw "*" if needed
if (current > previous) {
for (i = previous; i < current; i++) {
// steps are 20, so 20 - 1 = 19.
if (i == (19)) {
//If end of progress bar, finish progress bar by drawing "]"
print_Msg(F("]"));
}
else {
print_Msg(F("*"));
}
}
//update previous "*" status
previous = current;
//Update display
display_Update();
}
}
@ -503,8 +557,8 @@ void setup() {
DDRD &= ~(1 << 7);
DDRG &= ~(1 << 2);
// Activate Internal Pullup Resistors
//PORTD |= (1 << 7);
//PORTG |= (1 << 2);
PORTD |= (1 << 7);
PORTG |= (1 << 2);
// Read current folder number out of eeprom
EEPROM_readAnything(10, foldern);
@ -517,6 +571,8 @@ void setup() {
// Clear the screen buffer.
display_Clear();
#ifndef fast_start
delay(100);
// Draw line
@ -556,6 +612,7 @@ void setup() {
display.println(ver);
display_Update();
delay(200);
#endif
}
if (enable_Serial) {
@ -1412,8 +1469,8 @@ void loop() {
else if (mode == mode_GBM) {
gbmMenu();
}
else if (mode == mode_MD) {
mdMenu();
else if (mode == mode_MD_Cart) {
mdCartMenu();
}
else if (mode == mode_PCE) {
pceMenu();
@ -1421,6 +1478,15 @@ void loop() {
else if (mode == mode_SV) {
svMenu();
}
else if (mode == mode_NES) {
nesMenu();
}
else if (mode == mode_SMS) {
smsMenu();
}
else if (mode == mode_SEGA_CD) {
segaCDMenu();
}
else {
display_Clear();
println_Msg(F("Menu Error"));

View File

@ -1,20 +0,0 @@
#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;
}

View File

@ -1,15 +1,14 @@
//******************************************
// SEGA MEGA DRIVE MODULE
//******************************************
// Writes to Sega CD Backup RAM Cart require an extra wire from MRES (B02) to VRES (B27)
/******************************************
Variables
*****************************************/
unsigned long sramEnd;
byte eepbit[8];
int eepSize;
byte eeptemp;
word addrhi;
word addrlo;
@ -81,28 +80,110 @@ byte eepcount = (sizeof(eepid) / sizeof(eepid[0])) / 2;
byte index;
word eepdata;
// CD BACKUP RAM
unsigned long bramSize = 0;
/******************************************
Menu
*****************************************/
// MD menu items
static const char MDMenuItem1[] PROGMEM = "Read Rom";
static const char MDMenuItem2[] PROGMEM = "Read Sram";
static const char MDMenuItem3[] PROGMEM = "Write Sram";
static const char MDMenuItem4[] PROGMEM = "Read EEPROM";
static const char MDMenuItem5[] PROGMEM = "Write EEPROM";
static const char MDMenuItem6[] PROGMEM = "Write Flashcart";
static const char MDMenuItem7[] PROGMEM = "Reset";
static const char* const menuOptionsMD[] PROGMEM = {MDMenuItem1, MDMenuItem2, MDMenuItem3, MDMenuItem4, MDMenuItem5, MDMenuItem6, MDMenuItem7};
static const char MDMenuItem1[] PROGMEM = "Game Cartridge";
static const char MDMenuItem2[] PROGMEM = "SegaCD RamCart";
static const char MDMenuItem3[] PROGMEM = "Flash Repro";
static const char MDMenuItem4[] PROGMEM = "Reset";
static const char* const menuOptionsMD[] PROGMEM = {MDMenuItem1, MDMenuItem2, MDMenuItem3, MDMenuItem4};
// Cart menu items
static const char MDCartMenuItem1[] PROGMEM = "Read Rom";
static const char MDCartMenuItem2[] PROGMEM = "Read Sram";
static const char MDCartMenuItem3[] PROGMEM = "Write Sram";
static const char MDCartMenuItem4[] PROGMEM = "Read EEPROM";
static const char MDCartMenuItem5[] PROGMEM = "Write EEPROM";
static const char MDCartMenuItem6[] PROGMEM = "Reset";
static const char* const menuOptionsMDCart[] PROGMEM = {MDCartMenuItem1, MDCartMenuItem2, MDCartMenuItem3, MDCartMenuItem4, MDCartMenuItem5, MDCartMenuItem6};
// Sega CD Ram Backup Cartridge menu items
static const char SCDMenuItem1[] PROGMEM = "Read Backup RAM";
static const char SCDMenuItem2[] PROGMEM = "Write Backup RAM";
static const char SCDMenuItem3[] PROGMEM = "Reset";
static const char* const menuOptionsSCD[] PROGMEM = {SCDMenuItem1, SCDMenuItem2, SCDMenuItem3};
// Sega start menu
void segaMenu() {
display_Clear();
display_Update();
setup_MD();
mode = mode_MD;
void mdMenu() {
// create menu with title and 3 options to choose from
unsigned char mdDev;
// Copy menuOptions out of progmem
convertPgm(menuOptionsMD, 4);
mdDev = question_box(F("Select MD device"), menuOptions, 4, 0);
// wait for user choice to come back from the question box menu
switch (mdDev)
{
case 0:
display_Clear();
display_Update();
setup_MD();
mode = mode_MD_Cart;
break;
case 1:
display_Clear();
display_Update();
setup_MD();
mode = mode_SEGA_CD;
break;
case 2:
display_Clear();
display_Update();
setup_MD();
mode = mode_MD_Cart;
// Change working dir to root
filePath[0] = '\0';
sd.chdir("/");
fileBrowser(F("Select file"));
display_Clear();
// Setting CS(PH3) LOW
PORTH &= ~(1 << 3);
// ID flash
resetFlash_MD();
idFlash_MD();
resetFlash_MD();
print_Msg(F("Flash ID: "));
println_Msg(flashid);
if (strcmp(flashid, "C2F1") == 0) {
println_Msg(F("MX29F1610 detected"));
flashSize = 2097152;
}
else {
print_Error(F("Error: Unknown flashrom"), true);
}
display_Update();
eraseFlash_MD();
resetFlash_MD();
blankcheck_MD();
write29F1610_MD();
resetFlash_MD();
delay(1000);
resetFlash_MD();
delay(1000);
verifyFlash_MD();
// Set CS(PH3) HIGH
PORTH |= (1 << 3);
println_Msg(F(""));
println_Msg(F("Press Button..."));
display_Update();
wait();
break;
case 3:
resetArduino();
break;
}
}
void mdMenu() {
void mdCartMenu() {
// create menu with title and 7 options to choose from
unsigned char mainMenu;
// Copy menuOptions out of progmem
@ -189,43 +270,6 @@ void mdMenu() {
break;
case 5:
// Change working dir to root
filePath[0] = '\0';
sd.chdir("/");
fileBrowser(F("Select file"));
display_Clear();
// Setting CS(PH3) LOW
PORTH &= ~(1 << 3);
// ID flash
resetFlash_MD();
idFlash_MD();
resetFlash_MD();
print_Msg(F("Flash ID: "));
println_Msg(flashid);
if (strcmp(flashid, "C2F1") == 0) {
println_Msg(F("MX29F1610 detected"));
flashSize = 2097152;
}
else {
print_Error(F("Error: Unknown flashrom"), true);
}
display_Update();
eraseFlash_MD();
resetFlash_MD();
blankcheck_MD();
write29F1610_MD();
resetFlash_MD();
delay(1000);
resetFlash_MD();
delay(1000);
verifyFlash_MD();
// Set CS(PH3) HIGH
PORTH |= (1 << 3);
break;
case 6:
// Reset
resetArduino();
break;
@ -236,6 +280,49 @@ void mdMenu() {
wait();
}
void segaCDMenu() {
// create menu with title and 3 options to choose from
unsigned char scdMenu;
// Copy menuOptions out of progmem
convertPgm(menuOptionsSCD, 3);
scdMenu = question_box(F("SEGA CD RAM"), menuOptions, 3, 0);
// wait for user choice to come back from the question box menu
switch (scdMenu)
{
case 0:
display_Clear();
if (bramSize > 0)
readBram_MD();
else {
print_Error(F("Not CD Backup RAM Cart"), false);
}
break;
case 1:
display_Clear();
if (bramSize > 0) {
// Launch file browser
fileBrowser(F("Select brm file"));
display_Clear();
writeBram_MD();
}
else {
print_Error(F("Not CD Backup RAM Cart"), false);
}
break;
case 2:
// Reset
asm volatile (" jmp 0");
break;
}
println_Msg(F(""));
println_Msg(F("Press Button..."));
display_Update();
wait();
}
/******************************************
Setup
*****************************************/
@ -455,6 +542,12 @@ void getCartInfo_MD() {
}
}
// CD Backup RAM Cart Check
// 4 = 128KB (2045 Blocks) Sega CD Backup RAM Cart
// 6 = 512KB (8189 Blocks) Ultra CD Backup RAM Cart (Aftermarket)
word bramCheck = readWord_MD(0x00);
if (((bramCheck == 0x0004) && (chksum == 0x0004)) || ((bramCheck == 0x0006) && (chksum == 0x0006)))
bramSize = pow(2, bramCheck) * 0x2000;
if (saveType != 4) { // NOT SERIAL EEPROM
// Check if cart has sram
saveType = 0;
@ -1723,6 +1816,86 @@ void writeEEP_MD() {
dataIn_MD();
}
//******************************************
// CD Backup RAM Functions
//******************************************
void readBram_MD() {
dataIn_MD();
// Get name, add extension and convert to char array for sd lib
strcpy(fileName, "Cart.brm");
// create a new folder for the save file
EEPROM_readAnything(10, foldern);
sd.chdir();
sprintf(folder, "MD/RAM/%d", foldern);
sd.mkdir(folder, true);
sd.chdir(folder);
// write new folder number back to eeprom
foldern = foldern + 1;
EEPROM_writeAnything(10, foldern);
println_Msg(F("Reading..."));
display_Update();
// Open file on sd card
if (!myFile.open(fileName, O_RDWR | O_CREAT)) {
print_Error(F("SD Error"), true);
}
for (unsigned long currByte = 0; currByte < bramSize; currByte += 512) {
for (int i = 0; i < 512; i++) {
sdBuffer[i] = readWord_MD(0x300000 + currByte + i);
}
myFile.write(sdBuffer, 512);
}
// Close the file:
myFile.close();
println_Msg(F(""));
display_Clear();
print_Msg(F("Saved to "));
print_Msg(folder);
display_Update();
}
void writeBram_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)) {
// 0x700000-0x7FFFFF: Writes by /LWR latch D0; 1=RAM write enabled, 0=disabled
writeWord_MD(0x380000, 1); // Enable BRAM Writes
for (unsigned long currByte = 0; currByte < bramSize; currByte += 512) {
myFile.read(sdBuffer, 512);
for (int i = 0; i < 512; i++) {
writeWord_MD(0x300000 + currByte + i, sdBuffer[i]);
}
}
writeWord_MD(0x380000, 0); // Disable BRAM Writes
// Close the file:
myFile.close();
println_Msg(F(""));
display_Clear();
println_Msg(F("Done"));
display_Update();
}
else {
print_Error(F("SD Error"), true);
}
dataIn_MD();
}
//******************************************
// End of File
//******************************************

View File

@ -50,7 +50,8 @@ static const char n64MenuItem1[] PROGMEM = "Game Cartridge";
static const char n64MenuItem2[] PROGMEM = "Controller Pak";
static const char n64MenuItem3[] PROGMEM = "Flash Repro";
static const char n64MenuItem4[] PROGMEM = "Flash Gameshark";
static const char* const menuOptionsN64[] PROGMEM = {n64MenuItem1, n64MenuItem2, n64MenuItem3, n64MenuItem4};
static const char n64MenuItem5[] PROGMEM = "Reset";
static const char* const menuOptionsN64[] PROGMEM = {n64MenuItem1, n64MenuItem2, n64MenuItem3, n64MenuItem4, n64MenuItem5};
// N64 controller menu items
static const char N64ContMenuItem1[] PROGMEM = "Test Controller";
@ -133,6 +134,10 @@ void n64Menu() {
printCartInfo_N64();
mode = mode_N64_Cart;
break;
case 4:
resetArduino();
break;
}
}
@ -2160,68 +2165,66 @@ readn64rom:
unsigned long timeElapsed = (millis() - startTime) / 1000; // seconds
if (n64crc) {
print_Msg(F("Check CRC: "));
display_Update();
// convert checksum to string
char crcStr[9];
sprintf(crcStr, "%08lx", ~oldcrc32);
// Print checksum
println_Msg(crcStr);
display_Update();
print_Msg(F("CRC: "));
display_Update();
// convert checksum to string
char crcStr[9];
sprintf(crcStr, "%08lx", ~oldcrc32);
// Print checksum
println_Msg(crcStr);
display_Update();
// Search n64.txt for crc
if (searchCRC(crcStr)) {
// Dump was a known good rom
println_Msg(F("Checksum matches"));
}
else {
// Dump was bad or unknown
rgb.setColor(255, 0, 0);
// let bad crc show a short while
delay(3000);
// N64 CRC32 error Menu
unsigned char CRCMenu;
// Copy menuOptions out of progmem
convertPgm(menuOptionsN64CRC, 3);
CRCMenu = question_box(F("CRC ERROR "), menuOptions, 3, 0);
// wait for user choice to come back from the question box menu
switch (CRCMenu)
{
case 0:
// Change to last directory
sd.chdir(folder);
// Delete old file
if (!myFile.open(fileName, O_RDWR | O_CREAT)) {
print_Error(F("SD Error"), true);
}
if (!myFile.remove()) {
print_Error(F("Delete Error"), true);
}
// Dump again
display_Clear();
println_Msg(F("Reading Rom..."));
display_Update();
rgb.setColor(0, 0, 0);
goto readn64rom;
break;
case 1:
// Return to N64 menu
break;
case 2:
// Reset
resetArduino();
break;
}
}
display_Update();
// Search n64.txt for crc
if (searchCRC(crcStr)) {
// Dump was a known good rom
println_Msg(F("Checksum matches"));
}
else {
// Dump was bad or unknown
rgb.setColor(255, 0, 0);
// let bad crc show a short while
delay(3000);
// N64 CRC32 error Menu
unsigned char CRCMenu;
// Copy menuOptions out of progmem
convertPgm(menuOptionsN64CRC, 3);
CRCMenu = question_box(F("CRC ERROR "), menuOptions, 3, 0);
// wait for user choice to come back from the question box menu
switch (CRCMenu)
{
case 0:
// Change to last directory
sd.chdir(folder);
// Delete old file
if (!myFile.open(fileName, O_RDWR | O_CREAT)) {
print_Error(F("SD Error"), true);
}
if (!myFile.remove()) {
print_Error(F("Delete Error"), true);
}
// Dump again
display_Clear();
println_Msg(F("Reading Rom..."));
display_Update();
rgb.setColor(0, 0, 0);
goto readn64rom;
break;
case 1:
// Return to N64 menu
break;
case 2:
// Reset
resetArduino();
break;
}
}
display_Update();
print_Msg(F("Done ("));
print_Msg(timeElapsed); // include elapsed time

30
Cart_Reader/NES.ino Normal file
View File

@ -0,0 +1,30 @@
//******************************************
// NES MODULE
//******************************************
// unfinished and untested
/******************************************
Variables
*****************************************/
/******************************************
Menu
*****************************************/
void nesMenu() {
}
/******************************************
Setup
*****************************************/
/******************************************
Low level functions
*****************************************/
/******************************************
NES functions
*****************************************/
//******************************************
// End of File
//******************************************

View File

@ -25,9 +25,6 @@
/******************************************
Prototype Declarations
*****************************************/
void pcsMenu(void);
void pceMenu(void);
/* Several PCE dedicated functions */
void pin_read_write_PCE(void);
void pin_init_PCE(void);

253
Cart_Reader/SMS.ino Normal file
View File

@ -0,0 +1,253 @@
//******************************************
// 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:
cartSize = 8 * 1024;
break;
case 0xb:
cartSize = 16 * 1024;
break;
case 0xc:
cartSize = 32 * 1024;
break;
case 0xd:
cartSize = 48 * 1024;
break;
case 0xe:
cartSize = 64 * 1024;
break;
case 0xf:
cartSize = 128 * 1024;
break;
case 0x0:
cartSize = 256 * 1024;
break;
case 0x1:
cartSize = 512 * 1024;
break;
case 0x2:
cartSize = 512 * 1024;
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
if (enable_OLED) {
println_Msg(F("Press Button..."));
display_Update();
wait();
}
}
// 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
//******************************************