From 792b91f8218645a9b72b8f6d41cb19d1236ec893 Mon Sep 17 00:00:00 2001
From: alyosha-tas <alexei.f.k@gmail.com>
Date: Sat, 20 Nov 2021 21:15:41 -0500
Subject: [PATCH] SG1000: work on 8kb ram adapter

---
 Assets/gamedb/gamedb_sega_sg1000.txt          |  8 ++++
 .../Consoles/Sega/SMS/MemoryMap.SG_EX_A.cs    | 47 +++++++++++++++++++
 .../Consoles/Sega/SMS/MemoryMap.SG_EX_B.cs    | 36 ++++++++++++++
 .../Consoles/Sega/SMS/SMS.IStatable.cs        | 15 ++----
 .../Consoles/Sega/SMS/SMS.cs                  |  8 ++++
 5 files changed, 102 insertions(+), 12 deletions(-)
 create mode 100644 src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/MemoryMap.SG_EX_A.cs
 create mode 100644 src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/MemoryMap.SG_EX_B.cs

diff --git a/Assets/gamedb/gamedb_sega_sg1000.txt b/Assets/gamedb/gamedb_sega_sg1000.txt
index baa9646a7a..411057e3cb 100644
--- a/Assets/gamedb/gamedb_sega_sg1000.txt
+++ b/Assets/gamedb/gamedb_sega_sg1000.txt
@@ -12,6 +12,7 @@ D2B0524A2CF5754C0FA1C900E9ECB06B		The Black Onyx (J)	SG	RPG		Japan
 0BF5B6959FC1B58D8E37F9647F47A0B3		Bomb Jack (J)	SG			Japan
 A50378ABE2636C5C47966B74A14DD127		Bomb Jack (T) (Chinese Logo)	SG			Taiwan
 8DB486C33C7D688BD5C0E9A81DEE2D29		Bomb Jack (T) (English Logo)	SG			Taiwan
+25044D56BC18AD8B66A726C2F9D0B26B		Bomberman Special (Taiwan)	SG		SG_EX_B	Taiwan
 25C742E43BC9F1329F3F26502FEFB10A		Borderline (JE)	SG			Europe;Japan
 D87DAAD7DE33105D703B613052CCC2DD		C_So! (J)	SG			Japan
 25AC91AFC22F7A09FF4543AF653CD281		C_So! (T)	SG			Taiwan
@@ -88,8 +89,11 @@ D7322428A4FB49AC593F80F30D3C7BD3		Home Mahjong (J)	SG	Puzzle;Mahjong		Japan
 8BE690D357A99ABD26EBB5378E9C0153		Hustle Chumy (J)	SG			Japan
 D8E6D89D520C91A9EA219291B55284BB		Hyper Sports (J)	SG	Sports		Japan
 F72F3DEF79FFD82FE2224F4732B2B994		Hyper Sports (T)	SG	Sports		Taiwan
+E0321CD713EC1B48FF88F7DF13E3CE28		Knightmare (Taiwan)	SG		SG_EX_A	Taiwan
+CFC8E61F51388609421FFE87539CAD44		Legend of Kage, The (Taiwan)	SG		SG_EX_A	Taiwan
 4B4F02EB3CF7D5F9DCD1311D72E6D742		Lode Runner (JE)	SG			Europe;Japan
 2BEA9EE88E177A13D7961017DD4F6120		Lode Runner (T)	SG			Taiwan
+C12474E0A2556ADB2478BC4D99FABA51		Magical Kid Wiz (Taiwan)	SG		SG_EX_B	Taiwan
 D9DA8A32BD3B18881DFA2B469C85944E		Mahjong (J)	SG	Puzzle;Mahjong		Japan
 1DBB5C85962C2110FFE35EC536F96329		Mahjong (J) (English Title)	SG	Puzzle;Mahjong		Japan
 BB8DA563CB6A38611B736C4973B56E1E		Mahjong (T)	SG	Puzzle;Mahjong		Taiwan
