Skip to content

Commit

Permalink
Mapper ocornut#28 MAPPER_GG_Super_12_in_1_FFFE for Super 12 in 1 Ga…
Browse files Browse the repository at this point in the history
…me Gear [Mortal Kombat] (Unl)

It turns out this multicart is severable and also reversible. This produces three more multicart "ghost ROMs" using the same mapper and some or all of the same data:

Just the first 2MB:
Super 7 in 1 Game Gear [Bare Knuckle 2] [Super 12 in 1] (Unl).gg

Just the last 2MB:
Super 5 in 1 Game Gear [Mortal Kombat] [Super 12 in 1] (Unl).gg

The last 2MB, followed by the first 2MB:
Super 12 in 1 Game Gear [Bare Knuckle 2] (Unl).gg

The menu is written such that it automatically adjusts to each of these subsets/layouts. Perhaps we will find physical carts containing these variations someday too?
  • Loading branch information
bsittler committed Mar 20, 2023
1 parent 3cb1c30 commit 2ea07b9
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 1 deletion.
6 changes: 5 additions & 1 deletion meka/compat.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1404,6 +1404,10 @@
Street Hero [Proto 1] [SMS-GG] Ok
Strider Returns Ok
Striker Ok
Super 5 in 1 Game Gear [Mortal Kombat] [Super 12 in 1] *Ok
Super 7 in 1 Game Gear [Bare Knuckle 2] [Super 12 in 1] *Ok
Super 12 in 1 Game Gear [Bare Knuckle 2] *Ok
Super 12 in 1 Game Gear [Mortal Kombat] *Ok
Super Battletank Ok
Super Columns Ok
Super Columns (JP) Ok
Expand Down Expand Up @@ -1497,7 +1501,7 @@
Zoop (US) Ok
Zoop [Proto] (US) Ok
-----------------------------------------------------------------------------
517 games tested - 506 are "Ok" - Compatibility rate: 97.63%
521 games tested - 510 are "Ok" - Compatibility rate: 97.89%
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions meka/meka.nam
Original file line number Diff line number Diff line change
Expand Up @@ -1286,6 +1286,10 @@ GG 0b618409 85CFE82DBD812633 Streets of Rage II/NAME_US=Streets of Rage 2/NAM
GG 6c395a69 BC45532F90B98FA5 Streets of Rage II [Proto]/NAME_US=Streets of Rage 2/NAME_JP=Bare Knuckle II/FLAGS=PROTO/COMMENT=Prototype version of the game.
GG 1ebfa5ca 24A227CBB87248D6 Strider Returns (Journey from Darkness)/COUNTRY=US,EU/PRODUCT_NO=T-79048,79048,79048-50
GG b421c057 96BD12C62621B8D6 Striker/COUNTRY=EU/PRODUCT_NO=2551-50
GG 0e098f92 F4782D31A464BB73 Super 5 in 1 Game Gear [Mortal Kombat] [Super 12 in 1]/EMU_MAPPER=28
GG 55d04386 97D2BF32485053BB Super 7 in 1 Game Gear [Bare Knuckle 2] [Super 12 in 1]/EMU_MAPPER=28
GG f56d3219 8B4AEC63ECB40E2E Super 12 in 1 Game Gear [Bare Knuckle 2]/EMU_MAPPER=28
GG 2ff576fa 8B4AEC63ECB40E2E Super 12 in 1 Game Gear [Mortal Kombat]/EMU_MAPPER=28
GG 73d6745a 18CC99C9849C9901 Super Battletank/COUNTRY=US/PRODUCT_NO=1239
GG 8ba43af3 DAA4C785B7042952 Super Columns/COUNTRY=US,EU/PRODUCT_NO=2449,2449-50
GG 2a100717 E7260408CEC8EE63 Super Columns/COUNTRY=JP/PRODUCT_NO=G-3226
Expand Down
18 changes: 18 additions & 0 deletions meka/srcs/machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ void Machine_Set_Handler_MemRW(void)
case MAPPER_SMS_Korean_MD_FFFA:
WrZ80 = WrZ80_NoHook = Write_Mapper_SMS_Korean_MD_FFFA;
break;
case MAPPER_GG_Super_12_in_1_FFFE:
WrZ80 = WrZ80_NoHook = Write_Mapper_GG_Super_12_in_1_FFFE;
break;
}
}

Expand Down Expand Up @@ -467,6 +470,21 @@ void Machine_Set_Mapping (void)
g_machine.mapper_regs[2] = 1;
break;

