cartreader/Cart_Reader/FLASH_CPS3.ino

1631 lines
44 KiB
Arduino
Raw Normal View History

2024-09-12 22:27:59 +02:00
//******************************************
// CP System III Module
// Cartridge
// 32/64/128 Mbits SIMM
// Tested with HW5
// https://github.com/herzmx/CPS3-OSCR-Adapter
//******************************************
#ifdef ENABLE_CPS3
/******************************************
Variables
*****************************************/
uint32_t cartRegion = 0;
uint32_t cartCD = 0;
uint32_t cartCDPatch = 0;
uint32_t multiCart = 0;
uint32_t multiCartPatch1 = 0;
uint32_t multiCartPatch2 = 0;
uint32_t cartRegionOffset = 0;
uint32_t cartnocdOffset = 0;
uint16_t flashids[8];
/******************************************
Menu
*****************************************/
// CPS3 start menu options
static const char cpsMenuItem1[] PROGMEM = "CPS3 cartridge";
static const char cpsMenuItem2[] PROGMEM = "32/128 Mbits SIMM";
static const char cpsMenuItem3[] PROGMEM = "64 Mbits SIMM";
static const char cpsMenuItem4[] PROGMEM = "32/128 MBytes SIMM";
static const char cpsMenuItem5[] PROGMEM = "64 MBytes SIMM";
static const char* const menuOptionsCPS[] PROGMEM = { cpsMenuItem1, cpsMenuItem2, cpsMenuItem3, cpsMenuItem4, cpsMenuItem5, FSTRING_RESET };
// Cartridge region options
static const char cpsCartRegion0[] PROGMEM = "No Patch";
static const char cpsCartRegion1[] PROGMEM = "JAP";
static const char cpsCartRegion2[] PROGMEM = "ASIA";
static const char cpsCartRegion3[] PROGMEM = "EUR";
static const char cpsCartRegion4[] PROGMEM = "USA";
static const char cpsCartRegion5[] PROGMEM = "HISPANIC";
static const char cpsCartRegion6[] PROGMEM = "BRAZIL";
static const char cpsCartRegion7[] PROGMEM = "OCEANIA";
static const char cpsCartRegion8[] PROGMEM = "ASIA NCD";
static const char* const menuOptionsCartRegion[] PROGMEM = { cpsCartRegion0, cpsCartRegion1, cpsCartRegion2, cpsCartRegion3, cpsCartRegion4, cpsCartRegion5, cpsCartRegion6, cpsCartRegion7, cpsCartRegion8, FSTRING_RESET };
// Cartridge cd options
static const char cpsCDItem1[] PROGMEM = "CD";
static const char cpsCDItem2[] PROGMEM = "NOCD";
static const char* const menuOptionsCartCD[] PROGMEM = { cpsCartRegion0, cpsCDItem1, cpsCDItem2, FSTRING_RESET };
// CPS3 start menu
void cpsMenu() {
// create menu with title and 6 options to choose from
unsigned char cpsType;
convertPgm(menuOptionsCPS, 6);
cpsType = question_box(FS(FSTRING_SELECT_CART_TYPE), menuOptions, 6, 0);
// wait for user choice to come back from the question box menu
switch (cpsType) {
case 0:
display_Clear();
display_Update();
mode = CORE_CPS3_CART;
setup_CPS3();
id_Flash8();
wait();
break;
case 1:
display_Clear();
display_Update();
mode = CORE_CPS3_128SIMM;
setup_CPS3();
id_SIMM2x8();
wait();
break;
case 2:
display_Clear();
display_Update();
mode = CORE_CPS3_64SIMM;
setup_CPS3();
id_SIMM4x8();
wait();
break;
case 3:
display_Clear();
display_Update();
mode = CORE_CPS3_01SIMM;
setup_CPS3();
break;
case 4:
display_Clear();
display_Update();
mode = CORE_CPS3_512SIMM;
setup_CPS3();
break;
case 5:
resetArduino();
break;
default:
print_MissingModule(); // does not return
}
}
// CPS3 Cartridge menu
void flashromCPS_Cartridge() {
// create menu with title and 7 options to choose from
unsigned char mainMenu;
// Copy menuOptions out of progmem
convertPgm(menuOptionsFLASH8, 7);
mainMenu = question_box(F("CPS3 Cartdrige Writer"), menuOptions, 7, 0);
// wait for user choice to come back from the question box menu
switch (mainMenu) {
case 0:
display_Clear();
println_Msg(F("Blankcheck"));
display_Update();
time = millis();
resetFlash8();
blankcheck_Flash();
break;
case 1:
if (flashromType != 0) {
display_Clear();
println_Msg(F("Warning: This will erase"));
println_Msg(F("your CPS3 Cartdrige BIOS"));
print_STR(press_button_STR, 1);
display_Update();
wait();
rgbLed(black_color);
println_Msg(FS(FSTRING_EMPTY));
println_Msg(F("Please wait..."));
display_Update();
time = millis();
switch (flashromType) {
case 1: eraseFlash29F032(); break;
case 2: eraseFlash29F1610(); break;
case 3: eraseFlash28FXXX(); break;
}
println_Msg(F("CPS3 Cartdrige BIOS erased"));
display_Update();
resetFlash8();
} else {
readOnlyMode();
}
break;
case 2:
time = millis();
resetFlash8();
readCartridge();
break;
case 3:
if (flashromType != 0) {
// Set cartridge region
filePath[0] = '\0';
sd.chdir("/");
fileBrowser(FS(FSTRING_SELECT_FILE));
// Calculate CRC32 of BIOS
display_Clear();
println_Msg("Looking BIOS patch");
println_Msg(FS(FSTRING_EMPTY));
println_Msg(F("Please wait..."));
display_Update();
char crcStr[9];
sprintf(crcStr, "%08lX", calculateCRC(fileName, filePath, 0));
setCartridgePatchData(crcStr);
display_Clear();
time = millis();
switch (flashromType) {
case 1:
break;
case 2:
if ((flashid == 0x0458) || (flashid == 0x0158) || (flashid == 0x01AB) || (flashid == 0x0422) || (flashid == 0x0423))
writeCartridge();
else if (flashid == 0x0) // Manual flash config, pick most common type
writeFlash29LV640();
break;
case 3:
break;
}
delay(100);
// Reset twice just to be sure
resetFlash8();
resetFlash8();
verifyCartridge();
} else {
readOnlyMode();
}
break;
case 4:
time = 0;
display_Clear();
resetFlash8();
println_Msg(F("ID Flashrom"));
switch (flashromType) {
case 0: break;
case 1: idFlash29F032(); break;
case 2: idFlash29F1610(); break;
case 3: idFlash28FXXX(); break;
}
println_Msg(FS(FSTRING_EMPTY));
printFlash(40);
println_Msg(FS(FSTRING_EMPTY));
display_Update();
resetFlash8();
break;
case 5:
time = 0;
display_Clear();
println_Msg(F("Print first 70Bytes"));
display_Update();
resetFlash8();
printFlash(70);
break;
case 6:
time = 0;
display_Clear();
display_Update();
resetFlash8();
resetArduino();
break;
}
if (time != 0) {
print_Msg(F("Operation took : "));
print_Msg((millis() - time) / 1000, DEC);
println_Msg(F("s"));
display_Update();
}
// Prints string out of the common strings array either with or without newline
print_STR(press_button_STR, 0);
display_Update();
wait();
}
// CPS3 Cartridge region patch menu
void cpsCartRegionMenu() {
cartRegion = pageMenu(F("Cartridge Region Patch"), menuOptionsCartRegion, 10);
if (cartRegion < 9) {
display_Clear();
display_Update();
} else {
time = 0;
display_Clear();
display_Update();
resetFlash8();
resetArduino();
}
}
// CPS3 Cartridge CD patch menu
void cpsCartCDMenu() {
// Copy menuOptions out of progmem
convertPgm(menuOptionsCartCD, 4);
cartCD = question_box(F("Cartridge CD Patch"), menuOptions, 4, 0);
// wait for user choice to come back from the question box menu
if (cartCD < 3) {
display_Clear();
display_Update();
} else {
time = 0;
display_Clear();
display_Update();
resetFlash8();
resetArduino();
}
}
// CPS3 32/128 SIMM menu
void flashromCPS_SIMM2x8() {
// create menu with title and 7 options to choose from
unsigned char mainMenu;
// Copy menuOptions out of progmem
convertPgm(menuOptionsFLASH8, 7);
mainMenu = question_box(F("CPS3 SIMM Writer 2x8bit"), menuOptions, 7, 0);
// wait for user choice to come back from the question box menu
switch (mainMenu) {
case 0:
display_Clear();
println_Msg(F("Blankcheck"));
display_Update();
time = millis();
resetSIMM2x8();
blankcheckSIMM2x8();
break;
case 1:
if (flashromType != 0) {
display_Clear();
println_Msg(F("Warning: This will erase"));
println_Msg(F("your CPS3 SIMM 2x8bit"));
print_STR(press_button_STR, 1);
display_Update();
wait();
rgbLed(black_color);
println_Msg(FS(FSTRING_EMPTY));
println_Msg(F("Please wait..."));
display_Update();
time = millis();
switch (flashromType) {
case 1: eraseSIMM2x8(); break;
case 2: break;
case 3: break;
}
println_Msg(F("CPS3 SIMM 2x8bit erased"));
display_Update();
resetSIMM2x8();
} else {
readOnlyMode();
}
break;
case 2:
time = millis();
resetSIMM2x8();
readSIMM2x8B();
break;
case 3:
if (flashromType != 0) {
// Set cartridge region
filePath[0] = '\0';
sd.chdir("/");
fileBrowser(FS(FSTRING_SELECT_FILE));
display_Clear();
time = millis();
switch (flashromType) {
case 1:
if (flashid == 0x04AD)
writeSIMM2x8();
break;
case 2:
break;
case 3:
break;
}
delay(100);
// Reset twice just to be sure
resetSIMM2x8();
resetSIMM2x8();
verifySIMM2x8();
} else {
readOnlyMode();
}
break;
case 4:
time = 0;
display_Clear();
resetFlash8();
println_Msg(F("ID Flashrom"));
switch (flashromType) {
case 0: break;
case 1: idFlash2x8(0x0); break;
case 2: break;
case 3: break;
}
println_Msg(FS(FSTRING_EMPTY));
printFlash16(40);
println_Msg(FS(FSTRING_EMPTY));
display_Update();
resetSIMM2x8();
break;
case 5:
time = 0;
display_Clear();
println_Msg(F("Print first 70Bytes"));
display_Update();
resetSIMM2x8();
printFlash16(70);
break;
case 6:
time = 0;
display_Clear();
display_Update();
resetSIMM2x8();
resetArduino();
break;
}
if (time != 0) {
print_Msg(F("Operation took : "));
print_Msg((millis() - time) / 1000, DEC);
println_Msg(F("s"));
display_Update();
}
// Prints string out of the common strings array either with or without newline
print_STR(press_button_STR, 0);
display_Update();
wait();
}
// CPS3 32/128 SIMM menu
void flashromCPS_SIMM4x8() {
// create menu with title and 7 options to choose from
unsigned char mainMenu;
// Copy menuOptions out of progmem
convertPgm(menuOptionsFLASH8, 7);
mainMenu = question_box(F("CPS3 SIMM Writer 4x8bit"), menuOptions, 7, 0);
// wait for user choice to come back from the question box menu
switch (mainMenu) {
case 0:
display_Clear();
println_Msg(F("Blankcheck"));
display_Update();
time = millis();
resetSIMM4x8();
blankcheckSIMM4x8();
break;
case 1:
if (flashromType != 0) {
display_Clear();
println_Msg(F("Warning: This will erase"));
println_Msg(F("your CPS3 SIMM 4x8bit"));
print_STR(press_button_STR, 1);
display_Update();
wait();
rgbLed(black_color);
println_Msg(FS(FSTRING_EMPTY));
println_Msg(F("Please wait..."));
display_Update();
time = millis();
switch (flashromType) {
case 1: eraseSIMM4x8(); break;
case 2: break;
case 3: break;
}
println_Msg(F("CPS3 SIMM 4x8bit erased"));
display_Update();
resetSIMM4x8();
} else {
readOnlyMode();
}
break;
case 2:
time = millis();
resetSIMM4x8();
readSIMM4x8();
break;
case 3:
if (flashromType != 0) {
// Set cartridge region
filePath[0] = '\0';
sd.chdir("/");
fileBrowser(FS(FSTRING_SELECT_FILE));
display_Clear();
time = millis();
switch (flashromType) {
case 1:
if (flashid == 0x04AD)
writeSIMM4x8();
break;
case 2:
break;
case 3:
break;
}
delay(100);
// Reset twice just to be sure
resetSIMM4x8();
resetSIMM4x8();
verifySIMM4x8();
} else {
readOnlyMode();
}
break;
case 4:
time = 0;
display_Clear();
resetFlash8();
println_Msg(F("ID Flashrom"));
switch (flashromType) {
case 0: break;
case 1:
enable64MSB();
idFlash2x8(0x0);
enable64LSB();
idFlash2x8(0x1);
break;
case 2: break;
case 3: break;
}
println_Msg(FS(FSTRING_EMPTY));
printSIMM4x8(40);
println_Msg(FS(FSTRING_EMPTY));
display_Update();
resetSIMM4x8();
break;
case 5:
time = 0;
display_Clear();
println_Msg(F("Print first 70Bytes"));
display_Update();
resetSIMM4x8();
enable64MSB();
printSIMM4x8(70);
break;
case 6:
time = 0;
display_Clear();
display_Update();
resetSIMM4x8();
resetArduino();
break;
}
if (time != 0) {
print_Msg(F("Operation took : "));
print_Msg((millis() - time) / 1000, DEC);
println_Msg(F("s"));
display_Update();
}
// Prints string out of the common strings array either with or without newline
print_STR(press_button_STR, 0);
display_Update();
wait();
}
/******************************************
Setup
*****************************************/
void setup_CPS3() {
// Set Address Pins to Output
//A0-A7
DDRF = 0xFF;
//A8-A15
DDRK = 0xFF;
//A16-A23
DDRL = 0xFF;
//A24(PJ0), A25(PJ1)
DDRJ |= (1 << 0) | (1 << 1);
// Set Control Pins to Output
// RST(PH0) OE(PH1) BYTE(PH3) WE(PH4) CKIO_CPU(PH5) CE/CER_CST(PH6)
DDRH |= (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
// CE64LSB(PE3) CE128(PE4)
DDRE |= (1 << 3) | (1 << 4);
// RST_CPUC(PG1) CE64MSB(PG5)
DDRG |= (1 << 1) | (1 << 5);
// Set Data Pins (D0-D15) to Input
DDRC = 0x00;
DDRA = 0x00;
// Disable Internal Pullups
PORTC = 0x00;
PORTA = 0x00;
// Setting RST(PH0) OE(PH1) WE(PH4) CKIO_CPU(PH5) HIGH
PORTH |= (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5);
// Setting CE64LSB(PE3) CE128(PE4) HIGH
PORTE |= (1 << 3) | (1 << 4);
// Setting CE64MSB(PG5) HIGH
PORTG |= (1 << 5);
// Setting CE_CART/CER_CST(PH6) HIGH
PORTH |= (1 << 6);
// Setting BYTE(PH3) LOW
PORTH &= ~(1 << 3);
// Setting RST_CPUC(PG1) LOW
PORTG &= ~(1 << 1);
if (mode == CORE_CPS3_128SIMM || mode == CORE_CPS3_01SIMM) {
// Setting CE128(PE4) LOW
PORTE &= ~(1 << 4);
} else if (mode == CORE_CPS3_CART) {
// Setting CE_CART/CER_CST(PH6) LOW
PORTH &= ~(1 << 6);
}
byteCtrl = 1;
}
/******************************************
Low level functions
*****************************************/
void enable64MSB() {
// Setting CE64LSB(PE3) HIGH
PORTE |= (1 << 3);
// Setting CE64MSB(PG5) LOW
PORTG &= ~(1 << 5);
// Wait till output is stable
NOP;
NOP;
}
void enable64LSB() {
// Setting CE64MSB(PG5) HIGH
PORTG |= (1 << 5);
// Setting CE64LSB(PE3) LOW
PORTE &= ~(1 << 3);
// Wait till output is stable
NOP;
NOP;
}
/******************************************
helper functions
*****************************************/
uint32_t char2int(char hex) {
uint32_t byte = 0;
// transform hex character to the 4bit equivalent number, using the ascii table indexes
if (hex >= '0' && hex <= '9')
byte = hex - 48;
else if (hex >= 'A' && hex <= 'F')
byte = hex - 55;
return byte;
}
/******************************************
Command functions
*****************************************/
void writeByteCommand_Flash2x8(uint32_t bank, byte command) {
writeWord_Flash((bank << 21) | 0x555, 0xaaaa);
writeWord_Flash((bank << 21) | 0x2aa, 0x5555);
writeWord_Flash((bank << 21) | 0x555, command << 8 | command);
}
/******************************************
Cartridge functions
*****************************************/
void readCartridge() {
// Reset to root directory
sd.chdir("/");
createFolderAndOpenFile("CPS3", "Cartridge", "29f400", "u2");
//Initialize progress bar
uint32_t processedProgressBar = 0;
uint32_t totalProgressBar = flashSize;
draw_progressbar(0, totalProgressBar);
for (unsigned long currByte = 0; currByte < flashSize; currByte += 512) {
for (int c = 0; c < 512; c++) {
sdBuffer[c] = readByte_Flash(currByte + c);
}
myFile.write(sdBuffer, 512);
// Update progress bar
processedProgressBar += 512;
draw_progressbar(processedProgressBar, totalProgressBar);
// Blink led
if (currByte % 25600 == 0)
blinkLED();
}
// Close the file:
myFile.close();
// Compare dump CRC with db values
compareCRC("cps3.txt", 0, 1, 0);
println_Msg(F("Finished reading"));
display_Update();
}
void writeCartridge() {
if (openFlashFile()) {
// Set data pins to output
dataOut();
// Initialize progress bar
uint32_t processedProgressBar = 0;
uint32_t totalProgressBar = (uint32_t)fileSize;
draw_progressbar(0, totalProgressBar);
// Fill sdBuffer
for (unsigned long currByte = 0; currByte < fileSize; currByte += 512) {
myFile.read(sdBuffer, 512);
// Blink led
if (currByte % 2048 == 0)
blinkLED();
for (int c = 0; c < 512; c++) {
// Write command sequence
writeByteCommandShift_Flash(0xa0);
// Write patch to avoid region menu in multi
if ((currByte + c) == 0x405F && cartRegion > 0 && multiCart == 1) {
writeByte_Flash(currByte + c, multiCartPatch1 & 0xFF);
busyCheck29F032(currByte + c, multiCartPatch1 & 0xFF);
continue;
}
if ((currByte + c) == 0x20746 && cartRegion > 0 && multiCart == 1) {
writeByte_Flash(currByte + c, multiCartPatch2 & 0xFF);
busyCheck29F032(currByte + c, multiCartPatch2 & 0xFF);
continue;
}
// Write cartridge region
if ((currByte + c) == cartRegionOffset && cartRegion > 0) {
writeByte_Flash(currByte + c, cartRegion & 0xFF);
busyCheck29F032(currByte + c, cartRegion & 0xFF);
continue;
}
// Write cartridge cd
if ((currByte + c) == cartnocdOffset && cartCD > 0) {
writeByte_Flash(currByte + c, cartCDPatch & 0xFF);
busyCheck29F032(currByte + c, cartCDPatch & 0xFF);
continue;
}
// Write current byte
writeByte_Flash(currByte + c, sdBuffer[c]);
busyCheck29F032(currByte + c, sdBuffer[c]);
}
// update progress bar
processedProgressBar += 512;
draw_progressbar(processedProgressBar, totalProgressBar);
}
// Set data pins to input again
dataIn8();
// Close the file:
myFile.close();
}
}
void verifyCartridge() {
if (openVerifyFlashFile()) {
blank = 0;
//Initialize progress bar
uint32_t processedProgressBar = 0;
uint32_t totalProgressBar = fileSize;
draw_progressbar(0, totalProgressBar);
for (unsigned long currByte = 0; currByte < fileSize; currByte += 512) {
//fill sdBuffer
myFile.read(sdBuffer, 512);
for (int c = 0; c < 512; c++) {
// Verify patch to avoid region menu
if ((currByte + c) == 0x405F && cartRegion > 0 && multiCart == 1 && readByte_Flash(currByte + c) == multiCartPatch1 & 0xFF) {
continue;
} else if ((currByte + c) == 0x20746 && cartRegion > 0 && multiCart == 1 && readByte_Flash(currByte + c) == multiCartPatch2 & 0xFF) {
continue;
// Verify cartridge region
} else if ((currByte + c) == cartRegionOffset && cartRegion > 0 && readByte_Flash(currByte + c) == cartRegion & 0xFF) {
continue;
// Verify cartridge cd
} else if ((currByte + c) == cartnocdOffset && cartCD > 0 && readByte_Flash(currByte + c) == cartCDPatch & 0xFF) {
continue;
} else if (readByte_Flash(currByte + c) != sdBuffer[c]) {
blank++;
}
}
// Update progress bar
processedProgressBar += 512;
draw_progressbar(processedProgressBar, totalProgressBar);
// Blink led
if (currByte % 25600 == 0)
blinkLED();
}
if (blank == 0) {
println_Msg(F("Cart BIOS verified OK"));
display_Update();
} else {
print_STR(error_STR, 0);
print_Msg(blank);
print_STR(_bytes_STR, 1);
print_Error(did_not_verify_STR);
}
// Close the file:
myFile.close();
}
}
void setCartridgePatchData(char crcStr[9]) {
// Init vars
cartRegionOffset = 0;
//Search for CRC32 in file
char crc_search[9];
char tmpDWord[9];
//go to root
sd.chdir("/");
if (myFile.open("cps3.txt", O_READ)) {
while (myFile.available()) {
// Skip first line with name
skip_line(&myFile);
// Read the CRC32 from database
for (byte i = 0; i < 8; i++) {
crc_search[i] = char(myFile.read());
}
crc_search[8] = '\0';
//if checksum search successful, set patch data
if (strcmp(crc_search, crcStr) == 0) {
// Skip the , in the file
myFile.seekCur(1);
// Read region offset
cartRegionOffset = char2int(myFile.read()) << 16 | char2int(myFile.read()) << 12 | char2int(myFile.read()) << 8 | char2int(myFile.read()) << 4 | char2int(myFile.read());
// Skip the , in the file
myFile.seekCur(1);
if (cartRegionOffset != 0) {
// Ask for cart region change
cpsCartRegionMenu();
if (cartRegion != 0) {
uint8_t skipRegions = 8 - cartRegion;
cartRegion -= 1;
myFile.seekCur(cartRegion * 2);
cartRegion = (char2int(myFile.read())) << 4 | char2int(myFile.read());
myFile.seekCur(skipRegions * 2);
} else {
myFile.seekCur(16);
}
} else {
myFile.seekCur(16);
}
// Skip the , in the file
myFile.seekCur(1);
cartnocdOffset = char2int(myFile.read()) << 16 | char2int(myFile.read()) << 12 | char2int(myFile.read()) << 8 | char2int(myFile.read()) << 4 | char2int(myFile.read());
// Skip the , in the file
myFile.seekCur(1);
if (cartnocdOffset != 0) {
// Ask for cart cd change
cpsCartCDMenu();
cartCDPatch = char2int(myFile.read()) << 4 | char2int(myFile.read());
if (cartCD == 1) {
cartCDPatch = char2int(myFile.read()) << 4 | char2int(myFile.read());
} else {
// Skip the byte
myFile.seekCur(2);
}
} else {
myFile.seekCur(4);
}
// Skip the , in the file
myFile.seekCur(1);
// Read multi cart dat from database
multiCart = char2int(myFile.read());
// Read multi cart patches
if (multiCart == 1) {
multiCartPatch1 = char2int(myFile.read()) << 4 | char2int(myFile.read());
multiCartPatch2 = char2int(myFile.read()) << 4 | char2int(myFile.read());
}
break;
}
// If no match go to next entry
else {
// skip rest of line
myFile.seekCur(42);
// skip third empty line
skip_line(&myFile);
}
}
myFile.close();
}
}
/******************************************
2x8bit SIMM functions
*****************************************/
void id_SIMM2x8() {
idFlash2x8(0x0);
idFlash2x8(0x1);
idFlash2x8(0x2);
idFlash2x8(0x3);
resetSIMM2x8();
uint8_t ngFlash = 0;
uint8_t okFlash = 0;
if (flashids[6] == flashids[7]) {
flashid = flashids[7];
sprintf(flashid_str, "%04X", flashid);
okFlash = 2;
for (byte i = 0; i < 6; i++) {
if (flashid == flashids[i])
okFlash += 1;
else
ngFlash += 1;
}
}
// Print start screen
display_Clear();
display_Update();
println_Msg(F("SIMM Writer 2x8bit"));
println_Msg("");
println_Msg("");
print_Msg(F("Flash ID: "));
println_Msg(flashid_str);
if (flashid == 0x04AD && okFlash == 2 && ngFlash == 6) {
println_Msg(F("32 Mbit Fujitsu SIMM detected"));
flashSize = 0x400000;
flashromType = 1;
} else if (flashid == 0x04AD && okFlash == 8) {
println_Msg(F("128 Mbit Fujitsu SIMM detected"));
flashSize = 0x1000000;
flashromType = 1;
} else if (flashid == 0x04AD && okFlash > 2) {
println_Msg(F("?? Mbit Fujitsu SIMM detected"));
println_Msg(F("With some bad flash"));
flashSize = 0x1000000;
flashromType = 0;
} else {
// ID not found
flashSize = 0x1000000;
flashromType = 0;
display_Clear();
println_Msg(F("SIMM Writer 2x8bit"));
println_Msg("");
print_Msg(F("ID Type 1: "));
println_Msg(vendorID);
print_Msg(F("ID Type 2: "));
println_Msg(flashid_str);
println_Msg("");
println_Msg(F("UNKNOWN FLASHROM"));
println_Msg("");
// Prints string out of the common strings array either with or without newline
print_Error(press_button_STR);
display_Update();
wait();
// print first 40 bytes of flash
display_Clear();
println_Msg(F("First 40 bytes:"));
println_Msg(FS(FSTRING_EMPTY));
printFlash16(40);
resetSIMM2x8();
}
println_Msg(FS(FSTRING_EMPTY));
// Prints string out of the common strings array either with or without newline
print_STR(press_button_STR, 1);
display_Update();
resetSIMM2x8();
}
void resetSIMM2x8() {
resetFlash2x8(0x3);
resetFlash2x8(0x2);
resetFlash2x8(0x1);
resetFlash2x8(0x0);
}
void blankcheckSIMM2x8() {
//Initialize progress bar
uint32_t processedProgressBar = 0;
uint32_t totalProgressBar = flashSize;
draw_progressbar(0, totalProgressBar);
blank = 1;
word d = 0;
unsigned long simmAddress = 0;
for (unsigned long currBuffer = 0; currBuffer < flashSize / 2; currBuffer += 256) {
// Fill buffer
for (int c = 0; c < 256; c++) {
simmAddress = currBuffer + c;
word currWord = readWord_Flash(simmAddress);
// Read byte right
sdBuffer[d + 1] = ((currWord >> 8) & 0xFF);
// Read byte left
sdBuffer[d] = (currWord & 0xFF);
d += 2;
}
// Check if all bytes are 0xFF
d = 0;
for (unsigned long currByte = 0; currByte < 256; currByte++) {
if (sdBuffer[d] != 0xFF || sdBuffer[d + 1] != 0xFF) {
currByte = 256;
currBuffer = flashSize / 2;
blank = 0;
}
d += 2;
}
d = 0;
// Update progress bar
processedProgressBar += 512;
draw_progressbar(processedProgressBar, totalProgressBar);
// Blink led
if (currBuffer % 25600 == 0)
blinkLED();
}
if (blank) {
println_Msg(F("SIMM is empty"));
display_Update();
} else {
println_Msg(FS(FSTRING_EMPTY));
print_Error(F("Error: Not blank"));
}
}
// From readFlash
void readSIMM2x8() {
// Reset to root directory
sd.chdir("/");
createFolderAndOpenFile("CPS3", "SIMM", "128M", "bin");
//Initialize progress bar
uint32_t processedProgressBar = 0;
uint32_t totalProgressBar = flashSize;
draw_progressbar(0, totalProgressBar);
word d = 0;
unsigned long simmAddress = 0;
char tmpWord[5];
char tmpDWord[9];
for (unsigned long currByte = 0; currByte < flashSize / 2; currByte += 256) {
for (word c = 0; c < 256; c++) {
simmAddress = currByte + c;
word currWord = readWord_Flash(simmAddress);
// Split word into two bytes
// Right
sdBuffer[d + 1] = ((currWord >> 8) & 0xFF);
// Left
sdBuffer[d] = (currWord & 0xFF);
d += 2;
}
myFile.write(sdBuffer, 512);
d = 0;
// Update progress bar
processedProgressBar += 512;
draw_progressbar(processedProgressBar, totalProgressBar);
// Blink led
if (currByte % 25600 == 0)
blinkLED();
}
// Close the file:
myFile.close();
println_Msg(F("Finished reading"));
display_Update();
}
// From readFlash16
void readSIMM2x8B() {
// Reset to root directory
sd.chdir("/");
createFolderAndOpenFile("CPS3", "SIMM", "128M", "bin");
//Initialize progress bar
uint32_t processedProgressBar = 0;
uint32_t totalProgressBar = flashSize;
draw_progressbar(0, totalProgressBar);
word d = 0;
unsigned long simmAddress = 0;
for (unsigned long currByte = 0; currByte < flashSize / 2; currByte += 256) {
for (word c = 0; c < 256; c++) {
simmAddress = currByte + c;
word currWord = readWord_Flash(simmAddress);
// Split word into two bytes
// Right
sdBuffer[d + 1] = ((currWord >> 8) & 0xFF);
// Left
sdBuffer[d] = (currWord & 0xFF);
d += 2;
}
myFile.write(sdBuffer, 512);
d = 0;
// Update progress bar
processedProgressBar += 512;
draw_progressbar(processedProgressBar, totalProgressBar);
// Blink led
if (currByte % 25600 == 0)
blinkLED();
}
// Close the file:
myFile.close();
println_Msg(F("Finished reading."));
display_Update();
}
void eraseSIMM2x8() {
eraseFlash2x8(0x3);
eraseFlash2x8(0x2);
eraseFlash2x8(0x1);
eraseFlash2x8(0x0);
}
// From writeFlash29F032
void writeSIMM2x8() {
if (openFlashFile()) {
// Set data pins to output
dataOut16();
//Initialize progress bar
uint32_t processedProgressBar = 0;
uint32_t totalProgressBar = (uint32_t)fileSize;
draw_progressbar(0, totalProgressBar);
// Fill sdBuffer LSB
unsigned long simmAddress = 0;
for (unsigned long currByte = 0; currByte < fileSize / 2; currByte += 256) {
myFile.read(sdBuffer, 512);
// Blink led
if (currByte % 4096 == 0)
blinkLED();
noInterrupts();
for (int c = 0; c < 256; c++) {
simmAddress = currByte + c;
word myWord = ((sdBuffer[(c * 2) + 1] & 0xFF) << 8) | (sdBuffer[c * 2] & 0xFF);
// Skip if data exist in flash
dataIn16();
word wordFlash = readWord_Flash(simmAddress);
dataOut16();
if (wordFlash == myWord || myWord == 0xFFFF) {
continue;
}
// Write command sequence
writeByteCommand_Flash2x8(simmAddress >> 21, 0xa0);
// Write current word
writeWord_Flash(simmAddress, myWord);
busyCheck2x8(simmAddress, myWord);
}
interrupts();
// update progress bar
processedProgressBar += 512;
draw_progressbar(processedProgressBar, totalProgressBar);
}
// Set data pins to input again
dataIn16();
// Close the file:
myFile.close();
}
}
// From verifyFlash16
void verifySIMM2x8() {
if (openVerifyFlashFile()) {
blank = 0;
word d = 0;
unsigned long simmAddress = 0;
//Initialize progress bar
uint32_t processedProgressBar = 0;
uint32_t totalProgressBar = fileSize;
draw_progressbar(0, totalProgressBar);
for (unsigned long currByte = 0; currByte < fileSize / 2; currByte += 256) {
//fill sdBuffer
myFile.read(sdBuffer, 512);
for (int c = 0; c < 256; c++) {
// Set address
simmAddress = currByte + c;
word currWord = ((sdBuffer[d + 1] << 8) | sdBuffer[d]);
if (readWord_Flash(simmAddress) != currWord) {
blank++;
}
d += 2;
}
d = 0;
// Update progress bar
if (currByte % 256 == 0) {
processedProgressBar += 512;
draw_progressbar(processedProgressBar, totalProgressBar);
}
// Blink led
if (currByte % 25600 == 0)
blinkLED();
}
if (blank == 0) {
println_Msg(F("SIMM verified OK"));
display_Update();
} else {
print_STR(error_STR, 0);
print_Msg(blank);
print_STR(_bytes_STR, 1);
print_Error(did_not_verify_STR);
}
// Close the file:
myFile.close();
}
}
/******************************************
4x8bit SIMM functions
*****************************************/
void id_SIMM4x8() {
enable64MSB();
idFlash2x8(0x0);
enable64LSB();
idFlash2x8(0x1);
resetSIMM4x8();
uint8_t ngFlash = 0;
uint8_t okFlash = 0;
flashid = flashids[7];
sprintf(flashid_str, "%04X", flashid);
for (byte i = 4; i < 8; i++) {
if (flashid == flashids[i])
okFlash += 1;
else
ngFlash += 1;
}
// Print start screen
display_Clear();
display_Update();
println_Msg(F("SIMM Writer 4x8bit"));
println_Msg("");
println_Msg("");
print_Msg(F("Flash ID: "));
println_Msg(flashid_str);
if (flashid == 0x04AD && okFlash == 4) {
println_Msg(F("64 Mbit Fujitsu SIMM detected"));
flashSize = 0x800000;
flashromType = 1;
} else if (flashid == 0x04AD && okFlash < 4) {
println_Msg(F("Fujitsu SIMM detected"));
println_Msg(F("With some bad flash"));
flashSize = 0x800000;
flashromType = 0;
} else {
// ID not found
display_Clear();
println_Msg(F("SIMM Writer 4x8bit"));
println_Msg("");
print_Msg(F("ID Type 1: "));
println_Msg(vendorID);
print_Msg(F("ID Type 2: "));
println_Msg(flashid_str);
println_Msg("");
println_Msg(F("UNKNOWN FLASHROM"));
println_Msg("");
// Prints string out of the common strings array either with or without newline
print_Error(press_button_STR);
display_Update();
wait();
// print first 40 bytes of flash
display_Clear();
println_Msg(F("First 40 bytes:"));
println_Msg(FS(FSTRING_EMPTY));
printFlash16(40);
resetSIMM4x8();
}
println_Msg(FS(FSTRING_EMPTY));
// Prints string out of the common strings array either with or without newline
print_STR(press_button_STR, 1);
display_Update();
resetSIMM4x8();
}
void resetSIMM4x8() {
enable64MSB();
resetFlash2x8(0x0);
enable64LSB();
resetFlash2x8(0x0);
}
void blankcheckSIMM4x8() {
//Initialize progress bar
uint32_t processedProgressBar = 0;
uint32_t totalProgressBar = flashSize;
draw_progressbar(0, totalProgressBar);
blank = 1;
word d = 0;
for (unsigned long currBuffer = 0; currBuffer < flashSize / 4; currBuffer += 128) {
// Fill buffer
for (int c = 0; c < 128; c++) {
enable64MSB();
word currWord = readWord_Flash(currBuffer + c);
// Read byte right
sdBuffer[d + 1] = ((currWord >> 8) & 0xFF);
// Read byte left
sdBuffer[d] = (currWord & 0xFF);
enable64LSB();
currWord = readWord_Flash(currBuffer + c);
// Read byte right
sdBuffer[d + 3] = ((currWord >> 8) & 0xFF);
// Read byte left
sdBuffer[d + 2] = (currWord & 0xFF);
d += 4;
}
// Check if all bytes are 0xFF
d = 0;
for (unsigned long currByte = 0; currByte < 128; currByte++) {
if (sdBuffer[d] != 0xFF || sdBuffer[d + 1] != 0xFF || sdBuffer[d + 2] != 0xFF || sdBuffer[d + 3] != 0xFF) {
currByte = 128;
currBuffer = flashSize / 4;
blank = 0;
}
d += 4;
}
d = 0;
// Update progress bar
processedProgressBar += 512;
draw_progressbar(processedProgressBar, totalProgressBar);
// Blink led
if (currBuffer % 25600 == 0)
blinkLED();
}
if (blank) {
println_Msg(F("SIMM is empty"));
display_Update();
} else {
println_Msg(FS(FSTRING_EMPTY));
print_Error(F("Error: Not blank"));
}
}
void eraseSIMM4x8() {
enable64MSB();
eraseFlash2x8(0x0);
enable64LSB();
eraseFlash2x8(0x0);
}
// From readFlash16
void readSIMM4x8() {
// Reset to root directory
sd.chdir("/");
createFolderAndOpenFile("CPS3", "SIMM", "64M", "bin");
//Initialize progress bar
uint32_t processedProgressBar = 0;
uint32_t totalProgressBar = flashSize;
draw_progressbar(0, totalProgressBar);
word d = 0;
for (unsigned long currByte = 0; currByte < flashSize / 4; currByte += 128) {
for (word c = 0; c < 128; c++) {
enable64MSB();
word currWord = readWord_Flash(currByte + c);
// Split word into two bytes
// Right
sdBuffer[d + 1] = ((currWord >> 8) & 0xFF);
// Left
sdBuffer[d] = (currWord & 0xFF);
enable64LSB();
currWord = readWord_Flash(currByte + c);
// Split word into two bytes
// Right
sdBuffer[d + 3] = ((currWord >> 8) & 0xFF);
// Left
sdBuffer[d + 2] = (currWord & 0xFF);
d += 4;
}
myFile.write(sdBuffer, 512);
d = 0;
// Update progress bar
processedProgressBar += 512;
draw_progressbar(processedProgressBar, totalProgressBar);
// Blink led
if (currByte % 12800 == 0)
blinkLED();
}
// Close the file:
myFile.close();
println_Msg(F("Finished reading."));
display_Update();
}
void writeSIMM4x8() {
if (openFlashFile()) {
// Set data pins to output
dataOut16();
//Initialize progress bar
uint32_t processedProgressBar = 0;
uint32_t totalProgressBar = (uint32_t)fileSize;
draw_progressbar(0, totalProgressBar);
// Fill sdBuffer
for (unsigned long currByte = 0; currByte < fileSize / 4; currByte += 128) {
myFile.read(sdBuffer, 512);
// Blink led
if (currByte % 2048 == 0)
blinkLED();
noInterrupts();
for (int c = 0; c < 128; c++) {
// 0600 0EA0
enable64MSB();
// 0006
word myWord = ((sdBuffer[(c * 4) + 1] & 0xFF) << 8) | (sdBuffer[(c * 4)] & 0xFF);
// Write command sequence
writeByteCommand_Flash2x8(0x0, 0xa0);
// Write current word
writeWord_Flash(currByte + c, myWord);
busyCheck2x8(currByte + c, myWord);
enable64LSB();
// A00E
myWord = ((sdBuffer[(c * 4) + 3] & 0xFF) << 8) | (sdBuffer[(c * 4) + 2] & 0xFF);
// Write command sequence
writeByteCommand_Flash2x8(0x0, 0xa0);
// Write current word
writeWord_Flash(currByte + c, myWord);
busyCheck2x8(currByte + c, myWord);
}
interrupts();
// update progress bar
processedProgressBar += 512;
draw_progressbar(processedProgressBar, totalProgressBar);
}
// Set data pins to input again
dataIn16();
// Close the file:
myFile.close();
}
}
void verifySIMM4x8() {
if (openVerifyFlashFile()) {
blank = 0;
word d = 0;
//Initialize progress bar
uint32_t processedProgressBar = 0;
uint32_t totalProgressBar = fileSize;
draw_progressbar(0, totalProgressBar);
for (unsigned long currByte = 0; currByte < fileSize / 4; currByte += 128) {
//fill sdBuffer
myFile.read(sdBuffer, 512);
for (int c = 0; c < 128; c++) {
enable64MSB();
word currWord = ((sdBuffer[d + 1] << 8) | sdBuffer[d]);
if (readWord_Flash(currByte + c) != currWord) {
blank++;
}
enable64LSB();
currWord = ((sdBuffer[d + 3] << 8) | sdBuffer[d + 2]);
if (readWord_Flash(currByte + c) != currWord) {
blank++;
}
d += 4;
}
d = 0;
// Update progress bar
if (currByte % 128 == 0) {
processedProgressBar += 512;
draw_progressbar(processedProgressBar, totalProgressBar);
}
// Blink led
if (currByte % 25600 == 0)
blinkLED();
}
if (blank == 0) {
println_Msg(F("SIMM verified OK"));
display_Update();
} else {
print_STR(error_STR, 0);
print_Msg(blank);
print_STR(_bytes_STR, 1);
print_Error(did_not_verify_STR);
}
// Close the file:
myFile.close();
}
}
void printSIMM4x8(int numBytes) {
/*
right_byte = short_val & 0xFF;
left_byte = ( short_val >> 8 ) & 0xFF
short_val = ( ( left_byte & 0xFF ) << 8 ) | ( right_byte & 0xFF );
*/
char buf[3];
for (int currByte = 0; currByte < numBytes / 4; currByte += 4) {
// 2 dwords per line
for (int c = 0; c < 2; c++) {
enable64MSB();
word currWord = readWord_Flash(currByte + c);
// Split word into two bytes
byte left_byte = currWord & 0xFF;
byte right_byte = (currWord >> 8) & 0xFF;
sprintf(buf, "%.2X", left_byte);
// Now print the significant bits
print_Msg(buf);
sprintf(buf, "%.2X", right_byte);
// Now print the significant bits
print_Msg(buf);
enable64LSB();
currWord = readWord_Flash(currByte + c);
// Split word into two bytes
left_byte = currWord & 0xFF;
right_byte = (currWord >> 8) & 0xFF;
sprintf(buf, "%.2X", left_byte);
// Now print the significant bits
print_Msg(buf);
sprintf(buf, "%.2X", right_byte);
// Now print the significant bits
print_Msg(buf);
}
println_Msg("");
}
display_Update();
}
/******************************************
SIMM 2x8bit flashrom functions
*****************************************/
void resetFlash2x8(uint32_t bank) {
// Set data pins to output
dataOut16();
// Reset command sequence
writeByteCommand_Flash2x8(bank, 0xf0);
// Set data pins to input again
dataIn16();
delay(500);
}
void idFlash2x8(uint32_t bank) {
// Set data pins to output
dataOut16();
// ID command sequence
writeByteCommand_Flash2x8(bank, 0x90);
// Set data pins to input again
dataIn16();
// Read the two id bytes into a string
flashids[(bank * 2)] = (readWord_Flash((bank << 21) | 0) >> 8) << 8;
flashids[(bank * 2)] |= readWord_Flash((bank << 21) | 1) >> 8;
//sprintf(flashid_str, "%04X", flashid);
// Read the two id bytes into a string
flashids[(bank * 2) + 1] = (readWord_Flash((bank << 21) | 0) & 0xFF) << 8;
flashids[(bank * 2) + 1] |= readWord_Flash((bank << 21) | 1) & 0xFF;
//sprintf(flashid_str2, "%04X", flashid2);
}
// From eraseFlash29F032
void eraseFlash2x8(uint32_t bank) {
// Set data pins to output
dataOut16();
// Erase command sequence
writeByteCommand_Flash2x8(bank, 0x80);
writeByteCommand_Flash2x8(bank, 0x10);
// Set data pins to input again
dataIn16();
// Read the status register
word statusReg = readWord_Flash((bank << 21) | 0);
// After a completed erase D7 and D15 will output 1
while ((statusReg & 0x8080) != 0x8080) {
// Blink led
blinkLED();
delay(100);
// Update Status
statusReg = readWord_Flash((bank << 21) | 0);
}
}
// From busyCheck29F032
int busyCheck2x8(uint32_t addr, word c) {
int ret = 0;
// Set data pins to input
dataIn16();
// Setting OE(PH1) LOW
PORTH &= ~(1 << 1);
// Setting WE(PH4) HIGH
PORTH |= (1 << 4);
NOP;
NOP;
//When the Embedded Program algorithm is complete, the device outputs the datum programmed to D7 and D15
for (;;) {
word d = readWord_Flash(addr);
if ((d & 0x8080) == (c & 0x8080)) {
break;
}
if ((d & 0x2020) == 0x2020) {
// From the datasheet:
// DQ 5 will indicate if the program or erase time has exceeded the specified limits (internal pulse count).
// Under these conditions DQ 5 will produce a “1”.
// This is a failure condition which indicates that the program or erase cycle was not successfully completed.
// Note : DQ 7 is rechecked even if DQ 5 = “1” because DQ 7 may change simultaneously with DQ 5 .
d = readWord_Flash(addr);
if ((d & 0x8080) == (c & 0x8080)) {
break;
} else {
ret = 1;
break;
}
}
}
// Set data pins to output
dataOut16();
// Setting OE(PH1) HIGH
PORTH |= (1 << 1);
NOP;
NOP;
return ret;
}
#endif