@@ -123,6 +127,8 @@ C34260B61C6A45BBDD074DF3F3E72C46		Pitfall II - The Lost Caverns (J) (Rev 0)	SG
 7F841AA0C225662E26CA7A8DF20B2EB8		Pop Flamer (JE)	SG			Europe;Japan
 E5082018FF7CBAC17DB003F159AB2DFB		Pop Flamer (T)	SG			Taiwan
 A768A8AE921126300E98F9D918A4A0C9		Q-bert (J)	SG			Japan
+3071F939AAA0911FC0907AAE5DAAA160		Rally-X (Taiwan) (DahJee)	SG		SG_EX_A	Taiwan
+E872BBE06FCEE32E53FB9E11B61FE762		Road Fighter (Taiwan) (Jumbo)	SG		SG_EX_A	Taiwan
 108FFE4BA5C2C8C5E0459CB7F0CFAC0E		Rock n' Bolt (J)	SG			Japan
 F05B48934A7D29AB2719273CBDC45B28		Rock n' Bolt (T)	SG			Taiwan
 F77826F62D943C4A24F7FB9C3BB4A5F9		Safari Hunting (J)	SG			Japan
@@ -162,6 +168,8 @@ ECCAD04698782862F3785FF9708F73E8		Star Jacker (J)	SG			Japan
 0104171ADE3CFEAF10C92926869E2A52		Star Jacker (T)	SG			Taiwan
 59D01BF1093A65E9EC08E533CFBBC5FF		Super Tank (J)	SG			Japan
 BCB549A442584255601DC7938ACCD2D6		Super Tank (T)	SG			Taiwan
