From e0763fbbfd09f48a4aa007eb98e7363b2746f12d Mon Sep 17 00:00:00 2001
From: Ignacio Sanchez Gines <863613+drhelius@users.noreply.github.com>
Date: Sun, 5 Jan 2025 14:11:37 +0100
Subject: [PATCH] Add 4 Pak All Action mapper. Fix #115
---
platforms/desktop-shared/Makefile.sources | 1 +
platforms/libretro/Makefile.common | 1 +
platforms/windows/Gearsystem.vcxproj | 2 +
src/Cartridge.cpp | 10 ++
src/Cartridge.h | 1 +
src/GearsystemCore.cpp | 8 ++
src/GearsystemCore.h | 4 +-
src/Multi4PAKAllActionMemoryRule.cpp | 131 ++++++++++++++++++++++
src/Multi4PAKAllActionMemoryRule.h | 43 +++++++
src/game_db.h | 3 +
10 files changed, 203 insertions(+), 1 deletion(-)
create mode 100644 src/Multi4PAKAllActionMemoryRule.cpp
create mode 100644 src/Multi4PAKAllActionMemoryRule.h
diff --git a/platforms/desktop-shared/Makefile.sources b/platforms/desktop-shared/Makefile.sources
index 6994f602..6c5e6b6d 100644
--- a/platforms/desktop-shared/Makefile.sources
+++ b/platforms/desktop-shared/Makefile.sources
@@ -41,6 +41,7 @@ SOURCES_CXX := \
$(SRC_DIR)/KoreanBFFCMemoryRule.cpp \
$(SRC_DIR)/KoreanFFF3FFFCMemoryRule.cpp \
$(SRC_DIR)/KoreanMDFFF5MemoryRule.cpp \
+ $(SRC_DIR)/Multi4PAKAllActionMemoryRule.cpp \
$(SRC_DIR)/Memory.cpp \
$(SRC_DIR)/MemoryRule.cpp \
$(SRC_DIR)/MSXMemoryRule.cpp \
diff --git a/platforms/libretro/Makefile.common b/platforms/libretro/Makefile.common
index 200a24a4..2904131e 100644
--- a/platforms/libretro/Makefile.common
+++ b/platforms/libretro/Makefile.common
@@ -20,6 +20,7 @@ SOURCES_CXX := $(CORE_DIR)/libretro.cpp \
$(SOURCE_DIR)/KoreanBFFCMemoryRule.cpp \
$(SOURCE_DIR)/KoreanFFF3FFFCMemoryRule.cpp \
$(SOURCE_DIR)/KoreanMDFFF5MemoryRule.cpp \
+ $(SOURCE_DIR)/Multi4PAKAllActionMemoryRule.cpp \
$(SOURCE_DIR)/Memory.cpp \
$(SOURCE_DIR)/MemoryRule.cpp \
$(SOURCE_DIR)/MSXMemoryRule.cpp \
diff --git a/platforms/windows/Gearsystem.vcxproj b/platforms/windows/Gearsystem.vcxproj
index e8be8958..973a0acf 100644
--- a/platforms/windows/Gearsystem.vcxproj
+++ b/platforms/windows/Gearsystem.vcxproj
@@ -76,6 +76,7 @@
+
@@ -158,6 +159,7 @@
+
diff --git a/src/Cartridge.cpp b/src/Cartridge.cpp
index 5d80143d..d754c1c2 100644
--- a/src/Cartridge.cpp
+++ b/src/Cartridge.cpp
@@ -240,6 +240,10 @@ void Cartridge::ForceConfig(Cartridge::ForceConfiguration config)
m_Type = config.type;
Log("Forcing Mapper: Janggun");
break;
+ case Cartridge::CartridgeMulti4PAKAllActionMapper:
+ m_Type = config.type;
+ Log("Forcing Mapper: Multi 4PAK All Action");
+ break;
default:
Log("Not forcing Mapper: Auto");
break;
@@ -651,6 +655,9 @@ bool Cartridge::GatherMetadata(u32 crc)
case Cartridge::CartridgeJanggunMapper:
Log("Janggun mapper found");
break;
+ case Cartridge::CartridgeMulti4PAKAllActionMapper:
+ Log("Multi 4PAK All Action mapper found");
+ break;
case Cartridge::CartridgeNotSupported:
Log("Cartridge not supported!!");
break;
@@ -740,6 +747,9 @@ void Cartridge::GetInfoFromDB(u32 crc)
case GS_DB_JANGGUN_MAPPER:
m_Type = Cartridge::CartridgeJanggunMapper;
break;
+ case GS_DB_MULTI_4PAK_ALL_ACTION_MAPPER:
+ m_Type = Cartridge::CartridgeMulti4PAKAllActionMapper;
+ break;
}
if (kGameDatabase[i].features & GS_DB_FEATURE_SMS_MODE)
diff --git a/src/Cartridge.h b/src/Cartridge.h
index dc89b5fe..54ff30b8 100644
--- a/src/Cartridge.h
+++ b/src/Cartridge.h
@@ -47,6 +47,7 @@ class Cartridge
CartridgeKoreanMDFFF5Mapper,
CartridgeMSXMapper,
CartridgeJanggunMapper,
+ CartridgeMulti4PAKAllActionMapper,
CartridgeNotSupported
};
diff --git a/src/GearsystemCore.cpp b/src/GearsystemCore.cpp
index 3984cdf2..bfcb282b 100644
--- a/src/GearsystemCore.cpp
+++ b/src/GearsystemCore.cpp
@@ -42,6 +42,7 @@
#include "KoreanMDFFF5MemoryRule.h"
#include "MSXMemoryRule.h"
#include "JanggunMemoryRule.h"
+#include "Multi4PAKAllActionMemoryRule.h"
#include "SG1000MemoryRule.h"
#include "SmsIOPorts.h"
#include "GameGearIOPorts.h"
@@ -73,6 +74,7 @@ GearsystemCore::GearsystemCore()
InitPointer(m_pKoreanMDFFF5MemoryRule);
InitPointer(m_pMSXMemoryRule);
InitPointer(m_pJanggunMemoryRule);
+ InitPointer(m_pMulti4PAKAllActionMemoryRule);
InitPointer(m_pSmsIOPorts);
InitPointer(m_pGameGearIOPorts);
InitPointer(m_pBootromMemoryRule);
@@ -104,6 +106,7 @@ GearsystemCore::~GearsystemCore()
SafeDelete(m_pKoreanMDFFF5MemoryRule);
SafeDelete(m_pMSXMemoryRule);
SafeDelete(m_pJanggunMemoryRule);
+ SafeDelete(m_pMulti4PAKAllActionMemoryRule);
SafeDelete(m_pCartridge);
SafeDelete(m_pInput);
SafeDelete(m_pVideo);
@@ -928,6 +931,7 @@ void GearsystemCore::InitMemoryRules()
m_pKoreanMDFFF5MemoryRule = new KoreanMDFFF5MemoryRule(m_pMemory, m_pCartridge, m_pInput);
m_pMSXMemoryRule = new MSXMemoryRule(m_pMemory, m_pCartridge, m_pInput);
m_pJanggunMemoryRule = new JanggunMemoryRule(m_pMemory, m_pCartridge, m_pInput);
+ m_pMulti4PAKAllActionMemoryRule = new Multi4PAKAllActionMemoryRule(m_pMemory, m_pCartridge, m_pInput);
m_pBootromMemoryRule = new BootromMemoryRule(m_pMemory, m_pCartridge, m_pInput);
m_pMemory->SetCurrentRule(m_pRomOnlyMemoryRule);
m_pMemory->SetBootromRule(m_pBootromMemoryRule);
@@ -996,6 +1000,9 @@ bool GearsystemCore::AddMemoryRules()
case Cartridge::CartridgeJanggunMapper:
m_pMemory->SetCurrentRule(m_pJanggunMemoryRule);
break;
+ case Cartridge::CartridgeMulti4PAKAllActionMapper:
+ m_pMemory->SetCurrentRule(m_pMulti4PAKAllActionMemoryRule);
+ break;
case Cartridge::CartridgeNotSupported:
notSupported = true;
break;
@@ -1042,6 +1049,7 @@ void GearsystemCore::Reset()
m_pKoreanMDFFF5MemoryRule->Reset();
m_pMSXMemoryRule->Reset();
m_pJanggunMemoryRule->Reset();
+ m_pMulti4PAKAllActionMemoryRule->Reset();
m_pBootromMemoryRule->Reset();
m_pGameGearIOPorts->Reset();
m_pSmsIOPorts->Reset();
diff --git a/src/GearsystemCore.h b/src/GearsystemCore.h
index 1a3e7dff..bcad5a5e 100644
--- a/src/GearsystemCore.h
+++ b/src/GearsystemCore.h
@@ -18,7 +18,7 @@
*/
#ifndef CORE_H
-#define CORE_H
+#define CORE_H
#include "definitions.h"
#include "Cartridge.h"
@@ -46,6 +46,7 @@ class KoreanFFF3FFFCMemoryRule;
class KoreanMDFFF5MemoryRule;
class MSXMemoryRule;
class JanggunMemoryRule;
+class Multi4PAKAllActionMemoryRule;
class MemoryRule;
class SmsIOPorts;
class GameGearIOPorts;
@@ -135,6 +136,7 @@ class GearsystemCore
KoreanMDFFF5MemoryRule* m_pKoreanMDFFF5MemoryRule;
MSXMemoryRule* m_pMSXMemoryRule;
JanggunMemoryRule* m_pJanggunMemoryRule;
+ Multi4PAKAllActionMemoryRule* m_pMulti4PAKAllActionMemoryRule;
SmsIOPorts* m_pSmsIOPorts;
GameGearIOPorts* m_pGameGearIOPorts;
BootromMemoryRule* m_pBootromMemoryRule;
diff --git a/src/Multi4PAKAllActionMemoryRule.cpp b/src/Multi4PAKAllActionMemoryRule.cpp
new file mode 100644
index 00000000..213c3fa7
--- /dev/null
+++ b/src/Multi4PAKAllActionMemoryRule.cpp
@@ -0,0 +1,131 @@
+/*
+ * Gearsystem - Sega Master System / Game Gear Emulator
+ * Copyright (C) 2013 Ignacio Sanchez
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/
+ *
+ */
+
+#include "Multi4PAKAllActionMemoryRule.h"
+#include "Memory.h"
+#include "Cartridge.h"
+
+Multi4PAKAllActionMemoryRule::Multi4PAKAllActionMemoryRule(Memory* pMemory, Cartridge* pCartridge, Input* pInput) : MemoryRule(pMemory, pCartridge, pInput)
+{
+ Reset();
+}
+
+Multi4PAKAllActionMemoryRule::~Multi4PAKAllActionMemoryRule()
+{
+}
+
+u8 Multi4PAKAllActionMemoryRule::PerformRead(u16 address)
+{
+ if (address < 0xC000)
+ {
+ int slot = (address >> 14) & 0x03;
+ if (slot > 3)
+ {
+ Debug("--> ** Invalid slot %d", slot);
+ return 0xFF;
+ }
+ return m_pCartridge->GetROM()[m_iMapperSlotAddress[slot] + (address & 0x3FFF)];
+ }
+ else
+ {
+ // RAM + RAM mirror
+ return m_pMemory->Retrieve(address);
+ }
+}
+
+void Multi4PAKAllActionMemoryRule::PerformWrite(u16 address, u8 value)
+{
+ if (address < 0xC000)
+ {
+ switch (address)
+ {
+ case 0x3FFE:
+ Debug("--> ** Writing to register $%X %X", address, value);
+ m_iMapperSlot[0] = value;
+ m_iMapperSlotAddress[0] = 0x4000 * (m_iMapperSlot[0] & (m_pCartridge->GetROMBankCount() - 1));
+ return;
+ case 0x7FFF:
+ Debug("--> ** Writing to register $%X %X", address, value);
+ m_iMapperSlot[1] = value;
+ m_iMapperSlotAddress[1] = 0x4000 * (m_iMapperSlot[1] & (m_pCartridge->GetROMBankCount() - 1));
+ return;
+ case 0xBFFF:
+ Debug("--> ** Writing to register $%X %X", address, value);
+ m_iMapperSlot[2] = value;
+ m_iMapperSlotAddress[2] = 0x4000 * (((m_iMapperSlot[0] & 0x30) + value) & (m_pCartridge->GetROMBankCount() - 1));
+ return;
+ default:
+ Debug("--> ** Attempting to write on ROM address $%X %X", address, value);
+ return;
+ }
+ }
+ else if (address < 0xE000)
+ {
+ // RAM
+ m_pMemory->Load(address, value);
+ m_pMemory->Load(address + 0x2000, value);
+ }
+ else
+ {
+ // RAM (mirror)
+ m_pMemory->Load(address, value);
+ m_pMemory->Load(address - 0x2000, value);
+ }
+}
+
+void Multi4PAKAllActionMemoryRule::Reset()
+{
+ m_iMapperSlot[0] = 0;
+ m_iMapperSlot[1] = 1;
+ m_iMapperSlot[2] = 2;
+
+ m_iMapperSlotAddress[0] = 0x0000;
+ m_iMapperSlotAddress[1] = 0x4000;
+ m_iMapperSlotAddress[2] = 0x8000;
+}
+
+u8* Multi4PAKAllActionMemoryRule::GetPage(int index)
+{
+ if (index < 0 || index > 2)
+ return m_pCartridge->GetROM();
+
+ return m_pCartridge->GetROM() + (m_iMapperSlot[index] * 0x4000);
+}
+
+int Multi4PAKAllActionMemoryRule::GetBank(int index)
+{
+ if (index < 0 || index > 2)
+ return 0;
+
+ return m_iMapperSlot[index];
+}
+
+void Multi4PAKAllActionMemoryRule::SaveState(std::ostream& stream)
+{
+ stream.write(reinterpret_cast (m_iMapperSlotAddress), sizeof(m_iMapperSlotAddress));
+ stream.write(reinterpret_cast (m_iMapperSlot), sizeof(m_iMapperSlot));
+}
+
+void Multi4PAKAllActionMemoryRule::LoadState(std::istream& stream)
+{
+ using namespace std;
+
+ stream.read(reinterpret_cast (m_iMapperSlotAddress), sizeof(m_iMapperSlotAddress));
+ stream.read(reinterpret_cast (m_iMapperSlot), sizeof(m_iMapperSlot));
+}
diff --git a/src/Multi4PAKAllActionMemoryRule.h b/src/Multi4PAKAllActionMemoryRule.h
new file mode 100644
index 00000000..3df4a6f8
--- /dev/null
+++ b/src/Multi4PAKAllActionMemoryRule.h
@@ -0,0 +1,43 @@
+/*
+ * Gearsystem - Sega Master System / Game Gear Emulator
+ * Copyright (C) 2013 Ignacio Sanchez
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/
+ *
+ */
+
+#ifndef MULTI4PAKALLACTIONMEMORYRULE_H
+#define MULTI4PAKALLACTIONMEMORYRULE_H
+
+#include "MemoryRule.h"
+
+class Multi4PAKAllActionMemoryRule : public MemoryRule
+{
+public:
+ Multi4PAKAllActionMemoryRule(Memory* pMemory, Cartridge* pCartridge, Input* pInput);
+ virtual ~Multi4PAKAllActionMemoryRule();
+ virtual u8 PerformRead(u16 address);
+ virtual void PerformWrite(u16 address, u8 value);
+ virtual void Reset();
+ virtual u8* GetPage(int index);
+ virtual int GetBank(int index);
+ virtual void SaveState(std::ostream& stream);
+ virtual void LoadState(std::istream& stream);
+
+private:
+ int m_iMapperSlot[3];
+ int m_iMapperSlotAddress[3];
+};
+
+#endif /* MULTI4PAKALLACTIONMEMORYRULE_H */
diff --git a/src/game_db.h b/src/game_db.h
index 5602b68e..1c0502d4 100644
--- a/src/game_db.h
+++ b/src/game_db.h
@@ -39,6 +39,7 @@
#define GS_DB_KOREAN_BFFC_MAPPER 14
#define GS_DB_KOREAN_FFF3_FFFC_MAPPER 15
#define GS_DB_KOREAN_MD_FFF5_MAPPER 16
+#define GS_DB_MULTI_4PAK_ALL_ACTION_MAPPER 17
#define GS_DB_FEATURE_NONE 0x00
#define GS_DB_FEATURE_PAL 0x01
@@ -407,6 +408,8 @@ const GS_GameDBEntry kGameDatabase[] =
{0x7F667485, GS_DB_KOREAN_MD_FFF5_MAPPER, GS_DB_FEATURE_NONE, "Mega Mode Super Game 138"},
{0xC0AC6956, GS_DB_KOREAN_MD_FFF5_MAPPER, GS_DB_FEATURE_NONE, "Pigu-Wang 7 Hap - Jaemiiss-neun Game Mo-eumjip"},
+ {0xA67F2A5C, GS_DB_MULTI_4PAK_ALL_ACTION_MAPPER, GS_DB_FEATURE_NONE, "4 PAK All Action"},
+
// Requires vint flag on boot
{0xD9096263, GS_DB_DEFAULT_MAPPER, GS_DB_FEATURE_INITIAL_VINT, "Sonic's Edusoft [Proto]"},