mirror of
https://github.com/sanni/cartreader.git
synced 2024-12-18 09:01:48 +01:00
887 lines
21 KiB
Arduino
887 lines
21 KiB
Arduino
|
/******************************************
|
||
|
GB MEMORY MODULE
|
||
|
******************************************/
|
||
|
|
||
|
#include "options.h"
|
||
|
#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("");
|
||
|
println_Msg(F("Press Button"));
|
||
|
println_Msg(F("to continue"));
|
||
|
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("");
|
||
|
println_Msg(F("Press Button"));
|
||
|
println_Msg(F("to continue"));
|
||
|
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("");
|
||
|
println_Msg(F("Press Button"));
|
||
|
println_Msg(F("to continue"));
|
||
|
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"), false);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Write mapping
|
||
|
writeMapping_GBM();
|
||
|
break;
|
||
|
}
|
||
|
println_Msg(F(""));
|
||
|
println_Msg(F("Press Button..."));
|
||
|
display_Update();
|
||
|
wait();
|
||
|
}
|
||
|
|
||
|
/******************************************
|
||
|
Setup
|
||
|
*****************************************/
|
||
|
void setup_GBM() {
|
||
|
// 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_Error(F("Please power cycle"), true);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**********************
|
||
|
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 (int 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_Error(F("Can't create file on SD"), true);
|
||
|
}
|
||
|
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_Error(F("Unknown Command"), true);
|
||
|
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_Error(F("Unknown Command"), true);
|
||
|
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
|
||
|
sprintf(flashid, "%02X%02X", readByte_GBM(0), readByte_GBM(1));
|
||
|
if (strcmp(flashid, "C289") == 0) {
|
||
|
print_Msg(F("Flash ID: "));
|
||
|
println_Msg(flashid);
|
||
|
display_Update();
|
||
|
resetFlash_GBM();
|
||
|
return 1;
|
||
|
}
|
||
|
else {
|
||
|
print_Msg(F("Flash ID: "));
|
||
|
println_Msg(flashid);
|
||
|
print_Error(F("Unknown Flash ID"), true);
|
||
|
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_Error(F("File is too big."), true);
|
||
|
}
|
||
|
|
||
|
// 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
|
||
|
PORTB ^= (1 << 4);
|
||
|
|
||
|
// 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();
|
||
|
println_Msg(F("Done"));
|
||
|
}
|
||
|
else {
|
||
|
print_Error(F("Can't open file"), false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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_Error(F("Can't create file on SD"), true);
|
||
|
}
|
||
|
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_Error(F("File is too big."), true);
|
||
|
}
|
||
|
|
||
|
// 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
|
||
|
PORTB ^= (1 << 4);
|
||
|
|
||
|
writeByte_GBM(currByte, sdBuffer[currByte]);
|
||
|
}
|
||
|
// Execute write
|
||
|
writeByte_GBM(127, 0xFF);
|
||
|
|
||
|
// Close the file:
|
||
|
myFile.close();
|
||
|
println_Msg(F("Done"));
|
||
|
}
|
||
|
else {
|
||
|
print_Error(F("Can't open file"), false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//******************************************
|
||
|
// End of File
|
||
|
//******************************************
|