2023-07-03 01:08:09 +02:00
//******************************************
// CASIO LOOPY MODULE
//******************************************
# ifdef enable_LOOPY
2023-07-03 09:15:20 +02:00
// SH-1 memory map locations, ROM starts here
const uint32_t LOOPY_MAP_ROM_ZERO = 0x0E000000 ;
const uint32_t LOOPY_MAP_SRAM_ZERO = 0x02000000 ;
const uint32_t LOOPY_SRAM_SIZE = 0x2000 ;
2023-07-03 01:08:09 +02:00
//******************************************
// SETUP
//******************************************
void setup_LOOPY ( ) {
// Request 5V
setVoltage ( VOLTS_SET_5V ) ;
// Set Address Pins to Output
2023-07-03 09:15:20 +02:00
// PK1-PK7, PA1-PA7, PC0-PC3, PL0-PL3 // Take whole port and unset the exceptions later
DDRK = DDRA = DDRC = DDRL = 0xFF ;
2023-07-03 01:08:09 +02:00
// Set Control Pins to Output
2023-07-03 09:15:20 +02:00
// /RAMWE(PH6)/RAMCS2(PH4)
DDRH | = ( 1 < < 6 ) | ( 1 < < 4 ) ;
// /CE(PL7) /OE(PL6)
DDRL | = ( 1 < < 7 ) | ( 1 < < 6 ) ;
2023-07-03 01:08:09 +02:00
// Set Pins (D0-D15) to Input
2023-07-03 09:15:20 +02:00
dataIn_LOOPY ( ) ;
2023-07-03 01:08:09 +02:00
2023-07-03 09:15:20 +02:00
// Reset HIGH (PF7)
DDRF | = ( 1 < < 7 ) ;
PORTF | = ( 1 < < 7 ) ;
2023-07-03 01:08:09 +02:00
2023-07-03 09:15:20 +02:00
strcpy ( romName , " LOOPY " ) ;
2023-07-03 01:08:09 +02:00
getCartInfo_LOOPY ( ) ;
mode = mode_LOOPY ;
}
//******************************************
// MENU
//******************************************
// Base Menu
static const char loopyMenuItem1 [ ] PROGMEM = " Read ROM " ;
static const char loopyMenuItem2 [ ] PROGMEM = " Read SRAM " ;
static const char loopyMenuItem3 [ ] PROGMEM = " Write SRAM " ;
//static const char loopyMenuItem4[] PROGMEM = "Reset"; (stored in common strings array)
static const char * const menuOptionsLOOPY [ ] PROGMEM = { loopyMenuItem1 , loopyMenuItem2 , loopyMenuItem3 , string_reset2 } ;
void loopyMenu ( ) {
convertPgm ( menuOptionsLOOPY , 4 ) ;
uint8_t mainMenu = question_box ( F ( " CASIO LOOPY MENU " ) , menuOptions , 4 , 0 ) ;
switch ( mainMenu ) {
case 0 :
// Read ROM
sd . chdir ( " / " ) ;
readROM_LOOPY ( ) ;
sd . chdir ( " / " ) ;
break ;
case 1 :
// Read SRAM
if ( sramSize ) {
sd . chdir ( " / " ) ;
display_Clear ( ) ;
println_Msg ( F ( " Reading SRAM... " ) ) ;
display_Update ( ) ;
readSRAM_LOOPY ( ) ;
sd . chdir ( " / " ) ;
} else {
print_Error ( F ( " Cart has no SRAM " ) ) ;
}
# if (defined(enable_OLED) || defined(enable_LCD))
// Wait for user input
// Prints string out of the common strings array either with or without newline
print_STR ( press_button_STR , 1 ) ;
display_Update ( ) ;
wait ( ) ;
# endif
break ;
case 2 :
// Write SRAM
if ( sramSize ) {
// Change working dir to root
sd . chdir ( " / " ) ;
fileBrowser ( F ( " Select SAV file " ) ) ;
display_Clear ( ) ;
writeSRAM_LOOPY ( ) ;
writeErrors = verifySRAM_LOOPY ( ) ;
if ( writeErrors = = 0 ) {
println_Msg ( F ( " SRAM verified OK " ) ) ;
display_Update ( ) ;
} else {
print_STR ( error_STR , 0 ) ;
print_Msg ( writeErrors ) ;
print_STR ( _bytes_STR , 1 ) ;
print_Error ( did_not_verify_STR ) ;
}
} else {
print_Error ( F ( " Cart has no SRAM " ) ) ;
}
# if (defined(enable_OLED) || defined(enable_LCD))
// Wait for user input
// Prints string out of the common strings array either with or without newline
print_STR ( press_button_STR , 1 ) ;
display_Update ( ) ;
wait ( ) ;
# endif
break ;
case 3 :
// reset
resetArduino ( ) ;
break ;
}
}
//******************************************
// LOW LEVEL FUNCTIONS
//******************************************
2023-07-03 09:15:20 +02:00
void setAddress_LOOPY ( unsigned long A ) {
// PK1 A0
// PK2 A1
// PK3 A21
// PK4 A3
// PK5 A20
// PK6 A15
// PK7 A13
PORTK = ( bitRead ( A , 0 ) < < 1 )
| ( bitRead ( A , 1 ) < < 2 )
| ( bitRead ( A , 21 ) < < 3 )
| ( bitRead ( A , 3 ) < < 4 )
| ( bitRead ( A , 20 ) < < 5 )
| ( bitRead ( A , 15 ) < < 6 )
| ( bitRead ( A , 13 ) < < 7 ) ;
// PA1 A2
// PA2 A4
// PA3 A19
// PA4 A18
// PA5 A16
// PA6 A17
// PA7 A14
PORTA = ( bitRead ( A , 2 ) < < 1 )
| ( bitRead ( A , 4 ) < < 2 )
| ( bitRead ( A , 19 ) < < 3 )
| ( bitRead ( A , 18 ) < < 4 )
| ( bitRead ( A , 16 ) < < 5 )
| ( bitRead ( A , 17 ) < < 6 )
| ( bitRead ( A , 14 ) < < 7 ) ;
// PC0 A6
// PC1 A8
// PC2 A10
// PC3 A12
PORTC = ( bitRead ( A , 6 ) )
| ( bitRead ( A , 8 ) < < 1 )
| ( bitRead ( A , 10 ) < < 2 )
| ( bitRead ( A , 12 ) < < 3 ) ;
// PL0 A5
// PL1 A7
// PL2 A9
// PL3 A11
PORTL = ( bitRead ( A , 5 ) )
| ( bitRead ( A , 7 ) < < 1 )
| ( bitRead ( A , 9 ) < < 2 )
| ( bitRead ( A , 11 ) < < 3 ) ;
}
uint16_t getWord_LOOPY ( ) {
return digitalRead ( A8 )
| ( digitalRead ( 22 ) < < 1 )
| ( digitalRead ( A6 ) < < 2 )
| ( digitalRead ( A5 ) < < 3 )
| ( digitalRead ( A3 ) < < 4 )
| ( digitalRead ( 40 ) < < 5 )
| ( digitalRead ( A2 ) < < 6 )
| ( digitalRead ( 41 ) < < 7 )
| ( digitalRead ( A1 ) < < 8 )
| ( digitalRead ( 3 ) < < 9 )
| ( digitalRead ( A0 ) < < 10 )
| ( digitalRead ( 2 ) < < 11 )
| ( digitalRead ( 14 ) < < 12 )
| ( digitalRead ( 15 ) < < 13 )
| ( digitalRead ( A4 ) < < 14 )
| ( digitalRead ( 4 ) < < 15 ) ;
}
uint8_t getByte_LOOPY ( ) {
return digitalRead ( A8 )
| ( digitalRead ( 22 ) < < 1 )
| ( digitalRead ( A6 ) < < 2 )
| ( digitalRead ( A5 ) < < 3 )
| ( digitalRead ( A3 ) < < 4 )
| ( digitalRead ( 40 ) < < 5 )
| ( digitalRead ( A2 ) < < 6 )
| ( digitalRead ( 41 ) < < 7 ) ;
}
void setByte_LOOPY ( uint8_t D ) {
digitalWrite ( A8 , bitRead ( D , 0 ) ) ;
digitalWrite ( 22 , bitRead ( D , 1 ) ) ;
digitalWrite ( A6 , bitRead ( D , 2 ) ) ;
digitalWrite ( A5 , bitRead ( D , 3 ) ) ;
digitalWrite ( A3 , bitRead ( D , 4 ) ) ;
digitalWrite ( 40 , bitRead ( D , 5 ) ) ;
digitalWrite ( A2 , bitRead ( D , 6 ) ) ;
digitalWrite ( 41 , bitRead ( D , 7 ) ) ;
}
2023-07-03 01:08:09 +02:00
void writeByte_LOOPY ( unsigned long myAddress , byte myData ) {
2023-07-03 09:15:20 +02:00
setAddress_LOOPY ( myAddress ) ;
2023-07-03 01:08:09 +02:00
__asm__ ( " nop \n \t " ) ;
PORTA = myData ;
// Set CS2(PH0), /CE(PH3), /OE(PH6) to HIGH
PORTH | = ( 1 < < 0 ) | ( 1 < < 3 ) | ( 1 < < 6 ) ;
// Set /CS1(PH4), /WE0(PH5) to LOW
PORTH & = ~ ( 1 < < 4 ) & ~ ( 1 < < 5 ) ;
__asm__ ( " nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t " ) ;
// Set CS2(PH0), /CS1(PH4), /WE0(PH5) to HIGH
PORTH | = ( 1 < < 0 ) | ( 1 < < 4 ) | ( 1 < < 5 ) ;
__asm__ ( " nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t " ) ;
}
word readWord_LOOPY ( unsigned long myAddress ) {
2023-07-03 09:15:20 +02:00
setAddress_LOOPY ( myAddress ) ;
2023-07-03 01:08:09 +02:00
__asm__ ( " nop \n \t " ) ;
// Set CS2(PH0), /CS1(PH4), /WE0(PH5) to HIGH
PORTH | = ( 1 < < 0 ) | ( 1 < < 4 ) | ( 1 < < 5 ) ;
// Set /CE(PH3), /OE(PH6) to LOW
PORTH & = ~ ( 1 < < 3 ) & ~ ( 1 < < 6 ) ;
__asm__ ( " nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t " ) ;
word tempWord = ( ( PINA & 0xFF ) < < 8 ) | ( PINC & 0xFF ) ;
// Set /CE(PH3), /OE(PH6) to HIGH
PORTH | = ( 1 < < 3 ) | ( 1 < < 6 ) ;
// Setting CS2(PH0) LOW
PORTH & = ~ ( 1 < < 0 ) ;
__asm__ ( " nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t " ) ;
return tempWord ;
}
byte readByte_LOOPY ( unsigned long myAddress ) { // SRAM BYTE
2023-07-03 09:15:20 +02:00
setAddress_LOOPY ( myAddress ) ;
2023-07-03 01:08:09 +02:00
__asm__ ( " nop \n \t " ) ;
// Set CS2(PH0), /CE(PH3), /WE0(PH5) to HIGH
PORTH | = ( 1 < < 0 ) | ( 1 < < 3 ) | ( 1 < < 5 ) ;
// Set /CS1(PH4), /OE(PH6) to LOW
PORTH & = ~ ( 1 < < 4 ) & ~ ( 1 < < 6 ) ;
__asm__ ( " nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t " ) ;
byte tempByte = PINA ;
__asm__ ( " nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t " ) ;
// Set /CS1(PH4), /OE(PH6) to HIGH
PORTH | = ( 1 < < 3 ) | ( 1 < < 6 ) ;
// Setting CS2(PH0) LOW
PORTH & = ~ ( 1 < < 0 ) ;
__asm__ ( " nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t "
" nop \n \t " ) ;
return tempByte ;
}
// Switch data pins to write
void dataOut_LOOPY ( ) {
2023-07-03 09:15:20 +02:00
// // PA0
// DDRA |= 0x01;
// // PK0
// DDRK |= 0x01;
// // PG0, PG1, PG5 (rest unused?)
// DDRG = 0xFF;
// // PJ0-1 (rest unused?)
// DDRJ = 0xFF;
// // PE4-PE5 (rest unused?)
// DDRE = 0xFF;
// // PF0-PF6
// DDRF |= 0b0111111;
pinMode ( A8 , OUTPUT ) ;
pinMode ( 22 , OUTPUT ) ;
pinMode ( A6 , OUTPUT ) ;
pinMode ( A5 , OUTPUT ) ;
pinMode ( A3 , OUTPUT ) ;
pinMode ( 40 , OUTPUT ) ;
pinMode ( A2 , OUTPUT ) ;
pinMode ( 41 , OUTPUT ) ;
pinMode ( A1 , OUTPUT ) ;
pinMode ( 3 , OUTPUT ) ;
pinMode ( A0 , OUTPUT ) ;
pinMode ( 2 , OUTPUT ) ;
pinMode ( 14 , OUTPUT ) ;
pinMode ( 15 , OUTPUT ) ;
pinMode ( A4 , OUTPUT ) ;
pinMode ( 4 , OUTPUT ) ;
2023-07-03 01:08:09 +02:00
}
// Switch data pins to read
void dataIn_LOOPY ( ) {
2023-07-03 09:15:20 +02:00
// // PA0
// DDRA &= ~0x01;
// // PK0
// DDRK &= ~0x01;
// // PG0, PG1, PG5 (rest unused?)
// DDRG = 0x00;
// // PJ0-1 (rest unused?)
// DDRJ = 0x00;
// // PE4-PE5 (rest unused?)
// DDRE = 0x00;
// // PF0-PF6
// DDRF &= ~0b0111111;
pinMode ( A8 , INPUT ) ;
pinMode ( 22 , INPUT ) ;
pinMode ( A6 , INPUT ) ;
pinMode ( A5 , INPUT ) ;
pinMode ( A3 , INPUT ) ;
pinMode ( 40 , INPUT ) ;
pinMode ( A2 , INPUT ) ;
pinMode ( 41 , INPUT ) ;
pinMode ( A1 , INPUT ) ;
pinMode ( 3 , INPUT ) ;
pinMode ( A0 , INPUT ) ;
pinMode ( 2 , INPUT ) ;
pinMode ( 14 , INPUT ) ;
pinMode ( 15 , INPUT ) ;
pinMode ( A4 , INPUT ) ;
pinMode ( 4 , INPUT ) ;
2023-07-03 01:08:09 +02:00
}
//******************************************
// CART INFO
//******************************************
void getCartInfo_LOOPY ( ) {
// Set control
dataIn_LOOPY ( ) ;
2023-07-03 09:15:20 +02:00
// Last word of ROM stored as 32-bit pointer at 000004h
// TODO make sure you have endianness right when interpreting this
uint32_t headerRomSize = ( ( uint32_t ) readWord_LOOPY ( 0x4 ) < < 16 | ( uint32_t ) readWord_LOOPY ( 0x6 ) ) ;
cartSize = headerRomSize - LOOPY_MAP_ROM_ZERO + 2 ;
2023-07-03 01:08:09 +02:00
2023-07-03 09:15:20 +02:00
// Get internal CRC32 from header
uint32_t cartHeaderCrc = ( uint32_t ) readWord_LOOPY ( 0x8 ) < < 16 | ( uint32_t ) readWord_LOOPY ( 0xA ) ;
snprintf ( checksumStr , 8 , " %08X " , cartHeaderCrc ) ;
2023-07-03 01:08:09 +02:00
2023-07-03 09:15:20 +02:00
// Look up in database
// compareCRC("loopy.txt", cartId, false, 0);
2023-07-03 01:08:09 +02:00
2023-07-03 09:15:20 +02:00
// SRAM size can be calculated from subtracting 32bit pointers 000014h (last byte of sram, memory mapped) - 000010h (first byte of sram, memory mapped)
// But this is fine
sramSize = LOOPY_SRAM_SIZE ;
2023-07-03 01:08:09 +02:00
display_Clear ( ) ;
println_Msg ( F ( " Cart Info " ) ) ;
println_Msg ( F ( " " ) ) ;
2023-07-03 09:15:20 +02:00
// print_Msg(F("Name: "));
// println_Msg(romName);
print_Msg ( F ( " CRC32: " ) ) ;
println_Msg ( checksumStr ) ;
2023-07-03 01:08:09 +02:00
print_Msg ( F ( " Size: " ) ) ;
print_Msg ( cartSize * 8 / 1024 / 1024 ) ;
println_Msg ( F ( " MBit " ) ) ;
print_Msg ( F ( " Sram: " ) ) ;
if ( sramSize > 0 ) {
print_Msg ( sramSize * 8 / 1024 ) ;
println_Msg ( F ( " KBit " ) ) ;
} else
println_Msg ( F ( " None " ) ) ;
println_Msg ( F ( " " ) ) ;
# if (defined(enable_OLED) || defined(enable_LCD))
// Wait for user input
// Prints string out of the common strings array either with or without newline
print_STR ( press_button_STR , 1 ) ;
display_Update ( ) ;
wait ( ) ;
# endif
}
//******************************************
// READ CODE
//******************************************
void readROM_LOOPY ( ) {
dataIn_LOOPY ( ) ;
strcpy ( fileName , romName ) ;
2023-07-03 09:15:20 +02:00
strcat ( fileName , " .bin " ) ;
2023-07-03 01:08:09 +02:00
EEPROM_readAnything ( 0 , foldern ) ;
sprintf ( folder , " LOOPY/ROM/%s/%d " , romName , foldern ) ;
sd . mkdir ( folder , true ) ;
sd . chdir ( folder ) ;
display_Clear ( ) ;
print_STR ( saving_to_STR , 0 ) ;
print_Msg ( folder ) ;
println_Msg ( F ( " /... " ) ) ;
display_Update ( ) ;
foldern = foldern + 1 ;
EEPROM_writeAnything ( 0 , foldern ) ;
if ( ! myFile . open ( fileName , O_RDWR | O_CREAT ) ) {
print_FatalError ( sd_error_STR ) ;
}
word d = 0 ;
uint32_t progress = 0 ;
draw_progressbar ( 0 , cartSize ) ;
2023-07-03 09:15:20 +02:00
for ( unsigned long currBuffer = 0 ; currBuffer < cartSize / 2 ; currBuffer + = 256 ) {
for ( int currWord = 0 ; currWord < 256 ; currWord + + ) {
word myWord = readWord_LOOPY ( currBuffer + currWord ) ;
// Split word into two bytes
sdBuffer [ d ] = ( ( myWord > > 8 ) & 0xFF ) ;
sdBuffer [ d + 1 ] = ( myWord & 0xFF ) ;
d + = 2 ;
2023-07-03 01:08:09 +02:00
}
2023-07-03 09:15:20 +02:00
myFile . write ( sdBuffer , 512 ) ;
d = 0 ;
progress + = 512 ;
draw_progressbar ( progress , cartSize ) ;
2023-07-03 01:08:09 +02:00
}
myFile . close ( ) ;
// Compare CRC32 to database and rename ROM if found
// Arguments: database name, precalculated crc string or 0 to calculate, rename rom or not, starting offset
2023-07-03 09:15:20 +02:00
compareCRC ( " loopy.txt " , 0 , 1 , 0 ) ;
2023-07-03 01:08:09 +02:00
# if (defined(enable_OLED) || defined(enable_LCD))
// Wait for user input
println_Msg ( F ( " " ) ) ;
// Prints string out of the common strings array either with or without newline
print_STR ( press_button_STR , 1 ) ;
display_Update ( ) ;
wait ( ) ;
# endif
}
//******************************************
// SRAM
//******************************************
void writeSRAM_LOOPY ( ) {
dataOut_LOOPY ( ) ;
sprintf ( filePath , " %s/%s " , filePath , fileName ) ;
println_Msg ( F ( " Writing... " ) ) ;
println_Msg ( filePath ) ;
display_Update ( ) ;
if ( myFile . open ( filePath , O_READ ) ) {
for ( unsigned long currByte = 0 ; currByte < sramSize ; currByte + + ) {
// writeWord_LOOPY(currByte, ((myFile.read() << 8 ) & 0xFF));
writeByte_LOOPY ( currByte , ( myFile . read ( ) ) ) ;
}
myFile . close ( ) ;
print_STR ( done_STR , 1 ) ;
display_Update ( ) ;
} else {
print_FatalError ( sd_error_STR ) ;
}
dataIn_LOOPY ( ) ;
}
void readSRAM_LOOPY ( ) {
dataIn_LOOPY ( ) ;
strcpy ( fileName , romName ) ;
strcat ( fileName , " .sav " ) ;
EEPROM_readAnything ( 0 , foldern ) ;
sprintf ( folder , " LOOPY/SAVE/%s/%d " , romName , foldern ) ;
sd . mkdir ( folder , true ) ;
sd . chdir ( folder ) ;
foldern = foldern + 1 ;
EEPROM_writeAnything ( 0 , foldern ) ;
if ( ! myFile . open ( fileName , O_RDWR | O_CREAT ) ) {
print_FatalError ( sd_error_STR ) ;
}
for ( unsigned long currBuffer = 0 ; currBuffer < sramSize ; currBuffer + = 512 ) {
for ( int currByte = 0 ; currByte < 512 ; currByte + + ) {
byte myByte = readByte_LOOPY ( currBuffer + currByte ) ;
sdBuffer [ currByte ] = myByte ;
}
myFile . write ( sdBuffer , 512 ) ;
}
myFile . close ( ) ;
print_Msg ( F ( " Saved to " ) ) ;
print_Msg ( folder ) ;
println_Msg ( F ( " / " ) ) ;
display_Update ( ) ;
}
unsigned long verifySRAM_LOOPY ( ) {
dataIn_LOOPY ( ) ;
writeErrors = 0 ;
if ( myFile . open ( filePath , O_READ ) ) {
for ( unsigned long currBuffer = 0 ; currBuffer < sramSize ; currBuffer + = 512 ) {
for ( int currByte = 0 ; currByte < 512 ; currByte + + ) {
byte myByte = readByte_LOOPY ( currBuffer + currByte ) ;
sdBuffer [ currByte ] = myByte ;
}
for ( int i = 0 ; i < 512 ; i + + ) {
if ( myFile . read ( ) ! = sdBuffer [ i ] ) {
writeErrors + + ;
}
}
}
myFile . close ( ) ;
} else {
print_FatalError ( sd_error_STR ) ;
}
return writeErrors ;
}
# endif
//******************************************
// End of File
//******************************************