mirror of
https://github.com/sanni/cartreader.git
synced 2024-12-30 15:01:53 +01:00
2cf7f5dbe7
The `setVoltage()` function should be called even when `ENABLE_VSELECT` is disabled because `ENABLE_3V3FIX` also uses it. There is no resource cost to do this as when both options are disabled the compiler will optimize this function out. This just "future proofs" the code so if that function ever does more it doesn't need updated everywhere. This applies to `setup_FlashVoltage()` as well. The changes to OSCR.cpp are just for code formatting and additional comments to clarify this.
913 lines
21 KiB
C++
913 lines
21 KiB
C++
//******************************************
|
|
// GB MEMORY MODULE
|
|
//******************************************
|
|
#ifdef enable_GBX
|
|
|
|
/******************************************
|
|
Menu
|
|
*****************************************/
|
|
// GBM menu items
|
|
static const char gbmMenuItem1[] PROGMEM = "Read ID";
|
|
static const char gbmMenuItem2[] PROGMEM = "Read Flash";
|
|
static const char gbmMenuItem3[] PROGMEM = "Erase Flash";
|
|
static const char gbmMenuItem4[] PROGMEM = "Blankcheck";
|
|
static const char gbmMenuItem5[] PROGMEM = "Write Flash";
|
|
static const char gbmMenuItem6[] PROGMEM = "Read Mapping";
|
|
static const char gbmMenuItem7[] PROGMEM = "Write Mapping";
|
|
static const char* const menuOptionsGBM[] PROGMEM = { gbmMenuItem1, gbmMenuItem2, gbmMenuItem3, gbmMenuItem4, gbmMenuItem5, gbmMenuItem6, gbmMenuItem7 };
|
|
|
|
void gbmMenu() {
|
|
// create menu with title and 7 options to choose from
|
|
unsigned char mainMenu;
|
|
// Copy menuOptions out of progmem
|
|
convertPgm(menuOptionsGBM, 7);
|
|
mainMenu = question_box(F("GB Memory Menu"), menuOptions, 7, 0);
|
|
|
|
// wait for user choice to come back from the question box menu
|
|
switch (mainMenu) {
|
|
// Read Flash ID
|
|
case 0:
|
|
// Clear screen
|
|
display_Clear();
|
|
readFlashID_GBM();
|
|
break;
|
|
|
|
// Read Flash
|
|
case 1:
|
|
// Clear screen
|
|
display_Clear();
|
|
// Print warning
|
|
println_Msg(F("Attention"));
|
|
println_Msg(F("Always power cycle"));
|
|
println_Msg(F("cartreader directly"));
|
|
println_Msg(F("before reading"));
|
|
println_Msg("");
|
|
// Prints string out of the common strings array either with or without newline
|
|
print_STR(press_button_STR, 1);
|
|
display_Update();
|
|
wait();
|
|
// Clear screen
|
|
display_Clear();
|
|
|
|
// Reset to root directory
|
|
sd.chdir("/");
|
|
|
|
// Enable access to ports 0120h
|
|
send_GBM(0x09);
|
|
// Map entire flashrom
|
|
send_GBM(0x04);
|
|
// Disable ports 0x0120...
|
|
send_GBM(0x08);
|
|
// Read 1MB rom
|
|
readROM_GBM(64);
|
|
break;
|
|
|
|
// Erase Flash
|
|
case 2:
|
|
// Clear screen
|
|
display_Clear();
|
|
// Print warning
|
|
println_Msg(F("Attention"));
|
|
println_Msg(F("This will erase your"));
|
|
println_Msg(F("NP Cartridge."));
|
|
println_Msg("");
|
|
println_Msg("");
|
|
// Prints string out of the common strings array either with or without newline
|
|
print_STR(press_button_STR, 1);
|
|
display_Update();
|
|
wait();
|
|
// Clear screen
|
|
display_Clear();
|
|
eraseFlash_GBM();
|
|
break;
|
|
|
|
// Blankcheck Flash
|
|
case 3:
|
|
// Clear screen
|
|
display_Clear();
|
|
if (blankcheckFlash_GBM()) {
|
|
println_Msg(F("OK"));
|
|
display_Update();
|
|
} else {
|
|
println_Msg(F("ERROR"));
|
|
display_Update();
|
|
}
|
|
break;
|
|
|
|
// Write Flash
|
|
case 4:
|
|
// Clear screen
|
|
display_Clear();
|
|
|
|
filePath[0] = '\0';
|
|
sd.chdir("/");
|
|
// Launch file browser
|
|
fileBrowser(F("Select 1MB file"));
|
|
display_Clear();
|
|
sprintf(filePath, "%s/%s", filePath, fileName);
|
|
|
|
// Write rom
|
|
writeFlash_GBM();
|
|
break;
|
|
|
|
// Read mapping
|
|
case 5:
|
|
// Clear screen
|
|
display_Clear();
|
|
|
|
// Reset to root directory
|
|
sd.chdir("/");
|
|
|
|
// Read mapping
|
|
readMapping_GBM();
|
|
break;
|
|
|
|
// Write mapping
|
|
case 6:
|
|
// Clear screen
|
|
display_Clear();
|
|
|
|
// Print warning
|
|
println_Msg(F("Attention"));
|
|
println_Msg(F("This will erase your"));
|
|
println_Msg(F("NP Cartridge's"));
|
|
println_Msg(F("mapping data"));
|
|
println_Msg("");
|
|
// Prints string out of the common strings array either with or without newline
|
|
print_STR(press_button_STR, 1);
|
|
display_Update();
|
|
wait();
|
|
|
|
// Reset to root directory
|
|
sd.chdir("/");
|
|
|
|
// Clear screen
|
|
display_Clear();
|
|
|
|
// Clear filepath
|
|
filePath[0] = '\0';
|
|
|
|
// Reset to root directory
|
|
sd.chdir("/");
|
|
|
|
// Launch file browser
|
|
fileBrowser(F("Select MAP file"));
|
|
display_Clear();
|
|
sprintf(filePath, "%s/%s", filePath, fileName);
|
|
display_Update();
|
|
|
|
// Clear screen
|
|
display_Clear();
|
|
|
|
// Erase mapping
|
|
eraseMapping_GBM();
|
|
if (blankcheckMapping_GBM()) {
|
|
println_Msg(F("OK"));
|
|
display_Update();
|
|
} else {
|
|
print_Error(F("Erasing failed"));
|
|
break;
|
|
}
|
|
|
|
// Write mapping
|
|
writeMapping_GBM();
|
|
break;
|
|
}
|
|
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();
|
|
}
|
|
|
|
/******************************************
|
|
Setup
|
|
*****************************************/
|
|
void setup_GBM() {
|
|
// Request 5V
|
|
setVoltage(VOLTS_SET_5V);
|
|
|
|
// Set RST(PH0) to Input
|
|
DDRH &= ~(1 << 0);
|
|
// Activate Internal Pullup Resistors
|
|
PORTH |= (1 << 0);
|
|
|
|
// Set Address Pins to Output
|
|
//A0-A7
|
|
DDRF = 0xFF;
|
|
//A8-A15
|
|
DDRK = 0xFF;
|
|
|
|
// Set Control Pins to Output RST(PH0) CS(PH3) WR(PH5) RD(PH6)
|
|
DDRH |= (1 << 3) | (1 << 5) | (1 << 6);
|
|
// Output a high signal on all pins, pins are active low therefore everything is disabled now
|
|
PORTH |= (1 << 3) | (1 << 5) | (1 << 6);
|
|
|
|
// Set Data Pins (D0-D7) to Input
|
|
DDRC = 0x00;
|
|
|
|
delay(400);
|
|
|
|
// Check for Nintendo Power GB Memory cart
|
|
byte timeout = 0;
|
|
|
|
// First byte of NP register is always 0x21
|
|
while (readByte_GBM(0x120) != 0x21) {
|
|
// Enable ports 0x120h (F2)
|
|
send_GBM(0x09);
|
|
__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"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t");
|
|
timeout++;
|
|
if (timeout > 10) {
|
|
println_Msg(F("Error: Time Out"));
|
|
print_FatalError(F("Please power cycle"));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**********************
|
|
LOW LEVEL
|
|
**********************/
|
|
// Read one word out of the cartridge
|
|
byte readByte_GBM(word myAddress) {
|
|
// Set data pins to Input
|
|
DDRC = 0x0;
|
|
PORTF = myAddress & 0xFF;
|
|
PORTK = (myAddress >> 8) & 0xFF;
|
|
|
|
__asm__("nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t");
|
|
|
|
// Switch CS(PH3) and RD(PH6) to LOW
|
|
PORTH &= ~(1 << 3);
|
|
PORTH &= ~(1 << 6);
|
|
|
|
__asm__("nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t");
|
|
|
|
// Read
|
|
byte tempByte = PINC;
|
|
|
|
// Switch CS(PH3) and RD(PH6) to HIGH
|
|
PORTH |= (1 << 6);
|
|
PORTH |= (1 << 3);
|
|
|
|
return tempByte;
|
|
}
|
|
|
|
// Write one word to data pins of the cartridge
|
|
void writeByte_GBM(word myAddress, byte myData) {
|
|
// Set data pins to Output
|
|
DDRC = 0xFF;
|
|
PORTF = myAddress & 0xFF;
|
|
PORTK = (myAddress >> 8) & 0xFF;
|
|
PORTC = myData;
|
|
|
|
// Pull CS(PH3) and write(PH5) low
|
|
PORTH &= ~(1 << 3);
|
|
PORTH &= ~(1 << 5);
|
|
|
|
__asm__("nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t");
|
|
|
|
// Pull CS(PH3) and write(PH5) high
|
|
PORTH |= (1 << 5);
|
|
PORTH |= (1 << 3);
|
|
|
|
__asm__("nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t");
|
|
|
|
// Set data pins to Input (or read errors??!)
|
|
DDRC = 0x0;
|
|
}
|
|
|
|
/**********************
|
|
HELPER FUNCTIONS
|
|
**********************/
|
|
void printSdBuffer(word startByte, word numBytes) {
|
|
for (word currByte = 0; currByte < numBytes; currByte += 10) {
|
|
for (byte c = 0; c < 10; c++) {
|
|
// Convert to char array so we don't lose leading zeros
|
|
char currByteStr[2];
|
|
sprintf(currByteStr, "%02X", sdBuffer[startByte + currByte + c]);
|
|
print_Msg(currByteStr);
|
|
}
|
|
// Add a new line every 10 bytes
|
|
println_Msg("");
|
|
}
|
|
display_Update();
|
|
}
|
|
|
|
void readROM_GBM(word numBanks) {
|
|
println_Msg(F("Reading Rom..."));
|
|
display_Update();
|
|
|
|
// Get name, add extension and convert to char array for sd lib
|
|
EEPROM_readAnything(0, foldern);
|
|
sprintf(fileName, "GBM%d", foldern);
|
|
strcat(fileName, ".bin");
|
|
sd.mkdir("NP", true);
|
|
sd.chdir("NP");
|
|
// 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)) {
|
|
print_FatalError(create_file_STR);
|
|
} else {
|
|
// Read rom
|
|
word currAddress = 0;
|
|
|
|
for (word currBank = 1; currBank < numBanks; currBank++) {
|
|
// Set rom bank
|
|
writeByte_GBM(0x2100, currBank);
|
|
|
|
// Switch bank start address
|
|
if (currBank > 1) {
|
|
currAddress = 0x4000;
|
|
}
|
|
|
|
for (; currAddress < 0x7FFF; currAddress += 512) {
|
|
for (int currByte = 0; currByte < 512; currByte++) {
|
|
sdBuffer[currByte] = readByte_GBM(currAddress + currByte);
|
|
}
|
|
myFile.write(sdBuffer, 512);
|
|
}
|
|
}
|
|
|
|
// Close the file:
|
|
myFile.close();
|
|
|
|
// Signal end of process
|
|
print_Msg(F("Saved to NP/"));
|
|
println_Msg(fileName);
|
|
display_Update();
|
|
}
|
|
}
|
|
|
|
/**********************
|
|
GB Memory Functions
|
|
**********************/
|
|
void send_GBM(byte myCommand) {
|
|
switch (myCommand) {
|
|
case 0x01:
|
|
//CMD_01h -> ???
|
|
writeByte_GBM(0x0120, 0x01);
|
|
writeByte_GBM(0x013F, 0xA5);
|
|
break;
|
|
|
|
case 0x02:
|
|
//CMD_02h -> Write enable Step 2
|
|
writeByte_GBM(0x0120, 0x02);
|
|
writeByte_GBM(0x013F, 0xA5);
|
|
break;
|
|
|
|
case 0x03:
|
|
//CMD_03h -> Undo write Step 2
|
|
writeByte_GBM(0x0120, 0x03);
|
|
writeByte_GBM(0x013F, 0xA5);
|
|
break;
|
|
|
|
case 0x04:
|
|
//CMD_04h -> Map entire flashrom (MBC4 mode)
|
|
writeByte_GBM(0x0120, 0x04);
|
|
writeByte_GBM(0x013F, 0xA5);
|
|
break;
|
|
|
|
case 0x05:
|
|
//CMD_05h -> Map menu (MBC5 mode)
|
|
writeByte_GBM(0x0120, 0x05);
|
|
writeByte_GBM(0x013F, 0xA5);
|
|
break;
|
|
|
|
case 0x08:
|
|
//CMD_08h -> disable writes/reads to/from special Nintendo Power registers (those at 0120h..013Fh)
|
|
writeByte_GBM(0x0120, 0x08);
|
|
writeByte_GBM(0x013F, 0xA5);
|
|
break;
|
|
|
|
case 0x09:
|
|
//CMD_09h Wakeup -> re-enable access to ports 0120h..013Fh
|
|
writeByte_GBM(0x0120, 0x09);
|
|
writeByte_GBM(0x0121, 0xAA);
|
|
writeByte_GBM(0x0122, 0x55);
|
|
writeByte_GBM(0x013F, 0xA5);
|
|
break;
|
|
|
|
case 0x0A:
|
|
//CMD_0Ah -> Write enable Step 1
|
|
writeByte_GBM(0x0120, 0x0A);
|
|
writeByte_GBM(0x0125, 0x62);
|
|
writeByte_GBM(0x0126, 0x04);
|
|
writeByte_GBM(0x013F, 0xA5);
|
|
break;
|
|
|
|
case 0x10:
|
|
//CMD_10h -> disable writes to normal MBC registers (such like 2100h)
|
|
writeByte_GBM(0x0120, 0x10);
|
|
writeByte_GBM(0x013F, 0xA5);
|
|
break;
|
|
|
|
case 0x11:
|
|
//CMD_11h -> re-enable access to MBC registers like 0x2100
|
|
writeByte_GBM(0x0120, 0x11);
|
|
writeByte_GBM(0x013F, 0xA5);
|
|
break;
|
|
|
|
default:
|
|
print_FatalError(F("Unknown Command"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void send_GBM(byte myCommand, word myAddress, byte myData) {
|
|
byte myAddrLow = myAddress & 0xFF;
|
|
byte myAddrHigh = (myAddress >> 8) & 0xFF;
|
|
|
|
switch (myCommand) {
|
|
case 0x0F:
|
|
// CMD_0Fh -> Write address/byte to flash
|
|
writeByte_GBM(0x0120, 0x0F);
|
|
writeByte_GBM(0x0125, myAddrHigh);
|
|
writeByte_GBM(0x0126, myAddrLow);
|
|
writeByte_GBM(0x0127, myData);
|
|
writeByte_GBM(0x013F, 0xA5);
|
|
break;
|
|
|
|
default:
|
|
print_FatalError(F("Unknown Command"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void switchGame_GBM(byte myData) {
|
|
// Enable ports 0x0120 (F2)
|
|
send_GBM(0x09);
|
|
|
|
//CMD_C0h -> map selected game without reset
|
|
writeByte_GBM(0x0120, 0xC0 & myData);
|
|
writeByte_GBM(0x013F, 0xA5);
|
|
}
|
|
|
|
void resetFlash_GBM() {
|
|
// Enable ports 0x0120 (F2)
|
|
send_GBM(0x09);
|
|
|
|
// Send reset command
|
|
writeByte_GBM(0x2100, 0x01);
|
|
send_GBM(0x0F, 0x5555, 0xAA);
|
|
send_GBM(0x0F, 0x2AAA, 0x55);
|
|
send_GBM(0x0F, 0x5555, 0xF0);
|
|
delay(100);
|
|
}
|
|
|
|
boolean readFlashID_GBM() {
|
|
// Enable ports 0x0120 (F2)
|
|
send_GBM(0x09);
|
|
|
|
writeByte_GBM(0x2100, 0x01);
|
|
// Read ID command
|
|
send_GBM(0x0F, 0x5555, 0xAA);
|
|
send_GBM(0x0F, 0x2AAA, 0x55);
|
|
send_GBM(0x0F, 0x5555, 0x90);
|
|
|
|
// Read the two id bytes into a string
|
|
flashid = readByte_GBM(0) << 8;
|
|
flashid |= readByte_GBM(1);
|
|
sprintf(flashid_str, "%04X", flashid);
|
|
if (flashid == 0xC289) {
|
|
print_Msg(F("Flash ID: "));
|
|
println_Msg(flashid_str);
|
|
display_Update();
|
|
resetFlash_GBM();
|
|
return 1;
|
|
} else {
|
|
print_Msg(F("Flash ID: "));
|
|
println_Msg(flashid_str);
|
|
print_FatalError(F("Unknown Flash ID"));
|
|
resetFlash_GBM();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void eraseFlash_GBM() {
|
|
println_Msg(F("Erasing..."));
|
|
display_Update();
|
|
|
|
//enable access to ports 0120h
|
|
send_GBM(0x09);
|
|
// Enable write
|
|
send_GBM(0x0A);
|
|
send_GBM(0x2);
|
|
|
|
// Unprotect sector 0
|
|
send_GBM(0x0F, 0x5555, 0xAA);
|
|
send_GBM(0x0F, 0x2AAA, 0x55);
|
|
send_GBM(0x0F, 0x5555, 0x60);
|
|
send_GBM(0x0F, 0x5555, 0xAA);
|
|
send_GBM(0x0F, 0x2AAA, 0x55);
|
|
send_GBM(0x0F, 0x5555, 0x40);
|
|
|
|
// Wait for unprotect to complete
|
|
while ((readByte_GBM(0) & 0x80) != 0x80) {}
|
|
|
|
// Send erase command
|
|
send_GBM(0x0F, 0x5555, 0xaa);
|
|
send_GBM(0x0F, 0x2AAA, 0x55);
|
|
send_GBM(0x0F, 0x5555, 0x80);
|
|
send_GBM(0x0F, 0x5555, 0xaa);
|
|
send_GBM(0x0F, 0x2AAA, 0x55);
|
|
send_GBM(0x0F, 0x5555, 0x10);
|
|
|
|
// Wait for erase to complete
|
|
while ((readByte_GBM(0) & 0x80) != 0x80) {}
|
|
|
|
// Reset flashrom
|
|
resetFlash_GBM();
|
|
}
|
|
|
|
boolean blankcheckFlash_GBM() {
|
|
print_Msg(F("Blankcheck..."));
|
|
display_Update();
|
|
|
|
//enable access to ports 0120h (F2)
|
|
send_GBM(0x09);
|
|
|
|
// Map entire flashrom
|
|
send_GBM(0x04);
|
|
// Disable ports 0x0120...
|
|
send_GBM(0x08);
|
|
|
|
// Read rom
|
|
word currAddress = 0;
|
|
|
|
for (byte currBank = 1; currBank < 64; currBank++) {
|
|
// Set rom bank
|
|
writeByte_GBM(0x2100, currBank);
|
|
|
|
// Switch bank start address
|
|
if (currBank > 1) {
|
|
currAddress = 0x4000;
|
|
}
|
|
|
|
for (; currAddress < 0x7FFF; currAddress++) {
|
|
if (readByte_GBM(currAddress) != 0xFF) {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void writeFlash_GBM() {
|
|
print_Msg(F("Writing..."));
|
|
display_Update();
|
|
|
|
// Open file on sd card
|
|
if (myFile.open(filePath, O_READ)) {
|
|
// Get rom size from file
|
|
fileSize = myFile.fileSize();
|
|
if ((fileSize / 0x4000) > 64) {
|
|
print_FatalError(F("File is too big."));
|
|
}
|
|
|
|
// Enable access to ports 0120h
|
|
send_GBM(0x09);
|
|
// Enable write
|
|
send_GBM(0x0A);
|
|
send_GBM(0x2);
|
|
|
|
// Map entire flash rom
|
|
send_GBM(0x4);
|
|
|
|
// Set bank for unprotect command, writes to 0x5555 need odd bank number
|
|
writeByte_GBM(0x2100, 0x1);
|
|
|
|
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
|
|
send_GBM(0x10);
|
|
send_GBM(0x08);
|
|
|
|
// Unprotect sector 0
|
|
writeByte_GBM(0x5555, 0xAA);
|
|
writeByte_GBM(0x2AAA, 0x55);
|
|
writeByte_GBM(0x5555, 0x60);
|
|
writeByte_GBM(0x5555, 0xAA);
|
|
writeByte_GBM(0x2AAA, 0x55);
|
|
writeByte_GBM(0x5555, 0x40);
|
|
|
|
// Check if flashrom is ready for writing or busy
|
|
while ((readByte_GBM(0) & 0x80) != 0x80) {}
|
|
|
|
// first bank: 0x0000-0x7FFF,
|
|
word currAddress = 0x0;
|
|
|
|
// Write 63 banks
|
|
for (byte currBank = 0x1; currBank < (fileSize / 0x4000); currBank++) {
|
|
// Blink led
|
|
blinkLED();
|
|
|
|
// all following banks: 0x4000-0x7FFF
|
|
if (currBank > 1) {
|
|
currAddress = 0x4000;
|
|
}
|
|
|
|
// Write single bank in 128 byte steps
|
|
for (; currAddress < 0x7FFF; currAddress += 128) {
|
|
// Fill SD buffer
|
|
myFile.read(sdBuffer, 128);
|
|
|
|
// Enable access to ports 0x120 and 0x2100
|
|
send_GBM(0x09);
|
|
send_GBM(0x11);
|
|
|
|
// Set bank
|
|
writeByte_GBM(0x2100, 0x1);
|
|
|
|
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
|
|
send_GBM(0x10);
|
|
send_GBM(0x08);
|
|
|
|
// Write flash buffer command
|
|
writeByte_GBM(0x5555, 0xAA);
|
|
writeByte_GBM(0x2AAA, 0x55);
|
|
writeByte_GBM(0x5555, 0xA0);
|
|
|
|
// Wait until flashrom is ready again
|
|
while ((readByte_GBM(0) & 0x80) != 0x80) {}
|
|
|
|
// Enable access to ports 0x120 and 0x2100
|
|
send_GBM(0x09);
|
|
send_GBM(0x11);
|
|
|
|
// Set bank
|
|
writeByte_GBM(0x2100, currBank);
|
|
|
|
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
|
|
send_GBM(0x10);
|
|
send_GBM(0x08);
|
|
|
|
// Fill flash buffer
|
|
for (word currByte = 0; currByte < 128; currByte++) {
|
|
writeByte_GBM(currAddress + currByte, sdBuffer[currByte]);
|
|
}
|
|
// Execute write
|
|
writeByte_GBM(currAddress + 127, 0xFF);
|
|
|
|
// Wait for write to complete
|
|
while ((readByte_GBM(currAddress) & 0x80) != 0x80) {}
|
|
}
|
|
}
|
|
// Close the file:
|
|
myFile.close();
|
|
print_STR(done_STR, 1);
|
|
} else {
|
|
print_Error(F("Can't open file"));
|
|
}
|
|
}
|
|
|
|
void readMapping_GBM() {
|
|
// Enable ports 0x0120
|
|
send_GBM(0x09);
|
|
|
|
// Set WE and WP
|
|
send_GBM(0x0A);
|
|
send_GBM(0x2);
|
|
|
|
// Enable hidden mapping area
|
|
writeByte_GBM(0x2100, 0x01);
|
|
send_GBM(0x0F, 0x5555, 0xAA);
|
|
send_GBM(0x0F, 0x2AAA, 0x55);
|
|
send_GBM(0x0F, 0x5555, 0x77);
|
|
send_GBM(0x0F, 0x5555, 0xAA);
|
|
send_GBM(0x0F, 0x2AAA, 0x55);
|
|
send_GBM(0x0F, 0x5555, 0x77);
|
|
|
|
// Read mapping
|
|
println_Msg(F("Reading Mapping..."));
|
|
display_Update();
|
|
|
|
// Get name, add extension and convert to char array for sd lib
|
|
EEPROM_readAnything(0, foldern);
|
|
sprintf(fileName, "GBM%d", foldern);
|
|
strcat(fileName, ".map");
|
|
sd.mkdir("NP", true);
|
|
sd.chdir("NP");
|
|
// 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)) {
|
|
print_FatalError(create_file_STR);
|
|
} else {
|
|
for (byte currByte = 0; currByte < 128; currByte++) {
|
|
sdBuffer[currByte] = readByte_GBM(currByte);
|
|
}
|
|
myFile.write(sdBuffer, 128);
|
|
|
|
// Close the file:
|
|
myFile.close();
|
|
|
|
// Signal end of process
|
|
printSdBuffer(0, 20);
|
|
printSdBuffer(102, 20);
|
|
println_Msg("");
|
|
print_Msg(F("Saved to NP/"));
|
|
println_Msg(fileName);
|
|
display_Update();
|
|
}
|
|
|
|
// Reset flash to leave hidden mapping area
|
|
resetFlash_GBM();
|
|
}
|
|
|
|
void eraseMapping_GBM() {
|
|
println_Msg(F("Erasing..."));
|
|
display_Update();
|
|
|
|
//enable access to ports 0120h
|
|
send_GBM(0x09);
|
|
// Enable write
|
|
send_GBM(0x0A);
|
|
send_GBM(0x2);
|
|
|
|
// Unprotect sector 0
|
|
send_GBM(0x0F, 0x5555, 0xAA);
|
|
send_GBM(0x0F, 0x2AAA, 0x55);
|
|
send_GBM(0x0F, 0x5555, 0x60);
|
|
send_GBM(0x0F, 0x5555, 0xAA);
|
|
send_GBM(0x0F, 0x2AAA, 0x55);
|
|
send_GBM(0x0F, 0x5555, 0x40);
|
|
|
|
// Wait for unprotect to complete
|
|
while ((readByte_GBM(0) & 0x80) != 0x80) {}
|
|
|
|
// Send erase command
|
|
send_GBM(0x0F, 0x5555, 0xAA);
|
|
send_GBM(0x0F, 0x2AAA, 0x55);
|
|
send_GBM(0x0F, 0x5555, 0x60);
|
|
send_GBM(0x0F, 0x5555, 0xAA);
|
|
send_GBM(0x0F, 0x2AAA, 0x55);
|
|
send_GBM(0x0F, 0x5555, 0x04);
|
|
|
|
// Wait for erase to complete
|
|
while ((readByte_GBM(0) & 0x80) != 0x80) {}
|
|
|
|
// Reset flashrom
|
|
resetFlash_GBM();
|
|
}
|
|
|
|
boolean blankcheckMapping_GBM() {
|
|
print_Msg(F("Blankcheck..."));
|
|
display_Update();
|
|
|
|
// Enable ports 0x0120
|
|
send_GBM(0x09);
|
|
|
|
// Set WE and WP
|
|
send_GBM(0x0A);
|
|
send_GBM(0x2);
|
|
|
|
// Enable hidden mapping area
|
|
writeByte_GBM(0x2100, 0x01);
|
|
send_GBM(0x0F, 0x5555, 0xAA);
|
|
send_GBM(0x0F, 0x2AAA, 0x55);
|
|
send_GBM(0x0F, 0x5555, 0x77);
|
|
send_GBM(0x0F, 0x5555, 0xAA);
|
|
send_GBM(0x0F, 0x2AAA, 0x55);
|
|
send_GBM(0x0F, 0x5555, 0x77);
|
|
|
|
// Disable ports 0x0120...
|
|
send_GBM(0x08);
|
|
|
|
// Read rom
|
|
for (byte currByte = 0; currByte < 128; currByte++) {
|
|
if (readByte_GBM(currByte) != 0xFF) {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void writeMapping_GBM() {
|
|
print_Msg(F("Writing..."));
|
|
display_Update();
|
|
|
|
// Open file on sd card
|
|
if (myFile.open(filePath, O_READ)) {
|
|
// Get map file size and check if it exceeds 128KByte
|
|
if (myFile.fileSize() > 0x80) {
|
|
print_FatalError(F("File is too big."));
|
|
}
|
|
|
|
// Enable access to ports 0120h
|
|
send_GBM(0x09);
|
|
|
|
// Enable write
|
|
send_GBM(0x0A);
|
|
send_GBM(0x2);
|
|
|
|
// Map entire flash rom
|
|
send_GBM(0x4);
|
|
|
|
// Set bank, writes to 0x5555 need odd bank number
|
|
writeByte_GBM(0x2100, 0x1);
|
|
|
|
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
|
|
send_GBM(0x10);
|
|
send_GBM(0x08);
|
|
|
|
// Unlock write to map area
|
|
writeByte_GBM(0x5555, 0xAA);
|
|
writeByte_GBM(0x2AAA, 0x55);
|
|
writeByte_GBM(0x5555, 0x60);
|
|
writeByte_GBM(0x5555, 0xAA);
|
|
writeByte_GBM(0x2AAA, 0x55);
|
|
writeByte_GBM(0x5555, 0xE0);
|
|
|
|
// Check if flashrom is ready for writing or busy
|
|
while ((readByte_GBM(0) & 0x80) != 0x80) {}
|
|
|
|
// Fill SD buffer
|
|
myFile.read(sdBuffer, 128);
|
|
|
|
// Enable access to ports 0x120 and 0x2100
|
|
send_GBM(0x09);
|
|
send_GBM(0x11);
|
|
|
|
// Set bank
|
|
writeByte_GBM(0x2100, 0x1);
|
|
|
|
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
|
|
send_GBM(0x10);
|
|
send_GBM(0x08);
|
|
|
|
// Write flash buffer command
|
|
writeByte_GBM(0x5555, 0xAA);
|
|
writeByte_GBM(0x2AAA, 0x55);
|
|
writeByte_GBM(0x5555, 0xA0);
|
|
|
|
// Wait until flashrom is ready again
|
|
while ((readByte_GBM(0) & 0x80) != 0x80) {}
|
|
|
|
// Enable access to ports 0x120 and 0x2100
|
|
send_GBM(0x09);
|
|
send_GBM(0x11);
|
|
|
|
// Set bank
|
|
writeByte_GBM(0x2100, 0);
|
|
|
|
// Disable ports 0x2100 and 0x120 or else those addresses will not be writable
|
|
send_GBM(0x10);
|
|
send_GBM(0x08);
|
|
|
|
// Fill flash buffer
|
|
for (word currByte = 0; currByte < 128; currByte++) {
|
|
// Blink led
|
|
blinkLED();
|
|
|
|
writeByte_GBM(currByte, sdBuffer[currByte]);
|
|
}
|
|
// Execute write
|
|
writeByte_GBM(127, 0xFF);
|
|
|
|
// Close the file:
|
|
myFile.close();
|
|
print_STR(done_STR, 1);
|
|
} else {
|
|
print_Error(F("Can't open file"));
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
//******************************************
|
|
// End of File
|
|
//******************************************
|