diff --git a/meka/compat.txt b/meka/compat.txt index 306b6a89..c2dffd1b 100644 --- a/meka/compat.txt +++ b/meka/compat.txt @@ -1334,6 +1334,7 @@ Quiz Gear Fight!!, The (JP) Ok Rastan Saga [SMS-GG] (JP) Ok R.C. Grand Prix [SMS-GG] Ok + Real 24 in 1 [Sonic II] *Ok Revenge of Drancon Ok Riddick Rowe Boxing (US) Ok Riddick Rowe Boxing (JP) Ok @@ -1502,7 +1503,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 35d87c35..532d8cd0 100644 --- a/meka/meka.nam +++ b/meka/meka.nam @@ -1218,6 +1218,7 @@ GG 8e54ee04 E463A36AE4D522D1 Puzzle Bobble/COUNTRY=JP/PRODUCT_NO=T-11047 GG 6c451ee1 2A50C584823D710D Quest for the Shaven Yak Starring Ren Hoëk & Stimpy/COUNTRY=US,EU/PRODUCT_NO=2519 GG 736cdb76 70BA6E9D99C81B4F Quiz Gear Fight!!, The/COUNTRY=JP/PRODUCT_NO=G-3367 GG 6dc3295e D56E2790AD1DEE4E R.B.I. Baseball '94/COUNTRY=US/PRODUCT_NO=T-48168 301073-0161 +GG de6471e8 0E01DB0FE65FBA08 Real 24 in 1 [Sonic II]/EMU_MAPPER=53 GG 03e9c607 EACA76A0EF9F1D8B Revenge of Drancon/NAME_BR=Wonder Boy/COUNTRY=US,BR/PRODUCT_NO=2302,012080/COMMENT=US version of "Wonder Boy", with a different title. GG 38d8ec56 46EF1611B14E079E Riddick Bowe Boxing/COUNTRY=US/PRODUCT_NO=T-22028 GG a45fffb7 45EF1710B24D079F Riddick Bowe Boxing/COUNTRY=JP/PRODUCT_NO=T-22027 diff --git a/meka/srcs/machine.cpp b/meka/srcs/machine.cpp index f6adcfdb..21c02be6 100644 --- a/meka/srcs/machine.cpp +++ b/meka/srcs/machine.cpp @@ -199,6 +199,9 @@ void Machine_Set_Handler_MemRW(void) case MAPPER_SMS_Korean_MSX_SMS_8000: WrZ80 = WrZ80_NoHook = Write_Mapper_SMS_Korean_MSX_SMS_8000; break; + case MAPPER_GG_Real_24_in_1_FFFE_0000_FFFF: + WrZ80 = WrZ80_NoHook = Write_Mapper_GG_Real_24_in_1_FFFE_0000_FFFF; + break; } } @@ -502,6 +505,23 @@ void Machine_Set_Mapping (void) g_machine.mapper_regs[i] = 0; break; + case MAPPER_GG_Real_24_in_1_FFFE_0000_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, 4 & tsms.Pages_Mask_8k); + Map_8k_ROM(5, 5 & 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[1] = 2; + g_machine.mapper_regs[2] = 1; + drv_set(DRV_GG); + 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 7610fbee..481e3883 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 @@ -989,6 +992,83 @@ WRITE_FUNC (Write_Mapper_SMS_Korean_MSX_SMS_8000) Write_Error (Addr, Value); } +// Mapper #53 +// Real 24 in 1 [Sonic II] (Unl) +WRITE_FUNC (Write_Mapper_GG_Real_24_in_1_FFFE_0000_FFFF) { + if ((Addr == 0x0000) || (Addr == 0xFFFE) || (Addr == 0xFFFF)) { // Configurable segment ----------------------------------------------- + // mapper register allocation: + // 0: 0x0000: outer paging configuration and SMS-GG mode + // - bit 0x80: set when mapping the second megabyte, clear otherwise + // - bit 0x40: set when activating SMS-GG mode, clear otherwise + // - bits 0x3F: 32KB base page for outer page selection + // + // For paging to work, the base page must be in an eligible region and + // all paging-modifiable bits of the 32KB base page must be set + // + // 16KB paging mask bits: + // - 0x10: when base page bit 0x08 is set and base page > 0x30 + // - 0x08: when base page bit 0x04 is set and base page > 0x20 + // - 0x04: when base page bit 0x02 is set and base page > 0x14 + // - 0x02: when base page bit 0x01 is set and base page > 0x12 + // - 0x01: always available + // + // 1: 0xFFFF: 16KB paging offset for region 0x8000..0xBFFF (restricted by 16KB paging mask) + // 2: 0xFFFE: 16KB paging offset for region 0x4000..0x7FFF (restricted by 16KB paging mask) + + if (Addr == 0x0000) { + g_machine.mapper_regs[0] |= Value; + bool sms_gg_mode = (g_machine.mapper_regs[0] & 0x40) ? true : false; + if (sms_gg_mode) { + drv_set(DRV_SMS); + } else { + drv_set(DRV_GG); + } + gamebox_resize_all(); + VDP_UpdateLineLimits(); + Video_GameMode_UpdateBounds(); + } else if (Addr == 0xFFFF) { + g_machine.mapper_regs[1] = Value; + } else if (Addr == 0xFFFE) { + if (Value & 0x80) { + // 0xB0 is written at startup, no idea what it means + } else { + g_machine.mapper_regs[2] = Value; + } + } + + unsigned int base_page_32k = (g_machine.mapper_regs[0] & 0x3F) | ((g_machine.mapper_regs[0] & 0x80) >> 2); + unsigned int paging_mask_16k = 0x01 | (2 * ( + ((base_page_32k > 0x12) ? (base_page_32k & 0x01) : 0x00) + | ((base_page_32k > 0x14) ? (base_page_32k & 0x02) : 0x00) + | ((base_page_32k > 0x20) ? (base_page_32k & 0x04) : 0x00) + | ((base_page_32k > 0x30) ? (base_page_32k & 0x08) : 0x00))); + unsigned int base_page_16k = (2 * base_page_32k) & ~paging_mask_16k; + unsigned int page_8000_offset_16k = g_machine.mapper_regs[1] & paging_mask_16k; + unsigned int page_4000_offset_16k = g_machine.mapper_regs[2] & paging_mask_16k; + + Map_8k_ROM(0, ((base_page_16k * 2) | 0) & tsms.Pages_Mask_8k); + Map_8k_ROM(1, ((base_page_16k * 2) | 1) & tsms.Pages_Mask_8k); + Map_8k_ROM(2, (((base_page_16k | page_4000_offset_16k) * 2) | 0) & tsms.Pages_Mask_8k); + Map_8k_ROM(3, (((base_page_16k | page_4000_offset_16k) * 2) | 1) & tsms.Pages_Mask_8k); + Map_8k_ROM(4, (((base_page_16k | page_8000_offset_16k) * 2) | 0) & tsms.Pages_Mask_8k); + Map_8k_ROM(5, (((base_page_16k | page_8000_offset_16k) * 2) | 1) & tsms.Pages_Mask_8k); + + if (Addr == 0x0000) { + // no RAM mirroring for register 0x0000 + 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 0ea32122..a011cdc6 100644 --- a/meka/srcs/mappers.h +++ b/meka/srcs/mappers.h @@ -51,6 +51,7 @@ #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_SMS_Korean_MSX_SMS_8000 (40) // Register at 0x8000 with 8KB granularity and both MSX and SMS game support (Zemina Best 88 [MISSING 64K]) +#define MAPPER_GG_Real_24_in_1_FFFE_0000_FFFF (53) // Registers at 0xFFFE, 0x0000, 0xFFFF (Real 24 in 1 [Sonic II]) #define READ_FUNC(_NAME) u8 _NAME(register u16 Addr) #define WRITE_FUNC(_NAME) void _NAME(register u16 Addr, register u8 Value) @@ -98,6 +99,7 @@ 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_SMS_Korean_MSX_SMS_8000); +WRITE_FUNC (Write_Mapper_GG_Real_24_in_1_FFFE_0000_FFFF); //----------------------------------------------------------------------------- void Out_SC3000_SurvivorsMulticarts_DataWrite(u8 v); diff --git a/meka/srcs/saves.cpp b/meka/srcs/saves.cpp index 34012e4e..674405fb 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 @@ -151,13 +154,21 @@ void Load_Game_Fixup(void) WrZ80_NoHook(0x8000, mapper_page); } break; + case MAPPER_GG_Real_24_in_1_FFFE_0000_FFFF: + // this will restore every other piece of mapper state by side-effect; + // this will also configure SMS-GG mode if needed + WrZ80_NoHook(0x0000, g_machine.mapper_regs[0]); + 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 ++) @@ -347,6 +358,7 @@ int Save_Game_MSV(FILE *f) case MAPPER_SMS_Korean_MD_FFFA: case MAPPER_SMS_Korean_MSX_32KB_2000: case MAPPER_SMS_Korean_MSX_SMS_8000: + case MAPPER_GG_Real_24_in_1_FFFE_0000_FFFF: default: fwrite (RAM, 0x2000, 1, f); // Do not use g_driver->ram because of g_driver video mode change break; @@ -527,6 +539,7 @@ int Load_Game_MSV(FILE *f) case MAPPER_SMS_Korean_MD_FFFA: case MAPPER_SMS_Korean_MSX_32KB_2000: case MAPPER_SMS_Korean_MSX_SMS_8000: + case MAPPER_GG_Real_24_in_1_FFFE_0000_FFFF: default: fread (RAM, 0x2000, 1, f); // Do not use g_driver->ram because of g_driver video mode change break;