V5.0: Add suport for NeoGeo Pocket

Many thanks to splash5
This commit is contained in:
sanni 2020-05-12 13:52:03 +02:00
parent 61ff6cff34
commit 615ef8d68c
6 changed files with 270 additions and 16 deletions

View File

@ -2,8 +2,8 @@
Cartridge Reader for Arduino Mega2560 Cartridge Reader for Arduino Mega2560
Author: sanni Author: sanni
Date: 20.04.2020 Date: 12.05.2020
Version: 4.9 Version: 5.0
SD lib: https://github.com/greiman/SdFat SD lib: https://github.com/greiman/SdFat
LCD lib: https://github.com/adafruit/Adafruit_SSD1306 LCD lib: https://github.com/adafruit/Adafruit_SSD1306
@ -38,12 +38,12 @@
rama - code speedup & improvements rama - code speedup & improvements
Gens-gs - Megadrive checksum Gens-gs - Megadrive checksum
Modman - N64 checksum comparison fix Modman - N64 checksum comparison fix
splash5 - EMS GB Smart cart support, Wonderswan module splash5 - EMS GB Smart cart support, Wonderswan module, NGP module
**********************************************************************************/ **********************************************************************************/
#include <SdFat.h> #include <SdFat.h>
char ver[5] = "4.9"; char ver[5] = "5.0";
/****************************************** /******************************************
Options Options
@ -155,6 +155,7 @@ typedef enum COLOR_T {
#define mode_GB_GBSmart_Flash 19 #define mode_GB_GBSmart_Flash 19
#define mode_GB_GBSmart_Game 20 #define mode_GB_GBSmart_Game 20
#define mode_WS 21 #define mode_WS 21
#define mode_NGP 22
// optimization-safe nop delay // optimization-safe nop delay
#define NOP __asm__ __volatile__ ("nop\n\t") #define NOP __asm__ __volatile__ ("nop\n\t")
@ -382,9 +383,10 @@ static const char addonsItem1[] PROGMEM = "NES/Famicom";
static const char addonsItem2[] PROGMEM = "Flashrom Programmer"; static const char addonsItem2[] PROGMEM = "Flashrom Programmer";
static const char addonsItem3[] PROGMEM = "PC Engine/TG16"; static const char addonsItem3[] PROGMEM = "PC Engine/TG16";
static const char addonsItem4[] PROGMEM = "Sega Master System"; static const char addonsItem4[] PROGMEM = "Sega Master System";
static const char addonsItem6[] PROGMEM = "WonderSwan"; static const char addonsItem5[] PROGMEM = "WonderSwan";
static const char addonsItem5[] PROGMEM = "Reset"; static const char addonsItem6[] PROGMEM = "NeoGeo Pocket";
static const char* const addonsOptions[] PROGMEM = {addonsItem1, addonsItem2, addonsItem3, addonsItem4, addonsItem6, addonsItem5}; static const char addonsItem7[] PROGMEM = "Reset";
static const char* const addonsOptions[] PROGMEM = {addonsItem1, addonsItem2, addonsItem3, addonsItem4, addonsItem5, addonsItem6, addonsItem7};
// Info Screen // Info Screen
void aboutScreen() { void aboutScreen() {
@ -479,11 +481,11 @@ void mainMenu() {
// Everything that needs an adapter // Everything that needs an adapter
void addonsMenu() { void addonsMenu() {
// create menu with title and 5 options to choose from // create menu with title and 7 options to choose from
unsigned char addonsMenu; unsigned char addonsMenu;
// Copy menuOptions out of progmem // Copy menuOptions out of progmem
convertPgm(addonsOptions, 6); convertPgm(addonsOptions, 7);
addonsMenu = question_box(F("Choose Adapter"), menuOptions, 6, 0); addonsMenu = question_box(F("Choose Adapter"), menuOptions, 7, 0);
// wait for user choice to come back from the question box menu // wait for user choice to come back from the question box menu
switch (addonsMenu) switch (addonsMenu)
@ -505,10 +507,20 @@ void addonsMenu() {
break; break;
case 4: case 4:
display_Clear();
display_Update();
setup_WS(); setup_WS();
mode = mode_WS;
break; break;
default: case 5:
display_Clear();
display_Update();
setup_NGP();
mode = mode_NGP;
break;
case 6:
resetArduino(); resetArduino();
break; break;
} }
@ -1509,6 +1521,9 @@ void loop() {
else if (mode == mode_WS) { else if (mode == mode_WS) {
wsMenu(); wsMenu();
} }
else if (mode == mode_NGP) {
ngpMenu();
}
else { else {
display_Clear(); display_Clear();
println_Msg(F("Menu Error")); println_Msg(F("Menu Error"));

238
Cart_Reader/NGP.ino Normal file
View File

@ -0,0 +1,238 @@
//******************************************
// NGP MODULE
//******************************************
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;
}

View File

@ -69,8 +69,6 @@ void setup_WS()
DDRG &= ~(1 << 5); DDRG &= ~(1 << 5);
PORTG |= (1 << 5); PORTG |= (1 << 5);
display_Clear();
// unlock MMC // unlock MMC
// if (!unlockMMC2003_WS()) // if (!unlockMMC2003_WS())
// print_Error(F("Can't initial MMC"), true); // print_Error(F("Can't initial MMC"), true);
@ -78,8 +76,8 @@ void setup_WS()
// if (getCartInfo_WS() != 0xea) // if (getCartInfo_WS() != 0xea)
// print_Error(F("Rom header read error"), true); // print_Error(F("Rom header read error"), true);
display.println("Initializing..."); println_Msg(F("Initializing..."));
display.display(); display_Update();
do { do {
unlockMMC2003_WS(); unlockMMC2003_WS();
@ -89,7 +87,6 @@ void setup_WS()
getCartInfo_WS(); getCartInfo_WS();
showCartInfo_WS(); showCartInfo_WS();
mode = mode_WS;
} }
boolean headerCheck() { boolean headerCheck() {

View File

@ -14,6 +14,10 @@
![image](https://dl.dropboxusercontent.com/s/755249v8smcuoft/wonderswan_adapter.png?dl=1) ![image](https://dl.dropboxusercontent.com/s/755249v8smcuoft/wonderswan_adapter.png?dl=1)
#### ngp_adapter.zip is an add-on for reading NeoGeo Pocket carts. [PCB thickness needs to be changed to 1.2mm](https://dl.dropboxusercontent.com/s/755249v8smcuoft/wonderswan_adapter.png?dl=1), this is very important or else it won't fit into the SNES slot.
![image](https://dl.dropboxusercontent.com/s/yvutwme8n7d4tiy/ngp_adapter.png?dl=1)
#### flash_adapter.zip is an add-on for writing flashroms like the 29F032, 29L3211, 29LV160, [PCB thickness needs to be changed to 1.2mm](https://dl.dropboxusercontent.com/s/va1c72073cqfy90/pcb12.jpg?dl=1), this is very important or else it won't fit into the SNES slot. #### flash_adapter.zip is an add-on for writing flashroms like the 29F032, 29L3211, 29LV160, [PCB thickness needs to be changed to 1.2mm](https://dl.dropboxusercontent.com/s/va1c72073cqfy90/pcb12.jpg?dl=1), this is very important or else it won't fit into the SNES slot.
![image](https://dl.dropboxusercontent.com/s/afrfmiuwvmvg9px/flash_adapter.png?dl=1) ![image](https://dl.dropboxusercontent.com/s/afrfmiuwvmvg9px/flash_adapter.png?dl=1)

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB