From 0d06c7bb2dae7cd9bdf8c1a3d6660e4e3f7f8b16 Mon Sep 17 00:00:00 2001 From: sanni Date: Mon, 13 Nov 2017 22:36:15 +0100 Subject: [PATCH] Add standalone Nintendo Power SF Memory writer sketch Uses the Arduino Serial Monitor and does not need the Adafruit Clock Generator. --- extras/npwriter/npwriter.ino | 1929 ++++++++++++++++++++++++++++++++++ 1 file changed, 1929 insertions(+) create mode 100644 extras/npwriter/npwriter.ino diff --git a/extras/npwriter/npwriter.ino b/extras/npwriter/npwriter.ino new file mode 100644 index 0000000..e383d71 --- /dev/null +++ b/extras/npwriter/npwriter.ino @@ -0,0 +1,1929 @@ +/********************************************************************************** + Nintendo Power Writer for Arduino Mega2560 + + Author: sanni + Date: 2017-11-13 + Version: V10 + + SD lib: https://github.com/greiman/SdFat + + Many thanks to MichlK, skaman and nocash + Please visit: http://forum.arduino.cc/index.php?topic=158974.0 + And also: http://forums.nesdev.com/viewtopic.php?f=12&t=11453 + *********************************************************************************/ + +/****************************************** + Libraries + *****************************************/ +// SD Card (Pin 50 = MISO, Pin 51 = MOSI, Pin 52 = SCK, Pin 53 = SS) +#include +#include +#define chipSelectPin 53 +SdFat sd; +SdBaseFile myFile; + +/****************************************** + Pinout + *****************************************/ +// Address Pins +#define a0Pin A0 +#define a1Pin A1 +#define a2Pin A2 +#define a3Pin A3 +#define a4Pin A4 +#define a5Pin A5 +#define a6Pin A6 +#define a7Pin A7 +#define a8Pin A8 +#define a9Pin A9 +#define a10Pin A10 +#define a11Pin A11 +#define a12Pin A12 +#define a13Pin A13 +#define a14Pin A14 +#define a15Pin A15 +#define ba0Pin 49 //a16 +#define ba1Pin 48 //a17 +#define ba2Pin 47 //a18 +#define ba3Pin 46 //a19 +#define ba4Pin 45 //a20 +#define ba5Pin 44 //a21 +#define ba6Pin 43 //a22 +#define ba7Pin 42 //a23 + +// Control Pins +#define csPin 6 +#define irqPin 7 +#define wrPin 8 +#define rdPin 9 + +// Data Pins +#define d0Pin 37 +#define d1Pin 36 +#define d2Pin 35 +#define d3Pin 34 +#define d4Pin 33 +#define d5Pin 32 +#define d6Pin 31 +#define d7Pin 30 + +// Clock & Reset Pin +#define rstPin 17 +#define clkPin 5 + +/****************************************** + Variables + *****************************************/ +// Buffer for the SD +byte SDBuffer[512]; +byte SDBuffer2[512]; + +// Filename of SD file +char fileName[13]; + +// Nintendo Power status +byte NPReady = 0; + +// Flashrom ID and size +char flashid[5]; +unsigned long flashSize = 4194304; +byte numBanks = 128; +boolean romType = 0; +byte sramSize = 64; + +// Variable to count errors +unsigned long writeErrors; + +// For incoming serial data +int incomingByte; + +/****************************************** + Setup + *****************************************/ +void setup() { + // Clock Pin to Output + DDRE |= (1 << 3); + // Clock Pin to Low + PORTE &= ~(1 << 3); + + // Set Address Pins to Output + //A0-A7 + DDRF = 0xFF; + //A8-A15 + DDRK = 0xFF; + //BA0-BA7 + DDRL = 0xFF; + + // Set Control Pins to Output RST(PH0) CS(PH3) WR(PH5) RD(PH6) + DDRH |= (1 << 0) | (1 << 3) | (1 << 5) | (1 << 6); + // Output a high signal on all pins, pins are active low therefore everything is disabled now + PORTH |= (1 << 0) | (1 << 3) | (1 << 5) | (1 << 6); + + // Set IRQ(PH4) to Input + DDRH &= ~(1 << 4); + // Activate Internal Pullup Resistors + PORTH |= (1 << 4); + + // Set Data Pins (D0-D7) to Input + DDRC = 0x00; + // Enable Internal Pullups + //PORTC = 0xFF; + + // Serial Begin + Serial.begin(9600); + Serial.println("--------------------------------------------------------->"); + Serial.println("Nintendo Power Writer V10 2017 sanni"); + Serial.println("--------------------------------------------------------->"); + + // Init SD card + if (!sd.begin(chipSelectPin, SPI_FULL_SPEED)) { + Serial.println("SD Error."); + while (1); + } + + // Print SD Info + Serial.print("SD Card: "); + Serial.print(sd.card()->cardSize() * 512E-9); + Serial.print("GB FAT"); + Serial.println(int(sd.vol()->fatType())); + Serial.println(""); + Serial.println("FILES---------------------------------------------------->"); + // Print all files in root of SD + Serial.println("Name - Size"); + sd.vwd()->rewind(); + while (myFile.openNext(sd.vwd(), O_READ)) { + if (myFile.isHidden()) { + } + else { + if (myFile.isDir()) { + // Indicate a directory. + Serial.write('/'); + } + myFile.printName(&Serial); + Serial.write(' '); + myFile.printFileSize(&Serial); + Serial.println(); + } + myFile.close(); + } + Serial.println(""); +} + +/****************************************** + Helper functions + *****************************************/ +// Prompt a filename from the Serial Monitor +void getfilename() { + Serial.println(""); + Serial.println("-------> Please enter a filename in 8.3 format: _ <-------"); + Serial.println(""); + while (Serial.available() == 0) { + } + String strBuffer; + strBuffer = Serial.readString(); + strBuffer.toCharArray(fileName, 13); +} + +// Send a clock pulse +void pulseClock(int times) { + for (int i = 0; i < times * 2; i++) { + // Switch the clock pin to 0 if it's 1 and 0 if it's 1 + PORTE ^= (1 << 3); + // Wait 62.5ns + __asm__("nop\n\t"); + } +} + +/****************************************** + I/O Functions + *****************************************/ +// Switch control pins to write +void controlOut() { + // Switch RD(PH6) and WR(PH5) to HIGH + PORTH |= (1 << 6) | (1 << 5); + // Switch CS(PH3) to LOW + PORTH &= ~(1 << 3); +} + +// Switch control pins to read +void controlIn() { + // Switch WR(PH5) to HIGH + PORTH |= (1 << 5); + // Switch CS(PH3) and RD(PH6) to LOW + PORTH &= ~((1 << 3) | (1 << 6)); +} + +// Switch data pins to write +void dataOut() { + DDRC = 0xFF; +} + +// Switch data pins to read +void dataIn() { + DDRC = 0x00; + // Pullups + //PORTC = 0xFF; +} + +// Write one byte of data to a location specified by bank and address, 00:0000 +void writeBank(byte myBank, word myAddress, byte myData) { + PORTL = myBank; + PORTF = myAddress & 0xFF; + PORTK = (myAddress >> 8) & 0xFF; + PORTC = myData; + + // Arduino running at 16Mhz -> one nop = 62.5ns + // Wait till output is stable + __asm__("nop\n\t""nop\n\t""nop\n\t"); + + // Switch WE(PH5) to LOW + PORTH &= ~(1 << 5); + + // Leave WE low for at least 60ns + __asm__("nop\n\t""nop\n\t""nop\n\t"); + + // Switch WR(PH5) to HIGH + PORTH |= (1 << 5); + + // Leave WE high for at least 50ns + __asm__("nop\n\t""nop\n\t""nop\n\t"); +} + +// Write a byte to the data pins and pulse the clock pin, used when sending to the MX15001 chip +void writeBankClock(byte myBank, word myAddress, byte myData) { + if ( (myAddress & 1) == 1 ) digitalWrite(a0Pin, 1); else digitalWrite(a0Pin, 0); + if ( (myAddress & 2) == 2 ) digitalWrite(a1Pin, 1); else digitalWrite(a1Pin, 0); + if ( (myAddress & 4) == 4 ) digitalWrite(a2Pin, 1); else digitalWrite(a2Pin, 0); + if ( (myAddress & 8) == 8 ) digitalWrite(a3Pin, 1); else digitalWrite(a3Pin, 0); + if ( (myAddress & 16) == 16 ) digitalWrite(a4Pin, 1); else digitalWrite(a4Pin, 0); + if ( (myAddress & 32) == 32 ) digitalWrite(a5Pin, 1); else digitalWrite(a5Pin, 0); + if ( (myAddress & 64) == 64 ) digitalWrite(a6Pin, 1); else digitalWrite(a6Pin, 0); + if ( (myAddress & 128) == 128 ) digitalWrite(a7Pin, 1); else digitalWrite(a7Pin, 0); + if ( (myAddress & 256) == 256 ) digitalWrite(a8Pin, 1); else digitalWrite(a8Pin, 0); + if ( (myAddress & 512) == 512 ) digitalWrite(a9Pin, 1); else digitalWrite(a9Pin, 0); + if ( (myAddress & 1024) == 1024 ) digitalWrite(a10Pin, 1); else digitalWrite(a10Pin, 0); + if ( (myAddress & 2048) == 2048 ) digitalWrite(a11Pin, 1); else digitalWrite(a11Pin, 0); + if ( (myAddress & 4096) == 4096 ) digitalWrite(a12Pin, 1); else digitalWrite(a12Pin, 0); + if ( (myAddress & 8192) == 8192 ) digitalWrite(a13Pin, 1); else digitalWrite(a13Pin, 0); + if ( (myAddress & 16384) == 16384 ) digitalWrite(a14Pin, 1); else digitalWrite(a14Pin, 0); + if ( (myAddress & 32768) == 32768 ) digitalWrite(a15Pin, 1); else digitalWrite(a15Pin, 0); + + if ( (myBank & 1) == 1 ) digitalWrite(ba0Pin, 1); else digitalWrite(ba0Pin, 0); + if ( (myBank & 2) == 2 ) digitalWrite(ba1Pin, 1); else digitalWrite(ba1Pin, 0); + if ( (myBank & 4) == 4 ) digitalWrite(ba2Pin, 1); else digitalWrite(ba2Pin, 0); + if ( (myBank & 8) == 8 ) digitalWrite(ba3Pin, 1); else digitalWrite(ba3Pin, 0); + if ( (myBank & 16) == 16 ) digitalWrite(ba4Pin, 1); else digitalWrite(ba4Pin, 0); + if ( (myBank & 32) == 32 ) digitalWrite(ba5Pin, 1); else digitalWrite(ba5Pin, 0); + if ( (myBank & 64) == 64 ) digitalWrite(ba6Pin, 1); else digitalWrite(ba6Pin, 0); + if ( (myBank & 128) == 128 ) digitalWrite(ba7Pin, 1); else digitalWrite(ba7Pin, 0); + + if ( (myData & 1) == 1 ) digitalWrite(d0Pin, 1); else digitalWrite(d0Pin, 0); + if ( (myData & 2) == 2 ) digitalWrite(d1Pin, 1); else digitalWrite(d1Pin, 0); + if ( (myData & 4) == 4 ) digitalWrite(d2Pin, 1); else digitalWrite(d2Pin, 0); + if ( (myData & 8) == 8 ) digitalWrite(d3Pin, 1); else digitalWrite(d3Pin, 0); + if ( (myData & 16) == 16 ) digitalWrite(d4Pin, 1); else digitalWrite(d4Pin, 0); + if ( (myData & 32) == 32 ) digitalWrite(d5Pin, 1); else digitalWrite(d5Pin, 0); + if ( (myData & 64) == 64 ) digitalWrite(d6Pin, 1); else digitalWrite(d6Pin, 0); + if ( (myData & 128) == 128 ) digitalWrite(d7Pin, 1); else digitalWrite(d7Pin, 0); + + // Pull WE low + digitalWrite(wrPin, LOW); + + // Pulse clock pin 4 times + pulseClock(8); + + // Pull WE high + digitalWrite(wrPin, HIGH); + + // Pulse clock pin 4 times + pulseClock(8); +} + +// Read one byte of data from a location specified by bank and address, 00:0000 +byte readBank(byte myBank, word myAddress) { + PORTL = myBank; + PORTF = myAddress & 0xFF; + PORTK = (myAddress >> 8) & 0xFF; + + // Arduino running at 16Mhz -> one nop = 62.5ns + __asm__("nop\n\t""nop\n\t""nop\n\t"); + + // Read + byte tempByte = PINC; + return tempByte; +} + +// Read a byte from the digital pins and pulse the clock, used when sending to the MX15001 chip +byte readBankClock(byte myBank, word myAddress) { + if ( (myAddress & 1) == 1 ) digitalWrite(a0Pin, 1); else digitalWrite(a0Pin, 0); + if ( (myAddress & 2) == 2 ) digitalWrite(a1Pin, 1); else digitalWrite(a1Pin, 0); + if ( (myAddress & 4) == 4 ) digitalWrite(a2Pin, 1); else digitalWrite(a2Pin, 0); + if ( (myAddress & 8) == 8 ) digitalWrite(a3Pin, 1); else digitalWrite(a3Pin, 0); + if ( (myAddress & 16) == 16 ) digitalWrite(a4Pin, 1); else digitalWrite(a4Pin, 0); + if ( (myAddress & 32) == 32 ) digitalWrite(a5Pin, 1); else digitalWrite(a5Pin, 0); + if ( (myAddress & 64) == 64 ) digitalWrite(a6Pin, 1); else digitalWrite(a6Pin, 0); + if ( (myAddress & 128) == 128 ) digitalWrite(a7Pin, 1); else digitalWrite(a7Pin, 0); + if ( (myAddress & 256) == 256 ) digitalWrite(a8Pin, 1); else digitalWrite(a8Pin, 0); + if ( (myAddress & 512) == 512 ) digitalWrite(a9Pin, 1); else digitalWrite(a9Pin, 0); + if ( (myAddress & 1024) == 1024 ) digitalWrite(a10Pin, 1); else digitalWrite(a10Pin, 0); + if ( (myAddress & 2048) == 2048 ) digitalWrite(a11Pin, 1); else digitalWrite(a11Pin, 0); + if ( (myAddress & 4096) == 4096 ) digitalWrite(a12Pin, 1); else digitalWrite(a12Pin, 0); + if ( (myAddress & 8192) == 8192 ) digitalWrite(a13Pin, 1); else digitalWrite(a13Pin, 0); + if ( (myAddress & 16384) == 16384 ) digitalWrite(a14Pin, 1); else digitalWrite(a14Pin, 0); + if ( (myAddress & 32768) == 32768 ) digitalWrite(a15Pin, 1); else digitalWrite(a15Pin, 0); + + if ( (myBank & 1) == 1 ) digitalWrite(ba0Pin, 1); else digitalWrite(ba0Pin, 0); + if ( (myBank & 2) == 2 ) digitalWrite(ba1Pin, 1); else digitalWrite(ba1Pin, 0); + if ( (myBank & 4) == 4 ) digitalWrite(ba2Pin, 1); else digitalWrite(ba2Pin, 0); + if ( (myBank & 8) == 8 ) digitalWrite(ba3Pin, 1); else digitalWrite(ba3Pin, 0); + if ( (myBank & 16) == 16 ) digitalWrite(ba4Pin, 1); else digitalWrite(ba4Pin, 0); + if ( (myBank & 32) == 32 ) digitalWrite(ba5Pin, 1); else digitalWrite(ba5Pin, 0); + if ( (myBank & 64) == 64 ) digitalWrite(ba6Pin, 1); else digitalWrite(ba6Pin, 0); + if ( (myBank & 128) == 128 ) digitalWrite(ba7Pin, 1); else digitalWrite(ba7Pin, 0); + + // Pulse clock 4 times + pulseClock(8); + + // Read + byte tempByte = 0; + if (digitalRead(d0Pin)) tempByte = tempByte + 1; + if (digitalRead(d1Pin)) tempByte = tempByte + 2; + if (digitalRead(d2Pin)) tempByte = tempByte + 4; + if (digitalRead(d3Pin)) tempByte = tempByte + 8; + if (digitalRead(d4Pin)) tempByte = tempByte + 16; + if (digitalRead(d5Pin)) tempByte = tempByte + 32; + if (digitalRead(d6Pin)) tempByte = tempByte + 64; + if (digitalRead(d7Pin)) tempByte = tempByte + 128; + + return tempByte; +} + +/****************************************** + 29F1601 flashrom functions + *****************************************/ +// Reset the MX29F1601 flashrom, startbank is 0xC0 for first and 0xE0 for second flashrom +void resetFlash(int startBank) { + // Configure control pins + controlOut(); + // Set data pins to output + dataOut(); + + // Reset command sequence + if (romType) { + writeBank(startBank, 0x5555 * 2, 0xaa); + writeBank(startBank, 0x2AAA * 2, 0x55); + writeBank(startBank, 0x5555 * 2, 0xf0); + } + else { + writeBank(1, 0x8000 + 0x1555 * 2, 0xaa); + writeBank(0, 0x8000 + 0x2AAA * 2, 0x55); + writeBank(1, 0x8000 + 0x1555 * 2, 0xf0); + } + + // Set data pins to input + dataIn(); + // Set control pins to input and therefore pull CE low and latch status register content + controlIn(); +} + +// Print flashrom manufacturer and device ID +void idFlash(int startBank) { + // Configure control pins + controlOut(); + // Set data pins to output + dataOut(); + + if (romType) { + // ID command sequence + writeBank(startBank, 0x5555 * 2, 0xaa); + writeBank(startBank, 0x2AAA * 2, 0x55); + writeBank(startBank, 0x5555 * 2, 0x90); + + // Set data pins to input again + dataIn(); + // Set control pins to input + controlIn(); + + // Read the two id bytes into a string + sprintf(flashid, "%x%x", readBank(startBank, 0x00), readBank(startBank, 0x02)); + } + else { + writeBank(1, 0x8000 + 0x1555 * 2, 0xaa); + writeBank(0, 0x8000 + 0x2AAA * 2, 0x55); + writeBank(1, 0x8000 + 0x1555 * 2, 0x90); + + // Set data pins to input again + dataIn(); + // Set control pins to input + controlIn(); + + // Read the two id bytes into a string + sprintf(flashid, "%x%x", readBank(0, 0x8000), readBank(0, 0x8000 + 0x02)); + } + + // Set data pins to input + dataIn(); + // Set control pins to input and therefore pull CE low and latch status register content + controlIn(); +} + +// Write the flashroms by reading a file from the SD card, pos defines where in the file the reading/writing should start +void writeFlash(int startBank, uint32_t pos) { + Serial.print("Writing "); + Serial.print(flashSize); + Serial.print(" Bytes into "); + Serial.print(numBanks); + Serial.print(" Banks "); + if (romType) + Serial.println("(HiROM)."); + else + Serial.println("(LoRom)."); + + // Open file on sd card + if (myFile.open(fileName, O_READ)) { + + // Seek to a new position in the file + if (pos != 0) + myFile.seekCur(pos); + + // Configure control pins + controlOut(); + // Set data pins to output + dataOut(); + + if (romType) { + // Write hirom + for (int currBank = startBank; currBank < startBank + numBanks; currBank++) { + // Print Status + Serial.print("."); + + // Fill SDBuffer with 4 pages + for (unsigned long currBuffer = 0; currBuffer < 0x10000; currBuffer += 512) { + myFile.read(SDBuffer, 512); + + // Write the four pages out of the buffer to the rom chip one page at a time + for (unsigned long currPage = 0; currPage < 512; currPage += 128) { + // Write command sequence + writeBank(startBank, 0x5555 * 2, 0xaa); + writeBank(startBank, 0x2AAA * 2, 0x55); + writeBank(startBank, 0x5555 * 2, 0xa0); + + for (byte currByte = 0; currByte < 128; currByte++) { + // Write one byte of data + writeBank(currBank, currBuffer + currPage + currByte, SDBuffer[currPage + currByte]); + + if (currByte == 127) { + // Write the last byte twice or else it won't write at all + writeBank(currBank, currBuffer + currPage + currByte, SDBuffer[currPage + currByte]); + } + } + // Wait until write is finished + busyCheck(startBank); + } + } + } + } + else { + // Write lorom + for (int currBank = 0; currBank < numBanks; currBank++) { + + // Print Status + Serial.print("."); + + for (unsigned long currByte = 0x8000; currByte < 0x10000; currByte += 128) { + myFile.read(SDBuffer, 128); + // Write command sequence + writeBank(1, 0x8000 + 0x1555 * 2, 0xaa); + writeBank(0, 0x8000 + 0x2AAA * 2, 0x55); + writeBank(1, 0x8000 + 0x1555 * 2, 0xa0); + + for (byte c = 0; c < 128; c++) { + // Write one byte of data + writeBank(currBank, currByte + c, SDBuffer[c]); + + if (c == 127) { + // Write the last byte twice or else it won't write at all + writeBank(currBank, currByte + c, SDBuffer[c]); + } + } + // Wait until write is finished + busyCheck(startBank); + } + } + } + // Close the file: + myFile.close(); + Serial.println(""); + } + else { + Serial.println("Can't open file on SD."); + } +} + +// Write 4MB to both flashroms in parallel +void writeNP() { + unsigned long bankSize = 0x10000; + int bufferSize = 512; + unsigned long currOffset = 2097152; + numBanks = 32; + + // Open file on sd card + if (myFile.open(fileName, O_READ)) { + + // Configure control pins + controlOut(); + // Set data pins to output + dataOut(); + + // Write 32 hirom banks at 65536B each per chip, so 4MB total + for (int currBank = 0; currBank < numBanks; currBank++) { + Serial.print("."); + + // Fill 2 SDBuffers with 4(if bufferSize=512) pages each, one page has 128B + for (unsigned long currBuffer = 0; currBuffer < bankSize; currBuffer += bufferSize) { + + // Seek to current position in the file + myFile.seekSet((currBank * bankSize) + currBuffer); + myFile.read(SDBuffer, bufferSize); + + myFile.seekSet((currBank * bankSize) + currOffset + currBuffer); + myFile.read(SDBuffer2, bufferSize); + + // Write 2x 128B at once out of the two SDBuffers to the flashroms until all the buffer's content was written + for (unsigned long currPage = 0; currPage < bufferSize; currPage += 128) { + + // Write command sequence to 1st flashrom + writeBank(0xC0, 0x5555 * 2, 0xaa); + writeBank(0xC0, 0x2AAA * 2, 0x55); + writeBank(0xC0, 0x5555 * 2, 0xa0); + + for (byte currByte = 0; currByte < 128; currByte++) { + + // Write one byte of data + writeBank(0xC0 + currBank, currBuffer + currPage + currByte, SDBuffer[currPage + currByte]); + + if (currByte == 127) { + // Write the last byte twice or else it won't write at all + writeBank(0xC0 + currBank, currBuffer + currPage + currByte, SDBuffer[currPage + currByte]); + } + } + + // Write command sequence to 2nd flashrom + writeBank(0xE0, 0x5555 * 2, 0xaa); + writeBank(0xE0, 0x2AAA * 2, 0x55); + writeBank(0xE0, 0x5555 * 2, 0xa0); + + for (byte currByte = 0; currByte < 128; currByte++) { + + // Write one byte of data + writeBank(0xE0 + currBank, currBuffer + currPage + currByte, SDBuffer2[currPage + currByte]); + + if (currByte == 127) { + // Write the last byte twice or else it won't write at all + writeBank(0xE0 + currBank, currBuffer + currPage + currByte, SDBuffer2[currPage + currByte]); + } + } + // Wait until writes are finished + busyCheck(0xC0); + busyCheck(0xE0); + } + } + } + // Close the file: + myFile.close(); + } + else { + Serial.println("Can't open file on SD."); + } +} + +// Delay between write operations based on status register +void busyCheck(byte startBank) { + // Set data pins to input + dataIn(); + // Set control pins to input and therefore pull CE low and latch status register content + controlIn(); + + // Read register + readBank(startBank, 0x0000); + + // Read D7 while D7 = 0 + //1 = B00000001, 1 << 7 = B10000000, PINC = B1XXXXXXX (X = don't care), & = bitwise and + while (!(PINC & (1 << 7))) { + // CE or OE must be toggled with each subsequent status read or the + // completion of a program or erase operation will not be evident. + // Switch RD(PH6) to HIGH + PORTH |= (1 << 6); + + // one nop ~62.5ns + __asm__("nop\n\t"); + + // Switch RD(PH6) to LOW + PORTH &= ~(1 << 6); + + // one nop ~62.5ns + __asm__("nop\n\t"); + } + + // Configure control pins + controlOut(); + // Set data pins to output + dataOut(); +} + +// Erase the flashrom to 0xFF +void eraseFlash(int startBank) { + // Configure control pins + controlOut(); + // Set data pins to output + dataOut(); + + if (romType) { + // Erase command sequence + writeBank(startBank, 0x5555 * 2, 0xaa); + writeBank(startBank, 0x2AAA * 2, 0x55); + writeBank(startBank, 0x5555 * 2, 0x80); + writeBank(startBank, 0x5555 * 2, 0xaa); + writeBank(startBank, 0x2AAA * 2, 0x55); + writeBank(startBank, 0x5555 * 2, 0x10); + } + else { + writeBank(1, 0x8000 + 0x1555 * 2, 0xaa); + writeBank(0, 0x8000 + 0x2AAA * 2, 0x55); + writeBank(1, 0x8000 + 0x1555 * 2, 0x80); + writeBank(1, 0x8000 + 0x1555 * 2, 0xaa); + writeBank(0, 0x8000 + 0x2AAA * 2, 0x55); + writeBank(1, 0x8000 + 0x1555 * 2, 0x10); + } + + // Wait for erase to complete + busyCheck(startBank); +} + +// Check if an erase succeeded, return 1 if blank and 0 if not +byte blankcheck(int startBank) { + // Set data pins to input again + dataIn(); + // Set control pins to input + controlIn(); + + byte blank = 1; + if (romType) { + for (int currBank = startBank; currBank < startBank + numBanks; currBank++) { + for (unsigned long currByte = 0; currByte < 0x10000; currByte++) { + if (readBank(currBank, currByte) != 0xFF) { + currBank = startBank + numBanks; + blank = 0; + } + } + } + } + else { + for (int currBank = 0; currBank < numBanks; currBank++) { + for (unsigned long currByte = 0x8000; currByte < 0x10000; currByte++) { + if (readBank(currBank, currByte) != 0xFF) { + currBank = numBanks; + blank = 0; + } + } + } + } + return blank; +} + +// Check if a write succeeded, returns 0 if all is ok and number of errors if not +unsigned long verifyFlash(int startBank, uint32_t pos) { + unsigned long verified = 0; + + // Open file on sd card + if (myFile.open(fileName, O_READ)) { + // Set file starting position + myFile.seekCur(pos); + + // Set data pins to input + dataIn(); + // Set control pins to input + controlIn(); + + if (romType) { + for (int currBank = startBank; currBank < startBank + numBanks; currBank++) { + for (unsigned long currByte = 0; currByte < 0x10000; currByte += 512) { + // Fill SDBuffer + myFile.read(SDBuffer, 512); + for (int c = 0; c < 512; c++) { + if (readBank(currBank, currByte + c) != SDBuffer[c]) { + verified++; + } + } + } + } + } + else { + for (int currBank = 0; currBank < numBanks; currBank++) { + for (unsigned long currByte = 0x8000; currByte < 0x10000; currByte += 512) { + // Fill SDBuffer + myFile.read(SDBuffer, 512); + for (int c = 0; c < 512; c++) { + if (readBank(currBank, currByte + c) != SDBuffer[c]) { + verified++; + } + } + } + } + } + // Close the file: + myFile.close(); + } + else { + // SD Error + verified = 999999; + Serial.println("Can't open file on SD."); + } + // Return 0 if verified ok, or number of errors + return verified; +} + +// Read flashroms and save them to the SD card +void readFlash() { + // Set data pins to input + dataIn(); + // Set control pins to input + controlIn(); + + Serial.print("Reading flash into file "); + Serial.println(fileName); + + // Open file on sd card + if (!myFile.open(fileName, O_RDWR | O_CREAT)) { + Serial.println("Can't create file on SD."); + while (1); + } + if (romType) { + for (int currBank = 0xC0; currBank < 0xC0 + numBanks; currBank++) { + + // Print Status + Serial.print("."); + + for (unsigned long currByte = 0; currByte < 0x10000; currByte += 512) { + for (int c = 0; c < 512; c++) { + SDBuffer[c] = readBank(currBank, currByte + c); + } + myFile.write(SDBuffer, 512); + } + } + } + else { + for (int currBank = 0; currBank < numBanks; currBank++) { + + // Print Status + Serial.print("."); + + for (unsigned long currByte = 0x8000; currByte < 0x10000; currByte += 512) { + for (int c = 0; c < 512; c++) { + SDBuffer[c] = readBank(currBank, currByte + c); + } + myFile.write(SDBuffer, 512); + } + } + } + // Close the file: + myFile.close(); + Serial.println(""); +} + +// Print part of the flash to the serial monitor +void printFlash(boolean hirom, unsigned long startByte, unsigned long startBank, int numBytes) { + + // Set data pins to input + dataIn(); + // Set control pins to input + controlIn(); + + char buffer[3]; + if (hirom) { + for (unsigned long currByte = 0; currByte < numBytes; currByte += 16) { + for (int c = 0; c < 16; c++) { + itoa (readBank(startBank, currByte + c), buffer, 16); + for (int i = 0; i < 2 - strlen(buffer); i++) { + Serial.print('0'); + } + // Now print the significant bits + Serial.print(buffer); + Serial.print(" "); + } + Serial.println(""); + } + } + else { + for (unsigned long currByte = 0x8000; currByte < 0x8000 + numBytes; currByte += 16) { + for (int c = 0; c < 16; c++) { + itoa (readBank(startBank, currByte + c), buffer, 16); + for (int i = 0; i < 2 - strlen(buffer); i++) { + Serial.print('0'); + } + // Now print the significant bits + Serial.print(buffer); + Serial.print(" "); + } + Serial.println(""); + } + } +} + +// Print multiple 64 bytes sections out of different parts of the flashroms +void printFlashAll() { + // Romtype, startByte, numBytes + Serial.println("0x00/0xC0"); + printFlash(romType, 0, 0xC0, 64); + Serial.println("0x80000/0xC8"); + printFlash(romType, 0x80000, 0xC8, 64); + Serial.println("0x100000/0xD0"); + printFlash(romType, 0x100000, 0xD0, 64); + Serial.println("0x180000/0xD8"); + printFlash(romType, 0x180000, 0xD8, 64); + Serial.println("0x200000/0xE0"); + printFlash(romType, 0x200000, 0xE0, 64); + Serial.println("0x280000/0xE8"); + printFlash(romType, 0x280000, 0xE8, 64); + Serial.println("0x300000/0xF0"); + printFlash(romType, 0x300000, 0xF0, 64); + Serial.println("0x380000/0xF8"); + printFlash(romType, 0x380000, 0xF8, 64); +} + +// Display protected sectors/banks as 0xc2 and unprotected as 0x00 +byte readSectorProtection(byte startBank) { + byte isProtected = 0; + + // Configure control pins + controlOut(); + // Set data pins to output + dataOut(); + + // Display Sector Protection Status + if (romType) { + writeBank(startBank, 0x5555 * 2, 0xaa); + writeBank(startBank, 0x2AAA * 2, 0x55); + writeBank(startBank, 0x5555 * 2, 0x90); + + // Configure control pins + controlIn(); + // Set data pins to output + dataIn(); + + for (int i = 0; i <= 0x1F; i++) { + if (readBank(startBank + i, 0x04) == 0xC2) { + Serial.print("Sector 0x"); + Serial.print(startBank + i, HEX); + Serial.println(" is protected"); + isProtected = 1; + } + else if (readBank(startBank + i, 0x04) == 0x0) { + /*Serial.print("Sector 0x"); + Serial.print(startBank + i, HEX); + Serial.println(" is not protected");*/ + } + else { + /*Serial.print("Sector 0x"); + Serial.print(startBank + i, HEX); + Serial.println(" READ ERROR");*/ + isProtected = 2; + } + } + } + else { + writeBank(1, 0x8000 + 0x1555 * 2, 0xaa); + writeBank(0, 0x8000 + 0x2AAA * 2, 0x55); + writeBank(1, 0x8000 + 0x1555 * 2, 0x90); + + // Configure control pins + controlIn(); + // Set data pins to output + dataIn(); + + for (int i = 0; i <= 0x1F; i++) { + if (readBank(0, 0x8000 + 0x04) == 0xC2) { + Serial.print("Sector 0x"); + Serial.print(startBank + i, HEX); + Serial.println(" is protected"); + isProtected = 1; + } + else if (readBank(0, 0x8000 + 0x04) == 0x0) { + } + else { + isProtected = 2; + } + } + } + return isProtected; +} + +void unlockSectorProtection(byte startBank) { + // Configure control pins + controlOut(); + // Set data pins to output + dataOut(); + + // Remove Sector Protection + if (romType) { + writeBank(startBank, 0x5555 * 2, 0xaa); + writeBank(startBank, 0x2AAA * 2, 0x55); + writeBank(startBank, 0x5555 * 2, 0x60); + writeBank(startBank, 0x5555 * 2, 0xaa); + writeBank(startBank, 0x2AAA * 2, 0x55); + writeBank(startBank, 0x0000 * 2, 0x40); + } + else { + writeBank(1, 0x8000 + 0x1555 * 2, 0xaa); + writeBank(0, 0x8000 + 0x2AAA * 2, 0x55); + writeBank(1, 0x8000 + 0x1555 * 2, 0x60); + writeBank(1, 0x8000 + 0x1555 * 2, 0xaa); + writeBank(0, 0x8000 + 0x2AAA * 2, 0x55); + writeBank(0, 0x8000 + 0x0000 * 2, 0x40); + } + // Wait until write is finished + busyCheck(startBank); +} + +void setSectorProtection(byte startBank) { + // Configure control pins + controlOut(); + // Set data pins to output + dataOut(); + + // Set Sector Protection + if (romType) { + writeBank(startBank, 0x5555 * 2, 0xaa); + writeBank(startBank, 0x2AAA * 2, 0x55); + writeBank(startBank, 0x5555 * 2, 0x60); + writeBank(startBank, 0x5555 * 2, 0xaa); + writeBank(startBank, 0x2AAA * 2, 0x55); + writeBank(startBank, 0x0000 * 2, 0x20); + } + else { + writeBank(1, 0x8000 + 0x1555 * 2, 0xaa); + writeBank(0, 0x8000 + 0x2AAA * 2, 0x55); + writeBank(1, 0x8000 + 0x1555 * 2, 0x60); + writeBank(1, 0x8000 + 0x1555 * 2, 0xaa); + writeBank(0, 0x8000 + 0x2AAA * 2, 0x55); + writeBank(0, 0x8000 + 0x0000 * 2, 0x20); + } + // Wait until write is finished + busyCheck(startBank); +} + +/****************************************** + Nintendo Power + *****************************************/ +// Switch to HiRom All and unlock Write Protection +boolean unlockedHirom() { + romType = 1; + + if (sendNP(0x04) == 0x2A) { + // Unlock Write Protection + sendNP(0x02); + if (readBankClock(0, 0x2401) == 0x4) { + return 1; + } + else { + Serial.println("Error: Unlocking WP failed."); + Serial.println("Please power-cycle NP cart."); + readPorts(); + return 0; + } + } + else { + Serial.println("Error: Switching to HiRom All failed."); + Serial.println("Please power-cycle NP cart."); + readPorts(); + return 0; + } +} + +// Read the ports at 0x2400-0x2407 and print the results +void readPorts() { + // Set data pins to input + dataIn(); + // Set control pins to input + controlIn(); + + for (unsigned long myAddr = 0x2400; myAddr < 0x2408; myAddr++) { + Serial.print(readBankClock(0, myAddr), HEX); + Serial.print(" "); + } + Serial.println(" "); +} + +void eraseMapping(byte startBank) { + // Switch to write + dataOut(); + controlOut(); + + if (romType) { + // Prepare to erase/write Page Buffer + writeBank(startBank, 0x5555 * 2, 0xaa); + writeBank(startBank, 0x2AAA * 2, 0x55); + writeBank(startBank, 0x5555 * 2, 0x77); + // Erase Page Buffer + writeBank(startBank, 0x5555 * 2, 0xaa); + writeBank(startBank, 0x2AAA * 2, 0x55); + writeBank(startBank, 0x5555 * 2, 0xe0); + } + else { + // Prepare to erase/write Page Buffer + writeBank(1, 0x8000 + 0x1555 * 2, 0xaa); + writeBank(0, 0x8000 + 0x2AAA * 2, 0x55); + writeBank(1, 0x8000 + 0x1555 * 2, 0x77); + + // Erase Page Buffer + writeBank(1, 0x8000 + 0x1555 * 2, 0xaa); + writeBank(0, 0x8000 + 0x2AAA * 2, 0x55); + writeBank(1, 0x8000 + 0x1555 * 2, 0xe0); + } + + // Wait until erase is finished + busyCheck(startBank); + + // Switch to read + dataIn(); + controlIn(); +} + +// Read the current mapping from the hidden "page buffer" +void readMapping() { + + Serial.print("Reading mapping into file "); + Serial.println(fileName); + + // Switch to write + dataOut(); + controlOut(); + + // Reset to defaults + writeBank(0xC0, 0x0000, 0x38); + writeBank(0xC0, 0x0000, 0xd0); + // Read Extended Status Register (GSR and PSR) + writeBank(0xC0, 0x0000, 0x71); + // Page Buffer Swap + writeBank(0xC0, 0x0000, 0x72); + // Read Page Buffer + writeBank(0xC0, 0x0000, 0x75); + + // Switch to read + dataIn(); + controlIn(); + + //open file on sd card + if (!myFile.open(fileName, O_RDWR | O_CREAT)) { + Serial.println("SD Error"); + } + + // Read the mapping info out of the 1st chip + for (unsigned long currByte = 0xFF00; currByte <= 0xFFFF; currByte++) { + myFile.write(readBank(0xC0, currByte)); + } + + // Switch to write + dataOut(); + controlOut(); + + // Reset to defaults + writeBank(0xE0, 0x0000, 0x38); + writeBank(0xE0, 0x0000, 0xd0); + // Read Extended Status Register (GSR and PSR) + writeBank(0xE0, 0x0000, 0x71); + // Page Buffer Swap + writeBank(0xE0, 0x0000, 0x72); + // Read Page Buffer + writeBank(0xE0, 0x0000, 0x75); + + // Switch to read + dataIn(); + controlIn(); + + // Read the mapping info out of the 1st chip + for (unsigned long currByte = 0xFF00; currByte <= 0xFFFF; currByte++) { + myFile.write(readBank(0xE0, currByte)); + } + + // Close the file: + myFile.close(); + + // Switch to write + dataOut(); + controlOut(); + + // Reset Flash + writeBank(0xC0, 0x5555 * 2, 0xaa); + writeBank(0xC0, 0x2AAA * 2, 0x55); + writeBank(0xC0, 0x5555 * 2, 0xf0); + + // Reset Flash + writeBank(0xE0, 0x5555 * 2, 0xaa); + writeBank(0xE0, 0x2AAA * 2, 0x55); + writeBank(0xE0, 0x5555 * 2, 0xf0); + + // Switch to read + dataIn(); + controlIn(); + + // Signal end of process + Serial.println("Done."); +} + +void writeMapping(byte startBank, uint32_t pos) { + // Switch to write + dataOut(); + controlOut(); + + // Open file on sd card + if (myFile.open(fileName, O_READ)) { + + // Seek to a new position in the file + if (pos != 0) + myFile.seekCur(pos); + + + if (romType) { + // Write to Page Buffer + for (unsigned long currByte = 0x00; currByte < 0x100; currByte += 128) { + // Prepare to erase/write Page Buffer + writeBank(startBank, 0x5555 * 2, 0xaa); + writeBank(startBank, 0x2AAA * 2, 0x55); + writeBank(startBank, 0x5555 * 2, 0x77); + // Write Page Buffer Command + writeBank(startBank, 0x5555 * 2, 0xaa); + writeBank(startBank, 0x2AAA * 2, 0x55); + writeBank(startBank, 0x5555 * 2, 0x99); + + myFile.read(SDBuffer, 128); + + for (byte c = 0; c < 128; c++) { + writeBank(startBank, currByte + c, SDBuffer[c]); + // Write last byte twice + if (c == 127) { + writeBank(startBank, currByte + c, SDBuffer[c]); + } + } + busyCheck(startBank); + } + } + else { + // Write to Page Buffer + for (unsigned long currByte = 0x0000; currByte < 0x100; currByte += 128) { + // Prepare to erase/write Page Buffer + writeBank(1, 0x8000 + 0x1555 * 2, 0xaa); + writeBank(0, 0x8000 + 0x2AAA * 2, 0x55); + writeBank(1, 0x8000 + 0x1555 * 2, 0x77); + // Write Page Buffer Command + writeBank(1, 0x8000 + 0x1555 * 2, 0xaa); + writeBank(0, 0x8000 + 0x2AAA * 2, 0x55); + writeBank(1, 0x8000 + 0x1555 * 2, 0x99); + + myFile.read(SDBuffer, 128); + + for (byte c = 0; c < 128; c++) { + writeBank(1, 0x8000 + currByte + c, SDBuffer[c]); + // Write last byte twice + if (c == 127) { + writeBank(1, 0x8000 + currByte + c, SDBuffer[c]); + } + } + busyCheck(startBank); + } + } + // Close the file: + myFile.close(); + } + else { + Serial.println("Can't open file on SD"); + } + + // Switch to read + dataIn(); + controlIn(); +} + +// Print the current mapping from the hidden "page buffer" +void printMapping(byte startBank) { + // Switch to write + dataOut(); + controlOut(); + + if (romType) { + // Unlock read map + writeBank(startBank, 0x0000, 0x38); + writeBank(startBank, 0x0000, 0xd0); + // Read Extended Status Register (GSR and PSR) + writeBank(startBank, 0x0000, 0x71); + // Page Buffer Swap + writeBank(startBank, 0x0000, 0x72); + // Read Page Buffer + writeBank(startBank, 0x0000, 0x75); + + // Switch to read + dataIn(); + controlIn(); + + char buffer[3]; + for (unsigned long currByte = 0xFF00; currByte < 0xFFFF; currByte += 16) { + Serial.print("0x"); + Serial.print(startBank, HEX); + Serial.print(currByte, HEX); + Serial.print(" "); + for (int c = 0; c < 16; c++) { + itoa (readBank(startBank, currByte + c), buffer, 16); + for (int i = 0; i < 2 - strlen(buffer); i++) { + Serial.print('0'); + } + // Now print the significant bits + Serial.print(buffer); + Serial.print(" "); + } + Serial.println(""); + } + + } + else { + writeBank(0, 0x8000 + 0x0000, 0x38); + writeBank(0, 0x8000 + 0x0000, 0xd0); + // Read Extended Status Register (GSR and PSR) + writeBank(0, 0x8000 + 0x0000, 0x71); + // Page Buffer Swap + writeBank(0, 0x8000 + 0x0000, 0x72); + // Read Page Buffer + writeBank(0, 0x8000 + 0x0000, 0x75); + + // Switch to read + dataIn(); + controlIn(); + + char buffer[3]; + for (unsigned long currByte = 0x0000; currByte < 0x100; currByte += 16) { + Serial.print("0x"); + Serial.print(currByte, HEX); + Serial.print(" "); + for (int c = 0; c < 16; c++) { + itoa (readBank(0, 0x8000 + currByte + c), buffer, 16); + for (int i = 0; i < 2 - strlen(buffer); i++) { + Serial.print('0'); + } + // Now print the significant bits + Serial.print(buffer); + Serial.print(" "); + } + Serial.println(""); + } + } + + // Switch to read + dataIn(); + controlIn(); +} + +// Send a command to the MX15001 chip +byte sendNP(byte command) { + // Switch to write + dataOut(); + controlOut(); + + // Write command then pulse clock pin 2 times + writeBankClock(0, 0x2400, 0x09); + pulseClock(4); + + // Switch to read + dataIn(); + controlIn(); + + // Read status + NPReady = readBankClock(0, 0x2400); + + // Switch to write + dataOut(); + controlOut(); + + writeBankClock(0, 0x2401, 0x28); + pulseClock(4); + writeBankClock(0, 0x2401, 0x84); + pulseClock(4); + + // NP_CMD_06h, send this only if above read has returned 7Dh, not if it's already returning 2Ah + if (NPReady == 0x7D) { + writeBankClock(0, 0x2400, 0x06); + pulseClock(4); + writeBankClock(0, 0x2400, 0x39); + pulseClock(4); + } + + // Write the command + writeBankClock(0, 0x2400, command); + + // Switch to read + dataIn(); + controlIn(); + + // Read status + NPReady = readBankClock(0, 0x2400); + return NPReady; +} + +// This function will erase and program one of the flashroms(0xC0 or 0xE0) from a file off the SD card +void programFlash(int startBank, uint32_t pos) { + // Switch NP cart's mapping + if (unlockedHirom()) { + + // Get ID + idFlash(startBank); + if (strcmp(flashid, "c2f3") == 0) { + Serial.print("Flash ID: "); + Serial.println(flashid); + resetFlash(startBank); + + // Erase flash + Serial.print("Checking if flash is empty..."); + if (blankcheck(startBank)) + Serial.println("Success."); + else { + Serial.println("Flash is not blank."); + Serial.print("Erasing..."); + eraseFlash(startBank); + resetFlash(startBank); + Serial.println("Done."); + Serial.print("Checking if flash is empty..."); + if (blankcheck(startBank)) + Serial.println("Success."); + else { + Serial.println("Abort: Could not erase flash."); + while (1); + } + } + // Write flash + writeFlash(startBank, pos); + + // Reset flash + resetFlash(startBank); + + // Checking for errors + Serial.print("Checking for write errors..."); + writeErrors = verifyFlash(startBank, pos); + if (writeErrors == 0) { + Serial.println("Flashrom verified ok"); + } + else { + Serial.print("Number of Errors: "); + Serial.println(writeErrors); + } + } + else { + Serial.println("Error: Wrong Flash ID"); + } + } +} + +// This function will erase and program the NP cart(both flashroms) from a 4MB file off the SD card +void programNP() { + // Switch NP cart's mapping + if (unlockedHirom()) { + + // Get ID + for (int currFlash = 0; currFlash < 33; currFlash += 32) { + idFlash(0xC0 + currFlash); + if (strcmp(flashid, "c2f3") == 0) { + resetFlash(0xC0 + currFlash); + + // Erase flash + Serial.print("Checking if flash 0x"); + Serial.print(0xC0 + currFlash, HEX); + Serial.print(" is empty..."); + if (blankcheck(0xC0 + currFlash)) + Serial.println("Success."); + else { + Serial.println("Flash is not blank."); + Serial.print("Erasing..."); + eraseFlash(0xC0 + currFlash); + resetFlash(0xC0 + currFlash); + if (blankcheck(0xC0 + currFlash)) + Serial.println("Done."); + else { + Serial.println("Abort: Could not erase flash."); + while (1); + } + } + } + else { + Serial.println("Error: Wrong Flash ID"); + while (1); + } + } + // Write flash + Serial.print("Writing..."); + writeNP(); + Serial.println(""); + + // Reset flash + resetFlash(0xC0); + resetFlash(0xE0); + + // Checking for errors + Serial.println("Checking for write errors..."); + writeErrors = verifyFlash(0xC0, 0); + if (writeErrors == 0) { + Serial.println("Flash 0xC0 verified OK."); + } + else { + Serial.print("Number of Errors: "); + Serial.println(writeErrors); + } + // Checking for errors + writeErrors = verifyFlash(0xE0, 2097152); + if (writeErrors == 0) { + Serial.println("Flash 0xE0 verified OK."); + } + else { + Serial.print("Number of Errors: "); + Serial.println(writeErrors); + } + } +} + +/****************************************** + SNES SRAM Functions +*****************************************/ +// Dump the SRAM to the SD card +void writeSRAM () { + //open file on sd card + if (myFile.open(fileName, O_READ)) { + + // Set pins to output + dataOut(); + // Set RST RD WR to High and CS to Low + controlOut(); + + // Dump HiRom + if (romType) { + // Writing SRAM on HiRom needs CS to be high + digitalWrite(csPin, HIGH); + // Sram size + long lastByte = (long(sramSize) * 128) + 24576; + for (long currByte = 24576; currByte < lastByte; currByte++) { //startAddr = 0x6000 + writeBank(48, currByte, myFile.read()); //startBank = 0x30 + } + } + // Dump LoRom + else { + // Sram size + long lastByte = (long(sramSize) * 128); + for (long currByte = 0; currByte < lastByte; currByte++) { //startAddr = 0x0000 + writeBank(112, currByte, myFile.read()); //startBank = 0x70 + } + } + + // set control + controlIn(); + // Set pins to input + dataIn(); + + // Close the file: + myFile.close(); + Serial.println("SRAM writing finished"); + } + else { + Serial.println("File doesnt exist"); + } +} + +void readSRAM () { + // set control + controlIn(); + // Set pins to input + dataIn(); + + //open file on sd card + if (!myFile.open(fileName, O_RDWR | O_CREAT)) { + Serial.println("SD Error"); + } + if (romType) { + // Dumping SRAM on HiRom needs CS to be high + digitalWrite(csPin, HIGH); + // Sram size + long lastByte = (long(sramSize) * 128) + 24576; + for (long currByte = 24576; currByte < lastByte; currByte++) { //startAddr = 0x6000 + myFile.write(readBank(48, currByte)); //startBank = 0x30 + } + } + else { + // Sram size + long lastByte = (long(sramSize) * 128); + for (long currByte = 0; currByte < lastByte; currByte++) { //startAddr = 0x0000 + myFile.write(readBank(112, currByte)); //startBank = 0x70 + } + } + // Close the file: + myFile.close(); + + // Signal end of process + Serial.print("Saved to "); + Serial.println(fileName); +} + +// Check if the SRAM was written without any error +unsigned long verifySRAM() { + //open file on sd card + if (myFile.open(fileName, O_READ)) { + + // Variable for errors + writeErrors = 0; + + // set control + controlIn(); + // Set pins to input + dataIn(); + + if (romType) { + // Dumping SRAM on HiRom needs CS to be high + digitalWrite(csPin, HIGH); + // Sram size + long lastByte = (long(sramSize) * 128) + 24576; + for (long currByte = 24576; currByte < lastByte; currByte += 512) { + //fill sdBuffer + myFile.read(SDBuffer, 512); + for (unsigned long c = 0; c < 512; c++) { + if ((readBank(48, currByte + c)) != SDBuffer[c]) { + writeErrors++; + } + } + } + } + else { + // Sram size + long lastByte = (long(sramSize) * 128); + for (long currByte = 0; currByte < lastByte; currByte += 512) { + //fill sdBuffer + myFile.read(SDBuffer, 512); + for (unsigned long c = 0; c < 512; c++) { + if ((readBank(112, currByte + c)) != SDBuffer[c]) { + writeErrors++; + } + } + } + } + + // Close the file: + myFile.close(); + return writeErrors; + } + else { + Serial.println("Can't open file"); + } +} + +/****************************************** + Main loop +*****************************************/ +void loop() { + // Print menu to serial monitor + Serial.println("MENU----------------------------------------------------->"); + Serial.println("Change Mode: "); + Serial.println("(0)Menu (2)GAME2 (4)GAME4 (6)GAME6 (8)HIROM ALL"); + Serial.println("(1)GAME1 (3)GAME3 (5)GAME5 (7)GAME7 (9)HIROM MENU"); + Serial.println(""); + Serial.println("Flash Commands: "); + Serial.println("(A)Read ID (B)Reset (C)Print Flash"); + Serial.println(""); + Serial.println("Read / Write Rom: "); + Serial.println("(D)Read Rom (E)Erase Flash (F)Write Rom"); + Serial.println(""); + Serial.println("Read / Write Mapping: "); + Serial.println("(G)Print mapping (H)Save mapping"); + Serial.println("(I)Erase mapping (J)Write mapping"); + Serial.println(""); + Serial.println("Sector Protection: "); + Serial.println("(K)Read Sector Protection"); + Serial.println("(L)Unlock Sector Protection"); + Serial.println("(M)Set Sector Protection"); + Serial.println(""); + Serial.println("Read / Write SRAM: "); + Serial.println("(N)Read SRAM"); + Serial.println("(O)Write SRAM"); + Serial.println(""); + Serial.println("Misc: "); + Serial.println("(P)Print Ports"); + Serial.println("(Q)Unlock WP"); + + Serial.println(""); + + // Wait for user input + Serial.println("-------> Please enter a single digit or letter: _ <-------"); + Serial.println(""); + + while (Serial.available() == 0) { + } + + // Read the incoming byte: + incomingByte = Serial.read(); + + // Execute user choice + switch (incomingByte) { + case 48: + Serial.println("(0)Menu 0x80"); + // Reset to Menu + romType = 0; + sendNP(0x80); + readPorts(); + break; + + case 49: + Serial.println("(1)GAME1 0x81"); + // Reset to GAME1 + romType = 0; + sendNP(0x81); + readPorts(); + break; + + case 50: + Serial.println("(2)GAME2 0x82"); + // Reset to GAME2 + romType = 0; + sendNP(0x82); + readPorts(); + break; + + case 51: + Serial.println("(3)GAME3 0x83"); + // Reset to GAME3 + romType = 0; + sendNP(0x83); + readPorts(); + break; + + case 52: + Serial.println("(4)GAME4 0x84"); + // Reset to GAME4 + romType = 0; + sendNP(0x84); + readPorts(); + break; + + case 53: + Serial.println("(5)GAME5 0x85"); + // Reset to GAME5 + romType = 0; + sendNP(0x85); + readPorts(); + break; + + case 54: + Serial.println("(6)GAME6 0x86"); + // Reset to GAME6 + romType = 0; + sendNP(0x86); + readPorts(); + break; + + case 55: + Serial.println("(7)GAME7 0x87"); + // Reset to GAME7 + romType = 0; + sendNP(0x87); + readPorts(); + break; + + case 56: + Serial.println("(8)HIROM ALL 0x04"); + // Reset to HIROM ALL + romType = 1; + if (sendNP(0x04) == 0x2A) + Serial.println("Success"); + else + Serial.println("Failed"); + readPorts(); + break; + + case 57: + Serial.println("(9)HIROM MENU 0x05"); + // Reset to HIROM MENU + romType = 1; + sendNP(0x05); + readPorts(); + break; + + case 97: + Serial.println("(A)Read Flash ID"); + // Read Flash ID + idFlash(0xC0); + Serial.print("Flash ID 1: "); + Serial.println(flashid); + resetFlash(0xC0); + idFlash(0xE0); + Serial.print("Flash ID 2: "); + Serial.println(flashid); + resetFlash(0xE0); + break; + + case 98: + Serial.println("(B)Reset flash"); + // Reset flash #1 + resetFlash(0xC0); + // Reset flash #2 + resetFlash(0xE0); + // Reset flash #2 + resetFlash(0xE0); + break; + + case 99: + Serial.println("(C)Print Flash"); + // Print flash + Serial.println("Flash: "); + printFlashAll(); + Serial.println(" "); + break; + + case 100: + Serial.println("(D)Dump NP"); + resetFlash(0xC0); + resetFlash(0xE0); + romType = 1; + flashSize = 4194304; + numBanks = 64; + Serial.print("Switching Mapping to HiRom All..."); + if (sendNP(0x04) == 0x2A) { + Serial.println("Success."); + // Read flash + getfilename(); + readFlash(); + } + else { + Serial.println("Error: Switching to HiRom All failed."); + Serial.println("Please power - cycle NP cart."); + readPorts(); + } + break; + + case 101: + Serial.println("(E)Erase NP"); + flashSize = 2097152; + numBanks = 32; + if (unlockedHirom()) { + Serial.println("Erasing flashrom #1"); + // Erase Flash #1 + eraseFlash(0xC0); + resetFlash(0xC0); + Serial.print("Blankcheck..."); + if (blankcheck(0xC0)) + Serial.println("Success."); + else + Serial.println("failed."); + // Erase Flash #2 + Serial.println("Erasing flashrom #2"); + eraseFlash(0xE0); + resetFlash(0xE0); + Serial.print("Blankcheck..."); + if (blankcheck(0xE0)) + Serial.println("Success."); + else + Serial.println("failed."); + } + break; + + case 102: + Serial.println("(F)Write NP"); + flashSize = 2097152; + numBanks = 32; + // Prompt user input + getfilename(); + + //Serial Programming + Serial.println("Programming 1st flashrom."); + // Program 1st flashrom + programFlash(0xC0, 0); + Serial.println(""); + Serial.println("Programming 2nd flashrom."); + // Program 2nd flashrom + programFlash(0xE0, 2097152); + + //Parallel Programming + //programNP(); + break; + + case 103: + Serial.println("(G)Print mapping"); + if (unlockedHirom()) { + printMapping(0xC0); + printMapping(0xE0); + } + break; + + case 104: + Serial.println("(H)Save mapping"); + if (unlockedHirom()) { + getfilename(); + readMapping(); + } + break; + + case 105: + Serial.println("(I)Erase mapping"); + if (unlockedHirom()) { + eraseMapping(0xD0); // 0xC0 not working + eraseMapping(0xE0); + printMapping(0xC0); + printMapping(0xE0); + } + break; + + case 106: + Serial.println("(J)Write mapping"); + if (unlockedHirom()) { + getfilename(); + writeMapping(0xD0, 0); // 0xC0 not working + writeMapping(0xE0, 256); + printMapping(0xC0); + printMapping(0xE0); + } + break; + + case 107: + Serial.println("(K)Read Sector Protection"); + if (unlockedHirom()) { + byte protectStatus; + protectStatus = readSectorProtection(0xC0); + if (protectStatus == 2) + Serial.println("Can't access Flash C0"); + else if (protectStatus == 0) + Serial.println("Flash C0 unprotected"); + protectStatus = readSectorProtection(0xE0); + if (protectStatus == 2) + Serial.println("Can't access Flash E0"); + else if (protectStatus == 0) + Serial.println("Flash E0 unprotected"); + } + break; + + case 108: + Serial.println("(L)Unlock Sector Protection"); + if (unlockedHirom()) { + unlockSectorProtection(0xC1); + unlockSectorProtection(0xE0); + } + break; + + case 109: + Serial.println("(M)Set Sector Protection"); + if (unlockedHirom()) { + setSectorProtection(0xC1); + setSectorProtection(0xE0); + } + break; + + case 110: + Serial.println("(N)Read SRAM"); + if (sendNP(0x04) == 0x2A) { + romType = 1; + getfilename(); + readSRAM(); + } + else + Serial.println("Switching to Hirom failed."); + break; + + case 111: + Serial.println("(O)Write SRAM"); + if (sendNP(0x04) == 0x2A) { + romType = 1; + getfilename(); + writeSRAM(); + Serial.print("Verifying..."); + if (verifySRAM() == 0) + Serial.println("OK."); + else + Serial.println("failed."); + } + else + Serial.println("Switching to Hirom failed."); + break; + + case 112: + Serial.println("(P)Print Ports"); + readPorts(); + break; + + case 113: + Serial.println("(Q)Unlock WP"); + sendNP(0x02); + if (readBankClock(0, 0x2401) == 0x4) { + Serial.println("Success."); + readPorts(); + } + else { + Serial.println("Error: Unlocking WP failed."); + Serial.println("Please power - cycle NP cart."); + readPorts(); + } + break; + } + Serial.println(""); +} + +//****************************************** +// End of File +//******************************************