mirror of
https://github.com/sanni/cartreader.git
synced 2024-11-23 21:19:16 +01:00
V5.5: Reduce memory usage in Filebrowser
This commit is contained in:
parent
6ffd175e7b
commit
9eca87d975
@ -1,16 +1,17 @@
|
||||
/**********************************************************************************
|
||||
Cartridge Reader for Arduino Mega2560
|
||||
|
||||
Author: sanni
|
||||
Date: 06.07.2020
|
||||
Version: 5.4
|
||||
Date: 28.10.2020
|
||||
Version: 5.5
|
||||
|
||||
SD lib: https://github.com/greiman/SdFat
|
||||
LCD lib: https://github.com/adafruit/Adafruit_SSD1306
|
||||
Clockgen: https://github.com/etherkit/Si5351Arduino
|
||||
RGB Tools lib: https://github.com/joushx/Arduino-RGB-Tools
|
||||
SD lib: https://github.com/greiman/SdFat
|
||||
LCD lib: https://github.com/adafruit/Adafruit_SSD1306
|
||||
GFX Lib: https://github.com/adafruit/Adafruit-GFX-Library
|
||||
BusIO: https://github.com/adafruit/Adafruit_BusIO
|
||||
RGB Tools lib: https://github.com/joushx/Arduino-RGB-Tools
|
||||
SI5351 lib: https://github.com/etherkit/Si5351Arduino
|
||||
|
||||
Compiled with Arduino 1.8.12
|
||||
Compiled with Arduino 1.8.13
|
||||
|
||||
Thanks to:
|
||||
MichlK - ROM-Reader for Super Nintendo
|
||||
@ -42,7 +43,7 @@
|
||||
**********************************************************************************/
|
||||
#include <SdFat.h>
|
||||
|
||||
char ver[5] = "5.4";
|
||||
char ver[5] = "5.5";
|
||||
|
||||
#include "options.h"
|
||||
|
||||
@ -192,7 +193,7 @@ boolean ignoreError = 0;
|
||||
// File browser
|
||||
#define FILENAME_LENGTH 32
|
||||
#define FILEPATH_LENGTH 64
|
||||
#define FILEOPTS_LENGTH 20
|
||||
#define FILEOPTS_LENGTH 18
|
||||
|
||||
char fileName[FILENAME_LENGTH];
|
||||
char filePath[FILEPATH_LENGTH];
|
||||
@ -201,7 +202,6 @@ byte lastPage;
|
||||
byte numPages;
|
||||
boolean root = 0;
|
||||
boolean filebrowse = 0;
|
||||
char fileOptions[30][FILEOPTS_LENGTH];
|
||||
|
||||
// Common
|
||||
char romName[17];
|
||||
@ -1390,16 +1390,12 @@ browserstart:
|
||||
else if (myFile.isDir()) {
|
||||
// Copy full dirname into fileNames
|
||||
snprintf(fileNames[currFile], FILENAME_LENGTH, "%s%s", "/", nameStr);
|
||||
// Copy short string into fileOptions
|
||||
snprintf(fileOptions[currFile], FILEOPTS_LENGTH, "%s%s", "/", nameStr);
|
||||
currFile++;
|
||||
}
|
||||
// It's just a file
|
||||
else if (myFile.isFile()) {
|
||||
// Copy full filename into fileNames
|
||||
snprintf(fileNames[currFile], FILENAME_LENGTH, "%s", nameStr);
|
||||
// Copy short string into fileOptions
|
||||
snprintf(fileOptions[currFile], FILEOPTS_LENGTH, "%s", nameStr);
|
||||
currFile++;
|
||||
}
|
||||
myFile.close();
|
||||
@ -1451,7 +1447,7 @@ page:
|
||||
|
||||
for (byte i = 0; i < 8; i++ ) {
|
||||
// Copy short string into fileOptions
|
||||
snprintf( answers[i], FILEOPTS_LENGTH, "%s", fileOptions[ ((currPage - 1) * 7 + i)] );
|
||||
snprintf( answers[i], FILEOPTS_LENGTH, "%s", fileNames[ ((currPage - 1) * 7 + i)] );
|
||||
}
|
||||
|
||||
// Create menu with title and 1-7 options to choose from
|
||||
|
@ -2060,8 +2060,13 @@ void idFlashrom_GBA() {
|
||||
resetMX29GL128E_GBA();
|
||||
}
|
||||
else {
|
||||
println_Msg(F("Error"));
|
||||
println_Msg(F(""));
|
||||
println_Msg(F("Unknown Flash"));
|
||||
print_Msg(F("Flash ID: "));
|
||||
println_Msg(flashid);
|
||||
print_Error(F("Unknown Flashid"), true);
|
||||
println_Msg(F(""));
|
||||
print_Error(F("Check voltage"), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2508,7 +2513,7 @@ void flashRepro_GBA() {
|
||||
println_Msg("");
|
||||
println_Msg(F("This will erase your"));
|
||||
println_Msg(F("Repro Cartridge."));
|
||||
println_Msg(F("Please use 3.3V!"));
|
||||
println_Msg(F(""));
|
||||
println_Msg("");
|
||||
println_Msg(F("Press Button"));
|
||||
display_Update();
|
||||
@ -2633,9 +2638,13 @@ void flashRepro_GBA() {
|
||||
}
|
||||
}
|
||||
else {
|
||||
print_Msg(F("ID: "));
|
||||
println_Msg(F("Error"));
|
||||
println_Msg(F(""));
|
||||
println_Msg(F("Unknown Flash"));
|
||||
print_Msg(F("Flash ID: "));
|
||||
println_Msg(flashid);
|
||||
print_Error(F("Unknown Flash ID"), true);
|
||||
println_Msg(F(""));
|
||||
print_Error(F("Check voltage"), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
886
Cart_Reader/GBM.ino
Normal file
886
Cart_Reader/GBM.ino
Normal file
@ -0,0 +1,886 @@
|
||||
/******************************************
|
||||
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
|
||||
//******************************************
|
@ -54,8 +54,13 @@ GBSmartGameInfo gbSmartGames[GB_SMART_GAMES_PER_PAGE];
|
||||
byte signature[48];
|
||||
uint16_t gameMenuStartBank;
|
||||
|
||||
#ifdef enable_NP
|
||||
extern boolean hasMenu;
|
||||
extern byte numGames;
|
||||
#else
|
||||
boolean hasMenu;
|
||||
byte numGames;
|
||||
#endif
|
||||
|
||||
byte readByte_GBS(word myAddress) {
|
||||
PORTF = myAddress & 0xFF;
|
||||
@ -776,4 +781,4 @@ uint8_t gbSmartGetResizeParam(uint8_t rom_size, uint8_t sram_size)
|
||||
return (sram_size | rom_size);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -97,7 +97,7 @@ void mdLoadConf() {
|
||||
char line[64];
|
||||
int n;
|
||||
int i;
|
||||
while ((n = myFile.fgets(line, sizeof(line)-1)) > 0) {
|
||||
while ((n = myFile.fgets(line, sizeof(line) - 1)) > 0) {
|
||||
// preprocess
|
||||
for (i = 0; i < n; i++) {
|
||||
if (line[i] == ';') {
|
||||
@ -1191,7 +1191,7 @@ unsigned long verifySram_MD() {
|
||||
for (unsigned long currBuffer = sramBase; currBuffer < sramBase + sramSize; currBuffer += 256) {
|
||||
for (int currWord = 0; currWord < 256; currWord++) {
|
||||
word myWord = readWord_MD(currBuffer + currWord);
|
||||
|
||||
|
||||
if (saveType == 2) {
|
||||
// Only use the upper byte
|
||||
sdBuffer[currWord * 2] = (( myWord >> 8 ) & 0xFF);
|
||||
|
@ -1,15 +1,10 @@
|
||||
//******************************************
|
||||
// NINTENDO POWER MODULE
|
||||
// NINTENDO POWER SF MEMORY MODULE
|
||||
//******************************************
|
||||
// (GB Memory starts at around line 1740)
|
||||
|
||||
#include "options.h"
|
||||
#ifdef enable_NP
|
||||
|
||||
/******************************************
|
||||
SF Memory Cassette
|
||||
******************************************/
|
||||
|
||||
/******************************************
|
||||
SF Memory Clock Source
|
||||
******************************************/
|
||||
@ -1742,884 +1737,6 @@ void write_SFM(int startBank, uint32_t pos) {
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************
|
||||
GB Memory Cassette
|
||||
******************************************/
|
||||
|
||||
/******************************************
|
||||
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
|
||||
|
||||
//******************************************
|
||||
|
@ -585,7 +585,7 @@ void read_tennokoe_bank_PCE(int bank_index)
|
||||
println_Msg(F("RAM bank size: 2KB"));
|
||||
|
||||
// Get name, add extension and convert to char array for sd lib
|
||||
sprintf(fileName, "BANKRAM%d.sav", bank_index+1);
|
||||
sprintf(fileName, "BANKRAM%d.sav", bank_index + 1);
|
||||
|
||||
// create a new folder for the save file
|
||||
EEPROM_readAnything(0, foldern);
|
||||
@ -603,7 +603,7 @@ void read_tennokoe_bank_PCE(int bank_index)
|
||||
// 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);
|
||||
@ -620,7 +620,7 @@ void read_tennokoe_bank_PCE(int bank_index)
|
||||
data_input_PCE();
|
||||
|
||||
//Read Tennokoe bank RAM
|
||||
read_bank_PCE_RAM(0x080000 + 2048UL*bank_index, block_index);
|
||||
read_bank_PCE_RAM(0x080000 + 2048UL * bank_index, block_index);
|
||||
|
||||
//Lock Tennokoe Bank RAM
|
||||
data_output_PCE();
|
||||
@ -726,7 +726,7 @@ void write_tennokoe_bank_PCE(int bank_index)
|
||||
unlock_tennokoe_bank_RAM();
|
||||
data_input_PCE();
|
||||
//Read Tennokoe bank RAM
|
||||
read_bank_PCE_RAM(0x080000 + 2048UL*bank_index, block_index);
|
||||
read_bank_PCE_RAM(0x080000 + 2048UL * bank_index, block_index);
|
||||
//Lock Tennokoe Bank RAM
|
||||
data_output_PCE();
|
||||
lock_tennokoe_bank_RAM();
|
||||
@ -750,7 +750,7 @@ void write_tennokoe_bank_PCE(int bank_index)
|
||||
println_Msg(F(" bytes "));
|
||||
print_Error(F("did not verify."), false);
|
||||
}
|
||||
|
||||
|
||||
pin_init_PCE();
|
||||
|
||||
// Close the file:
|
||||
@ -862,8 +862,8 @@ void pceMenu() {
|
||||
|
||||
if (pce_internal_mode == HUCARD || pce_internal_mode == HUCARD_NOSWAP)
|
||||
{
|
||||
sprintf(pceCartMenuItem2, "Read RAM Bank %d", tennokoe_bank_index+1);
|
||||
sprintf(pceCartMenuItem3, "Write RAM Bank %d", tennokoe_bank_index+1);
|
||||
sprintf(pceCartMenuItem2, "Read RAM Bank %d", tennokoe_bank_index + 1);
|
||||
sprintf(pceCartMenuItem3, "Write RAM Bank %d", tennokoe_bank_index + 1);
|
||||
strcpy(menuOptionspceCart[0], pceCartMenuItem1);
|
||||
strcpy(menuOptionspceCart[1], pceCartMenuItem2);
|
||||
strcpy(menuOptionspceCart[2], pceCartMenuItem3);
|
||||
|
@ -60,5 +60,6 @@ Needed libraries(already included in the portable Arduino IDE under Releases)
|
||||
SD lib: https://github.com/greiman/SdFat
|
||||
LCD lib: https://github.com/adafruit/Adafruit_SSD1306
|
||||
GFX Lib: https://github.com/adafruit/Adafruit-GFX-Library
|
||||
BusIO: https://github.com/adafruit/Adafruit_BusIO
|
||||
RGB Tools lib: https://github.com/joushx/Arduino-RGB-Tools
|
||||
SI5351 lib: https://github.com/etherkit/Si5351Arduino
|
||||
|
@ -16,20 +16,15 @@
|
||||
#define enable_Button2
|
||||
|
||||
// define enable_XXX to enable
|
||||
#define enable_FLASH
|
||||
#define enable_GBX
|
||||
#define enable_MD
|
||||
#define enable_SMS
|
||||
|
||||
#define enable_PCE
|
||||
|
||||
#define enable_N64
|
||||
#define enable_NES
|
||||
#define enable_NGP
|
||||
#define enable_NP
|
||||
#define enable_PCE
|
||||
#define enable_SMS
|
||||
#define enable_SNES
|
||||
#define enable_SV
|
||||
#define enable_NP
|
||||
#define enable_GBX
|
||||
#define enable_N64
|
||||
|
||||
#define enable_WS
|
||||
|
||||
#define enable_NGP
|
||||
|
||||
#define enable_FLASH
|
||||
|
Loading…
Reference in New Issue
Block a user