mirror of
https://github.com/sanni/cartreader.git
synced 2024-12-30 23:11:57 +01:00
d6dd621aa9
Added support for the Hudson Soft Bee Pack and Bee Cards. Requires a Hudson Soft Bee Pack inserted into the MSX Adapter. Be sure to fully insert the Bee Card into the Bee Pack. Select Mapper 14 "Hudson Soft Bee Pack" and set the ROM size (16K/32K).
1306 lines
36 KiB
C++
1306 lines
36 KiB
C++
//******************************************
|
|
// MSX COMPUTER MODULE
|
|
//******************************************
|
|
#ifdef ENABLE_MSX
|
|
// MSX
|
|
// Cartridge Pinout
|
|
// 50P 2.54mm pitch connector
|
|
//
|
|
// FRONT BACK
|
|
// SIDE SIDE
|
|
// +-------+
|
|
// /CS2 -| 2 1 |- /CS1
|
|
// /SLTSL -| 4 3 |- /CS12
|
|
// /RFSH -| 6 5 |- RSV(NC)
|
|
// /INT -| 8 7 |- /WAIT
|
|
// /BUSDIR -| 10 9 |- /M1
|
|
// /MERQ -| 12 11 |- /IORQ
|
|
// /RD -| 14 13 |- /WR
|
|
// RSV(NC) -| 16 15 |- /RESET
|
|
// A15 -| 18 17 |- A9
|
|
// A10 -| 20 19 |- A11
|
|
// A6 -| 22 21 |- A7
|
|
// A8 -| 24 23 |- A12
|
|
// A13-| 26 25 |- A14
|
|
// A0 -| 28 27 |- A1
|
|
// A2 -| 30 29 |- A3
|
|
// A4 -| 32 31 |- A5
|
|
// D0 -| 34 33 |- D1
|
|
// D2 -| 36 35 |- D3
|
|
// D4 -| 38 37 |- D5
|
|
// D6 -| 40 39 |- D7
|
|
// CLOCK -| 42 41 |- GND
|
|
// SW1 -| 44 43 |- GND
|
|
// SW2 -| 46 45 |- +5V
|
|
// +12V -| 48 47 |- +5V
|
|
// -12V -| 50 49 |- SOUNDIN
|
|
// +-------+
|
|
//
|
|
// BACK
|
|
// +----------------------------------------------------------------------------+
|
|
// | 49 47 45 43 41 39 37 35 33 31 29 27 25 23 21 19 17 15 13 11 9 7 5 3 1 |
|
|
// LEFT | | RIGHT
|
|
// | 50 48 46 44 42 40 38 36 34 32 30 28 26 24 22 20 18 16 14 12 10 8 6 4 2 |
|
|
// +----------------------------------------------------------------------------+
|
|
// FRONT
|
|
//
|
|
// CONTROL PINS:
|
|
// /RESET(PH0) - SNES RESET
|
|
// CLOCK(PH1) - SNES CPUCLK
|
|
// /SLTSL(PH3) - SNES /CS
|
|
// /MERQ(PH4) - SNES /IRQ
|
|
// /WR(PH5) - SNES /WR
|
|
// /RD(PH6) - SNES /RD
|
|
// /CS1(PL0) - SNES A16
|
|
// /CS2(PL1) - SNES A17
|
|
// /CS12(PL2) - SNES A18
|
|
|
|
//******************************************
|
|
// Defines
|
|
//******************************************
|
|
#define CS1_DISABLE PORTL |= (1 << 0) // ROM SELECT 4000-7FFF
|
|
#define CS1_ENABLE PORTL &= ~(1 << 0)
|
|
#define CS2_DISABLE PORTL |= (1 << 1) // ROM SELECT 8000-BFFF
|
|
#define CS2_ENABLE PORTL &= ~(1 << 1)
|
|
#define CS12_DISABLE PORTL |= (1 << 2) // ROM SELECT 4000-BFFF
|
|
#define CS12_ENABLE PORTL &= ~(1 << 2)
|
|
#define MERQ_DISABLE PORTH |= (1 << 4)
|
|
#define MERQ_ENABLE PORTH &= ~(1 << 4)
|
|
|
|
//******************************************
|
|
// Supported Mappers
|
|
//******************************************
|
|
// Supported Mapper Array
|
|
// Format = {msxmapper,msxlo,msxhi,msxramlo,msxramhi}
|
|
static const byte PROGMEM msxmapsize[] = {
|
|
0, 1, 4, 0, 0, // No Mapper
|
|
1, 4, 7, 0, 2, // ASCII8 [sram r/w] 2K (Dires), 8K (Xanadu/Wizardry)
|
|
2, 4, 8, 0, 2, // ASCII16 [sram r/w] 2K (Daisenryaku/Hydlide 2), 8K (A-Train)
|
|
3, 4, 4, 0, 0, // Cross Blaim (db-Soft) 64K
|
|
4, 5, 5, 2, 2, // Game Master 2 128K [sram r/w] 8K
|
|
5, 8, 8, 3, 3, // Halnote (HAL) 1024K [sram r/w] 16K
|
|
6, 4, 4, 0, 0, // Harry Fox (Micro Cabin) 64K
|
|
7, 6, 8, 2, 4, // Koei [sram r/w] 8K (Nobunaga no Yabou - Zenkoku Ban), 32K (Sangokushi II)
|
|
8, 4, 8, 0, 0, // Konami without SCC "Konami4"
|
|
9, 5, 8, 0, 0, // Konami with SCC "Konami5"
|
|
10, 4, 4, 0, 0, // MSX-DOS2 64K
|
|
11, 0, 4, 2, 2, // PAC 0K/FM-PAC 64K [sram r/w] 8K
|
|
12, 7, 7, 0, 0, // R-Type 384K
|
|
13, 5, 5, 0, 0, // Super Lode Runner (Irem) 128K
|
|
14, 2, 3, 0, 0, // Hudson Soft Bee Pack
|
|
};
|
|
|
|
// MSX1 = 8,16,32,128,256
|
|
// MSX2 = 32,64,128,256,512,1024
|
|
int MSX[] = { 0, 8, 16, 32, 64, 128, 256, 512, 1024 };
|
|
byte msxlo = 0; // Lowest Entry
|
|
byte msxhi = 8; // Highest Entry
|
|
|
|
byte MSXRAM[] = { 0, 2, 8, 16, 32 };
|
|
byte msxramlo = 0; // Lowest Entry
|
|
byte msxramhi = 4; // Highest Entry
|
|
|
|
byte msxmapcount = 15; // (sizeof(mapsize)/sizeof(mapsize[0])) / 5;
|
|
boolean msxmapfound = false;
|
|
byte msxmapselect;
|
|
int msxindex;
|
|
|
|
byte msxmapper;
|
|
byte msxsize;
|
|
byte msxramsize;
|
|
uint8_t msxbanks;
|
|
byte chipselect;
|
|
|
|
boolean srambit5 = false;
|
|
boolean srambit6 = false;
|
|
boolean srambit7 = false;
|
|
|
|
// EEPROM MAPPING
|
|
// 07 MAPPER
|
|
// 08 ROM SIZE
|
|
// 10 RAM SIZE
|
|
|
|
//******************************************
|
|
// MENU
|
|
//******************************************
|
|
// Base Menu
|
|
static const char msxMenuItem2[] PROGMEM = "Read Cart";
|
|
static const char msxMenuItem3[] PROGMEM = "Set Mapper + Size";
|
|
static const char msxMenuItem4[] PROGMEM = "Write SRAM";
|
|
static const char* const menuOptionsMSX[] PROGMEM = { FSTRING_SELECT_CART, msxMenuItem2, msxMenuItem3, msxMenuItem4, FSTRING_RESET };
|
|
|
|
void msxMenu() {
|
|
convertPgm(menuOptionsMSX, 5);
|
|
uint8_t mainMenu = question_box(F("MSX MENU"), menuOptions, 5, 0);
|
|
|
|
switch (mainMenu) {
|
|
case 0:
|
|
// Select Cart
|
|
setCart_MSX();
|
|
setup_MSX();
|
|
break;
|
|
|
|
case 1:
|
|
// Read ROM + Read RAM
|
|
sd.chdir("/");
|
|
readROM_MSX();
|
|
readRAM_MSX();
|
|
sd.chdir("/");
|
|
break;
|
|
|
|
case 2:
|
|
// Set Mapper + Size
|
|
setMapper_MSX();
|
|
checkMapperSize_MSX();
|
|
setROMSize_MSX();
|
|
setRAMSize_MSX();
|
|
break;
|
|
|
|
case 3:
|
|
// Write RAM
|
|
writeRAM_MSX();
|
|
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 4:
|
|
// reset
|
|
resetArduino();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//******************************************
|
|
// SETUP
|
|
//******************************************
|
|
void setup_MSX() {
|
|
// Request 5V
|
|
setVoltage(VOLTS_SET_5V);
|
|
|
|
// Set Address Pins to Output
|
|
// MSX uses A0-A15
|
|
//A0-A7
|
|
DDRF = 0xFF;
|
|
//A8-A15
|
|
DDRK = 0xFF;
|
|
//A16-A23 - Use A16-A18 for /CS1, /CS2, /CS12
|
|
DDRL = 0xFF;
|
|
|
|
// Set Control Pins to Output
|
|
// /RST(PH0) CLOCK(PH1) /SLTSL(PH3) /MERQ(PH4) /WR(PH5) /RD(PH6)
|
|
DDRH |= (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
|
|
|
// Set TIME(PJ0) to Output (UNUSED)
|
|
DDRJ |= (1 << 0);
|
|
|
|
// Set Pins (D0-D7) to Input
|
|
DDRC = 0x00;
|
|
|
|
// Setting Control Pins to HIGH
|
|
// /RST(PH0) CLOCK(PH1) /SLTSL(PH3) /MERQ(PH4) /WR(PH5) /RD(PH6)
|
|
PORTH |= (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
|
|
|
|
// Set /SLTSL(PH3) to LOW
|
|
PORTH &= ~(1 << 3);
|
|
|
|
// Set /CS1, /CS2, /CS12 to HIGH
|
|
PORTL = 0xFF; // A16-A23 (A16 = /CS1, A17 = /CS2, A18 = /CS12)
|
|
|
|
// Set Unused Data Pins (PA0-PA7) to Output
|
|
DDRA = 0xFF;
|
|
|
|
// Set Unused Pins HIGH
|
|
PORTA = 0xFF;
|
|
PORTJ |= (1 << 0); // TIME(PJ0)
|
|
|
|
checkStatus_MSX();
|
|
strcpy(romName, "MSX");
|
|
|
|
mode = CORE_MSX;
|
|
}
|
|
|
|
//******************************************
|
|
// READ DATA
|
|
//******************************************
|
|
uint8_t readData_MSX(uint16_t addr) {
|
|
PORTF = addr & 0xFF; // A0-A7
|
|
PORTK = (addr >> 8) & 0xFF; // A8-A15
|
|
NOP;
|
|
NOP;
|
|
|
|
// Set /SLTSL(PH3) to LOW
|
|
// PORTH &= ~(1 << 3);
|
|
|
|
// Set /RD to LOW
|
|
PORTH &= ~(1 << 6); // /RD LOW (ENABLE)
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
|
|
uint8_t ret = PINC;
|
|
|
|
// Pull /RD to HIGH
|
|
PORTH |= (1 << 6); // /RD HIGH (DISABLE)
|
|
|
|
// Set /SLTSL(PH3) to HIGH
|
|
// PORTH |= (1 << 3);
|
|
// NOP; NOP;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void readSegment_MSX(uint32_t startaddr, uint32_t endaddr) {
|
|
for (uint32_t addr = startaddr; addr < endaddr; addr += 512) {
|
|
for (int w = 0; w < 512; w++) {
|
|
uint8_t temp = readData_MSX(addr + w);
|
|
sdBuffer[w] = temp;
|
|
}
|
|
myFile.write(sdBuffer, 512);
|
|
}
|
|
}
|
|
|
|
//******************************************
|
|
// WRITE DATA
|
|
//******************************************
|
|
void writeData_MSX(uint16_t addr, uint8_t data) {
|
|
PORTF = addr & 0xFF; // A0-A7
|
|
PORTK = (addr >> 8) & 0xFF; // A8-A15
|
|
NOP;
|
|
NOP;
|
|
|
|
DDRC = 0xFF; // Set to Output
|
|
PORTC = data;
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
|
|
// Set /WR(PH5) to LOW
|
|
PORTH &= ~(1 << 5);
|
|
NOP;
|
|
NOP;
|
|
NOP;
|
|
|
|
// Set /WR(PH5) to HIGH
|
|
PORTH |= (1 << 5);
|
|
NOP;
|
|
NOP;
|
|
|
|
DDRC = 0x00; // Reset to Input
|
|
}
|
|
|
|
//******************************************
|
|
// CS CODE
|
|
//******************************************
|
|
void setCS() // Set CS Line
|
|
{
|
|
chipselect = 0;
|
|
for (int x = 0; x < 4; x++) {
|
|
uint8_t check0 = readData_MSX(0x4000);
|
|
uint8_t check1 = readData_MSX(0x4001);
|
|
if ((check0 == 0x41) && (check1 == 0x42))
|
|
break;
|
|
chipselect++;
|
|
enableCS();
|
|
}
|
|
}
|
|
|
|
void checkCS() // Check for 2nd Chip
|
|
{
|
|
if (chipselect == 1) {
|
|
uint8_t check0 = readData_MSX(0x8000);
|
|
uint8_t check1 = readData_MSX(0x8001);
|
|
if ((check0 == 0x41) && (check1 == 0x42)) {
|
|
disableCS();
|
|
chipselect = 2;
|
|
enableCS();
|
|
}
|
|
}
|
|
}
|
|
|
|
void enableCS() {
|
|
if (chipselect == 1)
|
|
CS1_ENABLE;
|
|
else if (chipselect == 2)
|
|
CS2_ENABLE;
|
|
else if (chipselect == 3)
|
|
CS12_ENABLE;
|
|
}
|
|
|
|
void disableCS() {
|
|
CS1_DISABLE;
|
|
CS2_DISABLE;
|
|
CS12_DISABLE;
|
|
}
|
|
|
|
//******************************************
|
|
// READ ROM
|
|
//******************************************
|
|
void readROM_MSX() {
|
|
if (msxsize == 0) {
|
|
display_Clear();
|
|
println_Msg(F("ROM SIZE 0K"));
|
|
display_Update();
|
|
} else {
|
|
createFolderAndOpenFile("MSX", "ROM", romName, "bin");
|
|
|
|
switch (msxmapper) {
|
|
case 0: // No Mapper
|
|
disableCS();
|
|
if (msxsize == 4) // 64K
|
|
readSegment_MSX(0x0000, 0x4000); // +16K
|
|
setCS();
|
|
readSegment_MSX(0x4000, 0x6000); // 8K
|
|
if (msxsize > 1)
|
|
readSegment_MSX(0x6000, 0x8000); // +8K = 16K
|
|
if (msxsize > 2) {
|
|
checkCS(); // Check for 2nd Chip
|
|
readSegment_MSX(0x8000, 0xC000); // +16K = 32K
|
|
}
|
|
disableCS();
|
|
if (msxsize == 4) // 64K
|
|
readSegment_MSX(0xC000, 0x10000); // +16K
|
|
break;
|
|
|
|
case 1: // ASCII8 (64K/128K/256K/512K)
|
|
case 7: // Koei (256K/512K/1024K)
|
|
msxbanks = int_pow(2, msxsize - 1);
|
|
for (int x = 0; x < msxbanks; x += 4) {
|
|
writeData_MSX(0x6000, x);
|
|
readSegment_MSX(0x4000, 0x6000); // 8K Init Bank 0
|
|
writeData_MSX(0x6800, x + 1);
|
|
readSegment_MSX(0x6000, 0x8000); // 8K Init Bank 0
|
|
writeData_MSX(0x7000, x + 2);
|
|
readSegment_MSX(0x8000, 0xA000); // 8K Init Bank 0
|
|
writeData_MSX(0x7800, x + 3);
|
|
readSegment_MSX(0xA000, 0xC000); // 8K Init Bank 0
|
|
}
|
|
break;
|
|
|
|
case 2: // ASCII16 (64K/128K/256K/512K)
|
|
msxbanks = int_pow(2, msxsize - 1) / 2;
|
|
for (int x = 0; x < msxbanks; x += 2) {
|
|
writeData_MSX(0x6000, x);
|
|
readSegment_MSX(0x4000, 0x8000); // 16K Init Bank 0
|
|
writeData_MSX(0x7000, x + 1);
|
|
readSegment_MSX(0x8000, 0xC000); // 16K Init Bank 0
|
|
}
|
|
break;
|
|
|
|
case 3: // Cross Blaim (64K)
|
|
CS1_ENABLE;
|
|
readSegment_MSX(0x4000, 0x8000); // 16K Fixed Bank 0
|
|
CS1_DISABLE;
|
|
CS2_ENABLE;
|
|
for (int x = 1; x < 4; x++) {
|
|
writeData_MSX(0x4045, x);
|
|
readSegment_MSX(0x8000, 0xC000); // 16K Init Bank 1
|
|
}
|
|
CS2_DISABLE;
|
|
break;
|
|
|
|
case 4: // Game Master 2 (128K)
|
|
readSegment_MSX(0x4000, 0x6000); // 8K Fixed Bank 0
|
|
writeData_MSX(0x6000, 1); // Set Bank 1 for subsequent reads
|
|
readSegment_MSX(0x6000, 0x8000); // 8K Init Bank 1
|
|
for (int x = 2; x < 16; x += 2) {
|
|
writeData_MSX(0x8000, x);
|
|
readSegment_MSX(0x8000, 0xA000); // 8K
|
|
writeData_MSX(0xA000, x + 1);
|
|
readSegment_MSX(0xA000, 0xC000); // 8K
|
|
}
|
|
break;
|
|
|
|
case 5: // HAL Note (1024K)
|
|
MERQ_ENABLE;
|
|
// Dummy Read - Needed to prevent random bytes
|
|
for (int y = 0; y < 32; y++) {
|
|
writeData_MSX(0x4FFF, y);
|
|
for (uint32_t addr = 0x4000; addr < 0x6000; addr++)
|
|
readData_MSX(addr); // Dummy Read
|
|
}
|
|
// READ
|
|
for (int x = 0; x < 128; x++) {
|
|
writeData_MSX(0x4FFF, x);
|
|
readSegment_MSX(0x4000, 0x6000); // 8K Init Bank 0
|
|
}
|
|
MERQ_DISABLE;
|
|
break;
|
|
|
|
case 6: // Harry Fox (64K)
|
|
CS1_ENABLE;
|
|
writeData_MSX(0x6000, 0);
|
|
readSegment_MSX(0x4000, 0x8000); // 16K Init Bank 0
|
|
CS1_DISABLE;
|
|
|
|
CS2_ENABLE;
|
|
writeData_MSX(0x7000, 0);
|
|
readSegment_MSX(0x8000, 0xC000); // 16K Init Bank 1
|
|
CS2_DISABLE;
|
|
|
|
CS1_ENABLE;
|
|
writeData_MSX(0x6000, 1);
|
|
readSegment_MSX(0x4000, 0x8000); // 16K
|
|
CS1_DISABLE;
|
|
|
|
CS2_ENABLE;
|
|
writeData_MSX(0x7000, 1);
|
|
readSegment_MSX(0x8000, 0xC000); // 16K
|
|
CS2_DISABLE;
|
|
break;
|
|
|
|
case 8: // Konami MegaROM without SCC
|
|
readSegment_MSX(0x4000, 0x6000); // 8K Fixed Bank 0
|
|
readSegment_MSX(0x6000, 0x8000); // 8K Init Bank 1
|
|
msxbanks = int_pow(2, msxsize - 1);
|
|
for (int x = 2; x < msxbanks; x += 2) {
|
|
writeData_MSX(0x8000, x);
|
|
readSegment_MSX(0x8000, 0xA000); // 8K
|
|
writeData_MSX(0xA000, x + 1);
|
|
readSegment_MSX(0xA000, 0xC000); // 8K
|
|
}
|
|
break;
|
|
|
|
case 9: // Konami MegaROM with SCC
|
|
msxbanks = int_pow(2, msxsize - 1);
|
|
for (int x = 0; x < msxbanks; x += 4) {
|
|
writeData_MSX(0x5000, x);
|
|
readSegment_MSX(0x4000, 0x6000); // 8K
|
|
writeData_MSX(0x7000, x + 1);
|
|
readSegment_MSX(0x6000, 0x8000); // 8K
|
|
writeData_MSX(0x9000, x + 2);
|
|
readSegment_MSX(0x8000, 0xA000); // 8K
|
|
writeData_MSX(0xB000, x + 3);
|
|
readSegment_MSX(0xA000, 0xC000); // 8K
|
|
}
|
|
break;
|
|
|
|
case 10: // MSX-DOS2 (64K)
|
|
MERQ_ENABLE;
|
|
CS1_ENABLE;
|
|
for (int x = 0; x < 4; x++) {
|
|
writeData_MSX(0x7FFE, x); // Official v2.20
|
|
readSegment_MSX(0x4000, 0x8000); // 16K Init Bank 0
|
|
}
|
|
CS1_DISABLE;
|
|
MERQ_DISABLE;
|
|
break;
|
|
|
|
case 11: // FM-PAC (64K)
|
|
CS1_ENABLE;
|
|
for (int x = 0; x < 4; x++) {
|
|
writeData_MSX(0x7FF7, x);
|
|
readSegment_MSX(0x4000, 0x8000); // 16K
|
|
}
|
|
CS1_DISABLE;
|
|
break;
|
|
|
|
case 12: // R-TYPE (384K)
|
|
for (int x = 0; x < 23; x++) {
|
|
writeData_MSX(0x7000, x);
|
|
readSegment_MSX(0x8000, 0xC000); // 16K Init Bank 0
|
|
}
|
|
readSegment_MSX(0x4000, 0x8000); // 16K Init Bank 0F
|
|
break;
|
|
|
|
case 13: // Super Lode Runner (128K)
|
|
MERQ_ENABLE;
|
|
CS2_ENABLE;
|
|
for (int x = 0; x < 8; x++) {
|
|
writeData_MSX(0x0000, x);
|
|
readSegment_MSX(0x8000, 0xC000); // 16K Init Bank 0
|
|
}
|
|
CS2_DISABLE;
|
|
MERQ_DISABLE;
|
|
break;
|
|
|
|
case 14: // Hudson Soft Bee Pack (16K/32K)
|
|
CS1_ENABLE;
|
|
readSegment_MSX(0x4000,0x8000); // 16K Bank 0
|
|
CS1_DISABLE;
|
|
if (msxsize == 3) { // 32K
|
|
CS2_ENABLE;
|
|
readSegment_MSX(0x8000, 0xC000); // +16K Bank 1
|
|
CS2_DISABLE;
|
|
}
|
|
break;
|
|
}
|
|
myFile.close();
|
|
|
|
printCRC(fileName, NULL, 0);
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
//******************************************
|
|
// TEST/CHECK RAM
|
|
//******************************************
|
|
boolean testRAM(byte enable1, byte enable2) {
|
|
boolean testbit = false;
|
|
for (int x = 0; x < 0x10; x++) { // Test 16 Bytes
|
|
writeData_MSX(0x7000, enable1);
|
|
byte test1 = readData_MSX(0x8000 + x);
|
|
writeData_MSX(0x7000, enable2);
|
|
byte test2 = readData_MSX(0x8000 + x);
|
|
if (test1 == test2)
|
|
testbit = true;
|
|
else {
|
|
testbit = false;
|
|
break;
|
|
}
|
|
}
|
|
return testbit;
|
|
}
|
|
|
|
void checkRAM() {
|
|
// Test carts to identify SRAM Enable Bits (Bit 5/6/7)
|
|
// Bit 5 Test
|
|
srambit5 = testRAM(0x20, 0xB0);
|
|
if (!srambit5) {
|
|
// Bit 6 Test
|
|
srambit6 = testRAM(0x40, 0xC0);
|
|
if (!srambit6) {
|
|
// Bit 7 Test
|
|
srambit7 = testRAM(0x80, 0xF0);
|
|
if (!srambit7) {
|
|
display_Clear();
|
|
print_Error(F("SRAM FAILED - CHECK BATTERY"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//******************************************
|
|
// READ RAM
|
|
//******************************************
|
|
void readRAM_MSX() {
|
|
if (msxramsize == 0) {
|
|
display_Clear();
|
|
println_Msg(F("RAM SIZE 0K"));
|
|
display_Update();
|
|
} else {
|
|
strcpy(fileName, romName);
|
|
strcat(fileName, ".srm");
|
|
|
|
if (msxsize == 0) {
|
|
// create a new folder for storing ram file
|
|
EEPROM_readAnything(0, foldern);
|
|
sprintf(folder, "MSX/RAM/%d", foldern);
|
|
sd.mkdir(folder, true);
|
|
sd.chdir(folder);
|
|
}
|
|
|
|
display_Clear();
|
|
print_STR(saving_to_STR, 0);
|
|
print_Msg(folder);
|
|
println_Msg(F("/..."));
|
|
display_Update();
|
|
|
|
// open file on sdcard
|
|
if (!myFile.open(fileName, O_RDWR | O_CREAT))
|
|
print_FatalError(sd_error_STR);
|
|
|
|
if (msxsize == 0) {
|
|
// write new folder number back to EEPROM
|
|
foldern++;
|
|
EEPROM_writeAnything(0, foldern);
|
|
}
|
|
|
|
switch (msxmapper) {
|
|
case 1: // ASCII8 (2K/8K)
|
|
// ASCII8 carts use different SRAM Enable Bits
|
|
// Bit 4 (0x10) - Dires (2K)
|
|
// Bit 5 (0x20) - Xanadu
|
|
// Bit 7 (0x80) - Wizardry
|
|
if (msxramsize == 1) { // Dires (2K)
|
|
writeData_MSX(0x7000, 0x10); // Bit 4
|
|
readSegment_MSX(0x8000, 0x8800); // 2K
|
|
} else {
|
|
// Combine SRAM Enable Bit 5 + Bit 7 = 0xA0
|
|
writeData_MSX(0x7000, 0xA0); // Bit 5 + Bit 7
|
|
readSegment_MSX(0x8000, 0xA000); // 8K
|
|
}
|
|
writeData_MSX(0x7000, 0); // SRAM Disable
|
|
break;
|
|
|
|
case 2: // ASCII16 (2K/8K)
|
|
writeData_MSX(0x7000, 0x10); // Bit 4 Enable
|
|
readSegment_MSX(0x8000, 0x8800); // 2K - Hydlide 2 & Daisenryaku (2K)
|
|
if (msxramsize == 2) // A-Train (8K)
|
|
readSegment_MSX(0x8800, 0xA000); // +6K = 8K
|
|
writeData_MSX(0x7000, 0); // SRAM Disable
|
|
break;
|
|
|
|
case 4: // Game Master 2 (8K)
|
|
writeData_MSX(0xA000, 0x10); // Bit 4 Enable, Bit 5 SRAM Segment 0
|
|
readSegment_MSX(0xB000, 0xC000); // 4K
|
|
writeData_MSX(0xA000, 0x30); // Bit 4 Enable, Bit 5 SRAM Segment 1
|
|
readSegment_MSX(0xB000, 0xC000); // 4K
|
|
writeData_MSX(0xA000, 0); // SRAM Disable
|
|
break;
|
|
|
|
case 5: // HAL Note (16K)
|
|
MERQ_ENABLE;
|
|
writeData_MSX(0x4FFF, 0x80); // Bit 7 Enable
|
|
readSegment_MSX(0x0000, 0x4000); // 16K
|
|
writeData_MSX(0x4FFF, 0); // SRAM Disable
|
|
MERQ_DISABLE;
|
|
break;
|
|
|
|
case 7: // Koei (8K/32K) Nobunaga no Yabou - Zenkoku Ban (8K) & Sangokushi II (32K)
|
|
// Koei carts use different SRAM Enable Bits
|
|
// Bit 5 (0x20) - Nobunaga no Yabou - Zenkoku Ban MSX
|
|
// Bit 6 (0x40) - Nobunaga no Yabou - Zenkoku Ban MSX2
|
|
// Bit 7 (0x80) - Sangokushi II
|
|
// Use Combined Bits: 0xA0 (Bit 5 + Bit 7) and 0xC0 (Bit 6 + Bit 7)
|
|
// Note: Combined 0xE0 (Bit 5 + Bit 6 + Bit 7) does not work
|
|
checkRAM();
|
|
if (srambit6)
|
|
writeData_MSX(0x7000, 0xC0); // Bit 6 + Bit 7 Enable
|
|
else
|
|
writeData_MSX(0x7000, 0xA0); // Bit 5 + Bit 7 Enable
|
|
readSegment_MSX(0x8000, 0xA000); // 8K
|
|
if (msxramsize > 2) {
|
|
for (int x = 1; x < 4; x++) {
|
|
if (srambit6)
|
|
writeData_MSX(0x7000, 0xC0 + x); // Bit 6 + Bit 7 Enable
|
|
else
|
|
writeData_MSX(0x7000, 0xA0 + x); // Bit 5 + Bit 7 Enable
|
|
readSegment_MSX(0x8000, 0xA000); // 8K
|
|
}
|
|
}
|
|
writeData_MSX(0x7000, 0); // SRAM Disable
|
|
break;
|
|
|
|
case 11: // PAC/FM-PAC (8K)
|
|
writeData_MSX(0x5FFE, 0x4D); // SRAM Enable Step 1
|
|
writeData_MSX(0x5FFF, 0x69); // SRAM Enable Step 2
|
|
readSegment_MSX(0x4000, 0x6000); // 8K
|
|
writeData_MSX(0x5FFE, 0); // SRAM Disable
|
|
break;
|
|
}
|
|
myFile.close();
|
|
|
|
printCRC(fileName, NULL, 0);
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
//******************************************
|
|
// WRITE RAM
|
|
//******************************************
|
|
void writeRAM_MSX() {
|
|
display_Clear();
|
|
|
|
if (msxramsize == 0) {
|
|
print_Error(F("RAM SIZE 0K"));
|
|
} else {
|
|
fileBrowser(F("Select RAM File"));
|
|
sd.chdir();
|
|
sprintf(filePath, "%s/%s", filePath, fileName);
|
|
display_Clear();
|
|
println_Msg(F("Writing File: "));
|
|
println_Msg(filePath);
|
|
println_Msg(fileName);
|
|
display_Update();
|
|
|
|
//open file on sd card
|
|
if (myFile.open(filePath, O_READ)) {
|
|
|
|
switch (msxmapper) {
|
|
case 1: // ASCII8 (2K/8K)
|
|
for (word address = 0x0; address < (0x800 * msxramsize * msxramsize); address += 512) { // 2K/8K
|
|
if (msxramsize == 1)
|
|
writeData_MSX(0x7000, 0x10); // Bit 4
|
|
else
|
|
writeData_MSX(0x7000, 0xA0); // Bit 5 + Bit 7
|
|
myFile.read(sdBuffer, 512);
|
|
for (int x = 0; x < 512; x++) {
|
|
writeData_MSX(0x8000 + address + x, sdBuffer[x]);
|
|
}
|
|
}
|
|
writeData_MSX(0x7000, 0); // SRAM Disable
|
|
break;
|
|
|
|
case 2: // ASCII16 (2K/8K)
|
|
writeData_MSX(0x7000, 0x10); // Bit 4 Enable
|
|
for (word address = 0x0; address < (0x800 * msxramsize * msxramsize); address += 512) { // 2K/8K
|
|
myFile.read(sdBuffer, 512);
|
|
for (int x = 0; x < 512; x++) {
|
|
writeData_MSX(0x8000 + address + x, sdBuffer[x]);
|
|
}
|
|
}
|
|
writeData_MSX(0x7000, 0); // SRAM Disable
|
|
break;
|
|
|
|
case 4: // Game Master 2 (8K)
|
|
for (int y = 0; y < 2; y++) {
|
|
writeData_MSX(0xA000, 0x10 + (y * 0x20)); // Bit 4 Enable, Bit 5 SRAM Segment 0/1
|
|
for (word address = 0x0; address < 0x1000; address += 512) { // 4K
|
|
myFile.read(sdBuffer, 512);
|
|
for (int x = 0; x < 512; x++) {
|
|
writeData_MSX(0xB000 + address + x, sdBuffer[x]);
|
|
}
|
|
}
|
|
}
|
|
writeData_MSX(0xA000, 0); // SRAM Disable
|
|
break;
|
|
|
|
case 5: // HAL Note (16K)
|
|
MERQ_ENABLE;
|
|
writeData_MSX(0x4FFF, 0x80); // Bit 7 Enable
|
|
for (word address = 0; address < 0x4000; address += 512) { // 16K
|
|
myFile.read(sdBuffer, 512);
|
|
for (int x = 0; x < 512; x++) {
|
|
writeData_MSX(address + x, sdBuffer[x]);
|
|
}
|
|
}
|
|
writeData_MSX(0x4FFF, 0); // SRAM Disable
|
|
MERQ_DISABLE;
|
|
break;
|
|
|
|
case 7: // Koei (8K/32K)
|
|
checkRAM();
|
|
if (srambit6)
|
|
writeData_MSX(0x7000, 0xC0); // Bit 6 + Bit 7 Enable
|
|
else
|
|
writeData_MSX(0x7000, 0xA0); // Bit 5 + Bit 7 Enable
|
|
for (word address = 0x0; address < 0x2000; address += 512) { // 8K
|
|
myFile.read(sdBuffer, 512);
|
|
for (int x = 0; x < 512; x++) {
|
|
writeData_MSX(0x8000 + address + x, sdBuffer[x]);
|
|
}
|
|
}
|
|
if (msxramsize > 2) {
|
|
for (int y = 1; y < 4; y++) {
|
|
if (srambit6)
|
|
writeData_MSX(0x7000, 0xC0 + y); // Bit 6 + Bit 7 Enable
|
|
else
|
|
writeData_MSX(0x7000, 0xA0 + y); // Bit 5 + Bit 7 Enable
|
|
for (word address = 0x0; address < 0x2000; address += 512) { // 8K
|
|
myFile.read(sdBuffer, 512);
|
|
for (int x = 0; x < 512; x++) {
|
|
writeData_MSX(0x8000 + address + x, sdBuffer[x]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
writeData_MSX(0x7000, 0); // SRAM Disable
|
|
break;
|
|
|
|
case 11: // PAC/FM-PAC (8K)
|
|
writeData_MSX(0x5FFE, 0x4D); // SRAM Enable Step 1
|
|
writeData_MSX(0x5FFF, 0x69); // SRAM Enable Step 2
|
|
for (word address = 0x0; address < 0x2000; address += 512) { // 8K
|
|
myFile.read(sdBuffer, 512);
|
|
for (int x = 0; x < 512; x++) {
|
|
writeData_MSX(0x4000 + address + x, sdBuffer[x]);
|
|
}
|
|
}
|
|
writeData_MSX(0x5FFE, 0); // SRAM Disable
|
|
break;
|
|
}
|
|
myFile.close();
|
|
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
println_Msg(F("RAM FILE WRITTEN!"));
|
|
display_Update();
|
|
|
|
} else {
|
|
print_FatalError(sd_error_STR);
|
|
}
|
|
}
|
|
sd.chdir(); // root
|
|
filePath[0] = '\0'; // Reset filePath
|
|
}
|
|
|
|
//******************************************
|
|
// MAPPER CODE
|
|
//******************************************
|
|
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
void printMapperSelection_MSX(int index) {
|
|
display_Clear();
|
|
print_Msg(FS(FSTRING_MAPPER));
|
|
msxindex = index * 5;
|
|
msxmapselect = pgm_read_byte(msxmapsize + msxindex);
|
|
println_Msg(msxmapselect);
|
|
printMapper(msxmapselect);
|
|
}
|
|
#endif
|
|
|
|
void setMapper_MSX() {
|
|
byte newmsxmapper;
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
navigateMenu(0, msxmapcount - 1, &printMapperSelection_MSX);
|
|
newmsxmapper = msxmapselect;
|
|
|
|
display.setCursor(0, 56);
|
|
print_Msg(F("MAPPER "));
|
|
print_Msg(newmsxmapper);
|
|
println_Msg(F(" SELECTED"));
|
|
display_Update();
|
|
delay(1000);
|
|
#else
|
|
setmapper:
|
|
String newmap;
|
|
msxmapfound = false;
|
|
printMapper(0);
|
|
Serial.print(F("Enter Mapper [0-14]: "));
|
|
while (Serial.available() == 0) {}
|
|
newmap = Serial.readStringUntil('\n');
|
|
Serial.println(newmap);
|
|
newmsxmapper = newmap.toInt();
|
|
for (int i = 0; i < msxmapcount; i++) {
|
|
msxindex = i * 5;
|
|
msxmapselect = pgm_read_byte(msxmapsize + msxindex);
|
|
if (newmsxmapper == msxmapselect)
|
|
msxmapfound = true;
|
|
}
|
|
if (msxmapfound == false) {
|
|
Serial.println(F("MAPPER NOT SUPPORTED!"));
|
|
Serial.println(FS(FSTRING_EMPTY));
|
|
newmsxmapper = 0;
|
|
goto setmapper;
|
|
}
|
|
#endif
|
|
EEPROM_writeAnything(7, newmsxmapper);
|
|
msxmapper = newmsxmapper;
|
|
}
|
|
|
|
void checkMapperSize_MSX() {
|
|
for (int i = 0; i < msxmapcount; i++) {
|
|
msxindex = i * 5;
|
|
byte mapcheck = pgm_read_byte(msxmapsize + msxindex);
|
|
if (mapcheck == msxmapper) {
|
|
msxlo = pgm_read_byte(msxmapsize + msxindex + 1);
|
|
msxhi = pgm_read_byte(msxmapsize + msxindex + 2);
|
|
msxramlo = pgm_read_byte(msxmapsize + msxindex + 3);
|
|
msxramhi = pgm_read_byte(msxmapsize + msxindex + 4);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//******************************************
|
|
// SET ROM SIZE
|
|
//******************************************
|
|
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
void printRomSize_MSX(uint8_t index) {
|
|
display_Clear();
|
|
print_Msg(FS(FSTRING_ROM_SIZE));
|
|
println_Msg(MSX[index]);
|
|
}
|
|
#endif
|
|
|
|
void setROMSize_MSX() {
|
|
byte newmsxsize;
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
display_Clear();
|
|
if (msxlo == msxhi)
|
|
newmsxsize = msxlo;
|
|
else {
|
|
uint8_t b = 0;
|
|
int i = msxlo;
|
|
|
|
printRomSize_MSX(i);
|
|
printInstructions();
|
|
|
|
while (1) {
|
|
b = checkButton();
|
|
if (b == 2) { // Previous (doubleclick)
|
|
if (msxmapper == 11) { // PAC/FM-PAC 0K/64K
|
|
if (i == msxlo)
|
|
i = msxhi; // 64K
|
|
else
|
|
i = msxlo; // 0K
|
|
} else {
|
|
if (i == msxlo)
|
|
i = msxhi;
|
|
else
|
|
i--;
|
|
|
|
// Only update display after input because of slow LCD library
|
|
printRomSize_MSX(i);
|
|
printInstructions();
|
|
}
|
|
}
|
|
if (b == 1) { // Next (press)
|
|
if (msxmapper == 11) { // PAC/FM-PAC 0K/64K
|
|
if (i == msxlo)
|
|
i = msxhi; // 64K
|
|
else
|
|
i = msxlo; // 0K
|
|
} else {
|
|
if (i == msxhi)
|
|
i = msxlo;
|
|
else
|
|
i++;
|
|
|
|
// Only update display after input because of slow LCD library
|
|
printRomSize_MSX(i);
|
|
printInstructions();
|
|
}
|
|
}
|
|
if (b == 3) { // Long Press - Execute (hold)
|
|
newmsxsize = i;
|
|
break;
|
|
}
|
|
}
|
|
display.setCursor(0, 56); // Display selection at bottom
|
|
}
|
|
print_Msg(FS(FSTRING_ROM_SIZE));
|
|
if (msxmapper == 12) // R-Type
|
|
print_Msg(F("384"));
|
|
else
|
|
print_Msg(MSX[newmsxsize]);
|
|
println_Msg(F("K"));
|
|
display_Update();
|
|
delay(1000);
|
|
#else
|
|
if (msxlo == msxhi)
|
|
newmsxsize = msxlo;
|
|
else {
|
|
setrom:
|
|
String sizeROM;
|
|
for (int i = 0; i < (msxhi - msxlo + 1); i++) {
|
|
Serial.print(F("Select ROM Size: "));
|
|
Serial.print(i);
|
|
Serial.print(F(" = "));
|
|
if (msxmapper == 12) // R-Type
|
|
Serial.print(F("384"));
|
|
else
|
|
Serial.print(MSX[i + msxlo]);
|
|
Serial.println(F("K"));
|
|
}
|
|
Serial.print(F("Enter ROM Size: "));
|
|
while (Serial.available() == 0) {}
|
|
sizeROM = Serial.readStringUntil('\n');
|
|
Serial.println(sizeROM);
|
|
newmsxsize = sizeROM.toInt() + msxlo;
|
|
if (msxmapper == 11) { // PAC/FM-PAC 0K/64K
|
|
if ((newmsxromsize > 0) && (newmsxromsize < 4)) {
|
|
Serial.println(F("SIZE NOT SUPPORTED"));
|
|
Serial.println(FS(FSTRING_EMPTY));
|
|
goto setrom;
|
|
}
|
|
}
|
|
if (newmsxsize > msxhi) {
|
|
Serial.println(F("SIZE NOT SUPPORTED"));
|
|
Serial.println(FS(FSTRING_EMPTY));
|
|
goto setrom;
|
|
}
|
|
}
|
|
Serial.print(F("ROM Size = "));
|
|
if (msxmapper == 12) // R-Type
|
|
Serial.print(F("384"));
|
|
else
|
|
Serial.print(MSX[newmsxsize]);
|
|
Serial.println(F("K"));
|
|
#endif
|
|
EEPROM_writeAnything(8, newmsxsize);
|
|
msxsize = newmsxsize;
|
|
}
|
|
|
|
//******************************************
|
|
// SET RAM SIZE
|
|
//******************************************
|
|
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
void printRamSize_MSX(uint8_t index) {
|
|
display_Clear();
|
|
print_Msg(F("RAM Size: "));
|
|
println_Msg(MSXRAM[index]);
|
|
}
|
|
#endif
|
|
|
|
void setRAMSize_MSX() {
|
|
byte newmsxramsize;
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
display_Clear();
|
|
if (msxramlo == msxramhi)
|
|
newmsxramsize = msxramlo;
|
|
else {
|
|
uint8_t b = 0;
|
|
int i = msxramlo;
|
|
|
|
printRamSize_MSX(i);
|
|
printInstructions();
|
|
|
|
while (1) {
|
|
b = checkButton();
|
|
if (b == 2) { // Previous (doubleclick)
|
|
if (msxmapper == 7) { // Koei 8K/32K
|
|
if (i == msxramlo)
|
|
i = msxramhi; // 32K
|
|
else
|
|
i = msxramlo; // 8K
|
|
} else {
|
|
if (i == msxramlo)
|
|
i = msxramhi;
|
|
else
|
|
i--;
|
|
|
|
// Only update display after input because of slow LCD library
|
|
printRamSize_MSX(i);
|
|
printInstructions();
|
|
}
|
|
}
|
|
if (b == 1) { // Next (press)
|
|
if (msxmapper == 7) { // Koei 8K/32K
|
|
if (i == msxramlo)
|
|
i = msxramhi; // 32K
|
|
else
|
|
i = msxramlo; // 8K
|
|
} else {
|
|
if (i == msxramhi)
|
|
i = msxramlo;
|
|
else
|
|
i++;
|
|
|
|
// Only update display after input because of slow LCD library
|
|
printRamSize_MSX(i);
|
|
printInstructions();
|
|
}
|
|
}
|
|
if (b == 3) { // Long Press - Execute (hold)
|
|
newmsxramsize = i;
|
|
break;
|
|
}
|
|
}
|
|
display.setCursor(0, 56); // Display selection at bottom
|
|
}
|
|
print_Msg(F("RAM SIZE "));
|
|
print_Msg(MSXRAM[newmsxramsize]);
|
|
println_Msg(F("K"));
|
|
display_Update();
|
|
delay(1000);
|
|
#else
|
|
if (msxramlo == msxramhi)
|
|
newmsxramsize = msxramlo;
|
|
else {
|
|
setram:
|
|
String sizeRAM;
|
|
for (int i = 0; i < (msxramhi - msxramlo + 1); i++) {
|
|
Serial.print(F("Select RAM Size: "));
|
|
Serial.print(i);
|
|
Serial.print(F(" = "));
|
|
Serial.print(MSXRAM[i + msxramlo]);
|
|
Serial.println(F("K"));
|
|
}
|
|
Serial.print(F("Enter RAM Size: "));
|
|
while (Serial.available() == 0) {}
|
|
sizeRAM = Serial.readStringUntil('\n');
|
|
Serial.println(sizeRAM);
|
|
newmsxramsize = sizeRAM.toInt() + msxramlo;
|
|
if (msxmapper == 7) { // Koei 8K/32K
|
|
if (newmsxramsize == 3) { // 16K
|
|
Serial.println(F("SIZE NOT SUPPORTED"));
|
|
Serial.println(FS(FSTRING_EMPTY));
|
|
goto setram;
|
|
}
|
|
}
|
|
if (newmsxramsize > msxramhi) {
|
|
Serial.println(F("SIZE NOT SUPPORTED"));
|
|
Serial.println(FS(FSTRING_EMPTY));
|
|
goto setram;
|
|
}
|
|
}
|
|
Serial.print(F("RAM Size = "));
|
|
Serial.print(MSXRAM[newmsxramsize]);
|
|
Serial.println(F("K"));
|
|
#endif
|
|
EEPROM_writeAnything(10, newmsxramsize);
|
|
msxramsize = newmsxramsize;
|
|
}
|
|
|
|
//******************************************
|
|
// CHECK STATUS
|
|
//******************************************
|
|
void checkStatus_MSX() {
|
|
EEPROM_readAnything(7, msxmapper);
|
|
EEPROM_readAnything(8, msxsize);
|
|
EEPROM_readAnything(10, msxramsize);
|
|
if (msxmapper > 14) {
|
|
msxmapper = 0;
|
|
EEPROM_writeAnything(7, msxmapper);
|
|
}
|
|
if (msxsize > 8) {
|
|
msxsize = 0;
|
|
EEPROM_writeAnything(8, msxsize);
|
|
}
|
|
if (msxramsize > 4) {
|
|
msxramsize = 0;
|
|
EEPROM_writeAnything(10, msxramsize);
|
|
}
|
|
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
display_Clear();
|
|
println_Msg(F("MSX READER"));
|
|
println_Msg(FS(FSTRING_CURRENT_SETTINGS));
|
|
println_Msg(FS(FSTRING_EMPTY));
|
|
print_Msg(F("MAPPER: "));
|
|
println_Msg(msxmapper);
|
|
printMapper(msxmapper);
|
|
print_Msg(FS(FSTRING_ROM_SIZE));
|
|
if (msxmapper == 12) // R-Type
|
|
print_Msg(F("384"));
|
|
else
|
|
print_Msg(MSX[msxsize]);
|
|
println_Msg(F("K"));
|
|
print_Msg(F("RAM SIZE: "));
|
|
print_Msg(MSXRAM[msxramsize]);
|
|
println_Msg(F("K"));
|
|
display_Update();
|
|
wait();
|
|
#else
|
|
Serial.print(F("CURRENT MAPPER: "));
|
|
Serial.println(msxmapper);
|
|
Serial.print(F("CURRENT ROM SIZE: "));
|
|
if (msxmapper == 12) // R-Type
|
|
Serial.print(F("384"));
|
|
else
|
|
Serial.print(MSX[msxsize]);
|
|
Serial.println(F("K"));
|
|
Serial.print(F("CURRENT RAM SIZE: "));
|
|
Serial.print(MSXRAM[msxramsize]);
|
|
Serial.println(F("K"));
|
|
Serial.println(FS(FSTRING_EMPTY));
|
|
#endif
|
|
}
|
|
|
|
void printMapper(byte msxmaplabel) {
|
|
#if (defined(ENABLE_OLED) || defined(ENABLE_LCD))
|
|
switch (msxmaplabel) {
|
|
case 0:
|
|
println_Msg(F("NONE"));
|
|
break;
|
|
case 1:
|
|
println_Msg(F("ASCII8"));
|
|
break;
|
|
case 2:
|
|
println_Msg(F("ASCII16"));
|
|
break;
|
|
case 3:
|
|
println_Msg(F("CROSS BLAIM"));
|
|
break;
|
|
case 4:
|
|
println_Msg(F("GAME MASTER 2"));
|
|
break;
|
|
case 5:
|
|
println_Msg(F("HAL NOTE"));
|
|
break;
|
|
case 6:
|
|
println_Msg(F("HARRY FOX YUKI"));
|
|
break;
|
|
case 7:
|
|
println_Msg(F("KOEI"));
|
|
break;
|
|
case 8:
|
|
println_Msg(F("KONAMI"));
|
|
break;
|
|
case 9:
|
|
println_Msg(F("KONAMI SCC"));
|
|
break;
|
|
case 10:
|
|
println_Msg(F("MSX-DOS2"));
|
|
break;
|
|
case 11:
|
|
println_Msg(F("PAC/FM-PAC"));
|
|
break;
|
|
case 12:
|
|
println_Msg(F("R-TYPE"));
|
|
break;
|
|
case 13:
|
|
println_Msg(F("SUPER LODE RUNNER"));
|
|
break;
|
|
case 14:
|
|
println_Msg(F("HUDSON SOFT BEE PACK"));
|
|
break;
|
|
}
|
|
#else
|
|
Serial.println(F("0 = NONE"));
|
|
Serial.println(F("1 = ASCII8"));
|
|
Serial.println(F("2 = ASCII16"));
|
|
Serial.println(F("3 = CROSS BLAIM"));
|
|
Serial.println(F("4 = GAME MASTER 2"));
|
|
Serial.println(F("5 = HAL NOTE"));
|
|
Serial.println(F("6 = HARRY FOX YUKI"));
|
|
Serial.println(F("7 = KOEI"));
|
|
Serial.println(F("8 = KONAMI"));
|
|
Serial.println(F("9 = KONAMI SCC"));
|
|
Serial.println(F("10 = MSX-DOS2"));
|
|
Serial.println(F("11 = PAC/FM-PAC"));
|
|
Serial.println(F("12 = R-TYPE"));
|
|
Serial.println(F("13 = SUPER LODE RUNNER"));
|
|
Serial.println(F("14 = HUDSON SOFT BEE PACK"));
|
|
#endif
|
|
}
|
|
|
|
//******************************************
|
|
// CART SELECT CODE
|
|
//******************************************
|
|
struct database_entry_MSX {
|
|
byte gameMapper;
|
|
byte gameSize;
|
|
byte ramSize;
|
|
};
|
|
|
|
void readDataLine_MSX(FsFile& database, void* entry) {
|
|
database_entry_MSX* castEntry = (database_entry_MSX*)entry;
|
|
// Read mapper
|
|
castEntry->gameMapper = ((database.read() - 48) * 10) + (database.read() - 48);
|
|
|
|
// Skip over semicolon
|
|
database.seekCur(1);
|
|
|
|
// Read rom size
|
|
castEntry->gameSize = database.read() - 48;
|
|
|
|
// Skip over semicolon
|
|
database.seekCur(1);
|
|
|
|
// Read ram size
|
|
castEntry->ramSize = database.read() - 48;
|
|
|
|
// Skip rest of line
|
|
database.seekCur(2);
|
|
}
|
|
|
|
void setCart_MSX() {
|
|
//go to root
|
|
sd.chdir();
|
|
|
|
struct database_entry_MSX entry;
|
|
|
|
// Select starting letter
|
|
byte myLetter = starting_letter();
|
|
|
|
// Open database
|
|
if (myFile.open("msxcart.txt", O_READ)) {
|
|
seek_first_letter_in_database(myFile, myLetter);
|
|
|
|
if(checkCartSelection(myFile, &readDataLine_MSX, &entry)) {
|
|
EEPROM_writeAnything(7, entry.gameMapper);
|
|
EEPROM_writeAnything(8, entry.gameSize);
|
|
EEPROM_writeAnything(10, entry.ramSize);
|
|
}
|
|
} else {
|
|
print_FatalError(FS(FSTRING_DATABASE_FILE_NOT_FOUND));
|
|
}
|
|
}
|
|
#endif
|