diff --git a/meka/compat.txt b/meka/compat.txt index ab16dc0f..5eff805a 100644 --- a/meka/compat.txt +++ b/meka/compat.txt @@ -1133,6 +1133,7 @@ Galaga '91 (JP) Ok Gamble Panic (JP) Ok Gambler Jikochuushin Ha (JP) Ok + Game Gear Super 16 in 1 ~ Wudi Xilie [Columns] *Ok Garou Densetsu Special (JP) Ok Ganbare Gorby! (JP) Ok Garfield: Caught in the Act Ok @@ -1498,7 +1499,7 @@ Zoop (US) Ok Zoop [Proto] (US) Ok ----------------------------------------------------------------------------- - 517 games tested - 506 are "Ok" - Compatibility rate: 97.63% + 518 games tested - 507 are "Ok" - Compatibility rate: 97.88% ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- diff --git a/meka/meka.nam b/meka/meka.nam index 77c032bf..0e671cfe 100644 --- a/meka/meka.nam +++ b/meka/meka.nam @@ -1029,6 +1029,7 @@ GG 09534742 45190AB92665163E Gamble Panic/COUNTRY=JP/PRODUCT_NO=G-3364 GG 423803a7 9E7E0CAD62261E85 Gambler Jikochuushin Ha/COUNTRY=JP/PRODUCT_NO=G-3309,G-3339 GG 0593ba24 905D6D377D1F9D36 Galaga '91/COUNTRY=JP/PRODUCT_NO=T-14057/COMMENT=Japanese version of "Galaga 2". GG 95ecece2 432C080C09AD5275 Galaga 2/COUNTRY=EU/PRODUCT_NO=2322/COMMENT=Export version of "Galaga '91". +GG 01d9f565 8A21D815D0D74879 Game Gear Super 16 in 1 ~ Wudi Xilie [Columns]/EMU_MAPPER=50 GG cd53f3af 5434506F49A77C4D Garfield: Caught in the Act/COUNTRY=US,EU/PRODUCT_NO=2560,2560-50 GG 9afb6f33 CE07E49360532BD6 Garou Densetsu Special/COUNTRY=JP/PRODUCT_NO=T-103017/COMMENT=Japanese version of "Fatal Fury Special". GG 0e300223 27BA4F0E3A5DBF6C Gear Stadium/COUNTRY=JP/PRODUCT_NO=T-14037/COMMENT=Japanese version of "Batter Up". diff --git a/meka/srcs/machine.cpp b/meka/srcs/machine.cpp index f23e934f..7929f596 100644 --- a/meka/srcs/machine.cpp +++ b/meka/srcs/machine.cpp @@ -22,6 +22,7 @@ #include "tvtype.h" #include "sound/fmunit.h" #include "sound/psg.h" +#include "app_game.h" //----------------------------------------------------------------------------- // Data @@ -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_16_in_1_Columns_FFFx: + WrZ80 = WrZ80_NoHook = Write_Mapper_GG_Super_16_in_1_Columns_FFFx; + break; } } @@ -485,6 +489,24 @@ void Machine_Set_Mapping (void) g_machine.mapper_regs[0] = 0; break; + case MAPPER_GG_Super_16_in_1_Columns_FFFx: + 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); // should actually be all zeroes initially + Map_8k_ROM(5, 1 & tsms.Pages_Mask_8k); // should actually be all zeroes initially + 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; + 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++) diff --git a/meka/srcs/mappers.cpp b/meka/srcs/mappers.cpp index 00bf3386..df650012 100644 --- a/meka/srcs/mappers.cpp +++ b/meka/srcs/mappers.cpp @@ -14,6 +14,9 @@ #include "shared.h" #include "mappers.h" #include "eeprom.h" +#include "vdp.h" +#include "video.h" +#include "app_game.h" //----------------------------------------------------------------------------- // Data @@ -952,6 +955,68 @@ WRITE_FUNC (Write_Mapper_SMS_Korean_MSX_32KB_2000) Write_Error (Addr, Value); } +// Mapper #50 +// Game Gear Super 16 in 1 ~ Wudi Xilie [Columns] (Unl) +WRITE_FUNC (Write_Mapper_GG_Super_16_in_1_Columns_FFFx) +{ + const unsigned int incomplete_address_decoding_assumed_bits = 0x000F; + + if ((Addr | incomplete_address_decoding_assumed_bits) == 0xFFFF) // Configurable segment ----------------------------------------------- + { + if ((Value & 0xC0) == 0xC0) { + g_machine.mapper_regs[0] = (g_machine.mapper_regs[0] & 0x3F) | ((Value & 0x30) << 2); + } else if ((Value & 0xC0) == 0x80) { + g_machine.mapper_regs[0] = (g_machine.mapper_regs[0] & 0xCF) | (Value & 0x30); + } else if ((Value & 0xC0) == 0x40) { + g_machine.mapper_regs[0] = (g_machine.mapper_regs[0] & 0xF3) | ((Value & 0x30) >> 2); + } + + bool sega_mode = (g_machine.mapper_regs[0] & 0x40) ? true : false; + bool sms_gg_mode = (g_machine.mapper_regs[0] & 0x10) ? true : false; + + // not sure whether real hardware aliases these too + if (Addr == 0xFFFF) { + g_machine.mapper_regs[1] = Value & 0x0F; + } + if (Addr == 0xFFFE) { + g_machine.mapper_regs[2] = Value & 0x0F; + } + + if (((Value & 0xC0) == 0x00) && !sega_mode) { + g_machine.mapper_regs[0] = (g_machine.mapper_regs[0] & 0xFC) | ((Value & 0x30) >> 4); + } + + unsigned int base_page_32k = g_machine.mapper_regs[0] & 0x0F; + unsigned int page_8000_offset_16k = sega_mode ? g_machine.mapper_regs[1] : 0; + unsigned int page_4000_offset_16k = sega_mode ? g_machine.mapper_regs[2] : 1; + + if (sms_gg_mode) { + drv_set(DRV_SMS); + } else { + drv_set(DRV_GG); + } + gamebox_resize_all(); + VDP_UpdateLineLimits(); + Video_GameMode_UpdateBounds(); + + Map_8k_ROM(0, ((base_page_32k * 4) | 0) & tsms.Pages_Mask_8k); + Map_8k_ROM(1, ((base_page_32k * 4) | 1) & tsms.Pages_Mask_8k); + Map_8k_ROM(2, ((base_page_32k * 4) | (page_4000_offset_16k * 2) | 0) & tsms.Pages_Mask_8k); + Map_8k_ROM(3, ((base_page_32k * 4) | (page_4000_offset_16k * 2) | 1) & tsms.Pages_Mask_8k); + Map_8k_ROM(4, ((base_page_32k * 4) | (page_8000_offset_16k * 2) | 0) & tsms.Pages_Mask_8k); + Map_8k_ROM(5, ((base_page_32k * 4) | (page_8000_offset_16k * 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. diff --git a/meka/srcs/mappers.h b/meka/srcs/mappers.h index 3711266f..a75a84e6 100644 --- a/meka/srcs/mappers.h +++ b/meka/srcs/mappers.h @@ -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_16_in_1_Columns_FFFx (50) // Register at 0xFFFx (Game Gear Super 16 in 1 ~ Wudi Xilie [Columns]) #define READ_FUNC(_NAME) u8 _NAME(register u16 Addr) #define WRITE_FUNC(_NAME) void _NAME(register u16 Addr, register u8 Value) @@ -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_16_in_1_Columns_FFFx); //----------------------------------------------------------------------------- void Out_SC3000_SurvivorsMulticarts_DataWrite(u8 v); diff --git a/meka/srcs/saves.cpp b/meka/srcs/saves.cpp index 09bb14b8..afae675b 100644 --- a/meka/srcs/saves.cpp +++ b/meka/srcs/saves.cpp @@ -16,6 +16,8 @@ #include "vmachine.h" #include "sound/fmunit.h" #include "sound/psg.h" +#include "video.h" +#include "app_game.h" //----------------------------------------------------------------------------- // Functions @@ -26,6 +28,7 @@ void Load_Game_Fixup(void) { int i; u8 b; + bool sms_gg_mode_in_mapper = false; // CPU #ifdef MARAT_Z80 @@ -144,13 +147,46 @@ 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_16_in_1_Columns_FFFx: + if (1) { + // these mapper writes will configure SMS-GG mode if needed + unsigned int mode_bits = g_machine.mapper_regs[0] & 0xF0; + unsigned int base_page_32k = g_machine.mapper_regs[0] & 0x0F; + unsigned int page_8000_offset_16k = g_machine.mapper_regs[1]; + unsigned int page_4000_offset_16k = g_machine.mapper_regs[2]; + + // restore "sega" mode paging registers + WrZ80_NoHook(0xFFFF, page_8000_offset_16k); + WrZ80_NoHook(0xFFFE, page_4000_offset_16k); + + // use 0xFFF8 for the rest of the writes to prevent + // paging register aliasing (not sure whether real + // hardware works this way, but our implementaiton + // does) + + // configure base page + WrZ80_NoHook(0xFFF8, 0xC0); + WrZ80_NoHook(0xFFF8, 0x40 | ((base_page_32k & 0x0C) << 2)); + WrZ80_NoHook(0xFFF8, 0x00 | ((base_page_32k & 0x03) << 4)); + + // restore SMS-GG mode if needed + WrZ80_NoHook(0xFFF8, 0x80 | (mode_bits & 0x30)); + + // restore "sega" mode if needed + WrZ80_NoHook(0xFFF8, 0xC0 | ((mode_bits & 0xC0) >> 2)); + + 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 ++) @@ -339,6 +375,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_16_in_1_Columns_FFFx: default: fwrite (RAM, 0x2000, 1, f); // Do not use g_driver->ram because of g_driver video mode change break; @@ -518,6 +555,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_16_in_1_Columns_FFFx: default: fread (RAM, 0x2000, 1, f); // Do not use g_driver->ram because of g_driver video mode change break;