case MAPPER_GG_Super_12_in_1_FFFE:
Map_8k_ROM(0, 0 & tsms.Pages_Mask_8k);
Map_8k_ROM(1, 1 & tsms.Pages_Mask_8k);
Map_8k_ROM(2, 2 & tsms.Pages_Mask_8k);
Map_8k_ROM(3, 3 & tsms.Pages_Mask_8k);
Map_8k_ROM(4, 0 & tsms.Pages_Mask_8k);
Map_8k_ROM(5, 1 & tsms.Pages_Mask_8k);
Map_8k_RAM(6, 0);
Map_8k_RAM(7, 0);
g_machine.mapper_regs_count = 3;
for (int i = 0; i != MAPPER_REGS_MAX; i++)
g_machine.mapper_regs[i] = 0;
g_machine.mapper_regs[2] = 1;
break;

case MAPPER_SC3000_Survivors_Multicart:
g_machine.mapper_regs_count = 1;
for (int i = 0; i != MAPPER_REGS_MAX; i++)
Expand Down
55 changes: 55 additions & 0 deletions meka/srcs/mappers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,61 @@ WRITE_FUNC(Write_Mapper_SMS_Korean_MD_FFFA)
Write_Error(Addr, Value);
}

// Mapper #28
//
// Super 5 in 1 Game Gear [Mortal Kombat] [Super 12 in 1]
// Super 7 in 1 Game Gear [Bare Knuckle 2] [Super 12 in 1]
// Super 12 in 1 Game Gear [Bare Knuckle 2] (Unl)
// Super 12 in 1 Game Gear [Mortal Kombat] (Unl)
WRITE_FUNC (Write_Mapper_GG_Super_12_in_1_FFFE)
{
if ((Addr == 0xFFFE) || (Addr == 0xFFFF)) // Configurable segment -----------------------------------------------
{
int in_menu_mode = (g_machine.mapper_regs[0] & 0x08) == 0x00;
if (Addr == 0xFFFE) {
if (in_menu_mode && ((Value & 0xF0) == 0x40)) {
g_machine.mapper_regs[0] = (g_machine.mapper_regs[0] & 0x1E) | (Value & 0x0E) << 4 | (Value & 0x01);
} else if (in_menu_mode && ((Value & 0xE0) == 0x00)) {
g_machine.mapper_regs[0] = (g_machine.mapper_regs[0] & 0xF0) | ((Value & 0x10) >> 4);
} else {
g_machine.mapper_regs[2] = Value & 0x1F;
}
}
if (Addr == 0xFFFF) {
if (in_menu_mode && ((Value & 0xF0) == 0x40)) {
g_machine.mapper_regs[0] |= 0x08;
in_menu_mode = 0;
} else if ((!in_menu_mode) && ((Value & 0xE0) == 0xE0)) {
// Meka extension: this is used to reliably reset the
// mapper to menu mode when loading save states
g_machine.mapper_regs[0] &= ~0x08;
in_menu_mode = 1;
}
g_machine.mapper_regs[1] = Value & 0x1F;
}
const int effective_mapbase = (g_machine.mapper_regs[0] & 0xF0) | ((g_machine.mapper_regs[0] & 0x01) << 4);
const int fixed_or_reg1 = in_menu_mode ? 1 : (g_machine.mapper_regs[2] & 0x1F);
const int fixed_or_reg0 = in_menu_mode ? 0 : (g_machine.mapper_regs[1] & 0x1F);
Map_8k_ROM(0, (effective_mapbase << 1) & tsms.Pages_Mask_8k);
Map_8k_ROM(1, ((effective_mapbase << 1) | 1) & tsms.Pages_Mask_8k);
Map_8k_ROM(2, ((effective_mapbase | fixed_or_reg1) << 1) & tsms.Pages_Mask_8k);
Map_8k_ROM(3, (((effective_mapbase | fixed_or_reg1) << 1) | 1) & tsms.Pages_Mask_8k);
Map_8k_ROM(4, ((effective_mapbase | fixed_or_reg0) << 1) & tsms.Pages_Mask_8k);
Map_8k_ROM(5, (((effective_mapbase | fixed_or_reg0) << 1) | 1) & tsms.Pages_Mask_8k);
//return;
}

switch (Addr >> 13)
{
// RAM [0xC000] = [0xE000] ------------------------------------------------
case 6: Mem_Pages[6][Addr] = Value; return;
case 7: Mem_Pages[7][Addr] = Value; return;
}

Write_Error (Addr, Value);
}


