Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion meka/compat.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1405,6 +1405,11 @@
Street Hero [Proto 1] [SMS-GG] Ok
Strider Returns Ok
Striker Ok
Super 21 in 1 [Pacmania] [Super 53 in 1] *Ok
Super 32 in 1 [Alien 3] [Super 53 in 1] *Ok
Super 53 in 1 [Alien 3] *Ok
Super 53 in 1 [Pacmania] *Ok
Super 68 in 1 [Simpson] *Ok
Super Battletank Ok
Super Columns Ok
Super Columns (JP) Ok
Expand Down Expand Up @@ -1498,7 +1503,7 @@
Zoop (US) Ok
Zoop [Proto] (US) Ok
-----------------------------------------------------------------------------
517 games tested - 506 are "Ok" - Compatibility rate: 97.63%
522 games tested - 511 are "Ok" - Compatibility rate: 97.89%
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
Expand Down
5 changes: 5 additions & 0 deletions meka/meka.nam
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,11 @@ 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 05539043 7AAAB32E98A513AB Super 21 in 1 [Pacmania] [Super 53 in 1]/EMU_MAPPER=41
GG 3b87194e 040AB4999C343E97 Super 32 in 1 [Alien 3] [Super 53 in 1]/EMU_MAPPER=41
GG 55b18291 7EB467C734D95142 Super 53 in 1 [Alien 3]/EMU_MAPPER=41
GG 83c15a37 F85E1AF5CC7E64ED Super 53 in 1 [Pacmania]/EMU_MAPPER=41
GG 179f3519 CDAB487A05130DA1 Super 68 in 1 [Simpson]/EMU_MAPPER=41
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
23 changes: 23 additions & 0 deletions meka/srcs/machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "tvtype.h"
#include "sound/fmunit.h"
#include "sound/psg.h"
#include "app_game.h"

//-----------------------------------------------------------------------------
// Data
Expand Down Expand Up @@ -196,6 +197,9 @@ void Machine_Set_Handler_MemRW(void)
case MAPPER_SMS_Korean_MSX_32KB_2000:
WrZ80 = WrZ80_NoHook = Write_Mapper_SMS_Korean_MSX_32KB_2000;
break;
case MAPPER_GG_Super_68_in_1_FFFE_FFFF:
WrZ80 = WrZ80_NoHook = Write_Mapper_GG_Super_68_in_1_FFFE_FFFF;
break;
}
}

Expand Down Expand Up @@ -485,6 +489,25 @@ void Machine_Set_Mapping (void)
g_machine.mapper_regs[0] = 0;
break;

case MAPPER_GG_Super_68_in_1_FFFE_FFFF:
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 = 4;
for (int i = 0; i != MAPPER_REGS_MAX; i++)
g_machine.mapper_regs[i] = 0;
g_machine.mapper_regs[2] = 1;
drv_set(DRV_GG);
gamebox_resize_all();
VDP_UpdateLineLimits();
Video_GameMode_UpdateBounds();
break;

case MAPPER_SC3000_Survivors_Multicart:
g_machine.mapper_regs_count = 1;
for (int i = 0; i != MAPPER_REGS_MAX; i++)
Expand Down
120 changes: 120 additions & 0 deletions meka/srcs/mappers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
#include "shared.h"
#include "mappers.h"
#include "eeprom.h"
#include "vdp.h"
#include "video.h"
#include "app_game.h"

//-----------------------------------------------------------------------------
// Data
Expand Down Expand Up @@ -952,6 +955,123 @@ WRITE_FUNC (Write_Mapper_SMS_Korean_MSX_32KB_2000)
Write_Error (Addr, Value);
}

