mirror of
https://github.com/sanni/cartreader.git
synced 2024-12-27 13:31:51 +01:00
0d06c7bb2d
Uses the Arduino Serial Monitor and does not need the Adafruit Clock Generator.
1930 lines
53 KiB
C++
1930 lines
53 KiB
C++
/**********************************************************************************
|
|
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 <SPI.h>
|
|
#include <SdFat.h>
|
|
#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
|
|
//******************************************
|