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; } }