mirror of
https://github.com/sanni/cartreader.git
synced 2024-11-27 23:14:14 +01:00
243 lines
4.8 KiB
C++
243 lines
4.8 KiB
C++
//******************************************
|
|
// NGP MODULE
|
|
//******************************************
|
|
|
|
#include "options.h"
|
|
#ifdef enable_NGP
|
|
|
|
static const char ngpMenuItem1[] PROGMEM = "Read Rom";
|
|
static const char ngpMenuItemReset[] PROGMEM = "Reset";
|
|
static const char* const menuOptionsNGP[] PROGMEM = {ngpMenuItem1, ngpMenuItemReset};
|
|
|
|
char ngpRomVersion[5];
|
|
|
|
void setup_NGP() {
|
|
// A0 - A7
|
|
DDRF = 0xff;
|
|
// A8 - A15
|
|
DDRK = 0xff;
|
|
// A16 - A20
|
|
DDRL = 0xff;
|
|
|
|
// D0 - D7
|
|
DDRC = 0x00;
|
|
|
|
// controls
|
|
// /CE0: PH3
|
|
// /CE1: PH0
|
|
// /OE: PH6
|
|
// /WE: PH5
|
|
// PWR: PH4
|
|
DDRH |= ((1 << 0) | (1 << 3) | (1 << 5) | (1 << 6));
|
|
DDRH &= ~(1 << 4);
|
|
|
|
PORTH |= ((1 << 0) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6));
|
|
|
|
if (getCartInfo_NGP())
|
|
{
|
|
showCartInfo_NGP();
|
|
}
|
|
else
|
|
{
|
|
println_Msg(F("NeoGeo Pocket"));
|
|
println_Msg(F(""));
|
|
println_Msg(F(""));
|
|
println_Msg(F("Rom Size Error"));
|
|
println_Msg(F(""));
|
|
println_Msg(F("Press Button..."));
|
|
display_Update();
|
|
wait();
|
|
}
|
|
}
|
|
|
|
void ngpMenu() {
|
|
|
|
uint8_t mainMenu;
|
|
|
|
convertPgm(menuOptionsNGP, 2);
|
|
mainMenu = question_box(F("NGP Menu"), menuOptions, 2, 0);
|
|
|
|
switch (mainMenu)
|
|
{
|
|
case 0:
|
|
sd.chdir("/");
|
|
readROM_NGP(filePath, FILEPATH_LENGTH);
|
|
sd.chdir("/");
|
|
break;
|
|
|
|
case 1:
|
|
resetArduino();
|
|
break;
|
|
}
|
|
|
|
println_Msg(F(""));
|
|
println_Msg(F("Press Button..."));
|
|
display_Update();
|
|
wait();
|
|
}
|
|
|
|
bool getCartInfo_NGP() {
|
|
uint8_t *tmp;
|
|
|
|
// enter autoselect mode
|
|
dataOut();
|
|
writeByte_NGP(0x555, 0xaa);
|
|
writeByte_NGP(0x2aa, 0x55);
|
|
writeByte_NGP(0x555, 0x90);
|
|
|
|
dataIn();
|
|
|
|
cartSize = 0;
|
|
tmp = (uint8_t*)&romSize;
|
|
*(tmp + 0) = readByte_NGP(0);
|
|
*(tmp + 1) = readByte_NGP(1);
|
|
|
|
switch (romSize)
|
|
{
|
|
case 0x2c98:
|
|
cartSize = 1048576;
|
|
break;
|
|
}
|
|
|
|
// reset to read mode
|
|
dataOut();
|
|
writeByte_NGP(0x000000, 0xf0);
|
|
|
|
if (cartSize == 0)
|
|
return false;
|
|
|
|
dataIn();
|
|
|
|
for (uint32_t addr = 0; addr < 28; addr++)
|
|
sdBuffer[addr] = readByte_NGP(addr);
|
|
|
|
if (memcmp_P(sdBuffer, PSTR("COPYRIGHT BY SNK CORPORATION"), 28) != 0 && memcmp_P(sdBuffer, PSTR(" LICENSED BY SNK CORPORATION"), 28) != 0)
|
|
return false;
|
|
|
|
snprintf(cartID, 5, "%02X%02X", readByte_NGP(0x000021), readByte_NGP(0x000020));
|
|
snprintf(ngpRomVersion, 5, "%02X%02X", readByte_NGP(0x000023), readByte_NGP(0x000022));
|
|
|
|
for (uint32_t i = 0; i < 17; i++)
|
|
romName[i] = readByte_NGP(0x24 + i);
|
|
|
|
return true;
|
|
}
|
|
|
|
void showCartInfo_NGP() {
|
|
display_Clear();
|
|
|
|
println_Msg(F("NGP Cart Info"));
|
|
|
|
print_Msg(F("Game: "));
|
|
println_Msg(romName);
|
|
|
|
print_Msg(F("GameID: "));
|
|
println_Msg(cartID);
|
|
|
|
print_Msg(F("Rom Size: "));
|
|
print_Msg((cartSize >> 17));
|
|
println_Msg(F(" Mb"));
|
|
|
|
print_Msg(F("Version: "));
|
|
println_Msg(ngpRomVersion);
|
|
|
|
println_Msg(F(""));
|
|
println_Msg(F("Press Button..."));
|
|
display_Update();
|
|
wait();
|
|
}
|
|
|
|
void readROM_NGP(char *outPathBuf, size_t bufferSize) {
|
|
// generate fullname of rom file
|
|
snprintf(fileName, FILENAME_LENGTH, "%s.ngp", romName);
|
|
|
|
// create a new folder for storing rom file
|
|
EEPROM_readAnything(0, foldern);
|
|
snprintf(folder, sizeof(folder), "NGP/ROM/%s/%d", romName, foldern);
|
|
sd.mkdir(folder, true);
|
|
sd.chdir(folder);
|
|
|
|
// filling output file path to buffer
|
|
if (outPathBuf != NULL && bufferSize > 0)
|
|
snprintf(outPathBuf, bufferSize, "%s/%s", folder, fileName);
|
|
|
|
display_Clear();
|
|
print_Msg(F("Saving to "));
|
|
print_Msg(folder);
|
|
println_Msg(F("/..."));
|
|
display_Update();
|
|
|
|
// open file on sdcard
|
|
if (!myFile.open(fileName, O_RDWR | O_CREAT))
|
|
print_Error(F("Can't create file on SD"), true);
|
|
|
|
// write new folder number back to EEPROM
|
|
foldern++;
|
|
EEPROM_writeAnything(0, foldern);
|
|
|
|
// back to read mode
|
|
dataOut();
|
|
writeByte_NGP(0x0, 0xf0);
|
|
|
|
dataIn();
|
|
for (uint32_t addr = 0; addr < cartSize; addr += 512) {
|
|
|
|
// blink LED
|
|
if ((addr & ((1 << 14) - 1)) == 0)
|
|
PORTB ^= (1 << 4);
|
|
|
|
for (uint32_t i = 0; i < 512; i++)
|
|
sdBuffer[i] = readByte_NGP(addr + i);
|
|
|
|
myFile.write(sdBuffer, 512);
|
|
}
|
|
|
|
myFile.close();
|
|
}
|
|
|
|
|
|
void writeByte_NGP(uint32_t addr, uint8_t data) {
|
|
PORTF = addr & 0xff;
|
|
PORTK = (addr >> 8) & 0xff;
|
|
PORTL = (addr >> 16) & 0x1f;
|
|
PORTC = data;
|
|
|
|
// which chip to select
|
|
// 0x000000 - 0x1fffff -> /CE0
|
|
// 0x200000 - 0x3fffff -> /CE1
|
|
data = (addr & 0x00200000 ? (1 << 0) : (1 << 3));
|
|
|
|
PORTH &= ~data;
|
|
PORTH &= ~(1 << 5);
|
|
NOP;
|
|
|
|
PORTH |= data;
|
|
PORTH |= (1 << 5);
|
|
NOP; NOP;
|
|
}
|
|
|
|
uint8_t readByte_NGP(uint32_t addr) {
|
|
uint8_t data;
|
|
|
|
PORTF = addr & 0xff;
|
|
PORTK = (addr >> 8) & 0xff;
|
|
PORTL = (addr >> 16) & 0x1f;
|
|
|
|
// which chip to select
|
|
// 0x000000 - 0x1fffff -> /CE0
|
|
// 0x200000 - 0x3fffff -> /CE1
|
|
data = (addr & 0x00200000 ? (1 << 0) : (1 << 3));
|
|
|
|
PORTH &= ~data;
|
|
PORTH &= ~(1 << 6);
|
|
NOP; NOP; NOP;
|
|
|
|
data = PINC;
|
|
|
|
PORTH |= data;
|
|
PORTH |= (1 << 6);
|
|
|
|
return data;
|
|
}
|
|
|
|
#endif |