// Mapper #41
// Super 68 in 1 [Simpson]
// Super 53 in 1 [Alien 3]
//
// This also works fine for ghost ROM data:
//
// Super 53 in 1 [Pacmania]
// Super 32 in 1 [Alien 3] [Super 53 in 1]
// Super 21 in 1 [Pacmania] [Super 53 in 1]
WRITE_FUNC(Write_Mapper_GG_Super_68_in_1_FFFE_FFFF)
{
if ((Addr == 0xFFFE) || (Addr == 0xFFFF)) // Configurable segment -----------------------------------------------
{
if (Addr == 0xFFFF)
{
g_machine.mapper_regs[1] = Value;
if (! (g_machine.mapper_regs[3] & 0x80)) {
// "menu mode"
if (Value & 0x08) {
g_machine.mapper_regs[1] = 0;
g_machine.mapper_regs[2] = 1;
// switch to "Sega mode"
g_machine.mapper_regs[3] |= 0x80;
bool sms_gg_mode = false;
if (g_machine.mapper_regs[3] & 0x08) {
// SMS-GG mode according to heuristic
int game_id_low = g_machine.mapper_regs[0] & 0x3F;
sms_gg_mode = (game_id_low < 0x14) || (game_id_low == 0x18) || (game_id_low == 0x28);
} else if (g_machine.mapper_regs[3] & 0x04) {
// SMS-GG mode according to game_id & 0x40
sms_gg_mode = !! (g_machine.mapper_regs[0] & 0x40);
} else {
// SMS-GG mode according to game_id & 0x20
// (game ID limited to six bits in this mode)
sms_gg_mode = !! (g_machine.mapper_regs[0] & 0x20);
}
if (sms_gg_mode) {
drv_set(DRV_SMS);
} else {
drv_set(DRV_GG);
}
gamebox_resize_all();
VDP_UpdateLineLimits();
Video_GameMode_UpdateBounds();
}
}
}
else if (Addr == 0xFFFE)
{
g_machine.mapper_regs[2] = Value;
if (! (g_machine.mapper_regs[3] & 0x80)) {
// "menu mode"
if ((Value & 0x0C) == 0x0C) {
g_machine.mapper_regs[0] &= 0x3F;
g_machine.mapper_regs[0] |= (Value & 0x03) << 6;

if (! (g_machine.mapper_regs[3] & 0x08)) {
// choose mechanism for SMS-GG mode signalling in non-heuristic mode:
// store "use game_id & 0x40" bit 0x04 in register 3
g_machine.mapper_regs[3] = 0x04 | (g_machine.mapper_regs[3] & 0xF3);
}
} else if (Value & 0x08) {
g_machine.mapper_regs[0] &= 0xCF;
g_machine.mapper_regs[0] |= (Value & 0x03) << 4;
} else if (Value & 0x04) {
g_machine.mapper_regs[0] &= 0xF3;
g_machine.mapper_regs[0] |= (Value & 0x03) << 2;
} else {
g_machine.mapper_regs[0] &= 0xFC;
g_machine.mapper_regs[0] |= Value & 0x03;
// choose mechanism for SMS-GG mode signalling:
// store "use heuristic" as bit 0x08 in register 3 (and clear bit 0x04)
g_machine.mapper_regs[3] = (g_machine.mapper_regs[0] & 0x08) | (g_machine.mapper_regs[3] & 0xF3);
}
}
}

unsigned int game_id = g_machine.mapper_regs[0];
// when ROM is three megabytes it acts like 4MB layout A B C C
// NOTE: tsms.Pages_Count_8k is actually a maximum value -- not a count!
unsigned int game_id_mask = ((game_id & 0x40) && ((tsms.Pages_Count_8k + 1) / 4 == 0x60)) ? 0x5F : 0xFF;
unsigned int base_page_8k = (game_id & game_id_mask) * 4;

// NOTE: 68-in-1 hardware masks pages with 0x07 for game_id
// less than 0x20 but 53-in-1 doesn't, and a wider mask
// doesn't break anything for 68-in-1
unsigned int paging_mask = 0x0F;

if (! (g_machine.mapper_regs[3] & 0x80)) {
// "menu mode"
Map_8k_ROM(0, base_page_8k & tsms.Pages_Mask_8k);
Map_8k_ROM(1, (base_page_8k | 1) & tsms.Pages_Mask_8k);
Map_8k_ROM(2, (base_page_8k | 2) & tsms.Pages_Mask_8k);
Map_8k_ROM(3, (base_page_8k | 3) & tsms.Pages_Mask_8k);
Map_8k_ROM(4, base_page_8k & tsms.Pages_Mask_8k);
Map_8k_ROM(5, (base_page_8k | 1) & tsms.Pages_Mask_8k);
} else {
// "Sega mode"
Map_8k_ROM(0, base_page_8k & tsms.Pages_Mask_8k);
Map_8k_ROM(1, (base_page_8k | 1) & tsms.Pages_Mask_8k);
Map_8k_ROM(2, (base_page_8k | ((g_machine.mapper_regs[2] & paging_mask) * 2)) & tsms.Pages_Mask_8k);
Map_8k_ROM(3, (base_page_8k | ((g_machine.mapper_regs[2] & paging_mask) * 2) | 1) & tsms.Pages_Mask_8k);
Map_8k_ROM(4, (base_page_8k | ((g_machine.mapper_regs[1] & paging_mask) * 2)) & tsms.Pages_Mask_8k);
Map_8k_ROM(5, (base_page_8k | ((g_machine.mapper_regs[1] & paging_mask) * 2) | 1) & tsms.Pages_Mask_8k);
}
}

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 @@ -50,6 +50,7 @@
#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_SMS_Korean_MSX_32KB_2000 (27) // Register at 0x2000 (2 Hap in 1 (Moai-ui bomul, David-2))
#define MAPPER_GG_Super_68_in_1_FFFE_FFFF (41) // Registers at 0xFFFE and 0xFFFF (Super 68 in 1 [Simpson], Super 53 in 1 [Alien 3])

#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 @@ -96,6 +97,7 @@ 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_SMS_Korean_MSX_32KB_2000);
WRITE_FUNC (Write_Mapper_GG_Super_68_in_1_FFFE_FFFF);
//-----------------------------------------------------------------------------
void Out_SC3000_SurvivorsMulticarts_DataWrite(u8 v);

Expand Down
60 changes: 57 additions & 3 deletions meka/srcs/saves.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include "vmachine.h"
#include "sound/fmunit.h"
#include "sound/psg.h"
#include "video.h"
#include "app_game.h"

//-----------------------------------------------------------------------------
// Functions
Expand All @@ -26,6 +28,7 @@ void Load_Game_Fixup(void)
{
int i;
u8 b;
bool sms_gg_mode_in_mapper = false;

// CPU
#ifdef MARAT_Z80
Expand Down Expand Up @@ -144,13 +147,62 @@ void Load_Game_Fixup(void)
case MAPPER_SMS_Korean_MSX_32KB_2000:
WrZ80_NoHook(0x2000, g_machine.mapper_regs[0]);
break;
case MAPPER_GG_Super_68_in_1_FFFE_FFFF:
if (1) {
unsigned int game_id = g_machine.mapper_regs[0];
unsigned int slot_8000_page_offset_16k_FFFF = g_machine.mapper_regs[1];
unsigned int slot_4000_page_offset_16k_FFFE = g_machine.mapper_regs[2];
unsigned int mapper_mode = g_machine.mapper_regs[3];
// mapper is initially in GG mode
drv_set(DRV_GG);
g_machine.mapper_regs[0] = 0x00;
g_machine.mapper_regs[1] = 0x00;
g_machine.mapper_regs[2] = 0x00;
g_machine.mapper_regs[3] = 0x00;
if (mapper_mode & 0x08) {
// "heuristic mode" for SMS-GG determination
WrZ80_NoHook(0xFFFE, 0x06);
}
// low two bits of game ID (also locks in "heuristic mode" bit)
WrZ80_NoHook(0xFFFE, game_id & 0x03);
// lower middle two bits of game ID
WrZ80_NoHook(0xFFFE, 0x04 | ((game_id & 0x0C) >> 2));
// upper middle two bits of game ID
WrZ80_NoHook(0xFFFE, 0x08 | ((game_id & 0x30) >> 4));
if ((mapper_mode & 0x0C) || (game_id & 0xC0)) {
// high two bits of game ID
//
// ... and also ...
//
// "use game_id & 0x40" for SMS-GG determination
// when not in heuristic mode
WrZ80_NoHook(0xFFFE, 0x0C | ((game_id & 0xC0) >> 6));
}
if (mapper_mode & 0x80) {
// "Sega mode"
WrZ80_NoHook(0xFFFF, 0x08);
WrZ80_NoHook(0xFFFF, slot_8000_page_offset_16k_FFFF);
WrZ80_NoHook(0xFFFE, slot_4000_page_offset_16k_FFFE);
}
g_machine.mapper_regs[0] = game_id;
g_machine.mapper_regs[1] = slot_8000_page_offset_16k_FFFF;
g_machine.mapper_regs[2] = slot_4000_page_offset_16k_FFFE;
g_machine.mapper_regs[3] = mapper_mode;
gamebox_resize_all();
VDP_UpdateLineLimits();
Video_GameMode_UpdateBounds();
sms_gg_mode_in_mapper = true;
}
break;
}
}

