2023-04-06 16:04:50 +02:00
//***********************************************************
// SEGA MASTER SYSTEM / MARK III / GAME GEAR / SG-1000 MODULE
//***********************************************************
2022-07-17 14:50:59 +02:00
# ifdef enable_SMS
2022-06-16 17:57:00 +02:00
2023-04-06 16:04:50 +02:00
//******************************************
// Menus
//******************************************
// Adapters menu
static const char SMSAdapterItem1 [ ] PROGMEM = " SMS/MarkIII raphnet " ;
static const char SMSAdapterItem2 [ ] PROGMEM = " SMS Retrode " ;
static const char SMSAdapterItem3 [ ] PROGMEM = " SMS Retron3in1 " ;
static const char SMSAdapterItem4 [ ] PROGMEM = " GameGear Retrode " ;
static const char SMSAdapterItem5 [ ] PROGMEM = " GameGear Retron3in1 " ;
static const char SMSAdapterItem6 [ ] PROGMEM = " SG-1000 raphnet " ;
static const char * const SMSAdapterMenu [ ] PROGMEM = { SMSAdapterItem1 , SMSAdapterItem2 , SMSAdapterItem3 , SMSAdapterItem4 , SMSAdapterItem5 , SMSAdapterItem6 } ;
// Operations menu
static const char SMSOperationItem1 [ ] PROGMEM = " Read Rom " ;
static const char SMSOperationItem2 [ ] PROGMEM = " Read from SRAM " ;
static const char SMSOperationItem3 [ ] PROGMEM = " Write to SRAM " ;
static const char * const SMSOperationMenu [ ] PROGMEM = { SMSOperationItem1 , SMSOperationItem2 , SMSOperationItem3 , string_reset2 } ;
// Rom sizes menu
static const char SMSRomSizeItem1 [ ] PROGMEM = " 8 KB " ;
static const char SMSRomSizeItem2 [ ] PROGMEM = " 16 KB " ;
static const char SMSRomSizeItem3 [ ] PROGMEM = " 24 KB " ;
static const char SMSRomSizeItem4 [ ] PROGMEM = " 32 KB " ;
2023-06-26 12:04:00 +02:00
static const char SMSRomSizeItem5 [ ] PROGMEM = " 40 KB " ; //SG-1000 40k mapping not yet supported
static const char SMSRomSizeItem6 [ ] PROGMEM = " 48 KB " ; //SG-1000 40k mapping not yet supported
2023-04-06 16:04:50 +02:00
static const char SMSRomSizeItem7 [ ] PROGMEM = " 64 KB " ;
static const char SMSRomSizeItem8 [ ] PROGMEM = " 128 KB " ;
static const char SMSRomSizeItem9 [ ] PROGMEM = " 256 KB " ;
static const char SMSRomSizeItem10 [ ] PROGMEM = " 512 KB " ;
static const char SMSRomSizeItem11 [ ] PROGMEM = " 1024 KB " ;
2023-06-26 12:04:00 +02:00
static const char * const SG1RomSizeMenu [ ] PROGMEM = { SMSRomSizeItem1 , SMSRomSizeItem2 , SMSRomSizeItem3 , SMSRomSizeItem4 } ; // Rom sizes for SG-1000
static const char * const SMSRomSizeMenu [ ] PROGMEM = { SMSRomSizeItem4 , SMSRomSizeItem7 , SMSRomSizeItem8 , SMSRomSizeItem9 , SMSRomSizeItem10 , SMSRomSizeItem11 } ; // Rom sizes for SMS and GG
2023-04-06 16:04:50 +02:00
// Init systems
2023-06-26 12:04:00 +02:00
static bool system_sms = false ; // SMS or MarkIII
static bool system_gg = false ; // GameGear
static bool system_sg1000 = false ; // SG-1000
2023-04-06 16:04:50 +02:00
// Init adapters
2023-06-26 12:04:00 +02:00
static bool adapter_raphnet = false ; // raphet adapater (SMS-to-MD or MIII-to-MD)
static bool adapter_retrode = false ; // Retrode adapter (SMS-to-MD or GG-to-MD)
static bool adapter_retron = false ; // Retron 3in1 adapter (SMS-to-MD or GG-to-MD)
2023-04-06 16:04:50 +02:00
//*********************************************************
// Main menu with systems/adapters setups to choose from
//*********************************************************
void smsMenu ( ) {
unsigned char SMSSetup ;
convertPgm ( SMSAdapterMenu , 6 ) ;
SMSSetup = question_box ( F ( " Select your setup " ) , menuOptions , 6 , 0 ) ;
2022-06-16 17:57:00 +02:00
2023-04-06 16:04:50 +02:00
switch ( SMSSetup ) {
2022-06-16 17:57:00 +02:00
case 0 :
2023-04-06 16:04:50 +02:00
// SMS or MarkIII with raphnet adapter
system_sms = true ;
adapter_raphnet = true ;
2022-06-16 17:57:00 +02:00
break ;
2023-06-26 12:04:00 +02:00
case 1 :
2023-04-06 16:04:50 +02:00
// SMS with Retrode adapter
system_sms = true ;
adapter_retrode = true ;
2022-06-16 17:57:00 +02:00
break ;
case 2 :
2023-04-06 16:04:50 +02:00
// SMS with Retron 3in1 adapter
system_sms = true ;
adapter_retron = true ;
2022-06-16 17:57:00 +02:00
break ;
case 3 :
2023-04-06 16:04:50 +02:00
// GameGear with Retrode adapter
system_gg = true ;
adapter_retrode = true ;
2022-06-16 17:57:00 +02:00
break ;
case 4 :
2023-04-06 16:04:50 +02:00
// GameGear with Retron 3in1 adapter
system_gg = true ;
adapter_retron = true ;
break ;
case 5 :
// SG-1000 with raphnet adapter
system_sg1000 = true ;
adapter_raphnet = true ;
2022-06-16 17:57:00 +02:00
break ;
}
2023-04-06 16:04:50 +02:00
for ( ; ; ) smsOperations ( ) ;
2022-06-16 17:57:00 +02:00
}
2023-04-06 16:04:50 +02:00
//****************************************************
// Create custom menu depending on selected setup
//****************************************************
void smsOperations ( ) {
unsigned char SMSOperation = ' 3 ' ;
convertPgm ( SMSOperationMenu , 4 ) ;
if ( system_sms ) {
if ( adapter_raphnet ) {
SMSOperation = question_box ( F ( " SMS/MarkIII raphnet " ) , menuOptions , 4 , 0 ) ;
} else if ( adapter_retrode ) {
SMSOperation = question_box ( F ( " SMS Retrode " ) , menuOptions , 4 , 0 ) ;
} else if ( adapter_retron ) {
SMSOperation = question_box ( F ( " SMS Retron 3in1 " ) , menuOptions , 4 , 0 ) ;
}
} else if ( system_gg ) {
if ( adapter_retrode ) {
SMSOperation = question_box ( F ( " GameGear Retrode " ) , menuOptions , 4 , 0 ) ;
} else if ( adapter_retron ) {
SMSOperation = question_box ( F ( " GameGear Retron 3in1 " ) , menuOptions , 4 , 0 ) ;
}
} else if ( system_sg1000 ) {
SMSOperation = question_box ( F ( " SG-1000 raphnet " ) , menuOptions , 1 , 0 ) ;
}
switch ( SMSOperation ) {
2022-06-16 17:57:00 +02:00
case 0 :
2023-04-06 16:04:50 +02:00
// Read ROM
mode = mode_SMS ;
setup_SMS ( ) ;
readROM_SMS ( ) ;
2022-06-16 17:57:00 +02:00
break ;
case 1 :
2023-04-06 16:04:50 +02:00
// Read SRAM
mode = mode_SMS ;
setup_SMS ( ) ;
readSRAM_SMS ( ) ;
2022-06-16 17:57:00 +02:00
break ;
case 2 :
2023-04-06 16:04:50 +02:00
// Write SRAM
mode = mode_SMS ;
setup_SMS ( ) ;
writeSRAM_SMS ( ) ;
2022-06-16 17:57:00 +02:00
break ;
case 3 :
2023-04-06 16:04:50 +02:00
// Reset
resetArduino ( ) ;
2022-06-16 17:57:00 +02:00
break ;
}
2023-04-06 16:04:50 +02:00
display_Update ( ) ;
wait ( ) ;
2022-06-16 17:57:00 +02:00
}
2023-04-06 16:04:50 +02:00
//********************************
// Setup I/O
//********************************
2022-06-16 17:57:00 +02:00
void setup_SMS ( ) {
2023-06-26 12:04:00 +02:00
# ifdef ENABLE_VSELECT
// Set Automatic Voltage Selection to 5V
setVoltage ( VOLTS_SET_5V ) ;
# endif
2022-06-16 17:57:00 +02:00
// Set Address Pins to Output
//A0-A7
DDRF = 0xFF ;
//A8-A14
DDRK = 0xFF ;
//A15
DDRH | = ( 1 < < 3 ) ;
2023-04-06 16:04:50 +02:00
//For Retrode adapter
if ( adapter_retrode ) {
2022-06-16 17:57:00 +02:00
PORTH & = ~ ( ( 1 < < 0 ) | ( 1 < < 3 ) | ( 1 < < 5 ) ) ;
PORTL & = ~ ( 1 < < 1 ) ;
DDRH & = ~ ( ( 1 < < 0 ) | ( 1 < < 5 ) ) ;
DDRL & = ~ ( ( 1 < < 1 ) ) ;
// Set Control Pins to Output OE(PH6)
DDRH | = ( 1 < < 6 ) ;
// WR(PL5) and RD(PL6)
DDRL | = ( 1 < < 5 ) | ( 1 < < 6 ) ;
// Setting OE(PH6) HIGH
PORTH | = ( 1 < < 6 ) ;
// Setting WR(PL5) and RD(PL6) HIGH
PORTL | = ( 1 < < 5 ) | ( 1 < < 6 ) ;
2023-06-26 12:04:00 +02:00
}
2023-04-06 16:04:50 +02:00
// For Raphnet and Retron adapters
else {
2022-06-16 17:57:00 +02:00
// Set Control Pins to Output RST(PH0) WR(PH5) OE(PH6)
DDRH | = ( 1 < < 0 ) | ( 1 < < 5 ) | ( 1 < < 6 ) ;
// CE(PL1)
DDRL | = ( 1 < < 1 ) ;
// Setting RST(PH0) WR(PH5) OE(PH6) HIGH
PORTH | = ( 1 < < 0 ) | ( 1 < < 5 ) | ( 1 < < 6 ) ;
// CE(PL1)
PORTL | = ( 1 < < 1 ) ;
}
2023-04-06 16:04:50 +02:00
if ( ! system_sg1000 ) {
// SMS/GG ROM has 16KB banks which can be mapped to one of three slots via register writes
// Register Slot Address space
// $fffd 0 $0000-$3fff
// $fffe 1 $4000-$7fff
// $ffff 2 $8000-$bfff
// Disable sram
writeByte_SMS ( 0xFFFC , 0 ) ;
// Map first 3 banks so we can read-out the header info
writeByte_SMS ( 0xFFFD , 0 ) ;
writeByte_SMS ( 0xFFFE , 1 ) ;
writeByte_SMS ( 0xFFFF , 2 ) ;
}
2022-06-16 17:57:00 +02:00
delay ( 400 ) ;
2023-04-06 16:04:50 +02:00
// Read and print cart info
2022-06-16 17:57:00 +02:00
getCartInfo_SMS ( ) ;
}
2023-04-06 16:04:50 +02:00
//*****************************************
2023-06-26 12:04:00 +02:00
// Low level functions
2023-04-06 16:04:50 +02:00
//*****************************************
2022-06-16 17:57:00 +02:00
void writeByte_SMS ( word myAddress , byte myData ) {
2023-04-06 16:04:50 +02:00
if ( adapter_retrode & & system_gg ) {
2022-06-16 17:57:00 +02:00
// Set Data Pins (D8-D15) to Output
DDRA = 0xFF ;
} else {
// Set Data Pins (D0-D7) to Output
DDRC = 0xFF ;
}
// Set address
PORTF = myAddress & 0xFF ;
PORTK = ( myAddress > > 8 ) & 0xFF ;
2023-04-06 16:04:50 +02:00
if ( ! adapter_retrode ) {
2022-06-16 17:57:00 +02:00
// CE(PH3) and OE(PH6) are connected
PORTH = ( PORTH & 0 b11110111 ) | ( ( myAddress > > 12 ) & 0 b00001000 ) ;
}
// Output data
2023-04-06 16:04:50 +02:00
if ( adapter_retrode & & system_gg ) {
2022-06-16 17:57:00 +02:00
PORTA = myData ;
} else {
PORTC = myData ;
}
// Arduino running at 16Mhz -> one nop = 62.5ns
// Wait till output is stable
2022-10-13 09:49:03 +02:00
__asm__ ( " nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t " ) ;
2022-06-16 17:57:00 +02:00
2023-04-06 16:04:50 +02:00
if ( adapter_retrode ) {
2022-06-16 17:57:00 +02:00
// Switch WR(PL5) and OE/CE(PH6) to LOW
PORTL & = ~ ( 1 < < 5 ) ;
PORTH & = ~ ( 1 < < 6 ) ;
} else {
// Switch CE(PL1) and WR(PH5) to LOW
PORTL & = ~ ( 1 < < 1 ) ;
PORTH & = ~ ( 1 < < 5 ) ;
}
// Leave WR low for at least 60ns
2022-10-13 09:49:03 +02:00
__asm__ ( " nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t " ) ;
2022-06-16 17:57:00 +02:00
2023-04-06 16:04:50 +02:00
if ( adapter_retrode ) {
2022-06-16 17:57:00 +02:00
// Switch WR(PL5) and OE/CE(PH6) to HIGH
PORTH | = ( 1 < < 6 ) ;
PORTL | = ( 1 < < 5 ) ;
} else {
// Switch CE(PL1) and WR(PH5) to HIGH
PORTH | = ( 1 < < 5 ) ;
PORTL | = ( 1 < < 1 ) ;
}
// Leave WR high for at least 50ns
2022-10-13 09:49:03 +02:00
__asm__ ( " nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t " ) ;
2022-06-16 17:57:00 +02:00
2023-04-06 16:04:50 +02:00
if ( adapter_retrode & & system_gg ) {
2022-06-16 17:57:00 +02:00
// Set Data Pins (D8-D15) to Input
DDRA = 0x00 ;
} else {
// Set Data Pins (D0-D7) to Input
DDRC = 0x00 ;
}
}
byte readByte_SMS ( word myAddress ) {
2023-04-06 16:04:50 +02:00
if ( adapter_retrode & & system_gg ) {
2022-06-16 17:57:00 +02:00
// Set Data Pins (D8-D15) to Input
DDRA = 0x00 ;
} else {
// Set Data Pins (D0-D7) to Input
DDRC = 0x00 ;
}
// Set Address
PORTF = myAddress & 0xFF ;
PORTK = ( myAddress > > 8 ) & 0xFF ;
2023-04-06 16:04:50 +02:00
if ( ! adapter_retrode ) {
2022-06-16 17:57:00 +02:00
// CE(PH3) and OE(PH6) are connected
PORTH = ( PORTH & 0 b11110111 ) | ( ( myAddress > > 12 ) & 0 b00001000 ) ;
}
2022-10-13 09:49:03 +02:00
__asm__ ( " nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t " ) ;
2022-06-16 17:57:00 +02:00
2023-04-06 16:04:50 +02:00
if ( adapter_retrode ) {
2022-06-16 17:57:00 +02:00
// Switch RD(PL6) and OE(PH6) to LOW
PORTL & = ~ ( 1 < < 6 ) ;
PORTH & = ~ ( 1 < < 6 ) ;
} else {
// Switch CE(PL1) and OE(PH6) to LOW
PORTL & = ~ ( 1 < < 1 ) ;
PORTH & = ~ ( 1 < < 6 ) ;
}
2022-10-13 09:49:03 +02:00
__asm__ ( " nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t " ) ;
2022-06-16 17:57:00 +02:00
// Read
2023-04-06 16:04:50 +02:00
byte tempByte = ( adapter_retrode & & system_gg ) ? PINA : PINC ;
2022-06-16 17:57:00 +02:00
2023-04-06 16:04:50 +02:00
if ( adapter_retrode ) {
2022-06-16 17:57:00 +02:00
// Switch RD(PL6) and OE(PH6) to HIGH
PORTH | = ( 1 < < 6 ) ;
PORTL | = ( 1 < < 6 ) ;
} else {
// Switch CE(PL1) and OE(PH6) to HIGH
PORTH | = ( 1 < < 6 ) ;
PORTL | = ( 1 < < 1 ) ;
}
2022-10-13 09:49:03 +02:00
__asm__ ( " nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t " ) ;
2022-06-16 17:57:00 +02:00
return tempByte ;
}
byte readNibble ( byte data , byte number ) {
2023-04-06 16:04:50 +02:00
return ( ( data > > ( number * 4 ) ) & 0xF ) ;
2022-06-16 17:57:00 +02:00
}
2023-04-06 16:04:50 +02:00
//*****************************************
// Cartridges functions
//*****************************************
2023-06-26 12:04:00 +02:00
void getCartInfo_SMS ( ) {
2023-04-06 16:04:50 +02:00
// Get rom size
switch ( readNibble ( readByte_SMS ( 0x7FFF ) , 0 ) ) {
// Adding UL gets rid of integer overflow compiler warning
2022-06-16 17:57:00 +02:00
case 0xa :
2022-10-13 09:49:03 +02:00
cartSize = 8 * 1024UL ;
2022-06-16 17:57:00 +02:00
break ;
case 0xb :
2022-10-13 09:49:03 +02:00
cartSize = 16 * 1024UL ;
2022-06-16 17:57:00 +02:00
break ;
case 0xc :
2022-10-13 09:49:03 +02:00
cartSize = 32 * 1024UL ;
2022-06-16 17:57:00 +02:00
break ;
case 0xd :
2022-10-13 09:49:03 +02:00
cartSize = 48 * 1024UL ;
2022-06-16 17:57:00 +02:00
break ;
case 0xe :
2022-10-13 09:49:03 +02:00
cartSize = 64 * 1024UL ;
2022-06-16 17:57:00 +02:00
break ;
case 0xf :
2022-10-13 09:49:03 +02:00
cartSize = 128 * 1024UL ;
2022-06-16 17:57:00 +02:00
break ;
case 0x0 :
2022-10-13 09:49:03 +02:00
cartSize = 256 * 1024UL ;
2022-06-16 17:57:00 +02:00
break ;
case 0x1 :
2022-10-13 09:49:03 +02:00
cartSize = 512 * 1024UL ;
2022-06-16 17:57:00 +02:00
break ;
case 0x2 :
2022-10-13 09:49:03 +02:00
cartSize = 512 * 1024UL ;
2022-06-16 17:57:00 +02:00
break ;
case 0x3 :
// 0x3 is (only?) used in The Pro Yakyuu '91 (Game Gear)
2022-10-13 09:49:03 +02:00
cartSize = 128 * 1024UL ;
2022-06-16 17:57:00 +02:00
break ;
default :
2022-10-13 09:49:03 +02:00
cartSize = 48 * 1024UL ;
2022-06-16 17:57:00 +02:00
// LED Error
setColor_RGB ( 0 , 0 , 255 ) ;
break ;
}
2023-04-06 16:04:50 +02:00
// Get rom name (expecting "TMR SEGA" string)
2022-06-16 17:57:00 +02:00
for ( byte i = 0 ; i < 8 ; i + + ) {
2023-04-06 16:04:50 +02:00
romName [ i ] = char ( readByte_SMS ( 0x7FF0 + i ) ) ;
2022-06-16 17:57:00 +02:00
}
romName [ 8 ] = ' \0 ' ;
2023-04-06 16:04:50 +02:00
// Attempt to detect cart size by checking if "TMR SEGA" is mirrored
2022-06-16 17:57:00 +02:00
unsigned long mirror_offset = cartSize ;
char romName2 [ 9 ] ;
while ( mirror_offset < 1024 * 1024UL ) {
byte bank = 1 + ( mirror_offset / ( 16 * 1024UL ) ) ;
2023-04-06 16:04:50 +02:00
writeByte_SMS ( 0xfffe , bank ) ;
2022-06-16 17:57:00 +02:00
for ( byte i = 0 ; i < 8 ; i + + ) {
2023-04-06 16:04:50 +02:00
romName2 [ i ] = char ( readByte_SMS ( 0x7FF0 + i ) ) ;
2022-06-16 17:57:00 +02:00
}
romName2 [ 8 ] = ' \0 ' ;
2023-04-06 16:04:50 +02:00
2022-06-16 17:57:00 +02:00
// print_Msg(F("Name2: "));
// println_Msg(romName2);
// print_Msg(F("from bank "));
// print_Msg(bank);
// print_Msg(F(" offset "));
2023-04-06 16:04:50 +02:00
// print_Msg_PaddedHex32(mirror_offset + 0x7FF0);
2022-06-16 17:57:00 +02:00
// println_Msg(F(""));
2023-04-06 16:04:50 +02:00
2022-06-16 17:57:00 +02:00
if ( strcmp ( romName2 , romName ) = = 0 ) {
break ;
}
2023-04-06 16:04:50 +02:00
2022-06-16 17:57:00 +02:00
if ( cartSize = = 48 * 1024UL ) {
cartSize = 64 * 1024UL ;
} else {
cartSize * = 2 ;
}
mirror_offset = cartSize ;
}
2023-04-06 16:04:50 +02:00
2022-06-16 17:57:00 +02:00
writeByte_SMS ( 0xFFFE , 1 ) ;
// Fix for "Fantasy Zone (J) (V1.0)" that has not the normal header, but "COPYRIGHT SEGAPRG. BY T.ASAI".
char headerFZ [ 29 ] ;
if ( strcmp ( romName , " G. BY T.A " ) ! = 0 ) {
for ( byte i = 0 ; i < 28 ; i + + ) {
2023-04-06 16:04:50 +02:00
headerFZ [ i ] = char ( readByte_SMS ( 0x7FE0 + i ) ) ;
2022-06-16 17:57:00 +02:00
}
headerFZ [ 28 ] = ' \0 ' ;
if ( strcmp ( headerFZ , " COPYRIGHT SEGAPRG. BY T.ASAI " ) = = 0 ) {
strcpy ( romName , " TMR SEGA " ) ;
2022-10-13 09:49:03 +02:00
cartSize = 128 * 1024UL ;
2022-06-16 17:57:00 +02:00
}
}
2023-04-06 16:04:50 +02:00
// If "TMR SEGA" header is not found
2023-06-26 12:04:00 +02:00
if ( strcmp ( romName , " TMR SEGA " ) ! = 0 ) {
2023-04-06 16:04:50 +02:00
// Set rom size manually
unsigned char SMSRomSize ;
if ( system_sg1000 ) {
// Rom sizes for SG-1000
convertPgm ( SG1RomSizeMenu , 4 ) ;
SMSRomSize = question_box ( F ( " Select ROM size " ) , menuOptions , 4 , 0 ) ;
switch ( SMSRomSize ) {
case 0 :
2023-06-26 12:04:00 +02:00
cartSize = 8 * 1024UL ; // 8KB
2023-04-06 16:04:50 +02:00
break ;
case 1 :
2023-06-26 12:04:00 +02:00
cartSize = 16 * 1024UL ; // 16KB
2023-04-06 16:04:50 +02:00
break ;
case 2 :
2023-06-26 12:04:00 +02:00
cartSize = 24 * 1024UL ; // 24KB
2023-04-06 16:04:50 +02:00
break ;
case 3 :
2023-06-26 12:04:00 +02:00
cartSize = 32 * 1024UL ; // 32KB
2023-04-06 16:04:50 +02:00
break ;
2023-06-26 12:04:00 +02:00
//case 4:
// cartSize = 40 * 1024UL; // 40KB
// break;
//case 5:
// cartSize = 48 * 1024UL; // 48KB
// break;
2023-04-06 16:04:50 +02:00
}
} else {
// Rom sizes for SMS and GG
convertPgm ( SMSRomSizeMenu , 6 ) ;
SMSRomSize = question_box ( F ( " Select ROM size " ) , menuOptions , 6 , 0 ) ;
switch ( SMSRomSize ) {
case 0 :
2023-06-26 12:04:00 +02:00
cartSize = 32 * 1024UL ; // 32KB
2023-04-06 16:04:50 +02:00
break ;
case 1 :
2023-06-26 12:04:00 +02:00
cartSize = 64 * 1024UL ; // 64KB
2023-04-06 16:04:50 +02:00
break ;
case 2 :
2023-06-26 12:04:00 +02:00
cartSize = 128 * 1024UL ; // 128KB
2023-04-06 16:04:50 +02:00
break ;
case 3 :
2023-06-26 12:04:00 +02:00
cartSize = 256 * 1024UL ; // 256KB
2023-04-06 16:04:50 +02:00
break ;
case 4 :
2023-06-26 12:04:00 +02:00
cartSize = 512 * 1024UL ; // 512KB
2023-04-06 16:04:50 +02:00
break ;
case 5 :
2023-06-26 12:04:00 +02:00
cartSize = 1024 * 1024UL ; // 1MB
2023-04-06 16:04:50 +02:00
break ;
}
2022-06-16 17:57:00 +02:00
}
2023-04-06 16:04:50 +02:00
// Display cart info
2022-06-16 17:57:00 +02:00
display_Clear ( ) ;
2023-04-06 16:04:50 +02:00
println_Msg ( F ( " SMS/GG header not found " ) ) ;
2022-06-16 17:57:00 +02:00
println_Msg ( F ( " " ) ) ;
print_Msg ( F ( " Name: " ) ) ;
println_Msg ( romName ) ;
print_Msg ( F ( " Selected Size: " ) ) ;
print_Msg ( cartSize / 1024 ) ;
println_Msg ( F ( " KB " ) ) ;
println_Msg ( F ( " " ) ) ;
sprintf ( romName , " UNKNOWN " ) ;
}
2023-04-06 16:04:50 +02:00
// If "TMR SEGA" header is found
2022-06-16 17:57:00 +02:00
else {
display_Clear ( ) ;
2023-04-06 16:04:50 +02:00
if ( system_sms ) {
println_Msg ( F ( " SMS header info " ) ) ;
2022-10-13 09:49:03 +02:00
} else {
2023-04-06 16:04:50 +02:00
println_Msg ( F ( " GG header info " ) ) ;
2022-07-25 13:16:15 +02:00
}
2022-06-16 17:57:00 +02:00
println_Msg ( F ( " " ) ) ;
print_Msg ( F ( " Name: " ) ) ;
println_Msg ( romName ) ;
print_Msg ( F ( " Size: " ) ) ;
print_Msg ( cartSize / 1024 ) ;
println_Msg ( F ( " KB " ) ) ;
println_Msg ( F ( " " ) ) ;
}
2023-06-26 12:04:00 +02:00
// Wait for user input
# if (defined(enable_LCD) || defined(enable_OLED))
// Prints string out of the common strings array either with or without newline
print_STR ( press_button_STR , 1 ) ;
display_Update ( ) ;
wait ( ) ;
# endif
2023-04-06 16:04:50 +02:00
2022-06-16 17:57:00 +02:00
// Turn off LED
setColor_RGB ( 0 , 0 , 0 ) ;
}
2023-04-06 16:04:50 +02:00
//******************************************
// Read ROM and save it to the SD card
//******************************************
2022-06-16 17:57:00 +02:00
void readROM_SMS ( ) {
2022-10-27 22:25:34 +02:00
// Get name, add extension depending on the system and convert to char array for sd lib
EEPROM_readAnything ( 0 , foldern ) ;
2022-06-16 17:57:00 +02:00
strcpy ( fileName , romName ) ;
2023-04-06 16:04:50 +02:00
if ( system_sms ) {
strcat ( fileName , " .sms " ) ;
sprintf ( folder , " SMS/ROM/%s/%d " , romName , foldern ) ;
} else if ( system_gg ) {
2022-07-25 13:16:15 +02:00
strcat ( fileName , " .gg " ) ;
sprintf ( folder , " GG/ROM/%s/%d " , romName , foldern ) ;
2023-04-06 16:04:50 +02:00
} else {
2022-10-27 22:25:34 +02:00
strcat ( fileName , " .sg " ) ;
sprintf ( folder , " SG1000/ROM/%s/%d " , romName , foldern ) ;
2022-07-25 13:16:15 +02:00
}
2022-10-27 22:25:34 +02:00
// Create a new folder
2023-04-06 16:04:50 +02:00
sd . chdir ( " / " ) ;
2022-06-16 17:57:00 +02:00
sd . mkdir ( folder , true ) ;
sd . chdir ( folder ) ;
display_Clear ( ) ;
2022-10-21 15:59:06 +02:00
print_STR ( saving_to_STR , 0 ) ;
2022-06-16 17:57:00 +02:00
print_Msg ( folder ) ;
println_Msg ( F ( " /... " ) ) ;
display_Update ( ) ;
2023-04-06 16:04:50 +02:00
// Write new folder number back to eeprom
2022-06-16 17:57:00 +02:00
foldern = foldern + 1 ;
EEPROM_writeAnything ( 0 , foldern ) ;
// Open file on sd card
if ( ! myFile . open ( fileName , O_RDWR | O_CREAT ) ) {
2022-10-30 03:21:01 +01:00
print_FatalError ( sd_error_STR ) ;
2022-06-16 17:57:00 +02:00
}
2023-04-06 16:04:50 +02:00
// Set default bank size to 16KB
2022-06-16 17:57:00 +02:00
word bankSize = 16 * 1024UL ;
2023-04-06 16:04:50 +02:00
// For carts not using mappers (SG1000 or SMS/GG 32KB)
if ( ( system_sg1000 ) | | ( cartSize = = 32 * 1024UL ) ) {
2022-06-16 17:57:00 +02:00
bankSize = cartSize ;
}
2023-04-06 16:04:50 +02:00
// Initialize progress bar
2022-06-16 17:57:00 +02:00
uint32_t processedProgressBar = 0 ;
uint32_t totalProgressBar = ( uint32_t ) ( cartSize ) ;
draw_progressbar ( 0 , totalProgressBar ) ;
for ( byte currBank = 0x0 ; currBank < ( cartSize / bankSize ) ; currBank + + ) {
// Write current 16KB bank to slot 2 register 0xFFFF
2023-04-06 16:04:50 +02:00
if ( ! system_sg1000 ) {
2022-06-16 17:57:00 +02:00
writeByte_SMS ( 0xFFFF , currBank ) ;
}
// Blink led
blinkLED ( ) ;
2022-09-09 00:21:16 +02:00
2022-06-16 17:57:00 +02:00
// Read 16KB from slot 2 which starts at 0x8000
for ( word currBuffer = 0 ; currBuffer < bankSize ; currBuffer + = 512 ) {
// Fill SD buffer
for ( int currByte = 0 ; currByte < 512 ; currByte + + ) {
2023-04-06 16:04:50 +02:00
sdBuffer [ currByte ] = readByte_SMS ( ( ( system_sg1000 ) | | ( cartSize = = 32 * 1024UL ) ? 0 : 0x8000 ) + currBuffer + currByte ) ;
2022-06-16 17:57:00 +02:00
}
// hexdump for debugging:
// if (currBank == 0 && currBuffer == 0) {
// for (word xi = 0; xi < 0x100; xi++) {
// if (xi%16==0) {
// print_Msg_PaddedHex16(xi);
// print_Msg(F(" "));
// }
// print_Msg_PaddedHexByte(sdBuffer[xi]);
// if (xi>0&&((xi+1)%16)==0) {
// println_Msg(F(""));
// } else {
// print_Msg(F(" "));
// }
// }
// }
myFile . write ( sdBuffer , 512 ) ;
}
2023-04-06 16:04:50 +02:00
// Update progress bar
2022-06-16 17:57:00 +02:00
processedProgressBar + = bankSize ;
draw_progressbar ( processedProgressBar , totalProgressBar ) ;
}
2023-04-06 16:04:50 +02:00
// Close file
2022-06-16 17:57:00 +02:00
myFile . close ( ) ;
2023-04-06 16:04:50 +02:00
// Compare dump checksum with database values
if ( system_sms ) {
compareCRC ( " sms.txt " , 0 , 1 , 0 ) ;
} else if ( system_gg ) {
compareCRC ( " gg.txt " , 0 , 1 , 0 ) ;
} else {
compareCRC ( " sg1000.txt " , 0 , 1 , 0 ) ;
}
2023-06-26 12:04:00 +02:00
# ifdef global_log
save_log ( ) ;
# endif
2023-04-06 16:04:50 +02:00
print_STR ( press_button_STR , 1 ) ;
2022-06-16 17:57:00 +02:00
}
2023-04-06 16:04:50 +02:00
//******************************************
// Read SRAM and save to the SD card
///*****************************************
2022-06-16 17:57:00 +02:00
void readSRAM_SMS ( ) {
// Get name, add extension and convert to char array for sd lib
strcpy ( fileName , romName ) ;
2022-07-25 13:16:15 +02:00
strcat ( fileName , " .sav " ) ;
2022-06-16 17:57:00 +02:00
EEPROM_readAnything ( 0 , foldern ) ;
2023-04-06 16:04:50 +02:00
if ( system_gg ) {
2022-07-25 13:16:15 +02:00
sprintf ( folder , " GG/SAVE/%s/%d " , romName , foldern ) ;
2022-10-13 09:49:03 +02:00
} else {
2022-07-25 13:16:15 +02:00
sprintf ( folder , " SMS/SAVE/%s/%d " , romName , foldern ) ;
}
2023-04-06 16:04:50 +02:00
// Create a new folder
sd . chdir ( " / " ) ;
2022-06-16 17:57:00 +02:00
sd . mkdir ( folder , true ) ;
sd . chdir ( folder ) ;
display_Clear ( ) ;
2022-10-21 15:59:06 +02:00
print_STR ( saving_to_STR , 0 ) ;
2022-06-16 17:57:00 +02:00
print_Msg ( folder ) ;
println_Msg ( F ( " /... " ) ) ;
display_Update ( ) ;
// write new folder number back to eeprom
foldern = foldern + 1 ;
EEPROM_writeAnything ( 0 , foldern ) ;
2023-04-06 16:04:50 +02:00
// Create file on sd card
if ( myFile . open ( fileName , O_RDWR | O_CREAT ) ) {
// Write the whole 32KB
// When there is only 8KB of SRAM, the contents should be duplicated
word bankSize = 16 * 1024UL ;
for ( byte currBank = 0x0 ; currBank < 2 ; currBank + + ) {
writeByte_SMS ( 0xFFFC , 0x08 | ( currBank < < 2 ) ) ;
2022-06-16 17:57:00 +02:00
2023-04-06 16:04:50 +02:00
// Blink led
blinkLED ( ) ;
// Read 16KB from slot 2 which starts at 0x8000
for ( word currBuffer = 0 ; currBuffer < bankSize ; currBuffer + = 512 ) {
// Fill SD buffer
for ( int currByte = 0 ; currByte < 512 ; currByte + + ) {
sdBuffer [ currByte ] = readByte_SMS ( 0x8000 + currBuffer + currByte ) ;
}
myFile . write ( sdBuffer , 512 ) ;
2022-06-16 17:57:00 +02:00
}
}
2023-04-06 16:04:50 +02:00
// Close file
myFile . close ( ) ;
print_STR ( press_button_STR , 1 ) ;
display_Update ( ) ;
} else {
2023-06-26 12:04:00 +02:00
print_FatalError ( sd_error_STR ) ;
2022-06-16 17:57:00 +02:00
}
}
2023-04-06 16:04:50 +02:00
//**********************************************
// Read file from SD card and write it to SRAM
//**********************************************
2022-06-16 17:57:00 +02:00
void writeSRAM_SMS ( ) {
if ( false ) {
2022-10-30 03:21:01 +01:00
print_Error ( F ( " DISABLED " ) ) ;
2022-10-13 09:49:03 +02:00
} else {
2022-06-16 17:57:00 +02:00
fileBrowser ( F ( " Select file " ) ) ;
sd . chdir ( ) ;
sprintf ( filePath , " %s/%s " , filePath , fileName ) ;
display_Clear ( ) ;
println_Msg ( F ( " Restoring from " ) ) ;
println_Msg ( filePath ) ;
display_Update ( ) ;
if ( myFile . open ( filePath , O_READ ) ) {
// Get SRAM size from file, with a maximum of 32KB
uint32_t sramSize = myFile . fileSize ( ) ;
if ( sramSize > ( ( uint32_t ) 32 * ( uint32_t ) 1024 ) ) {
sramSize = ( uint32_t ) 32 * ( uint32_t ) 1024 ;
}
print_Msg ( F ( " sramSize: " ) ) ;
print_Msg ( sramSize ) ;
println_Msg ( F ( " " ) ) ;
word bankSize = 16 * 1024 ;
for ( word address = 0x0 ; address < sramSize ; address + = 512 ) {
byte currBank = address > = bankSize ? 1 : 0 ;
word page_address = address - ( currBank * bankSize ) ;
writeByte_SMS ( 0xFFFC , 0x08 | ( currBank < < 2 ) ) ;
// Blink led
blinkLED ( ) ;
myFile . read ( sdBuffer , 512 ) ;
for ( int x = 0 ; x < 512 ; x + + ) {
writeByte_SMS ( 0x8000 + page_address + x , sdBuffer [ x ] ) ;
}
}
2023-04-06 16:04:50 +02:00
// Close file
myFile . close ( ) ;
print_STR ( press_button_STR , 1 ) ;
2022-06-16 17:57:00 +02:00
display_Update ( ) ;
2022-10-13 09:49:03 +02:00
} else {
2022-10-30 03:21:01 +01:00
print_FatalError ( sd_error_STR ) ;
2022-06-16 17:57:00 +02:00
}
}
2022-10-13 09:49:03 +02:00
sd . chdir ( ) ; // root
filePath [ 0 ] = ' \0 ' ; // Reset filePath
2022-06-16 17:57:00 +02:00
}
# endif
//******************************************
// End of File
2023-04-06 16:04:50 +02:00
//******************************************