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 (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 [Super 12 in 1] (Unl).gg

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

The last 2MB, followed by the first 2MB:
Super 12 in 1 Game Gear [alt] (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 19, 2023
1 parent 3cb1c30 commit 9055778
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 [Mortal Kombat] *Ok
Super 12 in 1 Game Gear [Bare Knuckle 2] *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 2ff576fa 8B4AEC63ECB40E2E Super 12 in 1 Game Gear [Mortal Kombat]/EMU_MAPPER=28
GG f56d3219 8B4AEC63ECB40E2E Super 12 in 1 Game Gear [Bare Knuckle 2]/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 [Mortal Kombat] (Unl)
// Super 12 in 1 Game Gear [Bare Knuckle 2] (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 9055778

Please sign in to comment.