mirror of
https://github.com/sanni/cartreader.git
synced 2024-12-27 05:21:53 +01:00
2cf7f5dbe7
The `setVoltage()` function should be called even when `ENABLE_VSELECT` is disabled because `ENABLE_3V3FIX` also uses it. There is no resource cost to do this as when both options are disabled the compiler will optimize this function out. This just "future proofs" the code so if that function ever does more it doesn't need updated everywhere. This applies to `setup_FlashVoltage()` as well. The changes to OSCR.cpp are just for code formatting and additional comments to clarify this.
758 lines
20 KiB
C++
758 lines
20 KiB
C++
//******************************************
|
|
// SNES Satellaview 8M Memory pack code by tamanegi_taro
|
|
// Revision 1.0.0 October 22nd 2018
|
|
// Added BSX Sram, copied from skamans enhanced sketch //sanni
|
|
//******************************************
|
|
#ifdef enable_SV
|
|
|
|
/******************************************
|
|
Satellaview 8M Memory Pack
|
|
******************************************/
|
|
/******************************************
|
|
Prototype Declarations
|
|
*****************************************/
|
|
/* Hoping that sanni will use this progressbar function */
|
|
extern void draw_progressbar(uint32_t processedsize, uint32_t totalsize);
|
|
|
|
//void svMenu();
|
|
void readROM_SV();
|
|
//void setup_SV();
|
|
void writeROM_SV(void);
|
|
void eraseCheck_SV(void);
|
|
void supplyCheck_SV(void);
|
|
void writeCheck_SV(void);
|
|
void detectCheck_SV(void);
|
|
void eraseAll_SV(void);
|
|
|
|
/******************************************
|
|
Variables
|
|
*****************************************/
|
|
//No global variables
|
|
|
|
/******************************************
|
|
Menu
|
|
*****************************************/
|
|
// SV flash menu items
|
|
static const char svFlashMenuItem1[] PROGMEM = "Read Memory Pack";
|
|
static const char svFlashMenuItem2[] PROGMEM = "Write Memory Pack";
|
|
static const char svFlashMenuItem3[] PROGMEM = "Read BS-X Sram";
|
|
static const char svFlashMenuItem4[] PROGMEM = "Write BS-X Sram";
|
|
static const char svFlashMenuItem5[] PROGMEM = "Back";
|
|
static const char* const menuOptionsSVFlash[] PROGMEM = { svFlashMenuItem1, svFlashMenuItem2, svFlashMenuItem3, svFlashMenuItem4, svFlashMenuItem5 };
|
|
|
|
|
|
void svMenu() {
|
|
// create menu with title and 3 options to choose from
|
|
unsigned char mainMenu;
|
|
// Copy menuOptions out of progmem
|
|
convertPgm(menuOptionsSVFlash, 5);
|
|
mainMenu = question_box(F("Satellaview 8M Memory"), menuOptions, 5, 0);
|
|
|
|
// wait for user choice to come back from the question box menu
|
|
switch (mainMenu) {
|
|
// Read memory pack
|
|
case 0:
|
|
// Change working dir to root
|
|
sd.chdir("/");
|
|
readROM_SV();
|
|
break;
|
|
|
|
// Write memory pack
|
|
case 1:
|
|
// Change working dir to root
|
|
sd.chdir("/");
|
|
writeROM_SV();
|
|
break;
|
|
|
|
// Read BS-X Sram
|
|
case 2:
|
|
// Change working dir to root
|
|
sd.chdir("/");
|
|
readSRAM_SV();
|
|
break;
|
|
|
|
// Write BS-X Sram
|
|
case 3:
|
|
// Change working dir to root
|
|
sd.chdir("/");
|
|
writeSRAM_SV();
|
|
unsigned long wrErrors;
|
|
wrErrors = verifySRAM_SV();
|
|
if (wrErrors == 0) {
|
|
println_Msg(F("Verified OK"));
|
|
display_Update();
|
|
} else {
|
|
print_STR(error_STR, 0);
|
|
print_Msg(wrErrors);
|
|
print_STR(_bytes_STR, 1);
|
|
print_Error(did_not_verify_STR);
|
|
}
|
|
wait();
|
|
break;
|
|
|
|
// Reset
|
|
case 4:
|
|
resetArduino();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/******************************************
|
|
Setup
|
|
*****************************************/
|
|
void setup_SV() {
|
|
// Request 5V
|
|
setVoltage(VOLTS_SET_5V);
|
|
|
|
// Set cicrstPin(PG1) to Output
|
|
DDRG |= (1 << 1);
|
|
// Output a high signal until we're ready to start
|
|
PORTG |= (1 << 1);
|
|
// Set cichstPin(PG0) to Input
|
|
DDRG &= ~(1 << 0);
|
|
|
|
// Adafruit Clock Generator
|
|
i2c_found = clockgen.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0);
|
|
if (i2c_found) {
|
|
clockgen.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);
|
|
clockgen.set_pll(SI5351_PLL_FIXED, SI5351_PLLB);
|
|
clockgen.set_freq(2147727200ULL, SI5351_CLK0);
|
|
clockgen.set_freq(307200000ULL, SI5351_CLK2);
|
|
clockgen.output_enable(SI5351_CLK0, 1);
|
|
clockgen.output_enable(SI5351_CLK1, 0);
|
|
clockgen.output_enable(SI5351_CLK2, 1);
|
|
}
|
|
#ifdef clockgen_installed
|
|
else {
|
|
display_Clear();
|
|
print_FatalError(F("Clock Generator not found"));
|
|
}
|
|
#endif
|
|
|
|
// Set Address Pins to Output
|
|
//A0-A7
|
|
DDRF = 0xFF;
|
|
//A8-A15
|
|
DDRK = 0xFF;
|
|
//BA0-BA7
|
|
DDRL = 0xFF;
|
|
//PA0-PA7
|
|
DDRA = 0xFF;
|
|
|
|
// Set Control Pins to Output RST(PH0) CS(PH3) WR(PH5) RD(PH6)
|
|
DDRH |= (1 << 0) | (1 << 3) | (1 << 5) | (1 << 6);
|
|
// Switch RST(PH0) and WR(PH5) to HIGH
|
|
PORTH |= (1 << 0) | (1 << 5);
|
|
// Switch CS(PH3) and RD(PH6) to LOW
|
|
PORTH &= ~((1 << 3) | (1 << 6));
|
|
|
|
// Set Refresh(PE5) to Output
|
|
DDRE |= (1 << 5);
|
|
// Switch Refresh(PE5) to LOW (needed for SA-1)
|
|
PORTE &= ~(1 << 5);
|
|
|
|
// Set CPU Clock(PH1) to Output
|
|
DDRH |= (1 << 1);
|
|
//PORTH &= ~(1 << 1);
|
|
|
|
// Set IRQ(PH4) to Input
|
|
DDRH &= ~(1 << 4);
|
|
// Activate Internal Pullup Resistors
|
|
//PORTH |= (1 << 4);
|
|
|
|
// Set expand(PG5) to output
|
|
DDRG |= (1 << 5);
|
|
// Output High
|
|
PORTG |= (1 << 5);
|
|
|
|
// Set Data Pins (D0-D7) to Input
|
|
DDRC = 0x00;
|
|
// Enable Internal Pullups
|
|
//PORTC = 0xFF;
|
|
|
|
// Unused pins
|
|
// Set wram(PE4) to Output
|
|
DDRE |= (1 << 4);
|
|
//PORTE &= ~(1 << 4);
|
|
// Set pawr(PJ1) to Output
|
|
DDRJ |= (1 << 1);
|
|
//PORTJ &= ~(1 << 1);
|
|
// Set pard(PJ0) to Output
|
|
DDRJ |= (1 << 0);
|
|
//PORTJ &= ~(1 << 0);
|
|
|
|
// Start CIC by outputting a low signal to cicrstPin(PG1)
|
|
PORTG &= ~(1 << 1);
|
|
|
|
// Wait for CIC reset
|
|
delay(1000);
|
|
}
|
|
|
|
/******************************************
|
|
Low level functions
|
|
*****************************************/
|
|
// Write one byte of data to a location specified by bank and address, 00:0000
|
|
void writeBank_SV(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"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t");
|
|
|
|
// Switch WR(PH5) to LOW
|
|
PORTH &= ~(1 << 5);
|
|
|
|
// Leave WR low for at least 60ns
|
|
__asm__("nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t");
|
|
|
|
// Switch WR(PH5) to HIGH
|
|
PORTH |= (1 << 5);
|
|
|
|
// Leave WR high for at least 50ns
|
|
__asm__("nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t");
|
|
}
|
|
|
|
// Read one byte of data from a location specified by bank and address, 00:0000
|
|
byte readBank_SV(byte myBank, word myAddress) {
|
|
PORTL = myBank;
|
|
PORTF = myAddress & 0xFF;
|
|
PORTK = (myAddress >> 8) & 0xFF;
|
|
|
|
// Arduino running at 16Mhz -> one nop = 62.5ns -> 1000ns total
|
|
__asm__("nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t");
|
|
|
|
// Read
|
|
byte tempByte = PINC;
|
|
return tempByte;
|
|
}
|
|
|
|
/******************************************
|
|
SatellaView BS-X Sram functions
|
|
*****************************************/
|
|
void readSRAM_SV() {
|
|
// set control
|
|
controlIn_SNES();
|
|
|
|
// Get name, add extension and convert to char array for sd lib
|
|
strcpy(fileName, "BSX.srm");
|
|
|
|
// create a new folder for the save file
|
|
EEPROM_readAnything(0, foldern);
|
|
sprintf(folder, "SNES/SAVE/BSX/%d", foldern);
|
|
sd.mkdir(folder, true);
|
|
sd.chdir(folder);
|
|
|
|
// write new folder number back to eeprom
|
|
foldern = foldern + 1;
|
|
EEPROM_writeAnything(0, foldern);
|
|
|
|
//open file on sd card
|
|
if (!myFile.open(fileName, O_RDWR | O_CREAT)) {
|
|
print_FatalError(sd_error_STR);
|
|
}
|
|
|
|
readBank_SV(0x10, 0); // Preconfigure to fix corrupt 1st byte
|
|
|
|
//startBank = 0x10; endBank = 0x17; CS low
|
|
for (byte BSBank = 0x10; BSBank < 0x18; BSBank++) {
|
|
//startAddr = 0x5000
|
|
for (long currByte = 0x5000; currByte < 0x6000; currByte += 512) {
|
|
for (unsigned long c = 0; c < 512; c++) {
|
|
sdBuffer[c] = readBank_SV(BSBank, currByte + c);
|
|
}
|
|
myFile.write(sdBuffer, 512);
|
|
}
|
|
}
|
|
// Close the file:
|
|
myFile.close();
|
|
|
|
// Signal end of process
|
|
display_Clear();
|
|
print_Msg(F("Saved to "));
|
|
print_Msg(folder);
|
|
println_Msg(F("/..."));
|
|
display_Update();
|
|
wait();
|
|
}
|
|
|
|
void writeSRAM_SV() {
|
|
filePath[0] = '\0';
|
|
sd.chdir("/");
|
|
fileBrowser(F("Select srm file"));
|
|
// Create filepath
|
|
sprintf(filePath, "%s/%s", filePath, fileName);
|
|
//clear the screen
|
|
display_Clear();
|
|
|
|
//open file on sd card
|
|
if (myFile.open(filePath, O_READ)) {
|
|
// Set pins to output
|
|
dataOut();
|
|
|
|
// Set RST RD WR to High and CS to Low
|
|
controlOut_SNES();
|
|
|
|
println_Msg(F("Writing sram..."));
|
|
display_Update();
|
|
|
|
// Write to sram bank
|
|
for (byte currBank = 0x10; currBank < 0x18; currBank++) {
|
|
//startAddr = 0x5000
|
|
for (long currByte = 0x5000; currByte < 0x6000; currByte += 512) {
|
|
myFile.read(sdBuffer, 512);
|
|
for (unsigned long c = 0; c < 512; c++) {
|
|
//startBank = 0x10; CS low
|
|
writeBank_SV(currBank, currByte + c, sdBuffer[c]);
|
|
}
|
|
}
|
|
draw_progressbar(((currBank - 0x10) * 0x1000), 32768);
|
|
}
|
|
// Finish progressbar
|
|
draw_progressbar(32768, 32768);
|
|
delay(100);
|
|
// Set pins to input
|
|
dataIn();
|
|
|
|
// Close the file:
|
|
myFile.close();
|
|
println_Msg("");
|
|
println_Msg(F("SRAM writing finished"));
|
|
display_Update();
|
|
} else {
|
|
print_Error(F("File doesnt exist"));
|
|
}
|
|
}
|
|
|
|
// Check if the SRAM was written without any error
|
|
unsigned long verifySRAM_SV() {
|
|
//open file on sd card
|
|
if (myFile.open(filePath, O_READ)) {
|
|
// Variable for errors
|
|
writeErrors = 0;
|
|
|
|
// Set control
|
|
controlIn_SNES();
|
|
|
|
//startBank = 0x10; endBank = 0x17; CS low
|
|
for (byte BSBank = 0x10; BSBank < 0x18; BSBank++) {
|
|
//startAddr = 0x5000
|
|
for (long currByte = 0x5000; currByte < 0x6000; currByte += 512) {
|
|
//fill sdBuffer
|
|
myFile.read(sdBuffer, 512);
|
|
for (unsigned long c = 0; c < 512; c++) {
|
|
if ((readBank_SV(BSBank, currByte + c)) != sdBuffer[c]) {
|
|
writeErrors++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Close the file:
|
|
myFile.close();
|
|
return writeErrors;
|
|
} else {
|
|
print_Error(F("Can't open file"));
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/******************************************
|
|
SatellaView 8M Memory Pack functions
|
|
*****************************************/
|
|
// Read memory pack to SD card
|
|
void readROM_SV() {
|
|
// Set control
|
|
dataIn();
|
|
controlIn_SNES();
|
|
|
|
// Get name, add extension and convert to char array for sd lib
|
|
strcpy(fileName, "MEMPACK.bs");
|
|
|
|
// create a new folder for the save file
|
|
EEPROM_readAnything(0, foldern);
|
|
sprintf(folder, "SNES/ROM/%s/%d", "MEMPACK", foldern);
|
|
sd.mkdir(folder, true);
|
|
sd.chdir(folder);
|
|
|
|
//clear the screen
|
|
display_Clear();
|
|
print_STR(saving_to_STR, 0);
|
|
print_Msg(folder);
|
|
println_Msg(F("/..."));
|
|
display_Update();
|
|
|
|
// write new folder number back to eeprom
|
|
foldern = foldern + 1;
|
|
EEPROM_writeAnything(0, foldern);
|
|
|
|
//open file on sd card
|
|
if (!myFile.open(fileName, O_RDWR | O_CREAT)) {
|
|
print_FatalError(create_file_STR);
|
|
}
|
|
|
|
// Read Banks
|
|
for (int currBank = 0x40; currBank < 0x50; currBank++) {
|
|
// Dump the bytes to SD 512B at a time
|
|
for (long currByte = 0; currByte < 65536; currByte += 512) {
|
|
draw_progressbar((currBank - 0x40) * 0x10000 + currByte, 0x100000);
|
|
for (int c = 0; c < 512; c++) {
|
|
sdBuffer[c] = readBank_SV(currBank, currByte + c);
|
|
}
|
|
myFile.write(sdBuffer, 512);
|
|
}
|
|
}
|
|
draw_progressbar(0x100000, 0x100000); //Finish drawing progress bar
|
|
|
|
// Close the file:
|
|
myFile.close();
|
|
println_Msg(F("Read pack completed"));
|
|
display_Update();
|
|
wait();
|
|
}
|
|
|
|
void writeROM_SV(void) {
|
|
// Get Checksum as string to make sure that BS-X cart is inserted
|
|
dataIn();
|
|
controlIn_SNES();
|
|
sprintf(checksumStr, "%02X%02X", readBank_SV(0, 65503), readBank_SV(0, 65502));
|
|
|
|
//if CRC is not 8B86, BS-X cart is not inserted. Display error and reset
|
|
if (strcmp("8B86", checksumStr) != 0) {
|
|
display_Clear();
|
|
print_FatalError(F("Error: Must use BS-X cart"));
|
|
}
|
|
|
|
//Display file Browser and wait user to select a file. Size must be 1MB.
|
|
filePath[0] = '\0';
|
|
sd.chdir("/");
|
|
fileBrowser(F("Select BS file"));
|
|
// Create filepath
|
|
sprintf(filePath, "%s/%s", filePath, fileName);
|
|
display_Clear();
|
|
|
|
//open file on sd card
|
|
if (myFile.open(filePath, O_READ)) {
|
|
|
|
fileSize = myFile.fileSize();
|
|
if (fileSize != 0x100000) {
|
|
println_Msg(F("File must be 1MB"));
|
|
display_Update();
|
|
myFile.close();
|
|
wait();
|
|
return;
|
|
}
|
|
|
|
//Disable 8M memory pack write protection
|
|
dataOut();
|
|
controlOut_SNES();
|
|
writeBank_SV(0x0C, 0x5000, 0x80); //Modify write enable register
|
|
writeBank_SV(0x0E, 0x5000, 0x80); //Commit register modification
|
|
|
|
//Erase memory pack
|
|
println_Msg(F("Erasing pack..."));
|
|
display_Update();
|
|
eraseAll_SV();
|
|
|
|
//Blank check
|
|
//Set pins to input
|
|
dataIn();
|
|
controlIn_SNES();
|
|
println_Msg(F("Blank check..."));
|
|
display_Update();
|
|
for (int currBank = 0xC0; currBank < 0xD0; currBank++) {
|
|
draw_progressbar(((currBank - 0xC0) * 0x10000), 0x100000);
|
|
for (long currByte = 0; currByte < 65536; currByte++) {
|
|
if (0xFF != readBank_SV(currBank, currByte)) {
|
|
println_Msg(F(""));
|
|
println_Msg(F("Erase failed"));
|
|
display_Update();
|
|
myFile.close();
|
|
wait();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
draw_progressbar(0x100000, 0x100000);
|
|
|
|
//Write memory pack
|
|
dataOut();
|
|
controlOut_SNES();
|
|
println_Msg(F("Writing pack..."));
|
|
display_Update();
|
|
for (int currBank = 0xC0; currBank < 0xD0; currBank++) {
|
|
draw_progressbar(((currBank - 0xC0) * 0x10000), 0x100000);
|
|
for (long currByte = 0; currByte < 65536; currByte++) {
|
|
|
|
writeBank_SV(0xC0, 0x0000, 0x10); //Program Byte
|
|
writeBank_SV(currBank, currByte, myFile.read());
|
|
writeBank_SV(0xC0, 0x0000, 0x70); //Status Mode
|
|
writeCheck_SV();
|
|
}
|
|
}
|
|
|
|
writeBank_SV(0xC0, 0x0000, 0x70); //Status Mode
|
|
writeCheck_SV();
|
|
writeBank_SV(0xC0, 0x0000, 0xFF); //Terminate write
|
|
draw_progressbar(0x100000, 0x100000);
|
|
|
|
|
|
//Verify
|
|
dataIn(); //Set pins to input
|
|
controlIn_SNES();
|
|
myFile.seekSet(0); // Go back to file beginning
|
|
print_STR(verifying_STR, 1);
|
|
display_Update();
|
|
for (int currBank = 0xC0; currBank < 0xD0; currBank++) {
|
|
draw_progressbar(((currBank - 0xC0) * 0x10000), 0x100000);
|
|
for (long currByte = 0; currByte < 65536; currByte++) {
|
|
if (myFile.read() != readBank_SV(currBank, currByte)) {
|
|
println_Msg(F(""));
|
|
println_Msg(F("Verify failed"));
|
|
display_Update();
|
|
myFile.close();
|
|
wait();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Close the file:
|
|
myFile.close();
|
|
draw_progressbar(0x100000, 0x100000);
|
|
println_Msg(F("Finished successfully"));
|
|
display_Update();
|
|
wait();
|
|
|
|
} else {
|
|
print_Error(F("File doesn't exist"));
|
|
}
|
|
}
|
|
|
|
void eraseCheck_SV(void) {
|
|
byte ret;
|
|
dataIn();
|
|
controlIn_SNES();
|
|
|
|
// Read register
|
|
ret = readBank_SV(0xC0, 0x0004);
|
|
|
|
// CE or OE must be toggled with each subsequent status read or the
|
|
// completion of a program or erase operation will not be evident.
|
|
while ((ret & 0x80) == 0x00) { //Wait until X.bit7 = 1
|
|
controlOut_SNES();
|
|
// Switch CS(PH3) High
|
|
PORTH |= (1 << 3);
|
|
// Leave CE high for at least 60ns
|
|
__asm__("nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t");
|
|
controlIn_SNES();
|
|
// Leave CE low for at least 50ns
|
|
__asm__("nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t");
|
|
// Read register
|
|
ret = readBank_SV(0xC0, 0x0004);
|
|
}
|
|
// Switch to write
|
|
dataOut();
|
|
controlOut_SNES();
|
|
}
|
|
|
|
void supplyCheck_SV(void) {
|
|
byte ret;
|
|
dataIn();
|
|
controlIn_SNES();
|
|
|
|
// Read register
|
|
ret = readBank_SV(0xC0, 0x0004);
|
|
|
|
// CE or OE must be toggled with each subsequent status read or the
|
|
// completion of a program or erase operation will not be evident.
|
|
while ((ret & 0x08) == 0x08) { //Wait until X.bit3 = 0
|
|
controlOut_SNES();
|
|
// Switch CS(PH3) High
|
|
PORTH |= (1 << 3);
|
|
// Leave CE high for at least 60ns
|
|
__asm__("nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t");
|
|
controlIn_SNES();
|
|
// Leave CE low for at least 50ns
|
|
__asm__("nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t");
|
|
// Read register
|
|
ret = readBank_SV(0xC0, 0x0004);
|
|
}
|
|
// Switch to write
|
|
dataOut();
|
|
controlOut_SNES();
|
|
}
|
|
|
|
void writeCheck_SV(void) {
|
|
byte ret;
|
|
dataIn();
|
|
controlIn_SNES();
|
|
|
|
// Read register
|
|
ret = readBank_SV(0xC0, 0x0000);
|
|
|
|
// CE or OE must be toggled with each subsequent status read or the
|
|
// completion of a program or erase operation will not be evident.
|
|
while ((ret & 0x80) == 0x00) {
|
|
controlOut_SNES();
|
|
// Switch CS(PH3) High
|
|
PORTH |= (1 << 3);
|
|
// Leave CE high for at least 60ns
|
|
__asm__("nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t");
|
|
controlIn_SNES();
|
|
// Leave CE low for at least 50ns
|
|
__asm__("nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t");
|
|
// Read register
|
|
ret = readBank_SV(0xC0, 0x0000);
|
|
}
|
|
// Switch to write
|
|
dataOut();
|
|
controlOut_SNES();
|
|
}
|
|
|
|
|
|
void detectCheck_SV(void) {
|
|
int i = 0;
|
|
byte ret;
|
|
dataIn();
|
|
controlIn_SNES();
|
|
|
|
// Read register
|
|
ret = readBank_SV(0xC0, 0x0002);
|
|
|
|
// CE or OE must be toggled with each subsequent status read or the
|
|
// completion of a program or erase operation will not be evident.
|
|
while ((ret & 0x80) == 0x00) {
|
|
i++;
|
|
if (i > 10000) {
|
|
//timeout
|
|
break;
|
|
}
|
|
controlOut_SNES();
|
|
// Switch CS(PH3) High
|
|
PORTH |= (1 << 3);
|
|
// Leave CE high for at least 60ns
|
|
__asm__("nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t");
|
|
controlIn_SNES();
|
|
// Leave CE low for at least 50ns
|
|
__asm__("nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t"
|
|
"nop\n\t");
|
|
// Read register
|
|
ret = readBank_SV(0xC0, 0x0002);
|
|
}
|
|
// Switch to write
|
|
dataOut();
|
|
controlOut_SNES();
|
|
}
|
|
|
|
|
|
void eraseAll_SV(void) {
|
|
dataOut();
|
|
controlOut_SNES();
|
|
writeBank_SV(0xC0, 0x0000, 0x50); //Clear Status Registers
|
|
writeBank_SV(0xC0, 0x0000, 0x71); //Status Mode
|
|
supplyCheck_SV();
|
|
writeBank_SV(0xC0, 0x0000, 0xA7); //Chip Erase
|
|
writeBank_SV(0xC0, 0x0000, 0xD0); //Confirm
|
|
writeBank_SV(0xC0, 0x0000, 0x71); //Status Mode
|
|
eraseCheck_SV();
|
|
writeBank_SV(0xC0, 0x0000, 0xFF); //Teriminate
|
|
}
|
|
|
|
#endif
|
|
|
|
//******************************************
|
|
// End of File
|
|
//******************************************
|