2021-01-27 08:05:25 +01:00
//******************************************
// SUPER NINTENDO MODULE
//******************************************
2024-03-02 17:26:35 +01:00
# ifdef ENABLE_SNES
2021-01-27 08:05:25 +01:00
/******************************************
Defines
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// SNES Hi and LoRom, SA is HI with different Sram dumping
# define EX 4
# define SA 3
# define HI 1
# define LO 0
/******************************************
Variables
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Define SNES Cart Reader Variables
2022-10-13 09:49:03 +02:00
int romSpeed = 0 ; // 0 = SlowROM, 3 = FastROM
int romChips = 0 ; // 0 = ROM only, 1 = ROM & RAM, 2 = ROM & Save RAM, 3 = ROM & DSP1, 4 = ROM & RAM & DSP1, 5 = ROM & Save RAM & DSP1, 19 = ROM & SFX
2021-01-27 08:05:25 +01:00
// 227 = ROM & RAM & GameBoy data, 243 = CX4, 246 = ROM & DSP2
2022-10-13 09:49:03 +02:00
byte romSizeExp = 0 ; // ROM-Size Exponent
2021-01-27 08:05:25 +01:00
boolean NP = false ;
byte cx4Type = 0 ;
byte cx4Map = 0 ;
boolean altconf = 0 ;
/******************************************
Menu
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// SNES/Nintendo Power SF Memory start menu
2022-10-08 23:07:15 +02:00
static const char snsMenuItem1 [ ] PROGMEM = " SNES/SFC cartridge " ;
static const char snsMenuItem2 [ ] PROGMEM = " SF Memory Cassette " ;
2021-01-27 08:05:25 +01:00
static const char snsMenuItem3 [ ] PROGMEM = " Satellaview BS-X " ;
2023-11-25 00:32:51 +01:00
static const char snsMenuItem4 [ ] PROGMEM = " Sufami Turbo " ;
2024-02-09 22:06:44 +01:00
static const char snsMenuItem5 [ ] PROGMEM = " Game Processor RAM " ;
static const char snsMenuItem6 [ ] PROGMEM = " Flash repro " ;
2024-03-02 17:26:35 +01:00
# ifdef OPTION_CLOCKGEN_CALIBRATION
2024-02-09 22:06:44 +01:00
static const char snsMenuItem7 [ ] PROGMEM = " Calibrate Clock " ;
2024-03-02 17:26:35 +01:00
static const char * const menuOptionsSNS [ ] PROGMEM = { snsMenuItem1 , snsMenuItem2 , snsMenuItem3 , snsMenuItem4 , snsMenuItem5 , snsMenuItem6 , snsMenuItem7 , FSTRING_RESET } ;
2023-11-25 00:32:51 +01:00
# else
2024-03-02 17:26:35 +01:00
static const char * const menuOptionsSNS [ ] PROGMEM = { snsMenuItem1 , snsMenuItem2 , snsMenuItem3 , snsMenuItem4 , snsMenuItem5 , snsMenuItem6 , FSTRING_RESET } ;
2021-10-28 23:26:10 +02:00
# endif
2021-01-27 08:05:25 +01:00
// SNES menu items
static const char SnesMenuItem4 [ ] PROGMEM = " Test SRAM " ;
static const char SnesMenuItem6 [ ] PROGMEM = " Force cart type " ;
2024-03-02 17:26:35 +01:00
static const char * const menuOptionsSNES [ ] PROGMEM = { FSTRING_READ_ROM , FSTRING_READ_SAVE , FSTRING_WRITE_SAVE , SnesMenuItem4 , FSTRING_REFRESH_CART , SnesMenuItem6 , FSTRING_RESET } ;
2021-01-27 08:05:25 +01:00
// Manual config menu items
static const char confMenuItem1 [ ] PROGMEM = " Use header info " ;
2022-09-25 16:40:21 +02:00
static const char confMenuItem2 [ ] PROGMEM = " 4MB LoROM 256K SRAM " ;
static const char confMenuItem3 [ ] PROGMEM = " 4MB HiROM 64K SRAM " ;
static const char confMenuItem4 [ ] PROGMEM = " 6MB ExROM 256K SRAM " ;
2024-03-02 17:26:35 +01:00
static const char * const menuOptionsConfManual [ ] PROGMEM = { confMenuItem1 , confMenuItem2 , confMenuItem3 , confMenuItem4 , FSTRING_RESET } ;
2021-01-27 08:05:25 +01:00
2021-05-12 17:42:49 +02:00
// Repro menu items
2022-09-25 16:40:21 +02:00
static const char reproMenuItem1 [ ] PROGMEM = " LoROM (P0) " ;
static const char reproMenuItem2 [ ] PROGMEM = " HiROM (P0) " ;
static const char reproMenuItem3 [ ] PROGMEM = " ExLoROM (P1) " ;
static const char reproMenuItem4 [ ] PROGMEM = " ExHiROM (P1) " ;
2024-03-02 17:26:35 +01:00
static const char * const menuOptionsRepro [ ] PROGMEM = { reproMenuItem1 , reproMenuItem2 , reproMenuItem3 , reproMenuItem4 , FSTRING_RESET } ;
2021-05-12 17:42:49 +02:00
// SNES repro menu
void reproMenu ( ) {
// create menu with title and 6 options to choose from
unsigned char snsRepro ;
// Copy menuOptions out of progmem
2021-06-09 11:28:39 +02:00
convertPgm ( menuOptionsRepro , 5 ) ;
snsRepro = question_box ( F ( " Select Repro Type " ) , menuOptions , 5 , 0 ) ;
2021-05-12 17:42:49 +02:00
// wait for user choice to come back from the question box menu
2022-10-13 09:49:03 +02:00
switch ( snsRepro ) {
2024-03-02 17:26:35 +01:00
# ifdef ENABLE_FLASH
2021-05-12 17:42:49 +02:00
case 0 :
2021-06-09 11:28:39 +02:00
// LoRom
2021-05-12 17:42:49 +02:00
display_Clear ( ) ;
display_Update ( ) ;
2021-06-09 11:28:39 +02:00
mapping = 0 ;
2021-05-12 17:42:49 +02:00
setup_Flash8 ( ) ;
id_Flash8 ( ) ;
wait ( ) ;
2024-03-02 17:26:35 +01:00
mode = CORE_FLASH8 ;
2021-05-12 17:42:49 +02:00
break ;
case 1 :
2021-06-09 11:28:39 +02:00
// HiRom
2021-05-12 17:42:49 +02:00
display_Clear ( ) ;
display_Update ( ) ;
2021-06-09 11:28:39 +02:00
mapping = 1 ;
2021-05-12 17:42:49 +02:00
setup_Flash8 ( ) ;
id_Flash8 ( ) ;
wait ( ) ;
2024-03-02 17:26:35 +01:00
mode = CORE_FLASH8 ;
2021-05-12 17:42:49 +02:00
break ;
case 2 :
2021-06-09 11:28:39 +02:00
// ExLoRom
2021-05-12 17:42:49 +02:00
display_Clear ( ) ;
display_Update ( ) ;
2021-06-09 11:28:39 +02:00
mapping = 2 ;
2021-05-12 17:42:49 +02:00
setup_Flash8 ( ) ;
id_Flash8 ( ) ;
wait ( ) ;
2024-03-02 17:26:35 +01:00
mode = CORE_FLASH8 ;
2021-05-12 17:42:49 +02:00
break ;
case 3 :
2021-06-09 11:28:39 +02:00
// ExHiRom
display_Clear ( ) ;
display_Update ( ) ;
mapping = 3 ;
setup_Flash8 ( ) ;
id_Flash8 ( ) ;
wait ( ) ;
2024-03-02 17:26:35 +01:00
mode = CORE_FLASH8 ;
2021-06-09 11:28:39 +02:00
break ;
# endif
case 4 :
2021-05-12 17:42:49 +02:00
resetArduino ( ) ;
break ;
}
}
2021-01-27 08:05:25 +01:00
// SNES start menu
void snsMenu ( ) {
2023-11-25 00:32:51 +01:00
// create menu with title and 7 options to choose from
2021-01-27 08:05:25 +01:00
unsigned char snsCart ;
// Copy menuOptions out of progmem
2024-03-02 17:26:35 +01:00
# ifdef OPTION_CLOCKGEN_CALIBRATION
2024-02-09 22:06:44 +01:00
convertPgm ( menuOptionsSNS , 8 ) ;
2024-03-02 17:26:35 +01:00
snsCart = question_box ( FS ( FSTRING_SELECT_CART_TYPE ) , menuOptions , 8 , 0 ) ;
2024-02-09 22:06:44 +01:00
# else
2023-11-25 00:32:51 +01:00
convertPgm ( menuOptionsSNS , 7 ) ;
2024-03-02 17:26:35 +01:00
snsCart = question_box ( FS ( FSTRING_SELECT_CART_TYPE ) , menuOptions , 7 , 0 ) ;
2021-11-18 14:55:50 +01:00
# endif
2021-01-27 08:05:25 +01:00
// wait for user choice to come back from the question box menu
2022-10-13 09:49:03 +02:00
switch ( snsCart ) {
2021-01-27 08:05:25 +01:00
case 0 :
display_Clear ( ) ;
display_Update ( ) ;
setup_Snes ( ) ;
2024-03-02 17:26:35 +01:00
mode = CORE_SNES ;
2021-01-27 08:05:25 +01:00
break ;
2024-03-02 17:26:35 +01:00
# ifdef ENABLE_SFM
2021-01-27 08:05:25 +01:00
case 1 :
display_Clear ( ) ;
display_Update ( ) ;
setup_SFM ( ) ;
2024-03-02 17:26:35 +01:00
mode = CORE_SFM ;
2021-01-27 08:05:25 +01:00
break ;
# endif
2024-03-02 17:26:35 +01:00
# ifdef ENABLE_SV
2021-01-27 08:05:25 +01:00
case 2 :
display_Clear ( ) ;
display_Update ( ) ;
setup_SV ( ) ;
2024-03-02 17:26:35 +01:00
mode = CORE_SV ;
2021-01-27 08:05:25 +01:00
break ;
2021-11-18 14:55:50 +01:00
# endif
2021-01-27 08:05:25 +01:00
2024-03-02 17:26:35 +01:00
# ifdef ENABLE_ST
2021-01-27 08:05:25 +01:00
case 3 :
2023-11-25 00:32:51 +01:00
display_Clear ( ) ;
display_Update ( ) ;
setup_ST ( ) ;
2024-03-02 17:26:35 +01:00
mode = CORE_ST ;
2023-11-25 00:32:51 +01:00
break ;
# endif
2024-03-02 17:26:35 +01:00
# ifdef ENABLE_GPC
2023-11-25 00:32:51 +01:00
case 4 :
2024-02-09 22:06:44 +01:00
display_Clear ( ) ;
display_Update ( ) ;
setup_GPC ( ) ;
2024-03-02 17:26:35 +01:00
mode = CORE_GPC ;
2024-02-09 22:06:44 +01:00
break ;
# endif
2024-03-02 17:26:35 +01:00
# ifdef ENABLE_FLASH
2024-02-09 22:06:44 +01:00
case 5 :
2023-06-26 12:27:45 +02:00
setup_FlashVoltage ( ) ;
2021-05-12 17:42:49 +02:00
reproMenu ( ) ;
2021-01-27 08:05:25 +01:00
break ;
# endif
2024-02-09 22:06:44 +01:00
case 6 :
2024-03-02 17:26:35 +01:00
# ifdef OPTION_CLOCKGEN_CALIBRATION
2021-10-28 23:26:10 +02:00
clkcal ( ) ;
break ;
2024-02-09 22:06:44 +01:00
case 7 :
2021-11-18 14:55:50 +01:00
# endif
2021-01-27 08:05:25 +01:00
resetArduino ( ) ;
break ;
2023-09-23 00:11:08 +02:00
default :
print_MissingModule ( ) ; // does not return
2021-01-27 08:05:25 +01:00
}
}
// SNES Menu
void snesMenu ( ) {
// create menu with title and 7 options to choose from
unsigned char mainMenu ;
// Copy menuOptions out of progmem
convertPgm ( menuOptionsSNES , 7 ) ;
mainMenu = question_box ( F ( " SNES Cart Reader " ) , menuOptions , 7 , 0 ) ;
// wait for user choice to come back from the question box menu
2022-10-13 09:49:03 +02:00
switch ( mainMenu ) {
2021-01-27 08:05:25 +01:00
case 0 :
{
if ( numBanks > 0 ) {
display_Clear ( ) ;
// Change working dir to root
sd . chdir ( " / " ) ;
// start reading from cart
readROM_SNES ( ) ;
2022-06-21 13:29:19 +02:00
// Internal Checksum
2021-01-27 08:05:25 +01:00
compare_checksum ( ) ;
2022-06-21 13:29:19 +02:00
// CRC32
2022-08-03 12:14:32 +02:00
compareCRC ( " snes.txt " , 0 , 1 , 0 ) ;
2024-03-02 17:26:35 +01:00
# ifdef ENABLE_GLOBAL_LOG
2022-06-16 15:15:43 +02:00
save_log ( ) ;
# endif
2021-01-27 08:05:25 +01:00
display_Update ( ) ;
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
display_Clear ( ) ;
2022-10-30 03:21:01 +01:00
print_Error ( F ( " Does not have ROM " ) ) ;
2021-01-27 08:05:25 +01:00
}
}
break ;
case 1 :
if ( sramSize > 0 ) {
display_Clear ( ) ;
// Change working dir to root
sd . chdir ( " / " ) ;
readSRAM ( ) ;
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
display_Clear ( ) ;
2022-10-30 03:21:01 +01:00
print_Error ( F ( " Does not have SRAM " ) ) ;
2021-01-27 08:05:25 +01:00
}
break ;
case 2 :
if ( sramSize > 0 ) {
display_Clear ( ) ;
// Change working dir to root
sd . chdir ( " / " ) ;
writeSRAM ( 1 ) ;
unsigned long wrErrors ;
wrErrors = verifySRAM ( ) ;
if ( wrErrors = = 0 ) {
println_Msg ( F ( " Verified OK " ) ) ;
display_Update ( ) ;
2022-10-13 09:49:03 +02:00
} else {
2022-10-21 15:59:06 +02:00
print_STR ( error_STR , 0 ) ;
2021-01-27 08:05:25 +01:00
print_Msg ( wrErrors ) ;
2022-10-21 15:59:06 +02:00
print_STR ( _bytes_STR , 1 ) ;
2022-10-30 03:21:01 +01:00
print_Error ( did_not_verify_STR ) ;
2021-01-27 08:05:25 +01:00
}
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
display_Clear ( ) ;
2022-10-30 03:21:01 +01:00
print_Error ( F ( " Does not have SRAM " ) ) ;
2021-01-27 08:05:25 +01:00
}
break ;
case 3 :
if ( sramSize > 0 ) {
display_Clear ( ) ;
println_Msg ( F ( " Warning: " ) ) ;
println_Msg ( F ( " This can erase " ) ) ;
println_Msg ( F ( " your save games " ) ) ;
2024-03-02 17:26:35 +01:00
println_Msg ( FS ( FSTRING_EMPTY ) ) ;
println_Msg ( FS ( FSTRING_EMPTY ) ) ;
2021-01-27 08:05:25 +01:00
println_Msg ( F ( " Press any button to " ) ) ;
println_Msg ( F ( " start sram testing " ) ) ;
display_Update ( ) ;
wait ( ) ;
display_Clear ( ) ;
// Change working dir to root
sd . chdir ( " / " ) ;
readSRAM ( ) ;
eraseSRAM ( 0x00 ) ;
eraseSRAM ( 0xFF ) ;
writeSRAM ( 0 ) ;
unsigned long wrErrors = verifySRAM ( ) ;
if ( wrErrors = = 0 ) {
println_Msg ( F ( " Restored OK " ) ) ;
display_Update ( ) ;
2022-10-13 09:49:03 +02:00
} else {
2022-10-21 15:59:06 +02:00
print_STR ( error_STR , 0 ) ;
2021-01-27 08:05:25 +01:00
print_Msg ( wrErrors ) ;
2022-10-21 15:59:06 +02:00
print_STR ( _bytes_STR , 1 ) ;
2022-10-30 03:21:01 +01:00
print_Error ( did_not_verify_STR ) ;
2021-01-27 08:05:25 +01:00
}
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
display_Clear ( ) ;
2022-10-30 03:21:01 +01:00
print_Error ( F ( " Does not have SRAM " ) ) ;
2021-01-27 08:05:25 +01:00
}
break ;
case 4 :
// For arcademaster1 (Markfrizb) multi-game carts
// Set reset pin to output (PH0)
DDRH | = ( 1 < < 0 ) ;
// Switch RST(PH0) to LOW
PORTH & = ~ ( 1 < < 0 ) ;
// Note: It is probably not intended to reset CIC or clocks here
// But if that's false, uncomment this:
// stopSnesClocks_resetCic_resetCart();
display_Clear ( ) ;
print_Msg ( F ( " Resetting... " ) ) ;
display_Update ( ) ;
delay ( 3000 ) ; // wait 3 secs to switch to next game
resetArduino ( ) ;
break ;
case 5 :
confMenuManual ( ) ;
display_Clear ( ) ;
display_Update ( ) ;
break ;
case 6 :
stopSnesClocks_resetCic_resetCart ( ) ;
resetArduino ( ) ;
break ;
}
2024-03-02 17:26:35 +01:00
//println_Msg(FS(FSTRING_EMPTY));
2022-10-21 15:59:06 +02:00
// Prints string out of the common strings array either with or without newline
print_STR ( press_button_STR , 1 ) ;
2021-01-27 08:05:25 +01:00
display_Update ( ) ;
wait ( ) ;
}
// Menu for manual configuration
void confMenuManual ( ) {
// create menu with title and 5 options to choose from
unsigned char subMenu ;
// Copy menuOptions out of progmem
convertPgm ( menuOptionsConfManual , 5 ) ;
subMenu = question_box ( F ( " Choose mapping " ) , menuOptions , 5 , 0 ) ;
// wait for user choice to come back from the question box menu
2022-10-13 09:49:03 +02:00
switch ( subMenu ) {
2021-01-27 08:05:25 +01:00
case 0 :
break ;
case 1 :
romType = LO ;
numBanks = 128 ;
sramSize = 256 ;
2022-09-25 16:40:21 +02:00
strcpy ( romName , " LoROM " ) ;
2021-01-27 08:05:25 +01:00
break ;
case 2 :
romType = HI ;
numBanks = 64 ;
sramSize = 64 ;
2022-09-25 16:40:21 +02:00
strcpy ( romName , " HiROM " ) ;
2021-01-27 08:05:25 +01:00
break ;
case 3 :
romType = EX ;
numBanks = 96 ;
sramSize = 256 ;
2022-09-25 16:40:21 +02:00
strcpy ( romName , " ExROM " ) ;
2021-01-27 08:05:25 +01:00
break ;
case 4 :
// Reset
stopSnesClocks_resetCic_resetCart ( ) ;
resetArduino ( ) ;
break ;
}
}
void stopSnesClocks_resetCic_resetCart ( ) {
2022-10-13 09:49:03 +02:00
DDRG | = ( 1 < < 1 ) ; // Set cicrstPin(PG1) to Output
PORTG | = ( 1 < < 1 ) ; // pull high = reset CIC
DDRH | = ( 1 < < 0 ) ; // Set RST(PH0) pin to Output
PORTH & = ~ ( 1 < < 0 ) ; // Switch RST(PH0) to LOW
2021-11-18 14:55:50 +01:00
if ( i2c_found ) {
2022-10-13 09:49:03 +02:00
clockgen . output_enable ( SI5351_CLK1 , 0 ) ; // CPU clock
clockgen . output_enable ( SI5351_CLK2 , 0 ) ; // CIC clock
clockgen . output_enable ( SI5351_CLK0 , 0 ) ; // master clock
2021-11-18 14:55:50 +01:00
}
2021-01-27 08:05:25 +01:00
}
/******************************************
Setup
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void setup_Snes ( ) {
2023-06-26 21:25:54 +02:00
// Request 5V
2023-06-26 12:04:00 +02:00
setVoltage ( VOLTS_SET_5V ) ;
2021-01-27 08:05:25 +01:00
// Set cicrstPin(PG1) to Output
DDRG | = ( 1 < < 1 ) ;
// Output a high signal until we're ready to start
PORTG | = ( 1 < < 1 ) ;
// Set cichstPin(PG0) to Input
DDRG & = ~ ( 1 < < 0 ) ;
// Set Address Pins to Output
//A0-A7
DDRF = 0xFF ;
//A8-A15
DDRK = 0xFF ;
//BA0-BA7
DDRL = 0xFF ;
//PA0-PA7
DDRA = 0xFF ;
// Set Control Pins to Output RST(PH0) CS(PH3) WR(PH5) RD(PH6)
DDRH | = ( 1 < < 0 ) | ( 1 < < 3 ) | ( 1 < < 5 ) | ( 1 < < 6 ) ;
// Switch RST(PH0) and WR(PH5) to HIGH
PORTH | = ( 1 < < 0 ) | ( 1 < < 5 ) ;
// Switch CS(PH3) and RD(PH6) to LOW
PORTH & = ~ ( ( 1 < < 3 ) | ( 1 < < 6 ) ) ;
// Set Refresh(PE5) to Output
DDRE | = ( 1 < < 5 ) ;
// Switch Refresh(PE5) to LOW (needed for SA-1)
PORTE & = ~ ( 1 < < 5 ) ;
// Set CPU Clock(PH1) to Output
DDRH | = ( 1 < < 1 ) ;
//PORTH &= ~(1 << 1);
// Set IRQ(PH4) to Input
DDRH & = ~ ( 1 < < 4 ) ;
// Activate Internal Pullup Resistors
//PORTH |= (1 << 4);
// Set expand(PG5) to Input
DDRG & = ~ ( 1 < < 5 ) ;
// Activate Internal Pullup Resistors
//PORTG |= (1 << 5);
// Set Data Pins (D0-D7) to Input
DDRC = 0x00 ;
// Enable Internal Pullups
//PORTC = 0xFF;
// Unused pins
// Set wram(PE4) to Output
DDRE | = ( 1 < < 4 ) ;
//PORTE &= ~(1 << 4);
// Set pawr(PJ1) to Output
DDRJ | = ( 1 < < 1 ) ;
//PORTJ &= ~(1 << 1);
// Set pard(PJ0) to Output
DDRJ | = ( 1 < < 0 ) ;
//PORTJ &= ~(1 << 0);
// Adafruit Clock Generator
2022-02-27 06:20:33 +01:00
initializeClockOffset ( ) ;
2021-01-27 08:05:25 +01:00
2021-11-18 14:55:50 +01:00
if ( i2c_found ) {
// Set clocks to 4Mhz/1Mhz for better SA-1 unlocking
2022-10-13 09:49:03 +02:00
clockgen . set_freq ( 100000000ULL , SI5351_CLK1 ) ; // CPU
clockgen . set_freq ( 100000000ULL , SI5351_CLK2 ) ; // CIC
clockgen . set_freq ( 400000000ULL , SI5351_CLK0 ) ; // EXT
2021-01-27 08:05:25 +01:00
2021-11-18 14:55:50 +01:00
// Start outputting master clock, CIC clock
2022-10-13 09:49:03 +02:00
clockgen . output_enable ( SI5351_CLK1 , 0 ) ; // no CPU clock yet; seems to affect SA-1 success a lot
clockgen . output_enable ( SI5351_CLK2 , 1 ) ; // CIC clock (should go before master clock)
clockgen . output_enable ( SI5351_CLK0 , 1 ) ; // master clock
2021-01-27 08:05:25 +01:00
2021-11-18 14:55:50 +01:00
// Wait for clock generator
clockgen . update_status ( ) ;
delay ( 500 ) ;
}
2024-03-02 17:26:35 +01:00
# ifdef ENABLE_CLOCKGEN
2021-11-18 14:55:50 +01:00
else {
display_Clear ( ) ;
2022-10-30 03:21:01 +01:00
print_FatalError ( F ( " Clock Generator not found " ) ) ;
2021-11-18 14:55:50 +01:00
}
# endif
2021-01-27 08:05:25 +01:00
// Start CIC by outputting a low signal to cicrstPin(PG1)
PORTG & = ~ ( 1 < < 1 ) ;
// Wait for CIC reset
delay ( 500 ) ;
// Print all the info
getCartInfo_SNES ( ) ;
2021-11-18 14:55:50 +01:00
if ( i2c_found ) {
//Set clocks to standard or else SA-1 sram writing will fail
clockgen . set_freq ( 2147727200ULL , SI5351_CLK0 ) ;
clockgen . set_freq ( 357954500ULL , SI5351_CLK1 ) ;
clockgen . set_freq ( 307200000ULL , SI5351_CLK2 ) ;
}
2021-01-27 08:05:25 +01:00
}
/******************************************
I / O Functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Switch control pins to write
void controlOut_SNES ( ) {
// Switch RD(PH6) and WR(PH5) to HIGH
PORTH | = ( 1 < < 6 ) | ( 1 < < 5 ) ;
// Switch CS(PH3) to LOW
PORTH & = ~ ( 1 < < 3 ) ;
}
// Switch control pins to read
void controlIn_SNES ( ) {
// Switch WR(PH5) to HIGH
PORTH | = ( 1 < < 5 ) ;
// Switch CS(PH3) and RD(PH6) to LOW
PORTH & = ~ ( ( 1 < < 3 ) | ( 1 < < 6 ) ) ;
}
/******************************************
Low level functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Write one byte of data to a location specified by bank and address, 00:0000
void writeBank_SNES ( byte myBank , word myAddress , byte myData ) {
PORTL = myBank ;
PORTF = myAddress & 0xFF ;
PORTK = ( myAddress > > 8 ) & 0xFF ;
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 "
" nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t " ) ;
2021-01-27 08:05:25 +01:00
// Switch WR(PH5) to LOW
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 "
" 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 " ) ;
2021-01-27 08:05:25 +01:00
// Switch WR(PH5) to HIGH
PORTH | = ( 1 < < 5 ) ;
// 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 "
" 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 " ) ;
2021-01-27 08:05:25 +01:00
}
// Read one byte of data from a location specified by bank and address, 00:0000
byte readBank_SNES ( byte myBank , word myAddress ) {
PORTL = myBank ;
PORTF = myAddress & 0xFF ;
PORTK = ( myAddress > > 8 ) & 0xFF ;
// Wait for the Byte to appear on the data bus
// Arduino running at 16Mhz -> one nop = 62.5ns
// slowRom is good for 200ns, fastRom is <= 120ns; S-CPU best case read speed: 3.57MHz / 280ns
// let's be conservative and use 6 x 62.5 = 375ns
2022-10-13 09:49:03 +02:00
NOP ;
NOP ;
NOP ;
NOP ;
NOP ;
NOP ;
2021-01-27 08:05:25 +01:00
// Read
byte tempByte = PINC ;
return tempByte ;
}
2022-10-13 09:49:03 +02:00
void readLoRomBanks ( unsigned int start , unsigned int total , FsFile * file ) {
2021-01-27 08:05:25 +01:00
byte buffer [ 1024 ] = { 0 } ;
uint16_t c = 0 ;
uint16_t currByte = 32768 ;
//Initialize progress bar
uint32_t processedProgressBar = 0 ;
uint32_t totalProgressBar = ( uint32_t ) ( total - start ) * 1024 ;
draw_progressbar ( 0 , totalProgressBar ) ;
2022-10-31 15:41:29 +01:00
for ( word currBank = start ; currBank < total ; currBank + + ) {
2021-01-27 08:05:25 +01:00
PORTL = currBank ;
// Blink led
2021-10-26 17:13:42 +02:00
blinkLED ( ) ;
2021-01-27 08:05:25 +01:00
currByte = 32768 ;
while ( 1 ) {
c = 0 ;
while ( c < 1024 ) {
PORTF = ( currByte & 0xFF ) ;
PORTK = ( ( currByte > > 8 ) & 0xFF ) ;
// Wait for the Byte to appear on the data bus
// Arduino running at 16Mhz -> one nop = 62.5ns
// slowRom is good for 200ns, fastRom is <= 120ns; S-CPU best case read speed: 3.57MHz / 280ns
// let's be conservative and use 6 x 62.5 = 375ns
2022-10-13 09:49:03 +02:00
NOP ;
NOP ;
NOP ;
NOP ;
NOP ;
NOP ;
2021-01-27 08:05:25 +01:00
buffer [ c ] = PINC ;
c + + ;
currByte + + ;
}
file - > write ( buffer , 1024 ) ;
// exit while(1) loop once the uint16_t currByte overflows from 0xffff to 0 (current bank is done)
if ( currByte = = 0 ) break ;
}
// update progress bar
processedProgressBar + = 1024 ;
draw_progressbar ( processedProgressBar , totalProgressBar ) ;
}
}
2022-10-13 09:49:03 +02:00
void readHiRomBanks ( unsigned int start , unsigned int total , FsFile * file ) {
2021-01-27 08:05:25 +01:00
byte buffer [ 1024 ] = { 0 } ;
uint16_t c = 0 ;
uint16_t currByte = 0 ;
//Initialize progress bar
uint32_t processedProgressBar = 0 ;
uint32_t totalProgressBar = ( uint32_t ) ( total - start ) * 1024 ;
draw_progressbar ( 0 , totalProgressBar ) ;
2022-10-31 15:41:29 +01:00
for ( word currBank = start ; currBank < total ; currBank + + ) {
2021-01-27 08:05:25 +01:00
PORTL = currBank ;
// Blink led
2021-10-26 17:13:42 +02:00
blinkLED ( ) ;
2021-01-27 08:05:25 +01:00
currByte = 0 ;
while ( 1 ) {
c = 0 ;
while ( c < 1024 ) {
PORTF = ( currByte & 0xFF ) ;
PORTK = ( ( currByte > > 8 ) & 0xFF ) ;
// Wait for the Byte to appear on the data bus
// Arduino running at 16Mhz -> one nop = 62.5ns
// slowRom is good for 200ns, fastRom is <= 120ns; S-CPU best case read speed: 3.57MHz / 280ns
// let's be conservative and use 6 x 62.5 = 375ns
2022-10-13 09:49:03 +02:00
NOP ;
NOP ;
NOP ;
NOP ;
NOP ;
NOP ;
2021-01-27 08:05:25 +01:00
buffer [ c ] = PINC ;
c + + ;
currByte + + ;
}
file - > write ( buffer , 1024 ) ;
// exit while(1) loop once the uint16_t currByte overflows from 0xffff to 0 (current bank is done)
if ( currByte = = 0 ) break ;
}
// update progress bar
processedProgressBar + = 1024 ;
draw_progressbar ( processedProgressBar , totalProgressBar ) ;
}
}
/******************************************
SNES ROM Functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void getCartInfo_SNES ( ) {
boolean manualConfig = 0 ;
2022-11-01 08:52:51 +01:00
//Prime SA1 cartridge
PORTL = 192 ;
for ( uint16_t currByte = 0 ; currByte < 1024 ; currByte + + ) {
PORTF = currByte & 0xFF ;
PORTK = currByte > > 8 ;
// Wait for the Byte to appear on the data bus
// Arduino running at 16Mhz -> one nop = 62.5ns
// slowRom is good for 200ns, fastRom is <= 120ns; S-CPU best case read speed: 3.57MHz / 280ns
// let's be conservative and use 6 x 62.5 = 375ns
NOP ;
NOP ;
NOP ;
NOP ;
NOP ;
NOP ;
}
2021-01-27 08:05:25 +01:00
// Print start page
if ( checkcart_SNES ( ) = = 0 ) {
// Checksum either corrupt or 0000
manualConfig = 1 ;
errorLvl = 1 ;
2024-05-26 22:43:41 +02:00
rgbLed ( red_color ) ;
2021-01-27 08:05:25 +01:00
display_Clear ( ) ;
println_Msg ( F ( " ERROR " ) ) ;
println_Msg ( F ( " Rom header corrupt " ) ) ;
println_Msg ( F ( " or missing " ) ) ;
2024-03-02 17:26:35 +01:00
println_Msg ( FS ( FSTRING_EMPTY ) ) ;
println_Msg ( FS ( FSTRING_EMPTY ) ) ;
2021-01-27 08:05:25 +01:00
println_Msg ( F ( " Press button for " ) ) ;
println_Msg ( F ( " manual configuration " ) ) ;
println_Msg ( F ( " or powercycle if SA1 " ) ) ;
display_Update ( ) ;
wait ( ) ;
// Wait() clears errors but in this case we still have an error
errorLvl = 1 ;
}
display_Clear ( ) ;
2022-09-25 16:40:21 +02:00
print_Msg ( F ( " Title: " ) ) ;
2021-01-27 08:05:25 +01:00
println_Msg ( romName ) ;
2022-09-25 16:40:21 +02:00
print_Msg ( F ( " Revision: " ) ) ;
println_Msg ( romVersion ) ;
2021-01-27 08:05:25 +01:00
print_Msg ( F ( " Type: " ) ) ;
if ( romType = = HI )
print_Msg ( F ( " HiROM " ) ) ;
else if ( romType = = LO )
print_Msg ( F ( " LoROM " ) ) ;
else if ( romType = = EX )
print_Msg ( F ( " ExHiRom " ) ) ;
else
print_Msg ( romType ) ;
2024-03-02 17:26:35 +01:00
print_Msg ( FS ( FSTRING_SPACE ) ) ;
2021-01-27 08:05:25 +01:00
if ( romSpeed = = 0 )
println_Msg ( F ( " SlowROM " ) ) ;
else if ( romSpeed = = 2 )
println_Msg ( F ( " SlowROM " ) ) ;
else if ( romSpeed = = 3 )
println_Msg ( F ( " FastROM " ) ) ;
else
println_Msg ( romSpeed ) ;
print_Msg ( F ( " ICs: ROM " ) ) ;
if ( romChips = = 0 )
println_Msg ( F ( " ONLY " ) ) ;
else if ( romChips = = 1 )
println_Msg ( F ( " RAM " ) ) ;
else if ( romChips = = 2 )
println_Msg ( F ( " SAVE " ) ) ;
else if ( romChips = = 3 )
println_Msg ( F ( " DSP1 " ) ) ;
else if ( romChips = = 4 )
println_Msg ( F ( " DSP1 RAM " ) ) ;
else if ( romChips = = 5 )
println_Msg ( F ( " DSP1 SAVE " ) ) ;
else if ( ( romChips = = 19 ) | | ( romChips = = 20 ) | | ( romChips = = 21 ) | | ( romChips = = 26 ) )
println_Msg ( F ( " SuperFX " ) ) ;
else if ( romChips = = 52 ) {
println_Msg ( F ( " SA1 RAM " ) ) ;
romType = SA ;
2022-10-13 09:49:03 +02:00
} else if ( romChips = = 53 ) {
2021-01-27 08:05:25 +01:00
println_Msg ( F ( " SA1 RAM BATT " ) ) ;
romType = SA ;
2022-10-13 09:49:03 +02:00
} else if ( romChips = = 67 ) {
2022-08-24 05:48:49 +02:00
println_Msg ( F ( " SDD1 " ) ) ;
2022-10-13 09:49:03 +02:00
} else if ( romChips = = 69 ) {
2021-01-27 08:05:25 +01:00
println_Msg ( F ( " SDD1 BATT " ) ) ;
2022-12-20 10:31:35 +01:00
} else if ( romChips = = 85 )
2022-11-24 10:08:41 +01:00
println_Msg ( F ( " SRTC RAM BATT " ) ) ;
else if ( romChips = = 227 )
2021-01-27 08:05:25 +01:00
println_Msg ( F ( " RAM GBoy " ) ) ;
else if ( romChips = = 243 )
println_Msg ( F ( " CX4 " ) ) ;
else if ( romChips = = 246 )
println_Msg ( F ( " DSP2 " ) ) ;
else if ( romChips = = 245 )
println_Msg ( F ( " SPC RAM BATT " ) ) ;
else if ( romChips = = 249 )
println_Msg ( F ( " SPC RAM RTC " ) ) ;
else
2024-03-02 17:26:35 +01:00
println_Msg ( FS ( FSTRING_EMPTY ) ) ;
2021-01-27 08:05:25 +01:00
if ( altconf )
print_Msg ( F ( " Rom Size: " ) ) ;
else
print_Msg ( F ( " ROM Size: " ) ) ;
2022-09-25 16:40:21 +02:00
if ( ( romSize > > 3 ) < 1 ) {
print_Msg ( 1024 * romSize > > 3 ) ;
print_Msg ( F ( " KB " ) ) ;
} else {
print_Msg ( romSize > > 3 ) ;
print_Msg ( F ( " MB " ) ) ;
}
print_Msg ( F ( " ( " ) ) ;
2021-01-27 08:05:25 +01:00
print_Msg ( numBanks ) ;
2022-09-25 16:40:21 +02:00
println_Msg ( F ( " banks) " ) ) ;
2022-10-04 20:30:53 +02:00
2022-09-25 16:40:21 +02:00
//print_Msg(F("Chips: "));
//println_Msg(romChips);
2021-01-27 08:05:25 +01:00
2022-09-25 16:40:21 +02:00
print_Msg ( F ( " Save Size: " ) ) ;
print_Msg ( sramSize > > 3 ) ;
println_Msg ( F ( " KB " ) ) ;
2021-01-27 08:05:25 +01:00
print_Msg ( F ( " Checksum: " ) ) ;
println_Msg ( checksumStr ) ;
display_Update ( ) ;
// Wait for user input
2024-03-02 17:26:35 +01:00
# if (defined(ENABLE_LCD) || defined(ENABLE_OLED))
2022-10-21 15:59:06 +02:00
// Prints string out of the common strings array either with or without newline
print_STR ( press_button_STR , 1 ) ;
2021-01-27 08:05:25 +01:00
display_Update ( ) ;
wait ( ) ;
2021-10-24 00:41:18 +02:00
# endif
2024-03-02 17:26:35 +01:00
# ifdef ENABLE_SERIAL
println_Msg ( FS ( FSTRING_SPACE ) ) ;
2021-01-27 08:05:25 +01:00
# endif
// Start manual config
if ( manualConfig = = 1 ) {
confMenuManual ( ) ;
}
}
2022-08-22 17:49:19 +02:00
void checkAltConf ( char crcStr [ 9 ] ) {
2021-01-27 08:05:25 +01:00
char tempStr2 [ 5 ] ;
2022-08-22 17:49:19 +02:00
char tempStr3 [ 9 ] ;
2021-01-27 08:05:25 +01:00
altconf = 0 ;
if ( myFile . open ( " snes.txt " , O_READ ) ) {
2022-06-21 13:29:19 +02:00
// Get cart info
display_Clear ( ) ;
2022-10-27 23:43:46 +02:00
println_Msg ( F ( " Searching database... " ) ) ;
print_Msg ( F ( " Checksum: " ) ) ;
println_Msg ( checksumStr ) ;
2022-06-21 13:29:19 +02:00
display_Update ( ) ;
2021-01-27 08:05:25 +01:00
while ( myFile . available ( ) ) {
2022-06-21 13:29:19 +02:00
// Skip first line with name
skip_line ( & myFile ) ;
// Skip over the CRC checksum
2022-10-23 07:01:59 +02:00
myFile . seekCur ( 9 ) ;
2022-06-21 13:29:19 +02:00
2022-08-22 17:49:19 +02:00
// Get internal ROM checksum as string
for ( byte j = 0 ; j < 4 ; j + + ) {
tempStr2 [ j ] = char ( myFile . read ( ) ) ;
}
tempStr2 [ 4 ] = ' \0 ' ;
// Check if checksum string is a match else go to next entry in database
2021-01-27 08:05:25 +01:00
if ( strcmp ( tempStr2 , checksumStr ) = = 0 ) {
// Skip the , in the file
2022-10-23 07:01:59 +02:00
myFile . seekCur ( 1 ) ;
2021-01-27 08:05:25 +01:00
2022-08-22 17:49:19 +02:00
// Read the CRC32 of the SNES header out of database
for ( byte k = 0 ; k < 8 ; k + + ) {
tempStr3 [ k ] = char ( myFile . read ( ) ) ;
}
tempStr3 [ 8 ] = ' \0 ' ;
2023-07-04 19:58:45 +02:00
print_Msg ( F ( " Header CRC32: " ) ) ;
println_Msg ( tempStr3 ) ;
display_Update ( ) ;
2022-08-22 17:49:19 +02:00
// Skip the , in the file
2022-10-23 07:01:59 +02:00
myFile . seekCur ( 1 ) ;
2022-08-22 17:49:19 +02:00
2021-01-27 08:05:25 +01:00
// Read file size
2022-06-21 13:29:19 +02:00
byte romSize2 = ( myFile . read ( ) - 48 ) * 10 + ( myFile . read ( ) - 48 ) ;
2021-01-27 08:05:25 +01:00
// Skip the , in the file
2022-10-23 07:01:59 +02:00
myFile . seekCur ( 1 ) ;
2021-01-27 08:05:25 +01:00
// Read number of banks
2022-10-13 09:49:03 +02:00
byte numBanks2 = ( myFile . read ( ) - 48 ) * 100 + ( myFile . read ( ) - 48 ) * 10 + ( myFile . read ( ) - 48 ) ;
2021-01-27 08:05:25 +01:00
2023-07-04 19:58:45 +02:00
// skip CRLF
myFile . seekCur ( 2 ) ;
// skip third empty line
skip_line ( & myFile ) ;
2022-08-22 17:49:19 +02:00
// Some games have the same checksum, so compare CRC32 of header area with database too
2022-10-13 09:49:03 +02:00
if ( strcmp ( tempStr3 , crcStr ) = = 0 ) {
2022-08-22 21:20:05 +02:00
println_Msg ( F ( " Found " ) ) ;
display_Update ( ) ;
2022-08-22 17:49:19 +02:00
// Game found, check if ROM sizes differ but only change ROM size if non- standard size found in database, else trust the header to be right and the database to be wrong
2022-11-24 10:08:41 +01:00
if ( ( ( romSize ! = romSize2 ) | | ( numBanks ! = numBanks2 ) ) & & ( ( romSize2 = = 10 ) | | ( romSize2 = = 12 ) | | ( romSize2 = = 20 ) | | ( romSize2 = = 24 ) | | ( romSize2 = = 40 ) | | ( romSize2 = = 48 ) ) ) {
2022-08-22 17:49:19 +02:00
// Correct size
2022-08-22 21:20:05 +02:00
println_Msg ( F ( " Correcting size " ) ) ;
print_Msg ( F ( " Size: " ) ) ;
print_Msg ( romSize ) ;
print_Msg ( F ( " -> " ) ) ;
print_Msg ( romSize2 ) ;
println_Msg ( F ( " Mbit " ) ) ;
print_Msg ( F ( " Banks: " ) ) ;
print_Msg ( numBanks ) ;
print_Msg ( F ( " -> " ) ) ;
println_Msg ( numBanks2 ) ;
display_Update ( ) ;
delay ( 1000 ) ;
2022-08-19 12:16:14 +02:00
romSize = romSize2 ;
2022-10-13 09:49:03 +02:00
numBanks = numBanks2 ;
2022-08-19 12:16:14 +02:00
altconf = 1 ;
}
2022-08-22 17:49:19 +02:00
break ;
2022-06-21 13:29:19 +02:00
}
2021-01-27 08:05:25 +01:00
}
2022-08-22 17:49:19 +02:00
// If no match go to next entry
2021-01-27 08:05:25 +01:00
else {
2022-06-21 13:29:19 +02:00
// skip rest of line
2022-10-23 07:01:59 +02:00
myFile . seekCur ( 18 ) ;
2022-06-21 13:29:19 +02:00
// skip third empty line
skip_line ( & myFile ) ;
2021-01-27 08:05:25 +01:00
}
}
2022-06-21 13:29:19 +02:00
// Close the file:
myFile . close ( ) ;
2021-01-27 08:05:25 +01:00
}
}
// Read header
boolean checkcart_SNES ( ) {
// set control to read
dataIn ( ) ;
2022-08-22 17:49:19 +02:00
uint16_t headerStart = 0xFFB0 ;
2022-10-22 10:25:37 +02:00
byte snesHeader [ 80 ] ;
2021-01-27 08:05:25 +01:00
PORTL = 0 ;
2022-10-22 10:25:37 +02:00
for ( uint16_t c = 0 , currByte = headerStart ; c < 80 ; c + + , currByte + + ) {
2021-01-27 08:05:25 +01:00
PORTF = ( currByte & 0xFF ) ;
PORTK = ( ( currByte > > 8 ) & 0xFF ) ;
2022-10-13 09:49:03 +02:00
NOP ;
NOP ;
NOP ;
NOP ;
NOP ;
NOP ;
NOP ;
NOP ;
NOP ;
NOP ;
NOP ;
NOP ;
2021-01-27 08:05:25 +01:00
snesHeader [ c ] = PINC ;
}
2022-08-22 17:49:19 +02:00
// Calculate CRC32 of header
char crcStr [ 9 ] ;
2022-10-23 14:26:40 +02:00
sprintf ( crcStr , " %08lX " , calculateCRC ( snesHeader , 80 ) ) ;
2022-08-22 17:49:19 +02:00
2021-01-27 08:05:25 +01:00
// Get Checksum as string
sprintf ( checksumStr , " %02X%02X " , snesHeader [ 0xFFDF - headerStart ] , snesHeader [ 0xFFDE - headerStart ] ) ;
romType = snesHeader [ 0xFFD5 - headerStart ] ;
if ( ( romType > > 5 ) ! = 1 ) { // Detect invalid romType byte due to too long ROM name (22 chars)
2022-10-13 09:49:03 +02:00
romType = LO ; // LoROM // Krusty's Super Fun House (U) 1.0 & Contra 3 (U)
} else if ( romType = = 0x35 ) {
romType = EX ; // Check if ExHiROM
} else if ( romType = = 0x3A ) {
romType = HI ; // Check if SPC7110
2024-04-30 12:25:58 +02:00
} else if ( strcmp ( " 3BB0 " , checksumStr ) = = 0 ) { // invalid romType due to too long ROM name (Yuyu no Quiz de GO!GO!)
romType = LO ;
2022-10-13 09:49:03 +02:00
} else {
romType & = 1 ; // Must be LoROM or HiROM
2021-01-27 08:05:25 +01:00
}
// Check RomSpeed
romSpeed = ( snesHeader [ 0xFFD5 - headerStart ] > > 4 ) ;
// Check RomChips
romChips = snesHeader [ 0xFFD6 - headerStart ] ;
if ( romChips = = 69 ) {
romSize = 48 ;
numBanks = 96 ;
romType = HI ;
2022-10-13 09:49:03 +02:00
} else if ( romChips = = 67 ) {
2022-08-24 05:48:49 +02:00
romSize = 32 ;
numBanks = 64 ;
romType = HI ;
2022-10-13 09:49:03 +02:00
} else if ( romChips = = 243 ) {
2021-01-27 08:05:25 +01:00
cx4Type = snesHeader [ 0xFFC9 - headerStart ] & 0xF ;
2022-10-13 09:49:03 +02:00
if ( cx4Type = = 2 ) { // X2
2021-01-27 08:05:25 +01:00
romSize = 12 ;
numBanks = 48 ;
2022-10-13 09:49:03 +02:00
} else if ( cx4Type = = 3 ) { // X3
2021-01-27 08:05:25 +01:00
romSize = 16 ;
numBanks = 64 ;
}
2022-10-13 09:49:03 +02:00
} else if ( ( romChips = = 245 ) & & ( romType = = HI ) ) {
2021-01-27 08:05:25 +01:00
romSize = 24 ;
numBanks = 48 ;
2022-10-13 09:49:03 +02:00
} else if ( ( romChips = = 249 ) & & ( romType = = HI ) ) {
2021-01-27 08:05:25 +01:00
romSize = 40 ;
numBanks = 80 ;
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
// Check RomSize
byte romSizeExp = snesHeader [ 0xFFD7 - headerStart ] - 7 ;
romSize = 1 ;
while ( romSizeExp - - )
romSize * = 2 ;
if ( ( romType = = EX ) | | ( romType = = SA ) ) {
numBanks = long ( romSize ) * 2 ;
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
numBanks = ( long ( romSize ) * 1024 * 1024 / 8 ) / ( 32768 + ( long ( romType ) * 32768 ) ) ;
}
}
2022-08-22 17:49:19 +02:00
//Check SD card for alt config, pass CRC32 of snesHeader but filter out 0000 and FFFF checksums
if ( ! ( strcmp ( checksumStr , " 0000 " ) = = 0 ) & & ! ( strcmp ( checksumStr , " FFFF " ) = = 0 ) ) {
checkAltConf ( crcStr ) ;
}
2021-01-27 08:05:25 +01:00
// Get name
2022-10-28 13:38:16 +02:00
byte myLength = buildRomName ( romName , & snesHeader [ 0xFFC0 - headerStart ] , 21 ) ;
2022-09-25 10:36:28 +02:00
2021-01-27 08:05:25 +01:00
// If name consists out of all japanese characters use game code
if ( myLength = = 0 ) {
// Get rom code
romName [ 0 ] = ' S ' ;
romName [ 1 ] = ' H ' ;
romName [ 2 ] = ' V ' ;
romName [ 3 ] = ' C ' ;
romName [ 4 ] = ' - ' ;
for ( unsigned int i = 0 ; i < 4 ; i + + ) {
2022-10-23 17:49:38 +02:00
byte myByte ;
2021-01-27 08:05:25 +01:00
myByte = snesHeader [ 0xFFB2 + i - headerStart ] ;
2022-10-23 17:49:38 +02:00
if ( ( ( myByte > = ' 0 ' & & myByte < = ' 9 ' ) | | ( myByte > = ' A ' & & myByte < = ' z ' ) ) & & myLength < 4 ) {
romName [ myLength + 5 ] = myByte ;
2021-01-27 08:05:25 +01:00
myLength + + ;
}
}
if ( myLength = = 0 ) {
// Rom code unknown
romName [ 0 ] = ' U ' ;
romName [ 1 ] = ' N ' ;
romName [ 2 ] = ' K ' ;
romName [ 3 ] = ' N ' ;
romName [ 4 ] = ' O ' ;
romName [ 5 ] = ' W ' ;
romName [ 6 ] = ' N ' ;
}
}
// Read sramSizeExp
byte sramSizeExp ;
if ( ( romChips = = 19 ) | | ( romChips = = 20 ) | | ( romChips = = 21 ) | | ( romChips = = 26 ) ) {
// SuperFX
2022-10-26 02:54:40 +02:00
if ( snesHeader [ 0xFFDA - headerStart ] = = 0x33 ) {
sramSizeExp = snesHeader [ 0xFFBD - headerStart ] ;
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
if ( strncmp ( romName , " STARFOX2 " , 8 ) = = 0 ) {
sramSizeExp = 6 ;
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
sramSizeExp = 5 ;
}
}
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
// No SuperFX
sramSizeExp = snesHeader [ 0xFFD8 - headerStart ] ;
}
// Calculate sramSize
// Fail states usually have sramSizeExp at 255 (no cart inserted, SA-1 failure, etc)
if ( sramSizeExp ! = 0 & & sramSizeExp ! = 255 ) {
sramSizeExp = sramSizeExp + 3 ;
sramSize = 1 ;
while ( sramSizeExp - - )
sramSize * = 2 ;
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
sramSize = 0 ;
}
// Check Cart Country
//int cartCountry = snesHeader[0xFFD9 - headerStart];
// ROM Version
romVersion = snesHeader [ 0xFFDB - headerStart ] ;
// Test if checksum is equal to reverse checksum
2022-10-13 09:49:03 +02:00
if ( ( ( word ( snesHeader [ 0xFFDC - headerStart ] ) + ( word ( snesHeader [ 0xFFDD - headerStart ] ) * 256 ) ) + ( word ( snesHeader [ 0xFFDE - headerStart ] ) + ( word ( snesHeader [ 0xFFDF - headerStart ] ) * 256 ) ) ) = = 65535 ) {
2021-01-27 08:05:25 +01:00
if ( strcmp ( " 0000 " , checksumStr ) = = 0 ) {
return 0 ;
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
return 1 ;
}
}
// Either rom checksum is wrong or no cart is inserted
else {
return 0 ;
}
}
2022-10-13 09:49:03 +02:00
unsigned int calc_checksum ( char * fileName , char * folder ) {
2021-01-27 08:05:25 +01:00
unsigned int calcChecksum = 0 ;
unsigned int calcChecksumChunk = 0 ;
int calcFilesize = 0 ;
unsigned int c = 0 ;
unsigned long i = 0 ;
unsigned long j = 0 ;
if ( strcmp ( folder , " root " ) ! = 0 )
sd . chdir ( folder ) ;
// If file exists
if ( myFile . open ( fileName , O_READ ) ) {
calcFilesize = myFile . fileSize ( ) * 8 / 1024 / 1024 ;
// Nintendo Power (SF Memory Cassette)
// Read up to 0x60000 then add FFs to 0x80000
if ( NP = = true ) {
for ( i = 0 ; i < ( 0x60000 / 512 ) ; i + + ) {
myFile . read ( sdBuffer , 512 ) ;
for ( c = 0 ; c < 512 ; c + + ) {
calcChecksumChunk + = sdBuffer [ c ] ;
}
calcChecksum = calcChecksumChunk ;
}
2022-10-13 09:49:03 +02:00
calcChecksum + = 0xF47C ; // FFs from 0x60000-0x80000
} else if ( ( calcFilesize = = 10 ) | | ( calcFilesize = = 12 ) | | ( calcFilesize = = 20 ) | | ( calcFilesize = = 24 ) ) {
2021-01-27 08:05:25 +01:00
unsigned long calcBase = 0 ;
unsigned long calcMirror = 0 ;
byte calcMirrorCount = 0 ;
if ( calcFilesize > 16 )
calcBase = 2097152 ;
else
calcBase = 1048576 ;
calcMirror = myFile . fileSize ( ) - calcBase ;
calcMirrorCount = calcBase / calcMirror ;
// Momotarou Dentetsu Happy Fix 3MB (24Mbit)
if ( ( calcFilesize = = 24 ) & & ( romChips = = 245 ) ) {
for ( i = 0 ; i < ( myFile . fileSize ( ) / 512 ) ; i + + ) {
myFile . read ( sdBuffer , 512 ) ;
for ( c = 0 ; c < 512 ; c + + ) {
calcChecksumChunk + = sdBuffer [ c ] ;
}
}
calcChecksum = 2 * calcChecksumChunk ;
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
// Base 8/16 Mbit chunk
for ( j = 0 ; j < ( calcBase / 512 ) ; j + + ) {
myFile . read ( sdBuffer , 512 ) ;
for ( c = 0 ; c < 512 ; c + + ) {
calcChecksumChunk + = sdBuffer [ c ] ;
}
}
calcChecksum = calcChecksumChunk ;
calcChecksumChunk = 0 ;
// Add the mirrored chunk
for ( j = 0 ; j < ( calcMirror / 512 ) ; j + + ) {
myFile . read ( sdBuffer , 512 ) ;
for ( c = 0 ; c < 512 ; c + + ) {
calcChecksumChunk + = sdBuffer [ c ] ;
}
}
2022-10-13 09:49:03 +02:00
calcChecksum + = calcMirrorCount * calcChecksumChunk ;
2021-01-27 08:05:25 +01:00
}
2022-10-13 09:49:03 +02:00
} else if ( ( calcFilesize = = 40 ) & & ( romChips = = 85 ) ) {
2021-01-27 08:05:25 +01:00
// Daikaijuu Monogatari 2 Fix 5MB (40Mbit)
// Add the 4MB (32Mbit) start
for ( j = 0 ; j < ( 4194304 / 512 ) ; j + + ) {
myFile . read ( sdBuffer , 512 ) ;
for ( c = 0 ; c < 512 ; c + + ) {
calcChecksumChunk + = sdBuffer [ c ] ;
}
calcChecksum = calcChecksumChunk ;
}
calcChecksumChunk = 0 ;
// Add the 1MB (8Mbit) end
for ( j = 0 ; j < ( 1048576 / 512 ) ; j + + ) {
myFile . read ( sdBuffer , 512 ) ;
for ( c = 0 ; c < 512 ; c + + ) {
calcChecksumChunk + = sdBuffer [ c ] ;
}
}
2022-10-13 09:49:03 +02:00
calcChecksum + = 4 * calcChecksumChunk ;
} else if ( calcFilesize = = 48 ) {
2021-01-27 08:05:25 +01:00
// Star Ocean/Tales of Phantasia Fix 6MB (48Mbit)
// Add the 4MB (32Mbit) start
for ( j = 0 ; j < ( 4194304 / 512 ) ; j + + ) {
myFile . read ( sdBuffer , 512 ) ;
for ( c = 0 ; c < 512 ; c + + ) {
calcChecksumChunk + = sdBuffer [ c ] ;
}
calcChecksum = calcChecksumChunk ;
}
calcChecksumChunk = 0 ;
// Add the 2MB (16Mbit) end
for ( j = 0 ; j < ( 2097152 / 512 ) ; j + + ) {
myFile . read ( sdBuffer , 512 ) ;
for ( c = 0 ; c < 512 ; c + + ) {
calcChecksumChunk + = sdBuffer [ c ] ;
}
}
2022-10-13 09:49:03 +02:00
calcChecksum + = 2 * calcChecksumChunk ;
} else {
2021-01-27 08:05:25 +01:00
//calcFilesize == 2 || 4 || 8 || 16 || 32 || 40 || etc
for ( i = 0 ; i < ( myFile . fileSize ( ) / 512 ) ; i + + ) {
myFile . read ( sdBuffer , 512 ) ;
for ( c = 0 ; c < 512 ; c + + ) {
calcChecksumChunk + = sdBuffer [ c ] ;
}
calcChecksum = calcChecksumChunk ;
}
}
myFile . close ( ) ;
sd . chdir ( ) ;
return ( calcChecksum ) ;
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
// Else show error
2022-10-30 03:21:01 +01:00
print_Error ( F ( " DUMP ROM 1ST " ) ) ;
2021-01-27 08:05:25 +01:00
return 0 ;
}
}
boolean compare_checksum ( ) {
2022-09-25 16:40:21 +02:00
print_Msg ( F ( " Checksum... " ) ) ;
2021-01-27 08:05:25 +01:00
display_Update ( ) ;
char calcsumStr [ 5 ] ;
sprintf ( calcsumStr , " %04X " , calc_checksum ( fileName , folder ) ) ;
2022-09-25 16:40:21 +02:00
print_Msg ( calcsumStr ) ;
2022-10-04 20:30:53 +02:00
2021-01-27 08:05:25 +01:00
if ( strcmp ( calcsumStr , checksumStr ) = = 0 ) {
2022-09-25 16:40:21 +02:00
println_Msg ( F ( " -> OK " ) ) ;
2021-01-27 08:05:25 +01:00
display_Update ( ) ;
return 1 ;
2022-10-13 09:49:03 +02:00
} else {
2022-09-25 16:40:21 +02:00
print_Msg ( F ( " != " ) ) ;
println_Msg ( checksumStr ) ;
2022-10-30 03:21:01 +01:00
print_Error ( F ( " Invalid Checksum " ) ) ;
2021-01-27 08:05:25 +01:00
display_Update ( ) ;
return 0 ;
}
}
// Read rom to SD card
void readROM_SNES ( ) {
// Set control
dataIn ( ) ;
controlIn_SNES ( ) ;
// Get name, add extension and convert to char array for sd lib
2024-05-26 22:20:47 +02:00
createFolderAndOpenFile ( " SNES " , " ROM " , romName , " sfc " ) ;
2021-01-27 08:05:25 +01:00
2023-09-22 00:39:18 +02:00
//Dump Derby Stallion '96 (Japan) and Sound Novel Tsukuru (Japan) - Actual Size is 24Mb
2023-11-20 21:46:44 +01:00
if ( ( romType = = LO ) & & ( numBanks = = 96 ) & & ( ( strcmp ( " CC86 " , checksumStr ) = = 0 ) | | ( strcmp ( " A77B " , checksumStr ) = = 0 ) ) ) {
2021-01-27 08:05:25 +01:00
// Read Banks 0x00-0x3F for the 1st/2nd MB
for ( int currBank = 0 ; currBank < 64 ; currBank + + ) {
// Dump the bytes to SD 512B at a time
for ( long currByte = 32768 ; currByte < 65536 ; currByte + = 512 ) {
for ( int c = 0 ; c < 512 ; c + + ) {
sdBuffer [ c ] = readBank_SNES ( currBank , currByte + c ) ;
}
myFile . write ( sdBuffer , 512 ) ;
}
}
//Read Bank 0x80-9F for the 3rd MB
for ( int currBank = 128 ; currBank < 160 ; currBank + + ) {
// Dump the bytes to SD 512B at a time
for ( long currByte = 32768 ; currByte < 65536 ; currByte + = 512 ) {
for ( int c = 0 ; c < 512 ; c + + ) {
sdBuffer [ c ] = readBank_SNES ( currBank , currByte + c ) ;
}
myFile . write ( sdBuffer , 512 ) ;
}
}
}
//Dump Low-type ROM
else if ( romType = = LO ) {
2022-10-13 09:49:03 +02:00
if ( romChips = = 243 ) { //0xF3
cx4Map = readBank_SNES ( 0 , 32594 ) ; //0x7F52
if ( ( cx4Type = = 2 ) & & ( cx4Map ! = 0 ) ) { //X2
2021-01-27 08:05:25 +01:00
dataOut ( ) ;
controlOut_SNES ( ) ;
2022-10-13 09:49:03 +02:00
writeBank_SNES ( 0 , 32594 , 0 ) ; // Set 0x7F52 to 0
2021-01-27 08:05:25 +01:00
dataIn ( ) ;
controlIn_SNES ( ) ;
2022-10-13 09:49:03 +02:00
} else if ( ( cx4Type = = 3 ) & & ( cx4Map = = 0 ) ) { //X3
2021-01-27 08:05:25 +01:00
dataOut ( ) ;
controlOut_SNES ( ) ;
2022-10-13 09:49:03 +02:00
writeBank_SNES ( 0 , 32594 , 1 ) ; // Set 0x7F52 to 1
2021-01-27 08:05:25 +01:00
dataIn ( ) ;
controlIn_SNES ( ) ;
}
}
if ( romSize > 24 ) {
// ROM > 96 banks (up to 128 banks)
2022-10-13 09:49:03 +02:00
readLoRomBanks ( 0x80 , numBanks + 0x80 , & myFile ) ;
2021-01-27 08:05:25 +01:00
} else {
// Read up to 96 banks starting at bank 0× 00.
2022-10-13 09:49:03 +02:00
readLoRomBanks ( 0 , numBanks , & myFile ) ;
2021-01-27 08:05:25 +01:00
}
2022-10-13 09:49:03 +02:00
if ( romChips = = 243 ) { //0xF3
2021-01-27 08:05:25 +01:00
// Restore CX4 Mapping Register
dataOut ( ) ;
controlOut_SNES ( ) ;
2022-10-13 09:49:03 +02:00
writeBank_SNES ( 0 , 32594 , cx4Map ) ; // 0x7F52
2021-01-27 08:05:25 +01:00
dataIn ( ) ;
controlIn_SNES ( ) ;
}
}
// Dump SDD1 High-type ROM
2022-08-24 05:48:49 +02:00
else if ( ( romType = = HI ) & & ( romChips = = 69 | | romChips = = 67 ) ) {
2021-01-27 08:05:25 +01:00
println_Msg ( F ( " Dumping SDD1 HiRom " ) ) ;
display_Update ( ) ;
controlIn_SNES ( ) ;
byte initialSOMap = readBank_SNES ( 0 , 18439 ) ;
2022-11-01 08:43:42 +01:00
for ( word currMemmap = 0 ; currMemmap < ( numBanks / 16 ) ; currMemmap + + ) {
2021-01-27 08:05:25 +01:00
dataOut ( ) ;
controlOut_SNES ( ) ;
writeBank_SNES ( 0 , 18439 , currMemmap ) ;
dataIn ( ) ;
controlIn_SNES ( ) ;
2022-10-13 09:49:03 +02:00
readHiRomBanks ( 240 , 256 , & myFile ) ;
2021-01-27 08:05:25 +01:00
if ( currMemmap = = 2 ) display_Clear ( ) ; // need more space for the progress bars
}
dataOut ( ) ;
controlOut_SNES ( ) ;
writeBank_SNES ( 0 , 18439 , initialSOMap ) ;
dataIn ( ) ;
controlIn_SNES ( ) ;
}
// Dump SPC7110 High-type ROM
else if ( ( romType = = HI ) & & ( ( romChips = = 245 ) | | ( romChips = = 249 ) ) ) {
println_Msg ( F ( " Dumping SPC7110 HiRom " ) ) ;
display_Update ( ) ;
// 0xC00000-0xDFFFFF
//print_Msg(F("Part 1"));
display_Update ( ) ;
2022-10-13 09:49:03 +02:00
readHiRomBanks ( 192 , 224 , & myFile ) ;
2021-01-27 08:05:25 +01:00
if ( numBanks > 32 ) {
dataOut ( ) ;
controlOut_SNES ( ) ;
// Set 0x4834 to 0xFF
2022-10-13 09:49:03 +02:00
writeBank_SNES ( 0 , 0x4834 , 0xFF ) ;
2021-01-27 08:05:25 +01:00
dataIn ( ) ;
controlIn_SNES ( ) ;
// 0xE00000-0xEFFFFF
//print_Msg(F(" 2"));
display_Update ( ) ;
2022-10-13 09:49:03 +02:00
readHiRomBanks ( 224 , 240 , & myFile ) ;
2021-01-27 08:05:25 +01:00
if ( numBanks > 48 ) {
// 0xF00000-0xFFFFFF
//print_Msg(F(" 3"));
display_Update ( ) ;
2022-10-13 09:49:03 +02:00
readHiRomBanks ( 240 , 256 , & myFile ) ;
2021-01-27 08:05:25 +01:00
dataOut ( ) ;
controlOut_SNES ( ) ;
// Set 0x4833 to 3
2022-10-13 09:49:03 +02:00
writeBank_SNES ( 0 , 0x4833 , 3 ) ;
2021-01-27 08:05:25 +01:00
dataIn ( ) ;
controlIn_SNES ( ) ;
// 0xF00000-0xFFFFFF
//print_Msg(F(" 4"));
display_Update ( ) ;
2022-10-13 09:49:03 +02:00
readHiRomBanks ( 240 , 256 , & myFile ) ;
2021-01-27 08:05:25 +01:00
}
2024-03-02 17:26:35 +01:00
//println_Msg(FS(FSTRING_EMPTY));
2021-01-27 08:05:25 +01:00
display_Clear ( ) ; // need more space due to the 4 progress bars
// Return mapping registers to initial settings...
dataOut ( ) ;
controlOut_SNES ( ) ;
2022-10-13 09:49:03 +02:00
writeBank_SNES ( 0 , 0x4833 , 2 ) ;
writeBank_SNES ( 0 , 0x4834 , 0 ) ;
2021-01-27 08:05:25 +01:00
dataIn ( ) ;
controlIn_SNES ( ) ;
}
}
// Dump standard High-type ROM
else if ( ( romType = = HI ) | | ( romType = = SA ) | | ( romType = = EX ) ) {
println_Msg ( F ( " Dumping HiRom... " ) ) ;
display_Update ( ) ;
2022-11-24 10:08:41 +01:00
if ( romChips = = 85 ) {
// Daikaijuu Monogatari 2, keeps out S-RTC register area
readHiRomBanks ( 192 , 192 + 64 , & myFile ) ;
2022-12-20 10:31:35 +01:00
readHiRomBanks ( 64 , numBanks , & myFile ) ; // (64 + (numBanks - 64))
} else {
2022-11-24 10:08:41 +01:00
readHiRomBanks ( 192 , numBanks + 192 , & myFile ) ;
}
2021-01-27 08:05:25 +01:00
}
// Close the file:
myFile . close ( ) ;
}
/******************************************
SNES SRAM Functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Write file to SRAM
2022-10-13 09:49:03 +02:00
void writeSRAM ( boolean browseFile ) {
2021-01-27 08:05:25 +01:00
if ( browseFile ) {
filePath [ 0 ] = ' \0 ' ;
sd . chdir ( " / " ) ;
fileBrowser ( F ( " Select srm file " ) ) ;
// Create filepath
sprintf ( filePath , " %s/%s " , filePath , fileName ) ;
display_Clear ( ) ;
2022-10-13 09:49:03 +02:00
} else
2021-01-27 08:05:25 +01:00
sprintf ( filePath , " %s " , fileName ) ;
//open file on sd card
if ( myFile . open ( filePath , O_READ ) ) {
// Set pins to output
dataOut ( ) ;
// Set RST RD WR to High and CS to Low
controlOut_SNES ( ) ;
int sramBanks = 0 ;
// LoRom
if ( romType = = LO ) {
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) ;
2022-10-13 09:49:03 +02:00
if ( ( romChips = = 19 ) | | ( romChips = = 20 ) | | ( romChips = = 21 ) | | ( romChips = = 26 ) ) { // SuperFX
if ( lastByte > 0x10000 ) { // Large SuperFX SRAM (no known carts)
2021-01-27 08:05:25 +01:00
sramBanks = lastByte / 0x10000 ;
for ( int currBank = 0x70 ; currBank < sramBanks + 0x70 ; currBank + + ) {
for ( long currByte = 0x0000 ; currByte < 0x10000 ; currByte + + ) {
writeBank_SNES ( currBank , currByte , myFile . read ( ) ) ;
}
}
2022-10-13 09:49:03 +02:00
} else { // SuperFX SRAM
2021-01-27 08:05:25 +01:00
for ( long currByte = 0 ; currByte < lastByte ; currByte + + ) {
writeBank_SNES ( 0x70 , currByte , myFile . read ( ) ) ;
}
}
2022-10-13 09:49:03 +02:00
} else if ( lastByte > 0x8000 ) { // Large SRAM Fix
2021-01-27 08:05:25 +01:00
sramBanks = lastByte / 0x8000 ;
for ( int currBank = 0x70 ; currBank < sramBanks + 0x70 ; currBank + + ) {
for ( long currByte = 0x0000 ; currByte < 0x8000 ; currByte + + ) {
writeBank_SNES ( currBank , currByte , myFile . read ( ) ) ;
}
}
2022-10-13 09:49:03 +02:00
} else {
for ( long currByte = 0 ; currByte < lastByte ; currByte + + ) {
2021-01-27 08:05:25 +01:00
writeBank_SNES ( 0x70 , currByte , myFile . read ( ) ) ;
}
}
}
// HiRom
else if ( romType = = HI ) {
2022-10-13 09:49:03 +02:00
if ( ( romChips = = 245 ) | | ( romChips = = 249 ) ) { // SPC7110 SRAM
2021-01-27 08:05:25 +01:00
// Configure SPC7110 SRAM Register
// Set 0x4830 to 0x80
writeBank_SNES ( 0 , 0x4830 , 0x80 ) ;
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) + 0x6000 ;
// Write to sram bank
for ( long currByte = 0x6000 ; currByte < lastByte ; currByte + + ) {
writeBank_SNES ( 0x30 , currByte , myFile . read ( ) ) ;
}
// Reset SPC7110 SRAM Register
dataOut ( ) ;
// Reset 0x4830 to 0x0
writeBank_SNES ( 0 , 0x4830 , 0 ) ;
dataIn ( ) ;
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
// Writing SRAM on HiRom needs CS(PH3) to be high
2022-10-13 09:49:03 +02:00
PORTH | = ( 1 < < 3 ) ;
2021-01-27 08:05:25 +01:00
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) ;
2022-10-13 09:49:03 +02:00
if ( lastByte > 0x2000 ) { // Large SRAM Fix
2021-01-27 08:05:25 +01:00
sramBanks = lastByte / 0x2000 ;
for ( int currBank = 0x30 ; currBank < sramBanks + 0x30 ; currBank + + ) {
for ( long currByte = 0x6000 ; currByte < 0x8000 ; currByte + + ) {
writeBank_SNES ( currBank , currByte , myFile . read ( ) ) ;
}
}
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
lastByte + = 0x6000 ;
// Write to sram bank
for ( long currByte = 0x6000 ; currByte < lastByte ; currByte + + ) {
writeBank_SNES ( 0x30 , currByte , myFile . read ( ) ) ;
}
}
}
}
// ExHiRom
else if ( romType = = EX ) {
// Writing SRAM on HiRom needs CS(PH3) to be high
2022-10-13 09:49:03 +02:00
PORTH | = ( 1 < < 3 ) ;
2021-01-27 08:05:25 +01:00
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) + 0x6000 ;
for ( long currByte = 0x6000 ; currByte < lastByte ; currByte + + ) {
writeBank_SNES ( 0xB0 , currByte , myFile . read ( ) ) ;
}
}
// SA1
else if ( romType = = SA ) {
long lastByte = ( long ( sramSize ) * 128 ) ;
2021-11-18 14:55:50 +01:00
if ( i2c_found ) {
// Enable CPU Clock
clockgen . output_enable ( SI5351_CLK1 , 1 ) ;
}
2021-01-27 08:05:25 +01:00
// Direct writes to BW-RAM (SRAM) in banks 0x40-0x43 don't work
// Break BW-RAM (SRAM) into 0x2000 blocks
byte lastBlock = 0 ;
lastBlock = lastByte / 0x2000 ;
// Writing SRAM on SA1 needs CS(PH3) to be high
// PORTH |= (1 << 3);
// Setup BW-RAM
// Set 0x2224 (SNES BMAPS) to map SRAM Block 0 to 0x6000-0x7FFF
writeBank_SNES ( 0 , 0x2224 , 0 ) ;
// Set 0x2226 (SNES SBWE) to 0x80 Write Enable
writeBank_SNES ( 0 , 0x2226 , 0x80 ) ;
// Set 0x2228 (SNES BWPA) to 0x00 BW-RAM Write-Protected Area
writeBank_SNES ( 0 , 0x2228 , 0 ) ;
delay ( 1000 ) ;
// Use $2224 (SNES) to map BW-RAM block to 0x6000-0x7FFF
// Use $2226 (SNES) to write enable the BW-RAM
byte firstByte = 0 ;
for ( byte currBlock = 0 ; currBlock < lastBlock ; currBlock + + ) {
// Set 0x2224 (SNES BMAPS) to map SRAM Block to 0x6000-0x7FFF
writeBank_SNES ( 0 , 0x2224 , currBlock ) ;
// Set 0x2226 (SNES SBWE) to 0x80 Write Enable
writeBank_SNES ( 0 , 0x2226 , 0x80 ) ;
for ( long currByte = 0x6000 ; currByte < 0x8000 ; currByte + = 512 ) {
myFile . read ( sdBuffer , 512 ) ;
if ( ( currBlock = = 0 ) & & ( currByte = = 0x6000 ) ) {
firstByte = sdBuffer [ 0 ] ;
}
for ( int c = 0 ; c < 512 ; c + + ) {
writeBank_SNES ( 0 , currByte + c , sdBuffer [ c ] ) ;
}
}
}
// Rewrite First Byte
writeBank_SNES ( 0 , 0x2224 , 0 ) ;
writeBank_SNES ( 0 , 0x2226 , 0x80 ) ;
writeBank_SNES ( 0 , 0x6000 , firstByte ) ;
2021-11-18 14:55:50 +01:00
if ( i2c_found ) {
// Disable CPU clock
clockgen . output_enable ( SI5351_CLK1 , 0 ) ;
}
2021-01-27 08:05:25 +01:00
}
// Set pins to input
dataIn ( ) ;
// Close the file:
myFile . close ( ) ;
println_Msg ( F ( " SRAM writing finished " ) ) ;
display_Update ( ) ;
2022-10-13 09:49:03 +02:00
} else {
2024-05-11 23:32:06 +02:00
print_Error ( FS ( FSTRING_FILE_DOESNT_EXIST ) ) ;
2021-01-27 08:05:25 +01:00
}
}
2022-10-13 09:49:03 +02:00
void readSRAM ( ) {
2021-01-27 08:05:25 +01:00
// set control
controlIn_SNES ( ) ;
// Get name, add extension and convert to char array for sd lib
2024-05-12 15:37:11 +02:00
createFolder ( " SNES " , " SAVE " , romName , " srm " ) ;
2021-01-27 08:05:25 +01:00
// write new folder number back to eeprom
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 ) ;
2021-01-27 08:05:25 +01:00
}
int sramBanks = 0 ;
if ( romType = = LO ) {
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) ;
2022-10-13 09:49:03 +02:00
if ( ( romChips = = 19 ) | | ( romChips = = 20 ) | | ( romChips = = 21 ) | | ( romChips = = 26 ) ) { // SuperFX
if ( lastByte > 0x10000 ) { // Large SuperFX SRAM (no known carts)
2021-01-27 08:05:25 +01:00
sramBanks = lastByte / 0x10000 ;
for ( int currBank = 0x70 ; currBank < sramBanks + 0x70 ; currBank + + ) {
for ( long currByte = 0x0000 ; currByte < 0x10000 ; currByte + + ) {
myFile . write ( readBank_SNES ( currBank , currByte ) ) ;
}
}
2022-10-13 09:49:03 +02:00
} else { // SuperFX SRAM
2021-01-27 08:05:25 +01:00
for ( long currByte = 0 ; currByte < lastByte ; currByte + + ) {
myFile . write ( readBank_SNES ( 0x70 , currByte ) ) ;
}
}
2022-10-13 09:49:03 +02:00
} else if ( lastByte > 0x8000 ) { // Large SRAM Fix
2021-01-27 08:05:25 +01:00
sramBanks = lastByte / 0x8000 ;
for ( int currBank = 0x70 ; currBank < sramBanks + 0x70 ; currBank + + ) {
for ( long currByte = 0x0000 ; currByte < 0x8000 ; currByte + + ) {
myFile . write ( readBank_SNES ( currBank , currByte ) ) ;
}
}
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
for ( long currByte = 0 ; currByte < lastByte ; currByte + + ) {
myFile . write ( readBank_SNES ( 0x70 , currByte ) ) ;
}
}
2022-10-13 09:49:03 +02:00
} else if ( romType = = HI ) {
if ( ( romChips = = 245 ) | | ( romChips = = 249 ) ) { // SPC7110 SRAM
2021-01-27 08:05:25 +01:00
// Configure SPC7110 SRAM Register
dataOut ( ) ;
// Set 0x4830 to 0x80
writeBank_SNES ( 0 , 0x4830 , 0x80 ) ;
dataIn ( ) ;
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) + 0x6000 ;
for ( long currByte = 0x6000 ; currByte < lastByte ; currByte + + ) {
myFile . write ( readBank_SNES ( 0x30 , currByte ) ) ;
}
dataOut ( ) ;
// Reset 0x4830 to 0x0
writeBank_SNES ( 0 , 0x4830 , 0 ) ;
dataIn ( ) ;
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
// Dumping SRAM on HiRom needs CS(PH3) to be high
2022-10-13 09:49:03 +02:00
PORTH | = ( 1 < < 3 ) ;
2021-01-27 08:05:25 +01:00
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) ;
2022-10-13 09:49:03 +02:00
if ( lastByte > 0x2000 ) { // Large SRAM Fix
2021-01-27 08:05:25 +01:00
sramBanks = lastByte / 0x2000 ;
for ( int currBank = 0x30 ; currBank < sramBanks + 0x30 ; currBank + + ) {
for ( long currByte = 0x6000 ; currByte < 0x8000 ; currByte + + ) {
myFile . write ( readBank_SNES ( currBank , currByte ) ) ;
}
}
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
lastByte + = 0x6000 ;
for ( long currByte = 0x6000 ; currByte < lastByte ; currByte + + ) {
myFile . write ( readBank_SNES ( 0x30 , currByte ) ) ;
}
}
}
2022-10-13 09:49:03 +02:00
} else if ( romType = = EX ) {
2021-01-27 08:05:25 +01:00
// Dumping SRAM on HiRom needs CS(PH3) to be high
2022-10-13 09:49:03 +02:00
PORTH | = ( 1 < < 3 ) ;
2021-01-27 08:05:25 +01:00
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) + 0x6000 ;
for ( long currByte = 0x6000 ; currByte < lastByte ; currByte + + ) {
myFile . write ( readBank_SNES ( 0xB0 , currByte ) ) ;
}
2022-10-13 09:49:03 +02:00
} else if ( romType = = SA ) {
2021-01-27 08:05:25 +01:00
// Dumping SRAM on HiRom needs CS(PH3) to be high
2022-10-13 09:49:03 +02:00
PORTH | = ( 1 < < 3 ) ;
2021-01-27 08:05:25 +01:00
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) ;
if ( lastByte > 0x10000 ) {
sramBanks = lastByte / 0x10000 ;
for ( int currBank = 0x40 ; currBank < sramBanks + 0x40 ; currBank + + ) {
for ( long currByte = 0 ; currByte < 0x10000 ; currByte + + ) {
myFile . write ( readBank_SNES ( currBank , currByte ) ) ;
}
}
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
for ( long currByte = 0x0 ; currByte < lastByte ; currByte + + ) {
myFile . write ( readBank_SNES ( 0x40 , currByte ) ) ;
}
}
}
// Close the file:
myFile . close ( ) ;
// Signal end of process
display_Clear ( ) ;
print_Msg ( F ( " Saved to " ) ) ;
print_Msg ( folder ) ;
println_Msg ( F ( " /... " ) ) ;
display_Update ( ) ;
}
// Check if the SRAM was written without any error
unsigned long verifySRAM ( ) {
//open file on sd card
if ( myFile . open ( filePath , O_READ ) ) {
// Variable for errors
writeErrors = 0 ;
// Set control
controlIn_SNES ( ) ;
int sramBanks = 0 ;
if ( romType = = LO ) {
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) ;
2022-10-13 09:49:03 +02:00
if ( ( romChips = = 19 ) | | ( romChips = = 20 ) | | ( romChips = = 21 ) | | ( romChips = = 26 ) ) { // SuperFX
if ( lastByte > 0x10000 ) { // Large SuperFX SRAM (no known carts)
2021-01-27 08:05:25 +01:00
sramBanks = lastByte / 0x10000 ;
for ( int currBank = 0x70 ; currBank < sramBanks + 0x70 ; currBank + + ) {
for ( long currByte = 0 ; currByte < 0x10000 ; currByte + = 512 ) {
//fill sdBuffer
myFile . read ( sdBuffer , 512 ) ;
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( currBank , currByte + c ) ) ! = sdBuffer [ c ] ) {
writeErrors + + ;
}
}
}
}
2022-10-13 09:49:03 +02:00
} else { // SuperFX SRAM
2021-01-27 08:05:25 +01:00
for ( long currByte = 0 ; currByte < lastByte ; currByte + = 512 ) {
//fill sdBuffer
myFile . read ( sdBuffer , 512 ) ;
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( 0x70 , currByte + c ) ) ! = sdBuffer [ c ] ) {
writeErrors + + ;
}
}
}
}
2022-10-13 09:49:03 +02:00
} else if ( lastByte > 0x8000 ) { // Large SRAM Fix
2021-01-27 08:05:25 +01:00
sramBanks = lastByte / 0x8000 ;
for ( int currBank = 0x70 ; currBank < sramBanks + 0x70 ; currBank + + ) {
for ( long currByte = 0 ; currByte < 0x8000 ; currByte + = 512 ) {
//fill sdBuffer
myFile . read ( sdBuffer , 512 ) ;
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( currBank , currByte + c ) ) ! = sdBuffer [ c ] ) {
writeErrors + + ;
}
}
}
}
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
for ( long currByte = 0 ; currByte < lastByte ; currByte + = 512 ) {
//fill sdBuffer
myFile . read ( sdBuffer , 512 ) ;
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( 0x70 , currByte + c ) ) ! = sdBuffer [ c ] ) {
writeErrors + + ;
}
}
}
}
2022-10-13 09:49:03 +02:00
} else if ( romType = = HI ) {
if ( ( romChips = = 245 ) | | ( romChips = = 249 ) ) { // SPC7110 SRAM
2021-01-27 08:05:25 +01:00
// Configure SPC7110 SRAM Register
dataOut ( ) ;
// Set 0x4830 to 0x80
writeBank_SNES ( 0 , 0x4830 , 0x80 ) ;
dataIn ( ) ;
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) + 0x6000 ;
for ( long currByte = 0x6000 ; currByte < lastByte ; currByte + = 512 ) {
//fill sdBuffer
myFile . read ( sdBuffer , 512 ) ;
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( 0x30 , currByte + c ) ) ! = sdBuffer [ c ] ) {
writeErrors + + ;
}
}
}
dataOut ( ) ;
// Reset 0x4830 to 0x0
writeBank_SNES ( 0 , 0x4830 , 0 ) ;
dataIn ( ) ;
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
// Dumping SRAM on HiRom needs CS(PH3) to be high
2022-10-13 09:49:03 +02:00
PORTH | = ( 1 < < 3 ) ;
2021-01-27 08:05:25 +01:00
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) ;
2022-10-13 09:49:03 +02:00
if ( lastByte > 0x2000 ) { // Large SRAM Fix
2021-01-27 08:05:25 +01:00
sramBanks = lastByte / 0x2000 ;
for ( int currBank = 0x30 ; currBank < sramBanks + 0x30 ; currBank + + ) {
for ( long currByte = 0x6000 ; currByte < 0x8000 ; currByte + = 512 ) {
//fill sdBuffer
myFile . read ( sdBuffer , 512 ) ;
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( currBank , currByte + c ) ) ! = sdBuffer [ c ] ) {
writeErrors + + ;
}
}
}
}
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
lastByte + = 0x6000 ;
for ( long currByte = 0x6000 ; currByte < lastByte ; currByte + = 512 ) {
//fill sdBuffer
myFile . read ( sdBuffer , 512 ) ;
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( 0x30 , currByte + c ) ) ! = sdBuffer [ c ] ) {
writeErrors + + ;
}
}
}
}
}
2022-10-13 09:49:03 +02:00
} else if ( romType = = EX ) {
2021-01-27 08:05:25 +01:00
// Dumping SRAM on HiRom needs CS(PH3) to be high
2022-10-13 09:49:03 +02:00
PORTH | = ( 1 < < 3 ) ;
2021-01-27 08:05:25 +01:00
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) + 0x6000 ;
for ( long currByte = 0x6000 ; currByte < lastByte ; currByte + = 512 ) {
//fill sdBuffer
myFile . read ( sdBuffer , 512 ) ;
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( 0xB0 , currByte + c ) ) ! = sdBuffer [ c ] ) {
writeErrors + + ;
}
}
}
2022-10-13 09:49:03 +02:00
} else if ( romType = = SA ) {
2021-01-27 08:05:25 +01:00
// Dumping SRAM on HiRom needs CS(PH3) to be high
2022-10-13 09:49:03 +02:00
PORTH | = ( 1 < < 3 ) ;
2021-01-27 08:05:25 +01:00
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) ;
if ( lastByte > 0x10000 ) {
sramBanks = lastByte / 0x10000 ;
for ( int currBank = 0x40 ; currBank < sramBanks + 0x40 ; currBank + + ) {
for ( long currByte = 0x0 ; currByte < 0x10000 ; currByte + = 512 ) {
//fill sdBuffer
myFile . read ( sdBuffer , 512 ) ;
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( currBank , currByte + c ) ) ! = sdBuffer [ c ] ) {
writeErrors + + ;
}
}
}
}
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
for ( long currByte = 0x0 ; currByte < lastByte ; currByte + = 512 ) {
//fill sdBuffer
myFile . read ( sdBuffer , 512 ) ;
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( 0x40 , currByte + c ) ) ! = sdBuffer [ c ] ) {
writeErrors + + ;
}
}
}
}
// Reset SA1
// Set pins to input
dataIn ( ) ;
// Close the file:
myFile . close ( ) ;
if ( writeErrors = = 0 ) {
println_Msg ( F ( " Verified OK " ) ) ;
2022-10-13 09:49:03 +02:00
} else {
2022-10-21 15:59:06 +02:00
print_STR ( error_STR , 0 ) ;
2021-01-27 08:05:25 +01:00
print_Msg ( writeErrors ) ;
2022-10-21 15:59:06 +02:00
print_STR ( _bytes_STR , 1 ) ;
2022-10-30 03:21:01 +01:00
print_Error ( did_not_verify_STR ) ;
2021-01-27 08:05:25 +01:00
}
display_Update ( ) ;
wait ( ) ;
stopSnesClocks_resetCic_resetCart ( ) ;
display_Clear ( ) ;
print_Msg ( F ( " Resetting... " ) ) ;
display_Update ( ) ;
delay ( 3000 ) ; // wait 3 secs
resetArduino ( ) ;
}
// Close the file:
myFile . close ( ) ;
return writeErrors ;
2022-10-13 09:49:03 +02:00
} else {
2022-10-30 03:21:01 +01:00
print_Error ( F ( " Can't open file " ) ) ;
2022-10-22 10:25:37 +02:00
return 1 ;
2021-01-27 08:05:25 +01:00
}
}
// Overwrite the entire SRAM
2022-10-13 09:49:03 +02:00
boolean eraseSRAM ( byte b ) {
2021-01-27 08:05:25 +01:00
print_Msg ( F ( " 0x " ) ) ;
print_Msg ( b , HEX ) ;
print_Msg ( F ( " : " ) ) ;
display_Update ( ) ;
// Set pins to output
dataOut ( ) ;
// Set control pins
controlOut_SNES ( ) ;
int sramBanks = 0 ;
if ( romType = = LO ) {
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) ;
2022-10-13 09:49:03 +02:00
if ( ( romChips = = 19 ) | | ( romChips = = 20 ) | | ( romChips = = 21 ) | | ( romChips = = 26 ) ) { // SuperFX
if ( lastByte > 0x10000 ) { // Large SuperFX SRAM (no known carts)
2021-01-27 08:05:25 +01:00
sramBanks = lastByte / 0x10000 ;
for ( int currBank = 0x70 ; currBank < sramBanks + 0x70 ; currBank + + ) {
for ( long currByte = 0x0000 ; currByte < 0x10000 ; currByte + + ) {
writeBank_SNES ( currBank , currByte , b ) ;
}
}
2022-10-13 09:49:03 +02:00
} else { // SuperFX SRAM
2021-01-27 08:05:25 +01:00
for ( long currByte = 0 ; currByte < lastByte ; currByte + + ) {
writeBank_SNES ( 0x70 , currByte , b ) ;
}
}
2022-10-13 09:49:03 +02:00
} else if ( lastByte > 0x8000 ) { // Large SRAM Fix
2021-01-27 08:05:25 +01:00
sramBanks = lastByte / 0x8000 ;
for ( int currBank = 0x70 ; currBank < sramBanks + 0x70 ; currBank + + ) {
for ( long currByte = 0x0000 ; currByte < 0x8000 ; currByte + + ) {
writeBank_SNES ( currBank , currByte , b ) ;
}
}
2022-10-13 09:49:03 +02:00
} else {
for ( long currByte = 0 ; currByte < lastByte ; currByte + + ) {
2021-01-27 08:05:25 +01:00
writeBank_SNES ( 0x70 , currByte , b ) ;
}
}
2022-10-13 09:49:03 +02:00
} else if ( romType = = HI ) {
if ( ( romChips = = 245 ) | | ( romChips = = 249 ) ) { // SPC7110 SRAM
2021-01-27 08:05:25 +01:00
// Configure SPC7110 SRAM Register
// Set 0x4830 to 0x80
writeBank_SNES ( 0 , 0x4830 , 0x80 ) ;
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) + 0x6000 ;
// Write to sram bank
for ( long currByte = 0x6000 ; currByte < lastByte ; currByte + + ) {
writeBank_SNES ( 0x30 , currByte , b ) ;
}
// Reset SPC7110 SRAM Register
dataOut ( ) ;
// Reset 0x4830 to 0x0
writeBank_SNES ( 0 , 0x4830 , 0 ) ;
dataIn ( ) ;
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
// Writing SRAM on HiRom needs CS(PH3) to be high
2022-10-13 09:49:03 +02:00
PORTH | = ( 1 < < 3 ) ;
2021-01-27 08:05:25 +01:00
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) ;
2022-10-13 09:49:03 +02:00
if ( lastByte > 0x2000 ) { // Large SRAM Fix
2021-01-27 08:05:25 +01:00
sramBanks = lastByte / 0x2000 ;
for ( int currBank = 0x30 ; currBank < sramBanks + 0x30 ; currBank + + ) {
for ( long currByte = 0x6000 ; currByte < 0x8000 ; currByte + + ) {
writeBank_SNES ( currBank , currByte , b ) ;
}
}
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
lastByte + = 0x6000 ;
// Write to sram bank
for ( long currByte = 0x6000 ; currByte < lastByte ; currByte + + ) {
writeBank_SNES ( 0x30 , currByte , b ) ;
}
}
}
}
// ExHiRom
else if ( romType = = EX ) {
// Writing SRAM on HiRom needs CS(PH3) to be high
2022-10-13 09:49:03 +02:00
PORTH | = ( 1 < < 3 ) ;
2021-01-27 08:05:25 +01:00
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) + 0x6000 ;
for ( long currByte = 0x6000 ; currByte < lastByte ; currByte + + ) {
writeBank_SNES ( 0xB0 , currByte , b ) ;
}
}
// SA1
else if ( romType = = SA ) {
long lastByte = ( long ( sramSize ) * 128 ) ;
2021-11-18 14:55:50 +01:00
if ( i2c_found ) {
// Enable CPU Clock
clockgen . output_enable ( SI5351_CLK1 , 1 ) ;
}
2021-01-27 08:05:25 +01:00
// Direct writes to BW-RAM (SRAM) in banks 0x40-0x43 don't work
// Break BW-RAM (SRAM) into 0x2000 blocks
// Use $2224 to map BW-RAM block to 0x6000-0x7FFF
byte lastBlock = 0 ;
lastBlock = lastByte / 0x2000 ;
// Writing SRAM on SA1 needs CS(PH3) to be high
// PORTH |= (1 << 3);
// Setup BW-RAM
// Set 0x2224 (SNES BMAPS) to map SRAM Block 0 to 0x6000-0x7FFF
writeBank_SNES ( 0 , 0x2224 , 0 ) ;
// Set 0x2226 (SNES SBWE) to 0x80 Write Enable
writeBank_SNES ( 0 , 0x2226 , 0x80 ) ;
// Set 0x2228 (SNES BWPA) to 0x00 BW-RAM Write-Protected Area
writeBank_SNES ( 0 , 0x2228 , 0 ) ;
delay ( 1000 ) ;
// Use $2224 (SNES) to map BW-RAM block to 0x6000-0x7FFF
// Use $2226 (SNES) to write enable the BW-RAM
for ( byte currBlock = 0 ; currBlock < lastBlock ; currBlock + + ) {
// Set 0x2224 (SNES BMAPS) to map SRAM Block to 0x6000-0x7FFF
writeBank_SNES ( 0 , 0x2224 , currBlock ) ;
// Set 0x2226 (SNES SBWE) to 0x80 Write Enable
writeBank_SNES ( 0 , 0x2226 , 0x80 ) ;
for ( long currByte = 0x6000 ; currByte < 0x8000 ; currByte + = 512 ) {
for ( int c = 0 ; c < 512 ; c + + ) {
writeBank_SNES ( 0 , currByte + c , b ) ;
}
}
}
// Rewrite First Byte
writeBank_SNES ( 0 , 0x2224 , 0 ) ;
writeBank_SNES ( 0 , 0x2226 , 0x80 ) ;
writeBank_SNES ( 0 , 0x6000 , b ) ;
2021-11-18 14:55:50 +01:00
if ( i2c_found ) {
// Disable CPU clock
clockgen . output_enable ( SI5351_CLK1 , 0 ) ;
}
2021-01-27 08:05:25 +01:00
}
dataIn ( ) ;
// Variable for errors
writeErrors = 0 ;
// Set control
controlIn_SNES ( ) ;
sramBanks = 0 ;
if ( romType = = LO ) {
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) ;
2022-10-13 09:49:03 +02:00
if ( ( romChips = = 19 ) | | ( romChips = = 20 ) | | ( romChips = = 21 ) | | ( romChips = = 26 ) ) { // SuperFX
if ( lastByte > 0x10000 ) { // Large SuperFX SRAM (no known carts)
2021-01-27 08:05:25 +01:00
sramBanks = lastByte / 0x10000 ;
for ( int currBank = 0x70 ; currBank < sramBanks + 0x70 ; currBank + + ) {
for ( long currByte = 0 ; currByte < 0x10000 ; currByte + = 512 ) {
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( currBank , currByte + c ) ) ! = b ) {
writeErrors + + ;
}
}
}
}
2022-10-13 09:49:03 +02:00
} else { // SuperFX SRAM
2021-01-27 08:05:25 +01:00
for ( long currByte = 0 ; currByte < lastByte ; currByte + = 512 ) {
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( 0x70 , currByte + c ) ) ! = b ) {
writeErrors + + ;
}
}
}
}
2022-10-13 09:49:03 +02:00
} else if ( lastByte > 0x8000 ) { // Large SRAM Fix
2021-01-27 08:05:25 +01:00
sramBanks = lastByte / 0x8000 ;
for ( int currBank = 0x70 ; currBank < sramBanks + 0x70 ; currBank + + ) {
for ( long currByte = 0 ; currByte < 0x8000 ; currByte + = 512 ) {
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( currBank , currByte + c ) ) ! = b ) {
writeErrors + + ;
}
}
}
}
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
for ( long currByte = 0 ; currByte < lastByte ; currByte + = 512 ) {
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( 0x70 , currByte + c ) ) ! = b ) {
writeErrors + + ;
}
}
}
}
2022-10-13 09:49:03 +02:00
} else if ( romType = = HI ) {
if ( ( romChips = = 245 ) | | ( romChips = = 249 ) ) { // SPC7110 SRAM
2021-01-27 08:05:25 +01:00
// Configure SPC7110 SRAM Register
dataOut ( ) ;
// Set 0x4830 to 0x80
writeBank_SNES ( 0 , 0x4830 , 0x80 ) ;
dataIn ( ) ;
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) + 0x6000 ;
for ( long currByte = 0x6000 ; currByte < lastByte ; currByte + = 512 ) {
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( 0x30 , currByte + c ) ) ! = b ) {
writeErrors + + ;
}
}
}
dataOut ( ) ;
// Reset 0x4830 to 0x0
writeBank_SNES ( 0 , 0x4830 , 0 ) ;
dataIn ( ) ;
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
// Dumping SRAM on HiRom needs CS(PH3) to be high
2022-10-13 09:49:03 +02:00
PORTH | = ( 1 < < 3 ) ;
2021-01-27 08:05:25 +01:00
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) ;
2022-10-13 09:49:03 +02:00
if ( lastByte > 0x2000 ) { // Large SRAM Fix
2021-01-27 08:05:25 +01:00
sramBanks = lastByte / 0x2000 ;
for ( int currBank = 0x30 ; currBank < sramBanks + 0x30 ; currBank + + ) {
for ( long currByte = 0x6000 ; currByte < 0x8000 ; currByte + = 512 ) {
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( currBank , currByte + c ) ) ! = b ) {
writeErrors + + ;
}
}
}
}
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
lastByte + = 0x6000 ;
for ( long currByte = 0x6000 ; currByte < lastByte ; currByte + = 512 ) {
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( 0x30 , currByte + c ) ) ! = b ) {
writeErrors + + ;
}
}
}
}
}
2022-10-13 09:49:03 +02:00
} else if ( romType = = EX ) {
2021-01-27 08:05:25 +01:00
// Dumping SRAM on HiRom needs CS(PH3) to be high
2022-10-13 09:49:03 +02:00
PORTH | = ( 1 < < 3 ) ;
2021-01-27 08:05:25 +01:00
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) + 0x6000 ;
for ( long currByte = 0x6000 ; currByte < lastByte ; currByte + = 512 ) {
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( 0xB0 , currByte + c ) ) ! = b ) {
writeErrors + + ;
}
}
}
2022-10-13 09:49:03 +02:00
} else if ( romType = = SA ) {
2021-01-27 08:05:25 +01:00
// Dumping SRAM on HiRom needs CS(PH3) to be high
2022-10-13 09:49:03 +02:00
PORTH | = ( 1 < < 3 ) ;
2021-01-27 08:05:25 +01:00
// Sram size
long lastByte = ( long ( sramSize ) * 128 ) ;
if ( lastByte > 0x10000 ) {
sramBanks = lastByte / 0x10000 ;
for ( int currBank = 0x40 ; currBank < sramBanks + 0x40 ; currBank + + ) {
for ( long currByte = 0x0 ; currByte < 0x10000 ; currByte + = 512 ) {
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( currBank , currByte + c ) ) ! = b ) {
writeErrors + + ;
}
}
}
}
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
for ( long currByte = 0x0 ; currByte < lastByte ; currByte + = 512 ) {
for ( int c = 0 ; c < 512 ; c + + ) {
if ( ( readBank_SNES ( 0x40 , currByte + c ) ) ! = b ) {
writeErrors + + ;
}
}
}
}
}
if ( writeErrors = = 0 ) {
2024-03-02 17:26:35 +01:00
println_Msg ( FS ( FSTRING_OK ) ) ;
2021-01-27 08:05:25 +01:00
return 1 ;
2022-10-13 09:49:03 +02:00
} else {
2021-01-27 08:05:25 +01:00
println_Msg ( F ( " ERROR " ) ) ;
return 0 ;
}
display_Update ( ) ;
}
# endif
//******************************************
// End of File
2023-04-07 12:49:20 +02:00
//******************************************