mirror of
https://github.com/sanni/cartreader.git
synced 2024-11-15 01:15:06 +01:00
Support Flash repro A29040B
This commit is contained in:
parent
2e5aa97bef
commit
0cfb7f46ed
@ -244,7 +244,7 @@ uint8_t ramsize;
|
|||||||
static const char nesMenuItem1[] PROGMEM = "Read iNES Rom";
|
static const char nesMenuItem1[] PROGMEM = "Read iNES Rom";
|
||||||
static const char nesMenuItem2[] PROGMEM = "Read PRG/CHR";
|
static const char nesMenuItem2[] PROGMEM = "Read PRG/CHR";
|
||||||
static const char nesMenuItem5[] PROGMEM = "Change Mapper";
|
static const char nesMenuItem5[] PROGMEM = "Change Mapper";
|
||||||
static const char nesMenuItem6[] PROGMEM = "Flash NESMaker";
|
static const char nesMenuItem6[] PROGMEM = "Flash Repro";
|
||||||
static const char* const menuOptionsNES[] PROGMEM = { nesMenuItem1, nesMenuItem2, FSTRING_READ_SAVE, FSTRING_WRITE_SAVE, nesMenuItem5, nesMenuItem6, FSTRING_RESET };
|
static const char* const menuOptionsNES[] PROGMEM = { nesMenuItem1, nesMenuItem2, FSTRING_READ_SAVE, FSTRING_WRITE_SAVE, nesMenuItem5, nesMenuItem6, FSTRING_RESET };
|
||||||
|
|
||||||
// NES chips menu
|
// NES chips menu
|
||||||
@ -254,6 +254,12 @@ static const char nesChipsMenuItem3[] PROGMEM = "Read only CHR";
|
|||||||
static const char nesChipsMenuItem4[] PROGMEM = "Back";
|
static const char nesChipsMenuItem4[] PROGMEM = "Back";
|
||||||
static const char* const menuOptionsNESChips[] PROGMEM = { nesChipsMenuItem1, nesChipsMenuItem2, nesChipsMenuItem3, nesChipsMenuItem4 };
|
static const char* const menuOptionsNESChips[] PROGMEM = { nesChipsMenuItem1, nesChipsMenuItem2, nesChipsMenuItem3, nesChipsMenuItem4 };
|
||||||
|
|
||||||
|
// Repro Writer Menu
|
||||||
|
static const char nesFlashMenuItem1[] PROGMEM = "Flash NesMaker";
|
||||||
|
static const char nesFlashMenuItem2[] PROGMEM = "Flash A29040B-MAPPER0";
|
||||||
|
static const char nesFlashMenuItem3[] PROGMEM = "Back";
|
||||||
|
static const char* const menuOptionsNESFlash[] PROGMEM = { nesFlashMenuItem1, nesFlashMenuItem2, nesFlashMenuItem3 };
|
||||||
|
|
||||||
// NES start menu
|
// NES start menu
|
||||||
void nesMenu() {
|
void nesMenu() {
|
||||||
unsigned char answer;
|
unsigned char answer;
|
||||||
@ -324,20 +330,7 @@ void nesMenu() {
|
|||||||
|
|
||||||
// Write FLASH
|
// Write FLASH
|
||||||
case 5:
|
case 5:
|
||||||
if (mapper == 30) {
|
nesFlashMenu();
|
||||||
writeFLASH();
|
|
||||||
resetROM();
|
|
||||||
} else {
|
|
||||||
display_Clear();
|
|
||||||
println_Msg(FS(string_error5));
|
|
||||||
println_Msg(F("Can't write to this cartridge"));
|
|
||||||
println_Msg(FS(FSTRING_EMPTY));
|
|
||||||
// Prints string out of the common strings array either with or without newline
|
|
||||||
print_STR(press_button_STR, 1);
|
|
||||||
display_Update();
|
|
||||||
}
|
|
||||||
wait();
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Reset
|
// Reset
|
||||||
case 6:
|
case 6:
|
||||||
@ -401,6 +394,53 @@ void nesChipMenu() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nesFlashMenu() {
|
||||||
|
// create menu with title "Select NES Flash Repro" and 3 options to choose from
|
||||||
|
convertPgm(menuOptionsNESFlash, 3);
|
||||||
|
unsigned char answer = question_box(F("Select Flash Writer"), menuOptions, 3, 0);
|
||||||
|
switch (answer) {
|
||||||
|
case 0:
|
||||||
|
|
||||||
|
if (mapper == 30) {
|
||||||
|
writeFLASH();
|
||||||
|
resetROM();
|
||||||
|
} else {
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(FS(string_error5));
|
||||||
|
println_Msg(F("Can't write to this cartridge"));
|
||||||
|
println_Msg(FS(FSTRING_EMPTY));
|
||||||
|
// Prints string out of the common strings array either with or without newline
|
||||||
|
print_STR(press_button_STR, 1);
|
||||||
|
display_Update();
|
||||||
|
}
|
||||||
|
wait();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (mapper == 0) {
|
||||||
|
display_Clear();
|
||||||
|
A29040B_writeFLASH();
|
||||||
|
display_Update();
|
||||||
|
wait();
|
||||||
|
} else {
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(FS(string_error5));
|
||||||
|
println_Msg(F("Can't write to this cartridge"));
|
||||||
|
println_Msg(mapper);
|
||||||
|
// Prints string out of the common strings array either with or without newline
|
||||||
|
print_STR(press_button_STR, 1);
|
||||||
|
display_Update();
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
// Return to Main Menu
|
||||||
|
case 2:
|
||||||
|
nesMenu();
|
||||||
|
wait();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************
|
/******************************************
|
||||||
Setup
|
Setup
|
||||||
*****************************************/
|
*****************************************/
|
||||||
@ -821,6 +861,30 @@ static void write_prg_byte(unsigned int address, uint8_t data) {
|
|||||||
// _delay_us(1);
|
// _delay_us(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void write_chr_byte(unsigned int address, uint8_t data)
|
||||||
|
{
|
||||||
|
PHI2_LOW;
|
||||||
|
ROMSEL_HI;
|
||||||
|
MODE_WRITE;
|
||||||
|
PORTK = data;
|
||||||
|
set_address(address); // PHI2 low, ROMSEL always HIGH
|
||||||
|
_delay_us(1);
|
||||||
|
|
||||||
|
CHR_WRITE_LOW;
|
||||||
|
|
||||||
|
_delay_us(1); // WRITING
|
||||||
|
|
||||||
|
CHR_WRITE_HI;
|
||||||
|
|
||||||
|
_delay_us(1);
|
||||||
|
|
||||||
|
MODE_READ;
|
||||||
|
set_address(0);
|
||||||
|
PHI2_HI;
|
||||||
|
|
||||||
|
//_delay_us(1);
|
||||||
|
}
|
||||||
|
|
||||||
void resetROM() {
|
void resetROM() {
|
||||||
set_address(0);
|
set_address(0);
|
||||||
PHI2_HI;
|
PHI2_HI;
|
||||||
@ -4265,6 +4329,302 @@ void writeFLASH() {
|
|||||||
filePath[0] = '\0'; // Reset filePath
|
filePath[0] = '\0'; // Reset filePath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
A29040B Flash Cart [A29040B]
|
||||||
|
*****************************************/
|
||||||
|
|
||||||
|
// A29040B Software ID
|
||||||
|
void A29040B_ID() { // Read Flash ID
|
||||||
|
write_prg_byte(0x9555, 0xAA);
|
||||||
|
write_prg_byte(0xAAAA, 0x55);
|
||||||
|
write_prg_byte(0x9555, 0x90);
|
||||||
|
|
||||||
|
flashid = read_prg_byte(0x8000) << 8;
|
||||||
|
flashid |= read_prg_byte(0x8001);
|
||||||
|
sprintf(flashid_str, "%04X", flashid);
|
||||||
|
if (flashid == 0x3786) // A29040B
|
||||||
|
flashfound = 1;
|
||||||
|
|
||||||
|
A29040B_PRG_ResetFlash();
|
||||||
|
}
|
||||||
|
|
||||||
|
void A29040B_PRG_ResetFlash() { // Reset Flash
|
||||||
|
write_prg_byte(0x9555, 0xAA);
|
||||||
|
write_prg_byte(0xAAAA, 0x55);
|
||||||
|
write_prg_byte(0x9555, 0xF0); // Reset
|
||||||
|
delayMicroseconds(14); // Typical 14us
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void A29040B_PRG_Write(uint16_t address, uint8_t data) {
|
||||||
|
write_prg_byte(0x9555, 0xAA);
|
||||||
|
write_prg_byte(0xAAAA, 0x55);
|
||||||
|
write_prg_byte(0x9555, 0xA0);
|
||||||
|
write_prg_byte(address, data); // $8000-$BFFF
|
||||||
|
delayMicroseconds(20); // Typical 14us
|
||||||
|
}
|
||||||
|
|
||||||
|
void A29040B_PRG_SectorErase(uint16_t sec) {
|
||||||
|
if (flashfound) {
|
||||||
|
write_prg_byte(0x9555, 0xAA);
|
||||||
|
write_prg_byte(0xAAAA, 0x55);
|
||||||
|
write_prg_byte(0x9555, 0x80); //->setup
|
||||||
|
write_prg_byte(0x9555, 0xAA);
|
||||||
|
write_prg_byte(0xAAAA, 0x55);
|
||||||
|
write_prg_byte(sec, 0x30); //->erase
|
||||||
|
delay(1000); // WAIT MORE
|
||||||
|
} else {
|
||||||
|
println_Msg(F("FLASH NOT DETECTED OR SECTOR PROTECTED"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void A29040B_PRG_ChipErase() {
|
||||||
|
if (flashfound) {
|
||||||
|
write_prg_byte(0x9555, 0xAA);
|
||||||
|
write_prg_byte(0xAAAA, 0x55);
|
||||||
|
write_prg_byte(0x9555, 0x80); //->setup
|
||||||
|
write_prg_byte(0x9555, 0xAA);
|
||||||
|
write_prg_byte(0xAAAA, 0x55);
|
||||||
|
write_prg_byte(0x9555, 0x10); //->erase
|
||||||
|
delay(8000); // WAIT MORE
|
||||||
|
} else {
|
||||||
|
println_Msg(F("FLASH NOT DETECTED OR SECTOR PROTECTED"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHR ================================================
|
||||||
|
|
||||||
|
void A29040B_CHR_ResetFlash() { // Reset Flash
|
||||||
|
write_chr_byte(0x0555, 0xAA); // Original address for CHR
|
||||||
|
write_chr_byte(0x02AA, 0x55); // Original address for CHR
|
||||||
|
write_chr_byte(0x0555, 0xF0); // Reset command with original address
|
||||||
|
delayMicroseconds(14); // Typical 14us
|
||||||
|
}
|
||||||
|
|
||||||
|
void A29040B_CHR_Write(uint16_t address, uint8_t data) {
|
||||||
|
write_chr_byte(0x0555, 0xAA); // Original address for CHR
|
||||||
|
write_chr_byte(0x02AA, 0x55); // Original address for CHR
|
||||||
|
write_chr_byte(0x0555, 0xA0); // Program command with original address
|
||||||
|
write_chr_byte(address, data); // CHR address range (0x0000 - 0x1FFF)
|
||||||
|
delayMicroseconds(20); // Typical 14us
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void A29040B_CHR_SectorErase(uint16_t sec) {
|
||||||
|
if (flashfound) {
|
||||||
|
write_chr_byte(0x0555, 0xAA); // Original address for CHR
|
||||||
|
write_chr_byte(0x02AA, 0x55); // Original address for CHR
|
||||||
|
write_chr_byte(0x0555, 0x80); // Erase Setup with original address
|
||||||
|
write_chr_byte(0x0555, 0xAA); // Original address for CHR
|
||||||
|
write_chr_byte(0x02AA, 0x55); // Original address for CHR
|
||||||
|
write_chr_byte(sec, 0x30); // Sector Erase Command with sector address
|
||||||
|
delay(1000); // WAIT MORE
|
||||||
|
} else {
|
||||||
|
println_Msg(F("FLASH NOT DETECTED OR SECTOR PROTECTED"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void A29040B_CHR_ChipErase() {
|
||||||
|
if (flashfound) {
|
||||||
|
write_chr_byte(0x0555, 0xAA); // Original address for CHR
|
||||||
|
write_chr_byte(0x02AA, 0x55); // Original address for CHR
|
||||||
|
write_chr_byte(0x0555, 0x80); // Erase Setup with original address
|
||||||
|
write_chr_byte(0x0555, 0xAA); // Original address for CHR
|
||||||
|
write_chr_byte(0x02AA, 0x55); // Original address for CHR
|
||||||
|
write_chr_byte(0x0555, 0x10); // Chip Erase Command with original address
|
||||||
|
delay(8000); // WAIT MORE
|
||||||
|
} else {
|
||||||
|
println_Msg(F("FLASH NOT DETECTED OR SECTOR PROTECTED"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#define A29040B_TITLE "FLASH A29040B MAPPER 0"
|
||||||
|
void A29040B_writeFLASH() {
|
||||||
|
|
||||||
|
display_Clear();
|
||||||
|
A29040B_ID();
|
||||||
|
|
||||||
|
char data_str[10];
|
||||||
|
uint32_t prgSize = 0;
|
||||||
|
uint32_t chrSize = 0;
|
||||||
|
|
||||||
|
if (!flashfound) {
|
||||||
|
rgbLed(red_color);
|
||||||
|
println_Msg(F(A29040B_TITLE));
|
||||||
|
println_Msg(FS(FSTRING_EMPTY));
|
||||||
|
print_Msg(F("Flash ID: "));
|
||||||
|
println_Msg(flashid_str);
|
||||||
|
println_Msg(FS(FSTRING_EMPTY));
|
||||||
|
println_Msg(F("FLASH NOT FOUND"));
|
||||||
|
display_Update();
|
||||||
|
wait();
|
||||||
|
} else {
|
||||||
|
println_Msg(F(A29040B_TITLE));
|
||||||
|
println_Msg(FS(FSTRING_EMPTY));
|
||||||
|
print_Msg(F("Flash ID: "));
|
||||||
|
println_Msg(flashid_str);
|
||||||
|
println_Msg(FS(FSTRING_EMPTY));
|
||||||
|
println_Msg(F("Flash Found"));
|
||||||
|
println_Msg(FS(FSTRING_EMPTY));
|
||||||
|
display_Update();
|
||||||
|
delay(3000);
|
||||||
|
fileBrowser(F("Select FLASH File"));
|
||||||
|
sd.chdir();
|
||||||
|
sprintf(filePath, "%s/%s", filePath, fileName);
|
||||||
|
|
||||||
|
if (myFile.open(filePath, O_READ)) {
|
||||||
|
// Step 1: Read the header and extract PRG and CHR sizes
|
||||||
|
uint8_t header[16];
|
||||||
|
myFile.read(header, 16); // Read the 16-byte header
|
||||||
|
uint32_t prgAddress = 0x8000;
|
||||||
|
|
||||||
|
prgSize = (uint32_t)header[4] * 16384; // PRG size in bytes (header[4] gives size in 16 KB units)
|
||||||
|
chrSize = (uint32_t)header[5] * 8192; // CHR size in bytes (header[5] gives size in 8 KB units)
|
||||||
|
|
||||||
|
// Output the sizes for verification
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F(A29040B_TITLE));
|
||||||
|
println_Msg(FS(FSTRING_EMPTY));
|
||||||
|
println_Msg(F("PRG Size:"));
|
||||||
|
sprintf(data_str, "%lu", prgSize);
|
||||||
|
println_Msg(data_str);
|
||||||
|
|
||||||
|
println_Msg(F("CHR Size:"));
|
||||||
|
sprintf(data_str, "%lu", chrSize);
|
||||||
|
println_Msg(data_str);
|
||||||
|
display_Update();
|
||||||
|
delay(3000);
|
||||||
|
|
||||||
|
// Step 2: Erase the entire PRG space
|
||||||
|
rgbLed(red_color);
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F(A29040B_TITLE));
|
||||||
|
println_Msg(FS(FSTRING_EMPTY));
|
||||||
|
A29040B_PRG_ResetFlash();
|
||||||
|
println_Msg(F("ERASING PRG..."));
|
||||||
|
display_Update();
|
||||||
|
A29040B_PRG_ChipErase();
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t readByte = read_prg_byte(prgAddress);
|
||||||
|
if (readByte != 0xFF) {
|
||||||
|
println_Msg(F("Erase Error!"));
|
||||||
|
} else {
|
||||||
|
println_Msg(F("Erase OK!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
display_Update();
|
||||||
|
|
||||||
|
// Verify that the first byte has been erased
|
||||||
|
uint8_t erase_check = read_prg_byte(0x8000);
|
||||||
|
if (erase_check != 0xFF) {
|
||||||
|
println_Msg(F("SECTOR NOT ERASED"));
|
||||||
|
sprintf(data_str, "%02X", erase_check);
|
||||||
|
println_Msg(data_str);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(18); // Adjust delay as needed
|
||||||
|
|
||||||
|
rgbLed(red_color);
|
||||||
|
println_Msg(FS(FSTRING_EMPTY));
|
||||||
|
println_Msg(F("Writing PRG Data..."));
|
||||||
|
display_Update();
|
||||||
|
|
||||||
|
A29040B_PRG_ResetFlash();
|
||||||
|
|
||||||
|
// Step 3: Write PRG data
|
||||||
|
uint32_t bytesProcessed = 0;
|
||||||
|
uint8_t buffer[512];
|
||||||
|
myFile.seek(16); // Skip header to start of PRG data
|
||||||
|
|
||||||
|
while (bytesProcessed < prgSize) {
|
||||||
|
int bytesRead = myFile.read(buffer, sizeof(buffer));
|
||||||
|
if (bytesRead <= 0) break;
|
||||||
|
|
||||||
|
for (int i = 0; i < bytesRead; i++) {
|
||||||
|
A29040B_PRG_Write(prgAddress++, buffer[i]);
|
||||||
|
delayMicroseconds(14); // Typical 14us
|
||||||
|
|
||||||
|
uint8_t readByte = read_prg_byte(prgAddress - 1);
|
||||||
|
delayMicroseconds(14); // Typical 14us
|
||||||
|
if (readByte != buffer[i]) {
|
||||||
|
println_Msg(F("Write Error!"));
|
||||||
|
sprintf(data_str, "%02X", readByte);
|
||||||
|
println_Msg(data_str);
|
||||||
|
myFile.close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bytesProcessed += bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Erase and Write CHR data
|
||||||
|
A29040B_CHR_ResetFlash();
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F(A29040B_TITLE));
|
||||||
|
println_Msg(FS(FSTRING_EMPTY));
|
||||||
|
println_Msg(F("ERASING CHR..."));
|
||||||
|
display_Update();
|
||||||
|
A29040B_CHR_ChipErase();
|
||||||
|
delay(20);
|
||||||
|
display_Clear();
|
||||||
|
|
||||||
|
uint32_t chrAddress = 0x0000;
|
||||||
|
bytesProcessed = 0;
|
||||||
|
myFile.seek(16 + prgSize); // Seek to the start of CHR data
|
||||||
|
|
||||||
|
readByte = read_chr_byte(chrAddress);
|
||||||
|
if (readByte != 0xFF) {
|
||||||
|
println_Msg(F("Erase Error!"));
|
||||||
|
} else {
|
||||||
|
println_Msg(F("Erase OK!"));
|
||||||
|
}
|
||||||
|
display_Update();
|
||||||
|
|
||||||
|
println_Msg(F("Writing CHR Data..."));
|
||||||
|
display_Update();
|
||||||
|
|
||||||
|
|
||||||
|
while (bytesProcessed < chrSize) {
|
||||||
|
int bytesRead = myFile.read(buffer, sizeof(buffer));
|
||||||
|
if (bytesRead <= 0) break;
|
||||||
|
|
||||||
|
for (int i = 0; i < bytesRead; i++) {
|
||||||
|
A29040B_CHR_Write(chrAddress++, buffer[i]);
|
||||||
|
delayMicroseconds(14); // Typical 14us
|
||||||
|
|
||||||
|
uint8_t readByte = read_chr_byte(chrAddress - 1);
|
||||||
|
delayMicroseconds(14); // Typical 14us
|
||||||
|
if (readByte != buffer[i]) {
|
||||||
|
println_Msg(F("Write Error!"));
|
||||||
|
sprintf(data_str, "%02X", readByte);
|
||||||
|
println_Msg(data_str);
|
||||||
|
myFile.close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bytesProcessed += bytesRead;
|
||||||
|
}
|
||||||
|
delay(3000);
|
||||||
|
myFile.close();
|
||||||
|
rgbLed(green_color);
|
||||||
|
display_Clear();
|
||||||
|
println_Msg(F(A29040B_TITLE));
|
||||||
|
println_Msg(FS(FSTRING_EMPTY));
|
||||||
|
println_Msg(F("FLASH FILE WRITTEN!"));
|
||||||
|
display_Update();
|
||||||
|
} else {
|
||||||
|
rgbLed(red_color);
|
||||||
|
println_Msg(F("SD ERROR"));
|
||||||
|
display_Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
display_Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// avoid warnings
|
// avoid warnings
|
||||||
#undef MODE_READ
|
#undef MODE_READ
|
||||||
#undef MODE_WRITE
|
#undef MODE_WRITE
|
||||||
|
Loading…
Reference in New Issue
Block a user