// Based on MSX ASCII 8KB mapper? http://bifi.msxnet.org/msxnet/tech/megaroms.html#ascii8
// - This mapper requires 4 registers to save bank switching state.
// However, all other mappers so far used only 3 registers, stored as 3 bytes.
Expand Down
2 changes: 2 additions & 0 deletions meka/srcs/mappers.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#define MAPPER_SMS_Korean_MD_FFF0 (24) // Registers at 0xFFF0 and 0xFFFF (Mega Mode Super Game 30 [SMS-MD])
#define MAPPER_SMS_Korean_MD_FFF5 (25) // Registers at 0xFFF5 and 0xFFFF (Jaemiissneun Game Mo-eumjip 42/65 Hap [SMS-MD], Pigu Wang Hap ~ Jaemiiss-neun Game Mo-eumjip [SMS-MD])
#define MAPPER_SMS_Korean_MD_FFFA (26) // Registers at 0xFFFA and 0xFFFF (Game Jiphap 30 Hap [SMS-MD])
#define MAPPER_GG_Super_12_in_1_FFFE (28) // Registers at 0xFFFE 0xFFFF (Super 5/7/12 in 1 Game Gear [Mortal Kombat]/[Bare Knuckle 2])

#define READ_FUNC(_NAME) u8 _NAME(register u16 Addr)
#define WRITE_FUNC(_NAME) void _NAME(register u16 Addr, register u8 Value)
Expand Down Expand Up @@ -94,6 +95,7 @@ WRITE_FUNC (Write_Mapper_SMS_Korean_0000_xor_FF);
WRITE_FUNC (Write_Mapper_SMS_Korean_MD_FFF0);
WRITE_FUNC (Write_Mapper_SMS_Korean_MD_FFF5);
WRITE_FUNC (Write_Mapper_SMS_Korean_MD_FFFA);
WRITE_FUNC (Write_Mapper_GG_Super_12_in_1_FFFE);
//-----------------------------------------------------------------------------
void Out_SC3000_SurvivorsMulticarts_DataWrite(u8 v);

Expand Down
22 changes: 22 additions & 0 deletions meka/srcs/saves.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,26 @@ void Load_Game_Fixup(void)
WrZ80_NoHook(0xFFFF, g_machine.mapper_regs[1]);
WrZ80_NoHook(0xFFFE, g_machine.mapper_regs[2]);
break;
case MAPPER_GG_Super_12_in_1_FFFE:
if (1) {
const int in_menu_mode = (g_machine.mapper_regs[0] & 0x08) == 0x00;
const int mapbase = g_machine.mapper_regs[0] & 0xF1;
const int reg1 = g_machine.mapper_regs[2] & 0x1F;
const int reg0 = g_machine.mapper_regs[1] & 0x1F;
WrZ80_NoHook(0xFFFE, 0xE0); // Meka extension: mapper reset to menu mode
WrZ80_NoHook(0xFFFE, 0x40 | ((mapbase & 0xE0) >> 4) | (mapbase & 0x01));
WrZ80_NoHook(0xFFFE, mapbase & 0x10);
if (in_menu_mode) {
// Meka extension: reliable mapper register restoration in menu mode
WrZ80_NoHook(0xFFFE, 0x80 | reg1);
WrZ80_NoHook(0xFFFF, reg0);
} else {
WrZ80_NoHook(0xFFFF, 0x40);
WrZ80_NoHook(0xFFFE, reg1);
WrZ80_NoHook(0xFFFF, reg0);
}
}
break;
}
}

Expand Down Expand Up @@ -335,6 +355,7 @@ int Save_Game_MSV(FILE *f)
case MAPPER_SMS_Korean_MD_FFF0:
case MAPPER_SMS_Korean_MD_FFF5:
case MAPPER_SMS_Korean_MD_FFFA:
case MAPPER_GG_Super_12_in_1_FFFE:
default:
fwrite (RAM, 0x2000, 1, f); // Do not use g_driver->ram because of g_driver video mode change
break;
Expand Down Expand Up @@ -513,6 +534,7 @@ int Load_Game_MSV(FILE *f)
case MAPPER_SMS_Korean_MD_FFF0:
case MAPPER_SMS_Korean_MD_FFF5:
case MAPPER_SMS_Korean_MD_FFFA:
case MAPPER_GG_Super_12_in_1_FFFE:
default:
fread (RAM, 0x2000, 1, f); // Do not use g_driver->ram because of g_driver video mode change
break;
Expand Down

0 comments on commit 2ea07b9

Please sign in to comment.