[Core/MS] added support for latest Korean x-in-1 mappers (credits to Ben Sittler and Omar Cornut at smspower.org for mappers reverse-engineering and description)

This commit is contained in:
ekeeke 2023-04-06 01:00:40 +02:00
parent 94399728b8
commit 4a07f8a9f6
4 changed files with 327 additions and 60 deletions

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 MiB

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 MiB

After

Width:  |  Height:  |  Size: 4.0 MiB

View File

@ -4,6 +4,9 @@
*
* Copyright (C) 2007-2023 Eke-Eke (Genesis Plus GX)
*
* Credits to Ben Sittler and Omar Cornut at smspower.org for Korean mappers
* reverse-engineering and description
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
@ -52,10 +55,14 @@
#define MAPPER_MULTI_16K (0x14)
#define MAPPER_KOREA (0x15)
#define MAPPER_KOREA_16K (0x16)
#define MAPPER_MULTI_2x16K_V1 (0x17)
#define MAPPER_MULTI_2x16K_V2 (0x18)
#define MAPPER_MULTI_32K_16K (0x19)
#define MAPPER_KOREA_8K (0x20)
#define MAPPER_MSX (0x21)
#define MAPPER_MSX_NEMESIS (0x22)
#define MAPPER_MULTI_4X8K (0x23)
#define MAPPER_MULTI_8K (0x23)
#define MAPPER_MULTI_4x8K (0x24)
#define MAPPER_MULTI_32K (0x40)
typedef struct
@ -94,10 +101,10 @@ static const rominfo_t game_list[] =
/* games using "Korean" mappers */
{0x445525E2, 0, 0, 0, MAPPER_MSX, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Penguin Adventure (KR) */
{0x83F0EEDE, 0, 0, 0, MAPPER_MSX, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Street Master (KR) */
{0xA05258F5, 0, 0, 0, MAPPER_MSX, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Won-Si-In (KR) */
{0xA05258F5, 0, 0, 0, MAPPER_MSX, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Wonsiin (KR) */
{0x06965ED9, 0, 0, 0, MAPPER_MSX, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* F-1 Spirit - The way to Formula-1 (KR) */
{0x77EFE84A, 0, 0, 0, MAPPER_MSX, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Cyborg Z (KR) */
{0xF89AF3CC, 0, 0, 0, MAPPER_MSX, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Knightmare II - The Maze of Galious (KR) */
{0xF89AF3CC, 0, 0, 0, MAPPER_MSX, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Knightmare II: The Maze of Galious (KR) */
{0x9195C34C, 0, 0, 0, MAPPER_MSX, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Super Boy 3 (KR) */
{0xE316C06D, 0, 0, 0, MAPPER_MSX_NEMESIS, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Nemesis (KR) */
{0x0A77FA5E, 0, 0, 0, MAPPER_MSX, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Nemesis 2 (KR) */
@ -120,8 +127,22 @@ static const rominfo_t game_list[] =
{0xFBA94148, 0, 0, 0, MAPPER_MULTI_32K, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Hi-Com 8-in-1 The Best Game Collection (Vol. 1) (KR) */
{0x8333C86E, 0, 0, 0, MAPPER_MULTI_32K, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Hi-Com 8-in-1 The Best Game Collection (Vol. 2) (KR) */
{0x00E9809F, 0, 0, 0, MAPPER_MULTI_32K, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Hi-Com 8-in-1 The Best Game Collection (Vol. 3) (KR) */
{0xBA5EC0E3, 0, 0, 0, MAPPER_MULTI_4X8K, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* 128 Hap (KR) */
{0x380D7400, 0, 0, 0, MAPPER_MULTI_4X8K, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Game Mo-eumjip 188 Hap (KR) */
{0xBA5EC0E3, 0, 0, 0, MAPPER_MULTI_4x8K, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* 128 Hap (KR) */
{0x380D7400, 0, 0, 0, MAPPER_MULTI_4x8K, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Game Mo-eumjip 188 Hap [v0] (KR) */
{0xC76601E0, 0, 0, 0, MAPPER_MULTI_4x8K, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Game Mo-eumjip 188 Hap [v1] (KR) */
{0x38B3A72F, 0, 0, 0, MAPPER_MULTI_8K, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Game Chongjiphap 200 (KR).sms */
{0xD3056492, 0, 0, 0, MAPPER_MULTI_8K, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Super Game 270 Hap ~ Jaemissneun-270 (KR) */
{0xAB07ECD4, 0, 0, 0, MAPPER_MULTI_8K, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Super Game World 260 Hap (KR) */
{0x0CDE0938, 0, 0, 0, MAPPER_MULTI_8K, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Super Game World 30 Hap (KR) */
{0xC29BB8CD, 0, 0, 0, MAPPER_MULTI_8K, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Super Game World 75 Hap (KR) */
{0x660BF6EC, 0, 0, 0, MAPPER_MULTI_8K, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Super Multi Game - Super 75 in 1 (KR) */
{0xEB7790DE, 0, 0, 0, MAPPER_MULTI_8K, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Super Multi Game - Super 125 in 1 (KR) */
{0xE6AD4D4B, 0, 0, 0, MAPPER_MULTI_8K, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Super World 30 Hap (KR) */
{0xEDB13847, 0, 0, 0, MAPPER_MULTI_2x16K_V1, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Super Game 45 (KR) */
{0xA841C0B7, 0, 0, 0, MAPPER_MULTI_2x16K_V2, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Super Game 52 Hap (KR) */
{0x4E202AA2, 0, 0, 0, MAPPER_MULTI_2x16K_V2, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Super Game 180 (KR) */
{0xBA5D2776, 0, 0, 0, MAPPER_MULTI_2x16K_V2, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Super Game 200 (KR) */
{0xC0AC6956, 0, 0, 0, MAPPER_MULTI_32K_16K, SYSTEM_SMS, REGION_JAPAN_NTSC}, /* Pigu-Wang 7 Hap - Jaemiiss-neun Game Mo-eumjip (KR) */
/* games using Codemaster mapper */
{0x29822980, 0, 0, 0, MAPPER_CODIES, SYSTEM_SMS2, REGION_EUROPE}, /* Cosmic Spacehead */
@ -145,6 +166,7 @@ static const rominfo_t game_list[] =
/* games using serial EEPROM */
{0x36EBCD6D, 0, 0, 0, MAPPER_93C46, SYSTEM_GG, REGION_USA}, /* Majors Pro Baseball */
{0x2DA8E943, 0, 0, 0, MAPPER_93C46, SYSTEM_GG, REGION_USA}, /* Pro Yakyuu GG League */
{0x3D8D0DD6, 0, 0, 0, MAPPER_93C46, SYSTEM_GG, REGION_USA}, /* World Series Baseball [v0] */
{0xBB38CFD7, 0, 0, 0, MAPPER_93C46, SYSTEM_GG, REGION_USA}, /* World Series Baseball [v1] */
{0x578A8A38, 0, 0, 0, MAPPER_93C46, SYSTEM_GG, REGION_USA}, /* World Series Baseball '95 */
@ -160,22 +182,24 @@ static const rominfo_t game_list[] =
{0x092F29D6, 0, 0, 0, MAPPER_RAM_8K, SYSTEM_SG, REGION_JAPAN_NTSC}, /* The Castle (J) */
/* games requiring SG-1000 II 8K RAM extension adapter (type A) */
{0x16F240D3, 0, 0, 0, MAPPER_RAM_8K_EXT1, SYSTEM_SGII, REGION_JAPAN_NTSC}, /* Adventure Island [DahJee] (TW) */
{0xCE5648C3, 0, 0, 0, MAPPER_RAM_8K_EXT1, SYSTEM_SGII, REGION_JAPAN_NTSC}, /* Bomberman Special [DahJee] (TW) */
{0x223397A1, 0, 0, 0, MAPPER_RAM_8K_EXT1, SYSTEM_SGII, REGION_JAPAN_NTSC}, /* King's Valley (TW) */
{0x281D2888, 0, 0, 0, MAPPER_RAM_8K_EXT1, SYSTEM_SGII, REGION_JAPAN_NTSC}, /* Knightmare (TW) */
{0x281D2888, 0, 0, 0, MAPPER_RAM_8K_EXT1, SYSTEM_SGII, REGION_JAPAN_NTSC}, /* Knightmare [Jumbo] (TW) */
{0x306D5F78, 0, 0, 0, MAPPER_RAM_8K_EXT1, SYSTEM_SGII, REGION_JAPAN_NTSC}, /* Rally-X [DahJee] (TW) */
{0x29E047CC, 0, 0, 0, MAPPER_RAM_8K_EXT1, SYSTEM_SGII, REGION_JAPAN_NTSC}, /* Road Fighter (TW) */
{0x5CBD1163, 0, 0, 0, MAPPER_RAM_8K_EXT1, SYSTEM_SGII, REGION_JAPAN_NTSC}, /* Tank Battalion (TW) */
{0x40414556, 0, 0, 0, MAPPER_RAM_8K_EXT1, SYSTEM_SGII, REGION_JAPAN_NTSC}, /* The Goonies (TW) */
{0x2E7166D5, 0, 0, 0, MAPPER_RAM_8K_EXT1, SYSTEM_SGII, REGION_JAPAN_NTSC}, /* The Legend of Kage (TW) */
{0xC550B4F0, 0, 0, 0, MAPPER_RAM_8K_EXT1, SYSTEM_SGII, REGION_JAPAN_NTSC}, /* TwinBee (TW) */
{0xFC87463C, 0, 0, 0, MAPPER_RAM_8K_EXT1, SYSTEM_SGII, REGION_JAPAN_NTSC}, /* Yie Ar Kung-Fu II (TW) */
{0xDF7CBFA5, 0, 0, 0, MAPPER_RAM_8K_EXT1, SYSTEM_SGII, REGION_JAPAN_NTSC}, /* Pippols (TW) */
{0xE0816BB7, 0, 0, 0, MAPPER_RAM_8K_EXT1, SYSTEM_SGII, REGION_JAPAN_NTSC}, /* Star Soldier (TW) */
{0xE0816BB7, 0, 0, 0, MAPPER_RAM_8K_EXT1, SYSTEM_SGII, REGION_JAPAN_NTSC}, /* Star Soldier [DahJee] (TW) */
/* games requiring SG-1000 II 8K RAM extension adapter (type B) */
{0x69FC1494, 0, 0, 0, MAPPER_NONE, SYSTEM_SGII_RAM_EXT, REGION_JAPAN_NTSC}, /* Bomberman Special (TW) */
{0xFFC4EE3F, 0, 0, 0, MAPPER_NONE, SYSTEM_SGII_RAM_EXT, REGION_JAPAN_NTSC}, /* Magical Kid Wiz (TW) */
{0x2E366CCF, 0, 0, 0, MAPPER_NONE, SYSTEM_SGII_RAM_EXT, REGION_JAPAN_NTSC}, /* The Castle (TW) */
{0x2E366CCF, 0, 0, 0, MAPPER_NONE, SYSTEM_SGII_RAM_EXT, REGION_JAPAN_NTSC}, /* The Castle [MSX] (TW) */
{0xAAAC12CF, 0, 0, 0, MAPPER_NONE, SYSTEM_SGII_RAM_EXT, REGION_JAPAN_NTSC}, /* Rally-X (TW) */
{0xD2EDD329, 0, 0, 0, MAPPER_NONE, SYSTEM_SGII_RAM_EXT, REGION_JAPAN_NTSC}, /* Road Fighter (TW) */
@ -427,7 +451,11 @@ static void write_mapper_korea_8k(unsigned int address, unsigned char data);
static void write_mapper_korea_16k(unsigned int address, unsigned char data);
static void write_mapper_msx(unsigned int address, unsigned char data);
static void write_mapper_multi_16k(unsigned int address, unsigned char data);
static void write_mapper_multi_2x16k_v1(unsigned int address, unsigned char data);
static void write_mapper_multi_2x16k_v2(unsigned int address, unsigned char data);
static void write_mapper_multi_32k_16k(unsigned int address, unsigned char data);
static void write_mapper_multi_32k(unsigned int address, unsigned char data);
static void write_mapper_multi_8k(unsigned int address, unsigned char data);
static void write_mapper_multi_4x8k(unsigned int address, unsigned char data);
static void write_mapper_93c46(unsigned int address, unsigned char data);
static void write_mapper_terebi(unsigned int address, unsigned char data);
@ -616,7 +644,8 @@ void sms_cart_reset(void)
case MAPPER_KOREA_8K:
case MAPPER_MSX:
case MAPPER_MSX_NEMESIS:
case MAPPER_MULTI_4X8K:
case MAPPER_MULTI_4x8K:
case MAPPER_MULTI_8K:
cart_rom.fcr[0] = 0;
cart_rom.fcr[1] = 0;
cart_rom.fcr[2] = 0;
@ -855,7 +884,8 @@ int sms_cart_context_load(uint8 *state)
case MAPPER_KOREA_8K:
case MAPPER_MSX:
case MAPPER_MSX_NEMESIS:
case MAPPER_MULTI_4X8K:
case MAPPER_MULTI_4x8K:
case MAPPER_MULTI_8K:
cart_rom.fcr[0] = 0;
cart_rom.fcr[1] = 0;
cart_rom.fcr[2] = 0;
@ -1029,7 +1059,7 @@ static void mapper_reset(void)
/* "Nemesis" mapper specific */
if (slot.mapper == MAPPER_MSX_NEMESIS)
{
/* first 8KB page is mapped to last 8KB ROM bank */
/* first 8KB page ($0000-$1FFF) is mapped to last 8KB ROM bank */
for (i = 0x00; i < 0x08; i++)
{
z80_readmap[i] = &slot.rom[(0x0f << 13) | ((i & 0x07) << 10)];
@ -1044,12 +1074,26 @@ static void mapper_reset(void)
else
{
/* 16KB pages */
if ((slot.mapper == MAPPER_MULTI_2x16K_V1) || (slot.mapper == MAPPER_MULTI_2x16K_V2))
{
mapper_16k_w(1,slot.fcr[1]);
mapper_16k_w(2,slot.fcr[2]);
}
else if (slot.mapper == MAPPER_MULTI_32K_16K)
{
mapper_16k_w(1,slot.fcr[1]);
mapper_16k_w(2,slot.fcr[2]);
mapper_16k_w(3,slot.fcr[3]);
}
else
{
mapper_16k_w(0,slot.fcr[0]);
mapper_16k_w(1,slot.fcr[1]);
mapper_16k_w(2,slot.fcr[2]);
mapper_16k_w(3,slot.fcr[3]);
}
}
}
/* reset Z80 memory handlers */
switch (slot.mapper)
@ -1091,12 +1135,32 @@ static void mapper_reset(void)
z80_writemem = write_mapper_multi_16k;
break;
case MAPPER_MULTI_2x16K_V1:
z80_readmem = read_mapper_default;
z80_writemem = write_mapper_multi_2x16k_v1;
break;
case MAPPER_MULTI_2x16K_V2:
z80_readmem = read_mapper_default;
z80_writemem = write_mapper_multi_2x16k_v2;
break;
case MAPPER_MULTI_32K_16K:
z80_readmem = read_mapper_default;
z80_writemem = write_mapper_multi_32k_16k;
break;
case MAPPER_MULTI_32K:
z80_readmem = read_mapper_default;
z80_writemem = write_mapper_multi_32k;
break;
case MAPPER_MULTI_4X8K:
case MAPPER_MULTI_8K:
z80_readmem = read_mapper_default;
z80_writemem = write_mapper_multi_8k;
break;
case MAPPER_MULTI_4x8K:
z80_readmem = read_mapper_default;
z80_writemem = write_mapper_multi_4x8k;
break;
@ -1146,6 +1210,17 @@ static void mapper_8k_w(int offset, unsigned char data)
{
z80_readmap[i] = &page[(i & 0x07) << 10];
}
/* Multi Korean mapper specific */
if (slot.mapper == MAPPER_MULTI_8K)
{
/* $2000-$3FFF is mirror of $A000-$BFFF */
for (i = 0x08; i < 0x10; i++)
{
z80_readmap[i] = z80_readmap[0x20 + i];
}
}
break;
}
@ -1243,7 +1318,7 @@ static void mapper_16k_w(int offset, unsigned char data)
case 1: /* cartridge ROM bank (16KB) at $0000-$3FFF */
{
/* first 1KB is not fixed (CODEMASTER or MULTI mappers only) */
if ((slot.mapper == MAPPER_CODIES) || (slot.mapper == MAPPER_MULTI_16K))
if (slot.mapper >= MAPPER_CODIES)
{
z80_readmap[0] = &slot.rom[(page << 14)];
}
@ -1286,13 +1361,66 @@ static void mapper_16k_w(int offset, unsigned char data)
}
}
}
/* Multi Korean mappers specific */
else if (slot.mapper == MAPPER_MULTI_2x16K_V1)
{
if (slot.fcr[0] != 0x01)
{
/* $8000-$BFFF is not mapped to cartridge ROM (unused area) */
for (i = 0x20; i < 0x30; i++)
{
z80_readmap[i] = cart.rom + 0x510400;
}
}
else
{
/* $8000-$9FFF is mirror of $6000-$7FFF */
for (i = 0x20; i < 0x28; i++)
{
z80_readmap[i] = z80_readmap[i - 0x08];
}
/* $A000-$BFFF is mirror of $4000-$5FFF */
for (i = 0x28; i < 0x30; i++)
{
z80_readmap[i] = z80_readmap[i - 0x18];
}
}
}
else if (slot.mapper == MAPPER_MULTI_2x16K_V2)
{
if (slot.fcr[0] != 0x03)
{
/* $8000-$BFFF is not mapped to cartridge ROM (unused area) */
for (i = 0x20; i < 0x30; i++)
{
z80_readmap[i] = cart.rom + 0x510400;
}
}
else
{
/* $8000-$9FFF is mirror of $6000-$7FFF */
for (i = 0x20; i < 0x28; i++)
{
z80_readmap[i] = z80_readmap[i - 0x08];
}
/* $A000-$BFFF is mirror of $4000-$5FFF */
for (i = 0x28; i < 0x30; i++)
{
z80_readmap[i] = z80_readmap[i - 0x18];
}
}
}
break;
}
case 3: /* cartridge ROM bank (16KB) at $8000-$BFFF */
{
/* check that external RAM (16KB) is not mapped at $8000-$BFFF (SEGA mapper only) */
if ((slot.fcr[0] & 0x08)) break;
if ((slot.fcr[0] & 0x08) && (slot.mapper != MAPPER_MULTI_32K_16K)) break;
/* first 8KB */
for (i = 0x20; i < 0x28; i++)
@ -1407,6 +1535,116 @@ static void write_mapper_multi_16k(unsigned int address, unsigned char data)
z80_writemap[address >> 10][address & 0x03FF] = data;
}
static void write_mapper_multi_2x16k_v1(unsigned int address, unsigned char data)
{
if (address == 0xFFFE)
{
/* save mapper configuration to unused register */
slot.fcr[0] = (data >> 5) & 0x03;
switch (slot.fcr[0])
{
case 0x00:
{
data &= 0x1f;
mapper_16k_w(1,0x00);
mapper_16k_w(2,data);
break;
}
case 0x01:
{
data &= 0x1f;
mapper_16k_w(1,0x00);
mapper_16k_w(2,data);
break;
}
default:
{
data &= 0x1e;
mapper_16k_w(1,data);
mapper_16k_w(2,data+1);
break;
}
}
}
z80_writemap[address >> 10][address & 0x03FF] = data;
}
static void write_mapper_multi_2x16k_v2(unsigned int address, unsigned char data)
{
if (address == 0xBFFC)
{
/* save mapper configuration to unused register */
slot.fcr[0] = (data >> 6) & 0x03;
switch (slot.fcr[0])
{
case 0x00:
{
data &= 0x3e;
mapper_16k_w(1,data);
mapper_16k_w(2,data+1);
return;
}
case 0x01:
{
data &= 0x3f;
mapper_16k_w(1,data);
mapper_16k_w(2,data);
return;
}
case 0x02:
{
data &= 0x3f;
mapper_16k_w(1,0x20);
mapper_16k_w(2,data);
return;
}
default:
{
data &= 0x3f;
mapper_16k_w(1,0x20);
mapper_16k_w(2,data);
return;
}
}
}
z80_writemap[address >> 10][address & 0x03FF] = data;
}
static void write_mapper_multi_32k_16k(unsigned int address, unsigned char data)
{
z80_writemap[address >> 10][address & 0x03FF] = data;
address &= 0xBFEF;
if (address == 0xBFE5)
{
/* save 16K bank index to unused register */
slot.fcr[0] = (data & 0x3f) << 1;
mapper_16k_w(1,slot.fcr[0]);
mapper_16k_w(2,slot.fcr[0]+1);
mapper_16k_w(3,slot.fcr[0]+1);
}
else if (address == 0xBFEE)
{
data &= 0x1f;
mapper_16k_w(2,slot.fcr[0]+data);
}
else if (address == 0xBFEF)
{
data &= 0x1f;
mapper_16k_w(3,slot.fcr[0]+data);
}
}
static void write_mapper_multi_32k(unsigned int address, unsigned char data)
{
if (address == 0xFFFF)
@ -1417,6 +1655,35 @@ static void write_mapper_multi_32k(unsigned int address, unsigned char data)
z80_writemap[address >> 10][address & 0x03FF] = data;
}
static void write_mapper_multi_8k(unsigned int address, unsigned char data)
{
if (address == 0x0000)
{
mapper_8k_w(0,data);
return;
}
if (address == 0x0100)
{
mapper_8k_w(2,data);
return;
}
if (address == 0x0200)
{
mapper_8k_w(1,data);
return;
}
if (address == 0x0300)
{
mapper_8k_w(3,data);
return;
}
z80_writemap[address >> 10][address & 0x03FF] = data;
}
static void write_mapper_multi_4x8k(unsigned int address, unsigned char data)
{
if (address == 0x2000)