+DADA9D76F7743089811DCC8EC1543076		Tank Battalion (Taiwan)	SG		SG_EX_A	Taiwan
+8C2C0D7E8415AE7B0C577CF947E89E78		TwinBee (Taiwan)	SG		SG_EX_A	Taiwan
 BE31A84BFA537117A62EAEB8C0A07BF9		Terebi Oekaki (J)	SG	Art		Japan
 76F29FEE0CD3AF921E488A276DACE636		Wonder Boy (J)	SG	Arcade		Japan
 D26FABFE84AD40AE04A2CD3DC6CF75DF		Wonder Boy (J) (Rev 1)	SG	Arcade		Japan
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/MemoryMap.SG_EX_A.cs b/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/MemoryMap.SG_EX_A.cs
new file mode 100644
index 0000000000..7cd44c6b4a
--- /dev/null
+++ b/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/MemoryMap.SG_EX_A.cs
@@ -0,0 +1,47 @@
+namespace BizHawk.Emulation.Cores.Sega.MasterSystem
+{
+	public partial class SMS
+	{		
+		private byte ReadMemorySG_EX_A(ushort address)
+		{
+			byte ret;
+
+			if (address < 0x2000)
+				ret = RomData[address & RomMask];
+			else if (address < 0x4000)
+				ret = ExtRam[address & ExtRamMask];
+			else if (address < 0xC000)
+				ret = RomData[address & RomMask];
+			else
+				ret = SystemRam[address & 0x3FF]; // only 1 KB
+
+			return ret;
+		}
+
+		private CDLog_MapResults MapMemorySG_EX_A(ushort address, bool write)
+		{
+			if (address < 0x2000) return new CDLog_MapResults { Type = CDLog_AddrType.ROM, Address = address };
+			if (address < 0x4000) return new CDLog_MapResults { Type = CDLog_AddrType.CartRAM, Address = address & ExtRamMask };
+			if (address < 0xC000) return new CDLog_MapResults { Type = CDLog_AddrType.ROM, Address = address };
+			return new CDLog_MapResults { Type = CDLog_AddrType.MainRAM, Address = address & RamSizeMask };
+		}
+
+		private void WriteMemorySG_EX_A(ushort address, byte value)
+		{
+			if (address < 0x4000 && address >= 0x2000)
+				ExtRam[address & ExtRamMask] = value;
+			else if (address >= 0xC000)
+				SystemRam[address & 0x3FF] = value;
+		}
+
+		private void Init_SG_EX_A()
+		{
+			// 2 regions of RAM
+			ExtRam = new byte[0x2000];
+			ExtRamMask = 0x1FFF;
+			ReadMemoryMapper = ReadMemorySG_EX_A;
+			WriteMemoryMapper = WriteMemorySG_EX_A;
+			MapMemory = MapMemorySG_EX_A;
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/MemoryMap.SG_EX_B.cs b/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/MemoryMap.SG_EX_B.cs
new file mode 100644
index 0000000000..28936fc499
--- /dev/null
+++ b/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/MemoryMap.SG_EX_B.cs
@@ -0,0 +1,36 @@
+namespace BizHawk.Emulation.Cores.Sega.MasterSystem
+{
+	public partial class SMS
+	{		
+		private byte ReadMemorySG_EX_B(ushort address)
+		{
+			byte ret;
+
+			if (address < 0xC000)
+				ret = RomData[address & RomMask];
+			else
+				ret = SystemRam[address & RamSizeMask];
+
+			return ret;
+		}
+
+		private CDLog_MapResults MapMemorySG_EX_B(ushort address, bool write)
+		{
+			if (address < 0xC000) return new CDLog_MapResults { Type = CDLog_AddrType.ROM, Address = address & ExtRamMask };
+			return new CDLog_MapResults { Type = CDLog_AddrType.MainRAM, Address = address & RamSizeMask };
+		}
+
+		private void WriteMemorySG_EX_B(ushort address, byte value)
+		{
+			if (address >= 0xC000)
+				SystemRam[address & RamSizeMask] = value;
+		}
+
+		private void Init_SG_EX_B()
+		{
+			ReadMemoryMapper = ReadMemorySG_EX_B;
+			WriteMemoryMapper = WriteMemorySG_EX_B;
+			MapMemory = MapMemorySG_EX_B;
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs b/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs
index e3676f548a..ba0d11071b 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs
@@ -48,22 +48,13 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
 			ser.Sync("old_s_L", ref OldSl);
 			ser.Sync("old_s_R", ref OldSr);
 
-			if (SaveRAM != null)
-			{
-				ser.Sync(nameof(SaveRAM), ref SaveRAM, false);
-			}
+			if (SaveRAM != null) { ser.Sync(nameof(SaveRAM), ref SaveRAM, false); }
 
 			ser.Sync(nameof(SaveRamBank), ref SaveRamBank);
 
-			if (ExtRam != null)
-			{
-				ser.Sync("ExtRAM", ref ExtRam, true);
-			}
+			if (ExtRam != null) { ser.Sync("ExtRAM", ref ExtRam, true); }
 
-			if (HasYM2413)
-			{
-				YM2413.SyncState(ser);
-			}
+			if (HasYM2413) { YM2413.SyncState(ser); }
 
 			EEPROM?.SyncState(ser);
 
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs b/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs
index 0749f66865..7d07fc77e9 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs
@@ -40,6 +40,9 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
 			}
 
 			RomBanks = (byte)(RomData.Length / BankSize);
+			RomMask = RomData.Length - 1;
+			if (RomMask == 0x5FFF) { RomMask = 0x7FFF; }
+			if (RomMask == 0xBFFF) { RomMask = 0xFFFF; }
 
 			Region = DetermineDisplayType(SyncSettings.DisplayType, game.Region);
 			if (game["PAL"] && Region != DisplayType.PAL)
@@ -135,6 +138,10 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
 				InitTerebiOekaki();
 			else if (game["EEPROM"])
 				InitEEPROMMapper();
+			else if(game["SG_EX_A"])
+				Init_SG_EX_A();
+			else if (game["SG_EX_B"])
+				Init_SG_EX_B();
 			else
 				InitSegaMapper();
 
@@ -234,6 +241,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
 
 		// ROM
 		public byte[] RomData;
+		public int RomMask;
 		private byte RomBank0, RomBank1, RomBank2, RomBank3;
 		private byte Bios_bank;
 		private readonly byte RomBanks;