// VDP/Graphic related
tsms.VDP_Video_Change |= VDP_VIDEO_CHANGE_ALL;
VDP_UpdateLineLimits();
// FALSE!!! // tsms.VDP_Line = 224;
if (!sms_gg_mode_in_mapper) {
tsms.VDP_Video_Change |= VDP_VIDEO_CHANGE_ALL;
VDP_UpdateLineLimits();
// FALSE!!! // tsms.VDP_Line = 224;
}

// Rewrite all VDP registers (we can do that since it has zero side-effect)
for (i = 0; i < 16; i ++)
Expand Down Expand Up @@ -339,6 +391,7 @@ int Save_Game_MSV(FILE *f)
case MAPPER_SMS_Korean_MD_FFF5:
case MAPPER_SMS_Korean_MD_FFFA:
case MAPPER_SMS_Korean_MSX_32KB_2000:
case MAPPER_GG_Super_68_in_1_FFFE_FFFF:
default:
fwrite (RAM, 0x2000, 1, f); // Do not use g_driver->ram because of g_driver video mode change
break;
Expand Down Expand Up @@ -518,6 +571,7 @@ int Load_Game_MSV(FILE *f)
case MAPPER_SMS_Korean_MD_FFF5:
case MAPPER_SMS_Korean_MD_FFFA:
case MAPPER_SMS_Korean_MSX_32KB_2000:
case MAPPER_GG_Super_68_in_1_FFFE_FFFF:
default:
fread (RAM, 0x2000, 1, f); // Do not use g_driver->ram because of g_driver video mode change
break;
Expand Down