diff --git a/meka/compat.txt b/meka/compat.txt index ab16dc0f..aa575eca 100644 --- a/meka/compat.txt +++ b/meka/compat.txt @@ -1140,6 +1140,7 @@ Gear Stadium Heiseiban (JP) Ok Gear Works Ok George Foreman's KO Boxing Ok + GG 48 in 1 [Doraemon 2] *Ok GG Aleste (JP) Ok GG Portrait - Pai Chen (JP) Ok GG Portrait - Yuuki Akira (JP) 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..bd046da0 100644 --- a/meka/meka.nam +++ b/meka/meka.nam @@ -1035,6 +1035,7 @@ GG 0e300223 27BA4F0E3A5DBF6C Gear Stadium/COUNTRY=JP/PRODUCT_NO=T-14037/COMME GG a0530664 08ADE585B8DA024D Gear Stadium Heiseiban/COUNTRY=JP/PRODUCT_NO=T-14077 GG e9a2efb4 F9F734AF23CDB28B Gear Works/COUNTRY=US/PRODUCT_NO=T-93058 GG 58b44585 C92745E46E995090 George Foreman's KO Boxing/COUNTRY=US,EU/PRODUCT_NO=T-81038,T-81038-50 +GG 3394aaea F07FEFF54F0A7CD8 GG 48 in 1 [Doraemon 2]/EMU_MAPPER=48 GG 1b80a75b 682713F64A0AAD67 GG Aleste/COUNTRY=JP/PRODUCT_NO=T-66017 GG 695cc120 FCC991E880B52D60 GG Portrait - Pai Chen/COUNTRY=JP/PRODUCT_NO=G-3387 GG 51159f8f 5D96967FEE1C49A5 GG Portrait - Yuuki Akira/COUNTRY=JP/PRODUCT_NO=G-3386 diff --git a/meka/srcs/machine.cpp b/meka/srcs/machine.cpp index f23e934f..50ed7ad5 100644 --- a/meka/srcs/machine.cpp +++ b/meka/srcs/machine.cpp @@ -196,6 +196,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_48_in_1_FFF8_FFF9_FFFE_FFFF: + WrZ80 = WrZ80_NoHook = Write_Mapper_GG_48_in_1_FFF8_FFF9_FFFE_FFFF; + break; } } @@ -485,6 +488,22 @@ void Machine_Set_Mapping (void) g_machine.mapper_regs[0] = 0; break; + case MAPPER_GG_48_in_1_FFF8_FFF9_FFFE_FFFF: + 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[0] = 0x1F; + g_machine.mapper_regs[3] = 1; + 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); + 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..a4aaeae3 100644 --- a/meka/srcs/mappers.cpp +++ b/meka/srcs/mappers.cpp @@ -952,6 +952,84 @@ WRITE_FUNC (Write_Mapper_SMS_Korean_MSX_32KB_2000) Write_Error (Addr, Value); } +// Mapper #48 +// GG 48 in 1 [Doraemon 2] +WRITE_FUNC (Write_Mapper_GG_48_in_1_FFF8_FFF9_FFFE_FFFF) +{ + // Mapper register allocations: + // - Mode and mask: g_machine.mapper_regs[0] + // Bits 0xE0: configuration mode + // - 0x00: not in configuration mode + // - 0x80: expecting paging mask [step 1] + // - 0x40: expecting lower 5 bits of base page [step 2] + // - 0x20: expecting upper 3 bits of base page [step 3] + // - 0xE0: not expecting further configuration bytes + // Bits 0x1F: 16KB paging mask + // - Base page: g_machine.mapper_regs[1] + // Bits 0xFF: 16KB base page + // - Upper Sega paging register: g_machine.mapper_regs[2] + // Bits 0x1F: 16KB page offset for region 0x8000..0xBFFF + // - Lower Sega paging register: g_machine.mapper_regs[3] + // Bits 0x1F: 16KB page offset for region 0x4000..0x7FFF + if ((Addr == 0xFFF8) || (Addr == 0xFFF9) || (Addr == 0xFFFE) || (Addr == 0xFFFF)) // Configurable segment ----------------------------------------------- + { + if (Addr == 0xFFF8) { + // lock mapper + g_machine.mapper_regs[0] &= 0x1F; + if (Value & 0x10) { + // unlock mapper, expect paging mask next + g_machine.mapper_regs[0] |= 0x80; + } + } else if (Addr == 0xFFF9) { + if ((g_machine.mapper_regs[0] & 0xE0) == 0x80) { + // expecting paging mask + g_machine.mapper_regs[0] &= 0xE0; + g_machine.mapper_regs[0] |= Value & 0x1F; + // expect lower 5 bits of base page next + g_machine.mapper_regs[0] &= 0x1F; + g_machine.mapper_regs[0] |= 0x40; + } else if ((g_machine.mapper_regs[0] & 0xE0) == 0x40) { + // expecting lower 5 bits of base page + g_machine.mapper_regs[1] &= 0xE0; + g_machine.mapper_regs[1] |= Value & 0x1F; + // expect upper 3 bits of base page next + g_machine.mapper_regs[0] &= 0x1F; + g_machine.mapper_regs[0] |= 0x20; + } else if (((g_machine.mapper_regs[0] & 0xE0) == 0x20) && ((Value & 0x18) == 0x18)) { + // expecting upper 3 bits of base page + g_machine.mapper_regs[1] &= 0x1F; + g_machine.mapper_regs[1] |= (Value & 0x07) << 5; + // subsequent writes to 0xFFF9 ignored + g_machine.mapper_regs[0] &= 0x1F; + g_machine.mapper_regs[0] |= 0xE0; + } + } else if (Addr == 0xFFFF) { + g_machine.mapper_regs[2] = Value; + } else if (Addr == 0xFFFE) { + g_machine.mapper_regs[3] = Value; + } + unsigned int paging_mask = g_machine.mapper_regs[0] & 0x1F; + unsigned int base_page_16k = g_machine.mapper_regs[1]; + unsigned int upper_page_16k = base_page_16k + (g_machine.mapper_regs[2] & paging_mask); + unsigned int lower_page_16k = base_page_16k + (g_machine.mapper_regs[3] & paging_mask); + Map_8k_ROM(0, (base_page_16k * 2) & tsms.Pages_Mask_8k); + Map_8k_ROM(1, ((base_page_16k * 2) | 1) & tsms.Pages_Mask_8k); + Map_8k_ROM(2, (lower_page_16k * 2) & tsms.Pages_Mask_8k); + Map_8k_ROM(3, ((lower_page_16k * 2) | 1) & tsms.Pages_Mask_8k); + Map_8k_ROM(4, (upper_page_16k * 2) & tsms.Pages_Mask_8k); + Map_8k_ROM(5, ((upper_page_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..5080894b 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_48_in_1_FFF8_FFF9_FFFE_FFFF (48) // Registers at 0xFFF8, 0xFFF9, 0xFFFE, 0xFFFF (GG 48 in 1 [Doraemon 2]) #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_48_in_1_FFF8_FFF9_FFFE_FFFF); //----------------------------------------------------------------------------- void Out_SC3000_SurvivorsMulticarts_DataWrite(u8 v); diff --git a/meka/srcs/saves.cpp b/meka/srcs/saves.cpp index 09bb14b8..8deabc42 100644 --- a/meka/srcs/saves.cpp +++ b/meka/srcs/saves.cpp @@ -144,6 +144,12 @@ void Load_Game_Fixup(void) case MAPPER_SMS_Korean_MSX_32KB_2000: WrZ80_NoHook(0x2000, g_machine.mapper_regs[0]); break; + case MAPPER_GG_48_in_1_FFF8_FFF9_FFFE_FFFF: + // Re-writing these registers will have the side-effect of + // re-applying all the rest of the memory mapper state too + WrZ80_NoHook(0xFFFF, g_machine.mapper_regs[2]); + WrZ80_NoHook(0xFFFE, g_machine.mapper_regs[3]); + break; } } @@ -339,6 +345,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_48_in_1_FFF8_FFF9_FFFE_FFFF: default: fwrite (RAM, 0x2000, 1, f); // Do not use g_driver->ram because of g_driver video mode change break; @@ -518,6 +525,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_48_in_1_FFF8_FFF9_FFFE_FFFF: default: fread (RAM, 0x2000, 1, f); // Do not use g_driver->ram because of g_driver video mode change break;