diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
index b5a847cb21..e2ea538512 100644
--- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
+++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
@@ -581,7 +581,7 @@
VBANext.cs
-
+
@@ -598,6 +598,7 @@
+
@@ -780,7 +781,7 @@
-
+
@@ -1189,7 +1190,7 @@
-
+
@@ -1358,4 +1359,4 @@
-->
-
+
\ No newline at end of file
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs
index 9015a4fe1d..471b2a6b09 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs
@@ -191,6 +191,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
}
+ // special case for multi cart mappers
+ if ((_rom.HashMD5(0,_rom.Length) == "97122B9B183AAB4079C8D36A4CE6E9C1") ||
+ (_rom.HashMD5(0, _rom.Length) == "9FB9C42CF52DCFDCFBAD5E61AE1B5777") ||
+ (_rom.HashMD5(0, _rom.Length) == "CF1F58AB72112716D3C615A553B2F481")
+ )
+ {
+ Console.WriteLine("Using Multi-Cart Mapper");
+ mapper = new MapperMBC1Multi();
+ }
+
Console.Write("Mapper: ");
Console.WriteLine(header[0x47]);
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC1.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC1.cs
index 1224b9b954..2bdbff79f6 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC1.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC1.cs
@@ -11,6 +11,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public int RAM_bank;
public bool RAM_enable;
public bool sel_mode;
+ public int ROM_mask;
+ public int RAM_mask;
public override void Initialize()
{
@@ -18,14 +20,28 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
RAM_bank = 0;
RAM_enable = false;
sel_mode = false;
+ ROM_mask = Core._rom.Length / 0x4000 - 1;
+ RAM_mask = 0;
+ if (Core.cart_RAM != null)
+ {
+ RAM_mask = Core.cart_RAM.Length / 0x2000 - 1;
+ if (Core.cart_RAM.Length == 0x800) { RAM_mask = 0; }
+ }
}
public override byte ReadMemory(ushort addr)
{
if (addr < 0x4000)
{
- // lowest bank is fixed
- return Core._rom[addr];
+ // lowest bank is fixed, but is still effected by mode
+ if (sel_mode)
+ {
+ return Core._rom[(ROM_bank & 0x60) * 0x4000 + addr];
+ }
+ else
+ {
+ return Core._rom[addr];
+ }
}
else if (addr < 0x8000)
{
@@ -35,15 +51,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
{
if (Core.cart_RAM != null)
{
- if (RAM_enable)
+ if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length))
{
return Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000];
}
else
{
- return 0;
+ return 0xFF;
}
-
+
}
else
{
@@ -74,17 +90,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
ROM_bank &= 0xE0;
ROM_bank |= value;
+ ROM_bank &= ROM_mask;
}
else if (addr < 0x6000)
{
- if (sel_mode)
+ if (sel_mode && Core.cart_RAM != null)
{
- RAM_bank = value & 0x3;
+ RAM_bank = value & 3;
+ RAM_bank &= RAM_mask;
}
else
{
ROM_bank &= 0x1F;
ROM_bank |= ((value & 3) << 5);
+ ROM_bank &= ROM_mask;
}
}
else
@@ -94,6 +113,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
if (sel_mode)
{
ROM_bank &= 0x1F;
+ ROM_bank &= ROM_mask;
}
else
{
@@ -105,11 +125,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
{
if (Core.cart_RAM != null)
{
- if (RAM_enable)
+ if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length))
{
Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value;
}
-
}
}
}
@@ -122,7 +141,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
public override void SyncState(Serializer ser)
{
ser.Sync("ROM_Bank", ref ROM_bank);
+ ser.Sync("ROM_Mask", ref ROM_mask);
ser.Sync("RAM_Bank", ref RAM_bank);
+ ser.Sync("RAM_Mask", ref RAM_mask);
ser.Sync("RAM_enable", ref RAM_enable);
ser.Sync("sel_mode", ref sel_mode);
}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC1_Multi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC1_Multi.cs
new file mode 100644
index 0000000000..d72112aa40
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_MBC1_Multi.cs
@@ -0,0 +1,151 @@
+using BizHawk.Common;
+using BizHawk.Common.NumberExtensions;
+using System;
+
+namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
+{
+ // MBC1 with bank switching and RAM
+ public class MapperMBC1Multi : MapperBase
+ {
+ public int ROM_bank;
+ public int RAM_bank;
+ public bool RAM_enable;
+ public bool sel_mode;
+ public int ROM_mask;
+ public int RAM_mask;
+
+ public override void Initialize()
+ {
+ ROM_bank = 1;
+ RAM_bank = 0;
+ RAM_enable = false;
+ sel_mode = false;
+ ROM_mask = (Core._rom.Length / 0x4000 * 2) - 1; // due to how mapping workd, we want a 1 bit higher mask
+ RAM_mask = 0;
+ if (Core.cart_RAM != null)
+ {
+ RAM_mask = Core.cart_RAM.Length / 0x2000 - 1;
+ if (Core.cart_RAM.Length == 0x800) { RAM_mask = 0; }
+ }
+ }
+
+ public override byte ReadMemory(ushort addr)
+ {
+ if (addr < 0x4000)
+ {
+ // lowest bank is fixed, but is still effected by mode
+ if (sel_mode)
+ {
+ return Core._rom[((ROM_bank & 0x60) >> 1) * 0x4000 + addr];
+ }
+ else
+ {
+ return Core._rom[addr];
+ }
+ }
+ else if (addr < 0x8000)
+ {
+ return Core._rom[(addr - 0x4000) + (((ROM_bank & 0x60) >> 1) | (ROM_bank & 0xF)) * 0x4000];
+ }
+ else
+ {
+ if (Core.cart_RAM != null)
+ {
+ if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length))
+ {
+ return Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000];
+ }
+ else
+ {
+ return 0xFF;
+ }
+
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ }
+
+ public override byte PeekMemory(ushort addr)
+ {
+ return ReadMemory(addr);
+ }
+
+ public override void WriteMemory(ushort addr, byte value)
+ {
+ if (addr < 0x8000)
+ {
+ if (addr < 0x2000)
+ {
+ RAM_enable = ((value & 0xA) == 0xA) ? true : false;
+ }
+ else if (addr < 0x4000)
+ {
+ value &= 0x1F;
+
+ // writing zero gets translated to 1
+ if (value == 0) { value = 1; }
+
+ ROM_bank &= 0xE0;
+ ROM_bank |= value;
+ ROM_bank &= ROM_mask;
+ }
+ else if (addr < 0x6000)
+ {
+ if (sel_mode && Core.cart_RAM != null)
+ {
+ RAM_bank = value & 3;
+ RAM_bank &= RAM_mask;
+ }
+ else
+ {
+ ROM_bank &= 0x1F;
+ ROM_bank |= ((value & 3) << 5);
+ ROM_bank &= ROM_mask;
+ }
+ }
+ else
+ {
+ sel_mode = (value & 1) > 0;
+
+ if (sel_mode && Core.cart_RAM != null)
+ {
+ ROM_bank &= 0x1F;
+ ROM_bank &= ROM_mask;
+ }
+ else
+ {
+ RAM_bank = 0;
+ }
+ }
+ }
+ else
+ {
+ if (Core.cart_RAM != null)
+ {
+ if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length))
+ {
+ Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value;
+ }
+ }
+ }
+ }
+
+ public override void PokeMemory(ushort addr, byte value)
+ {
+ WriteMemory(addr, value);
+ }
+
+ public override void SyncState(Serializer ser)
+ {
+ ser.Sync("ROM_Bank", ref ROM_bank);
+ ser.Sync("ROM_Mask", ref ROM_mask);
+ ser.Sync("RAM_Bank", ref RAM_bank);
+ ser.Sync("RAM_Mask", ref RAM_mask);
+ ser.Sync("RAM_enable", ref RAM_enable);
+ ser.Sync("sel_mode", ref sel_mode);
+ }
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/PPU.cs
index 9f1742c09e..8bc8cee50d 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/PPU.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/PPU.cs
@@ -170,6 +170,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
if (DMA_clock >= 4)
{
OAM_access_read = false;
+ OAM_access_write = false;
if ((DMA_clock % 4) == 1)
{
// the cpu can't access memory during this time, but we still need the ppu to be able to.
@@ -194,10 +195,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
DMA_clock++;
- if (DMA_clock==648)
+ if (DMA_clock == 648)
{
- DMA_start = false;
OAM_access_read = true;
+ OAM_access_write = true;
+ DMA_start = false;
}
}