diff --git a/meka/compat.txt b/meka/compat.txt index ab16dc0f..c8444dd1 100644 --- a/meka/compat.txt +++ b/meka/compat.txt @@ -1454,6 +1454,7 @@ Tom and Jerry: The Movie (JP) Ok Torarete Tamaruka!? (JP) Ok True Lies Ok + Turbo 9 in 1 [Street Fighter 2] *Ok Ultimate Soccer Ok Urban Strike Ok Vampire - Master of Darkness (US) 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..2e43eca5 100644 --- a/meka/meka.nam +++ b/meka/meka.nam @@ -1332,6 +1332,7 @@ GG a1453efa D9F631F59C7933C3 Tom and Jerry: The Movie/COUNTRY=JP,BR/PRODUCT_N GG 5cd33ff2 DC1F080D96A53D78 Tom and Jerry: The Movie/COUNTRY=US,EU/PRODUCT_NO=2434 GG 5bcf9b97 F9471D41510253BC Torarete Tamaruka!?/COUNTRY=JP/PRODUCT_NO=G-3348 GG 5173b02a B31BDB3827A8440C True Lies/COUNTRY=US,EU,JP/PRODUCT_NO=T-81318,T-81318-50,T-81167 +GG 763b5d62 BD832687D3D0244C Turbo 9 in 1 [Street Fighter 2]/EMU_MAPPER=30 GG 820965a3 78192012DB30BF73 Ultimate Soccer/COUNTRY=JP,EU,BR/PRODUCT_NO=G-3333,075300 GG 185e9fc1 07D77087D26DD517 Urban Strike/COUNTRY=US/PRODUCT_NO=T-100048 GG 7ec64025 84C269594C15F3A4 Vampire - Master of Darkness/COUNTRY=US/PRODUCT_NO=2437/COMMENT=US version of "In the Wake of Vampire" (Japan) and "Master of Darkness" (Europe). diff --git a/meka/srcs/machine.cpp b/meka/srcs/machine.cpp index f23e934f..3f267760 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_Turbo_9_in_1_8000_4000: + WrZ80 = WrZ80_NoHook = Write_Mapper_GG_Turbo_9_in_1_8000_4000; + break; } } @@ -485,6 +489,26 @@ void Machine_Set_Mapping (void) g_machine.mapper_regs[0] = 0; break; + case MAPPER_GG_Turbo_9_in_1_8000_4000: + Map_8k_ROM(0, 0x00 & tsms.Pages_Mask_8k); + Map_8k_ROM(1, 0x01 & tsms.Pages_Mask_8k); + Map_8k_ROM(2, 0x02 & tsms.Pages_Mask_8k); + Map_8k_ROM(3, 0x03 & tsms.Pages_Mask_8k); + Map_8k_ROM(4, 0x00 & tsms.Pages_Mask_8k); + Map_8k_ROM(5, 0x01 & 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[0] = 0x80; + 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++) diff --git a/meka/srcs/mappers.cpp b/meka/srcs/mappers.cpp index 00bf3386..703ff79e 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,66 @@ WRITE_FUNC (Write_Mapper_SMS_Korean_MSX_32KB_2000) Write_Error (Addr, Value); } +// Mapper #30 +// Turbo 9 in 1 +WRITE_FUNC(Write_Mapper_GG_Turbo_9_in_1_8000_4000) +{ + if (Addr == 0x8000 || Addr == 0x4000) // Configurable segment ----------------------------------------------- + { + if (Addr == 0x8000) { + g_machine.mapper_regs[1] = Value; + } + if (Addr == 0x4000) { + g_machine.mapper_regs[2] = Value; + } + if ((g_machine.mapper_regs[2] == 0x11) && (g_machine.mapper_regs[0] == 0x80)) { + // use of 0x80 to signal the initial state is a Meka + // extension but does not conflict with the menu code's + // use of the mapper + g_machine.mapper_regs[0] = g_machine.mapper_regs[1]; + g_machine.mapper_regs[1] = 0; + g_machine.mapper_regs[2] = 1; + } else if ((g_machine.mapper_regs[2] == 0x11) && (g_machine.mapper_regs[1] == 0x80)) { + // use of 0x80 to return to the initial state is a Meka + // extension but does not conflict with the menu code's + // use of the mapper, nor does it conflict with the one + // game that uses the mapper + g_machine.mapper_regs[0] = 0x80; + g_machine.mapper_regs[1] = 0; + g_machine.mapper_regs[2] = 1; + } + Map_8k_ROM(0, (g_machine.mapper_regs[0] * 2) & tsms.Pages_Mask_8k); + Map_8k_ROM(1, (g_machine.mapper_regs[0] * 2 + 1) & tsms.Pages_Mask_8k); + Map_8k_ROM(2, ((g_machine.mapper_regs[0] + g_machine.mapper_regs[2]) * 2) & tsms.Pages_Mask_8k); + Map_8k_ROM(3, ((g_machine.mapper_regs[0] + g_machine.mapper_regs[2]) * 2 + 1) & tsms.Pages_Mask_8k); + Map_8k_ROM(4, ((g_machine.mapper_regs[0] + g_machine.mapper_regs[1]) * 2) & tsms.Pages_Mask_8k); + Map_8k_ROM(5, ((g_machine.mapper_regs[0] + g_machine.mapper_regs[1]) * 2 + 1) & tsms.Pages_Mask_8k); + // It is unclear how the cartridge decides whether to switch + // from native GG mode (which is the power-on default) to + // SMS-GG mode, but it appears to happen at the moment 0x11 is + // written to 0x4000 *unless* 0x0a was the most recent value + // previously written to 0x4000. + if ((g_machine.mapper_regs[0] != 0x80) && (g_machine.mapper_regs[0] != 0x0a)) { + drv_set(DRV_SMS); + } else { + drv_set(DRV_GG); + } + gamebox_resize_all(); + VDP_UpdateLineLimits(); + Video_GameMode_UpdateBounds(); + 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. diff --git a/meka/srcs/mappers.h b/meka/srcs/mappers.h index 3711266f..82d97d5d 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_Turbo_9_in_1_8000_4000 (30) // Registers at 0x8000 and 0x4000 (Turbo 9 in 1) #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_Turbo_9_in_1_8000_4000); //----------------------------------------------------------------------------- void Out_SC3000_SurvivorsMulticarts_DataWrite(u8 v); diff --git a/meka/srcs/saves.cpp b/meka/srcs/saves.cpp index 09bb14b8..ece5838f 100644 --- a/meka/srcs/saves.cpp +++ b/meka/srcs/saves.cpp @@ -26,6 +26,7 @@ void Load_Game_Fixup(void) { int i; u8 b; + bool sms_gg_mode_in_mapper = false; // CPU #ifdef MARAT_Z80 @@ -144,13 +145,33 @@ void Load_Game_Fixup(void) case MAPPER_SMS_Korean_MSX_32KB_2000: WrZ80_NoHook(0x2000, g_machine.mapper_regs[0]); break; + case MAPPER_GG_Turbo_9_in_1_8000_4000: + if (1) { + unsigned int base_page_16k = g_machine.mapper_regs[0]; + unsigned int page_8000_offset_16k = g_machine.mapper_regs[1]; + unsigned int page_4000_offset_16k = g_machine.mapper_regs[2]; + // use of 0x80 to return to the initial state is a Meka + // extension but does not conflict with the menu code's + // use of the mapper, nor does it conflict with the one + // game that uses the mapper + WrZ80_NoHook(0x8000, 0x80); + WrZ80_NoHook(0x4000, 0x11); + WrZ80_NoHook(0x8000, base_page_16k); + WrZ80_NoHook(0x4000, 0x11); + WrZ80_NoHook(0x4000, page_4000_offset_16k); + WrZ80_NoHook(0x8000, page_8000_offset_16k); + 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 +360,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_Turbo_9_in_1_8000_4000: default: fwrite (RAM, 0x2000, 1, f); // Do not use g_driver->ram because of g_driver video mode change break; @@ -518,6 +540,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_Turbo_9_in_1_8000_4000: default: fread (RAM, 0x2000, 1, f); // Do not use g_driver->ram because of g_driver video mode change break;