Adds internal checksumming, ID setting romname

This commit is contained in:
Roger Braunstein 2023-07-06 13:55:45 -07:00
parent 8a484b0214
commit 4621ad20f3
2 changed files with 241 additions and 180 deletions

View File

@ -609,6 +609,34 @@ void rewind_line(FsFile& readfile, byte count = 1) {
readfile.seekCur(1); readfile.seekCur(1);
} }
bool setRomName(const char* database, char* crcStr, int stripExtensionChars = 4) {
//Search for CRC32 in file
char gamename[96];
char crc_search[9];
bool found;
//go to root
sd.chdir();
if (!myFile.open(database, O_READ)) {
return false;
}
//Search for same CRC in list
while (myFile.available()) {
//Read 2 lines (game name and CRC)
get_line(gamename, &myFile, sizeof(gamename));
get_line(crc_search, &myFile, sizeof(crc_search));
skip_line(&myFile); //Skip every 3rd line
if (strcmp(crc_search, crcStr) == 0) {
found = true;
strlcpy(romName, gamename, strlen(gamename) - stripExtensionChars + 1);
break;
}
}
myFile.close();
return found;
}
// Calculate CRC32 if needed and compare it to CRC read from database // Calculate CRC32 if needed and compare it to CRC read from database
boolean compareCRC(const char* database, uint32_t crc32sum, boolean renamerom, int offset) { boolean compareCRC(const char* database, uint32_t crc32sum, boolean renamerom, int offset) {
char crcStr[9]; char crcStr[9];
@ -3612,6 +3640,12 @@ void loop() {
pokeMenu(); pokeMenu();
} }
#endif #endif
#ifdef enable_LOOPY
else if (mode == mode_LOOPY) {
loopyMenu();
}
#endif
else { else {
display_Clear(); display_Clear();
println_Msg(F("Menu Error")); println_Msg(F("Menu Error"));

View File

@ -1,6 +1,8 @@
//****************************************** //******************************************
// CASIO LOOPY MODULE // CASIO LOOPY MODULE
//****************************************** //******************************************
// IMPORTANT: All data are stored as BIG-ENDIAN. Many ROM dumps online are little endian.
// See https://github.com/kasamikona/Loopy-Tools/blob/master/ROM%20Structure.md
#ifdef enable_LOOPY #ifdef enable_LOOPY
// SH-1 memory map locations, ROM starts here // SH-1 memory map locations, ROM starts here
@ -15,7 +17,10 @@ const int LOOPY_RAMWE = 6;
const int LOOPY_RAMCS1 = 7; const int LOOPY_RAMCS1 = 7;
const int LOOPY_RAMCS2 = A7; const int LOOPY_RAMCS2 = A7;
char strbuf[9]; // The internal checksum read from the cart header at 08h, will be checked against an actual sum
uint32_t loopyChecksum;
// Whether the cart was found (by checksum) in the database
bool loopyCartRecognized;
//****************************************** //******************************************
// SETUP // SETUP
@ -55,7 +60,7 @@ void setup_LOOPY() {
//****************************************** //******************************************
// Base Menu // Base Menu
static const char loopyMenuItem0[] PROGMEM = "Cart Info"; static const char loopyMenuItem0[] PROGMEM = "Refresh Cart";
static const char loopyMenuItem1[] PROGMEM = "Read ROM"; static const char loopyMenuItem1[] PROGMEM = "Read ROM";
static const char loopyMenuItem2[] PROGMEM = "Read SRAM"; static const char loopyMenuItem2[] PROGMEM = "Read SRAM";
static const char loopyMenuItem3[] PROGMEM = "Write SRAM"; static const char loopyMenuItem3[] PROGMEM = "Write SRAM";
@ -65,11 +70,11 @@ static const char* const menuOptionsLOOPY[] PROGMEM = { loopyMenuItem0, loopyMen
void loopyMenu() { void loopyMenu() {
convertPgm(menuOptionsLOOPY, 4); convertPgm(menuOptionsLOOPY, 4);
uint8_t mainMenu = question_box(F("CASIO LOOPY MENU"), menuOptions, 4, 0); uint8_t mainMenu = question_box(F("CASIO LOOPY MENU"), menuOptions, 4, 0);
display_Clear();
display_Update();
switch (mainMenu) { switch (mainMenu) {
case 0: case 0:
display_Clear();
display_Update();
setup_LOOPY(); setup_LOOPY();
break; break;
@ -82,16 +87,11 @@ void loopyMenu() {
case 2: case 2:
// Read SRAM // Read SRAM
if (sramSize) {
sd.chdir("/"); sd.chdir("/");
display_Clear();
println_Msg(F("Reading SRAM...")); println_Msg(F("Reading SRAM..."));
display_Update(); display_Update();
readSRAM_LOOPY(); readSRAM_LOOPY();
sd.chdir("/"); sd.chdir("/");
} else {
print_Error(F("Cart has no SRAM"));
}
#if (defined(enable_OLED) || defined(enable_LCD)) #if (defined(enable_OLED) || defined(enable_LCD))
// Wait for user input // Wait for user input
// Prints string out of the common strings array either with or without newline // Prints string out of the common strings array either with or without newline
@ -103,7 +103,6 @@ void loopyMenu() {
case 3: case 3:
// Write SRAM // Write SRAM
if (sramSize) {
// Change working dir to root // Change working dir to root
sd.chdir("/"); sd.chdir("/");
fileBrowser(F("Select SAV file")); fileBrowser(F("Select SAV file"));
@ -119,9 +118,7 @@ void loopyMenu() {
print_STR(_bytes_STR, 1); print_STR(_bytes_STR, 1);
print_Error(did_not_verify_STR); print_Error(did_not_verify_STR);
} }
} else {
print_Error(F("Cart has no SRAM"));
}
#if (defined(enable_OLED) || defined(enable_LCD)) #if (defined(enable_OLED) || defined(enable_LCD))
// Wait for user input // Wait for user input
// Prints string out of the common strings array either with or without newline // Prints string out of the common strings array either with or without newline
@ -190,33 +187,75 @@ void setAddress_LOOPY(unsigned long A) {
} }
uint16_t getWord_LOOPY() { uint16_t getWord_LOOPY() {
return digitalRead(A8) // A8 PK0 D0
| (digitalRead(22) << 1) // D22 PA0 D1
| (digitalRead(A6) << 2) // A6 PF6 D2
| (digitalRead(A5) << 3) // A5 PF5 D3
| (digitalRead(A3) << 4) // A3 PF3 D4
| (digitalRead(40) << 5) // D40 PG1 D5
| (digitalRead(A2) << 6) // A2 PF2 D6
| (digitalRead(41) << 7) // D41 PG0 D7
| (digitalRead(A1) << 8) // A1 PF1 D8
| (digitalRead(3) << 9) // D3 PE5 D9
| (digitalRead(A0) << 10) // A0 PF0 D10
| (digitalRead(2) << 11) // D2 PE4 D11
| (digitalRead(14) << 12) // D14 PJ1 D12
| (digitalRead(15) << 13) // D15 PJ0 D13
| (digitalRead(A4) << 14) // A4 PF4 D14
| (digitalRead(4) << 15); // D4 PG5 D15
return bitRead(PINK, 0)
| (bitRead(PINA, 0) << 1)
| (bitRead(PINF, 6) << 2)
| (bitRead(PINF, 5) << 3)
| (bitRead(PINF, 3) << 4)
| (bitRead(PING, 1) << 5)
| (bitRead(PINF, 2) << 6)
| (bitRead(PING, 0) << 7)
| (bitRead(PINF, 1) << 8)
| (bitRead(PINE, 5) << 9)
| (bitRead(PINF, 0) << 10)
| (bitRead(PINE, 4) << 11)
| (bitRead(PINJ, 1) << 12)
| (bitRead(PINJ, 0) << 13)
| (bitRead(PINF, 4) << 14)
| (bitRead(PING, 5) << 15);
// 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() { uint8_t getByte_LOOPY() {
return digitalRead(A8) return bitRead(PINK, 0)
| (digitalRead(22) << 1) | (bitRead(PINA, 0) << 1)
| (digitalRead(A6) << 2) | (bitRead(PINF, 6) << 2)
| (digitalRead(A5) << 3) | (bitRead(PINF, 5) << 3)
| (digitalRead(A3) << 4) | (bitRead(PINF, 3) << 4)
| (digitalRead(40) << 5) | (bitRead(PING, 1) << 5)
| (digitalRead(A2) << 6) | (bitRead(PINF, 2) << 6)
| (digitalRead(41) << 7); | (bitRead(PING, 0) << 7);
// 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) { void setByte_LOOPY(uint8_t D) {
@ -230,35 +269,45 @@ void setByte_LOOPY(uint8_t D) {
digitalWrite(41, bitRead(D, 7)); digitalWrite(41, bitRead(D, 7));
} }
void writeByte_LOOPY(unsigned long myAddress, byte myData) { byte readByte_LOOPY(unsigned long myAddress) {
// TODO Update
setAddress_LOOPY(myAddress); setAddress_LOOPY(myAddress);
__asm__("nop\n\t"); digitalWrite(LOOPY_RAMCS1, LOW);
digitalWrite(LOOPY_OE, LOW);
PORTA = myData; NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
// Set CS2(PH0), /CE(PH3), /OE(PH6) to HIGH byte b = getByte_LOOPY();
PORTH |= (1 << 0) | (1 << 3) | (1 << 6);
// Set /CS1(PH4), /WE0(PH5) to LOW
PORTH &= ~(1 << 4) & ~(1 << 5);
__asm__("nop\n\t" digitalWrite(LOOPY_RAMCS1, HIGH);
"nop\n\t" digitalWrite(LOOPY_OE, HIGH);
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t");
// Set CS2(PH0), /CS1(PH4), /WE0(PH5) to HIGH return b;
PORTH |= (1 << 0) | (1 << 4) | (1 << 5); }
__asm__("nop\n\t" void writeByte_LOOPY(unsigned long myAddress, byte myData) {
"nop\n\t" setAddress_LOOPY(myAddress);
"nop\n\t"
"nop\n\t" setByte_LOOPY(myData);
"nop\n\t"
"nop\n\t"); digitalWrite(LOOPY_RAMCS1, LOW);
digitalWrite(LOOPY_OE, HIGH);
digitalWrite(LOOPY_RAMWE, LOW);
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
digitalWrite(LOOPY_RAMWE, HIGH);
digitalWrite(LOOPY_RAMCS1, HIGH);
} }
word readWord_LOOPY(unsigned long myAddress) { word readWord_LOOPY(unsigned long myAddress) {
@ -279,48 +328,6 @@ word readWord_LOOPY(unsigned long myAddress) {
return tempWord; return tempWord;
} }
byte readByte_LOOPY(unsigned long myAddress) { // SRAM BYTE
// TODO Update
setAddress_LOOPY(myAddress);
__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 // Switch data pins to write
void dataOut_LOOPY() { void dataOut_LOOPY() {
// // PA0 // // PA0
@ -397,39 +404,32 @@ void getCartInfo_LOOPY() {
dataIn_LOOPY(); dataIn_LOOPY();
// Last word of ROM stored as 32-bit pointer at 000004h // 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); uint32_t headerRomSize = ((uint32_t)readWord_LOOPY(0x4) << 16) | (uint32_t)readWord_LOOPY(0x6);
cartSize = headerRomSize - LOOPY_MAP_ROM_ZERO + 2; cartSize = headerRomSize - LOOPY_MAP_ROM_ZERO + 2;
// Get internal CRC32 from header // Get internal checksum from header
uint32_t cartHeaderCrc = ((uint32_t)readWord_LOOPY(0x8) << 16) | (uint32_t)readWord_LOOPY(0xA); loopyChecksum = ((uint32_t)readWord_LOOPY(0x8) << 16) | (uint32_t)readWord_LOOPY(0xA);
sprintf(checksumStr, "%08lx", cartHeaderCrc); sprintf(checksumStr, "%08lX", loopyChecksum);
// Look up in database // Look up in database
// compareCRC("loopy.txt", cartId, false, 0); loopyCartRecognized = setRomName("loopy.txt", checksumStr);
// 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;
println_Msg(F("Cart Info")); println_Msg(F("Cart Info"));
println_Msg(F(" ")); println_Msg(F(" "));
print_Msg(F("Magic: ")); print_Msg(F("Name: "));
sprintf(strbuf, "0x%08lx", ((uint32_t)readWord_LOOPY(0) << 16) | (uint32_t)readWord_LOOPY(0x2)); println_Msg(romName);
println_Msg(strbuf); print_Msg(F("Checksum: "));
// print_Msg(F("Name: "));
// println_Msg(romName);
print_Msg(F("CRC32: "));
println_Msg(checksumStr); println_Msg(checksumStr);
print_Msg(F("Size: ")); print_Msg(F("Size: "));
print_Msg(cartSize * 8 / 1024 / 1024); print_Msg(cartSize * 8 / 1024 / 1024);
println_Msg(F(" MBit")); println_Msg(F(" MBit"));
// 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;
print_Msg(F("Sram: ")); print_Msg(F("Sram: "));
if (sramSize > 0) {
print_Msg(sramSize * 8 / 1024); print_Msg(sramSize * 8 / 1024);
println_Msg(F(" KBit")); println_Msg(F(" KBit"));
} else
println_Msg(F("None"));
println_Msg(F(" ")); println_Msg(F(" "));
#if (defined(enable_OLED) || defined(enable_LCD)) #if (defined(enable_OLED) || defined(enable_LCD))
@ -448,11 +448,10 @@ void getCartInfo_LOOPY() {
void readROM_LOOPY() { void readROM_LOOPY() {
dataIn_LOOPY(); dataIn_LOOPY();
strcpy(fileName, romName); sprintf(fileName, "%s.bin", romName);
strcat(fileName, ".bin");
EEPROM_readAnything(0, foldern); EEPROM_readAnything(0, foldern);
sprintf(folder, "LOOPY/ROM/%s/%d", romName, foldern); sprintf(folder, "LOOPY/ROM/%d", foldern);
sd.mkdir(folder, true); sd.mkdir(folder, true);
sd.chdir(folder); sd.chdir(folder);
@ -471,23 +470,54 @@ void readROM_LOOPY() {
draw_progressbar(0, cartSize); draw_progressbar(0, cartSize);
// sdbuffer size is 512
const size_t sdBufferSize = 512; const size_t sdBufferSize = 512;
uint32_t sum = 0;
for (unsigned long ptr = 0; ptr < cartSize;) { for (unsigned long ptr = 0; ptr < cartSize;) {
word myWord = readWord_LOOPY(ptr); word myWord = readWord_LOOPY(ptr);
sdBuffer[ptr++ % sdBufferSize] = ((myWord >> 8) & 0xFF);
sdBuffer[ptr++ % sdBufferSize] = (myWord & 0xFF); // aggregate checksum over 16-bit words, starting at 80h, this address is stored in header but never varies
if (ptr >= 0x80) {
sum += myWord;
}
// Store in buffer
sdBuffer[ptr++ % sdBufferSize] = (myWord >> 8) & 0xFF;
sdBuffer[ptr++ % sdBufferSize] = myWord & 0xFF;
// Flush when buffer full
if (ptr % sdBufferSize == 0) { if (ptr % sdBufferSize == 0) {
myFile.write(sdBuffer, sdBufferSize); myFile.write(sdBuffer, sdBufferSize);
} blinkLED();
// Only update progress bar every 64kb
if (ptr % 0x10000 == 0) {
draw_progressbar(ptr, cartSize); draw_progressbar(ptr, cartSize);
} }
}
}
// TODO this assumes size is divisible by 512 // TODO this assumes size is divisible by 512
myFile.close(); myFile.close();
// Instead of the CRC32, check the internal integrity based on the header checksum
print_Msg(F("Header sum: "));
println_Msg(checksumStr);
print_Msg(F("Actual sum: "));
char calculatedChecksumStr[9];
sprintf(calculatedChecksumStr, "%08lX", sum);
println_Msg(calculatedChecksumStr);
if (sum == loopyChecksum) {
println_Msg(F("INTEGRITY OK :)"));
} else {
println_Msg(F("INTEGRITY FAIL! Bad dump"));
}
display_Update();
// Compare CRC32 to database and rename ROM if found // 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 // Arguments: database name, precalculated crc string or 0 to calculate, rename rom or not, starting offset
compareCRC("loopy.txt", 0, 1, 0); //compareCRC("loopy.txt", 0, 1, 0x80);
#if (defined(enable_OLED) || defined(enable_LCD)) #if (defined(enable_OLED) || defined(enable_LCD))
// Wait for user input // Wait for user input
@ -504,7 +534,6 @@ void readROM_LOOPY() {
//****************************************** //******************************************
void writeSRAM_LOOPY() { void writeSRAM_LOOPY() {
// TODO UPDATE
dataOut_LOOPY(); dataOut_LOOPY();
sprintf(filePath, "%s/%s", filePath, fileName); sprintf(filePath, "%s/%s", filePath, fileName);
@ -514,7 +543,6 @@ void writeSRAM_LOOPY() {
if (myFile.open(filePath, O_READ)) { if (myFile.open(filePath, O_READ)) {
for (unsigned long currByte = 0; currByte < sramSize; currByte++) { for (unsigned long currByte = 0; currByte < sramSize; currByte++) {
// writeWord_LOOPY(currByte, ((myFile.read() << 8 ) & 0xFF));
writeByte_LOOPY(currByte, (myFile.read())); writeByte_LOOPY(currByte, (myFile.read()));
} }
myFile.close(); myFile.close();
@ -527,11 +555,9 @@ void writeSRAM_LOOPY() {
} }
void readSRAM_LOOPY() { void readSRAM_LOOPY() {
// TODO UPDATE
dataIn_LOOPY(); dataIn_LOOPY();
strcpy(fileName, romName); sprintf(fileName, "%s.sav", romName);
strcat(fileName, ".sav");
EEPROM_readAnything(0, foldern); EEPROM_readAnything(0, foldern);
sprintf(folder, "LOOPY/SAVE/%s/%d", romName, foldern); sprintf(folder, "LOOPY/SAVE/%s/%d", romName, foldern);
@ -544,13 +570,15 @@ void readSRAM_LOOPY() {
if (!myFile.open(fileName, O_RDWR | O_CREAT)) { if (!myFile.open(fileName, O_RDWR | O_CREAT)) {
print_FatalError(sd_error_STR); print_FatalError(sd_error_STR);
} }
for (unsigned long currBuffer = 0; currBuffer < sramSize; currBuffer += 512) {
for (int currByte = 0; currByte < 512; currByte++) { const size_t sdBufferSize = 512;
byte myByte = readByte_LOOPY(currBuffer + currByte); for (unsigned long ptr = 0; ptr < sramSize;) {
sdBuffer[currByte] = myByte; sdBuffer[ptr++ % sdBufferSize] = readByte_LOOPY(ptr);
if (ptr % sdBufferSize == 0) {
myFile.write(sdBuffer, sdBufferSize);
} }
myFile.write(sdBuffer, 512);
} }
myFile.close(); myFile.close();
print_Msg(F("Saved to ")); print_Msg(F("Saved to "));
print_Msg(folder); print_Msg(folder);
@ -559,7 +587,6 @@ void readSRAM_LOOPY() {
} }
unsigned long verifySRAM_LOOPY() { unsigned long verifySRAM_LOOPY() {
// TODO UPDATE
dataIn_LOOPY(); dataIn_LOOPY();
writeErrors = 0; writeErrors = 0;