From 9faae458af3543957d7ac755367356b731365e54 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Wed, 22 Nov 2017 21:38:56 -0500 Subject: [PATCH] GBHawk: Sachen work --- .../BizHawk.Emulation.Cores.csproj | 2 + .../Nintendo/GBHawk/GBHawk.IMemoryDomains.cs | 2 +- .../Consoles/Nintendo/GBHawk/GBHawk.cs | 16 +- .../GBHawk/Mappers/Mapper_Sachen_MMC1.cs | 157 +++++++++++++++++ .../GBHawk/Mappers/Mapper_Sachen_MMC2.cs | 159 ++++++++++++++++++ .../Consoles/Nintendo/GBHawk/MemoryMap.cs | 91 ++++++++++ 6 files changed, 424 insertions(+), 3 deletions(-) create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_Sachen_MMC1.cs create mode 100644 BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_Sachen_MMC2.cs diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 89b09fb05a..4a00050be4 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -582,6 +582,8 @@ + + diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IMemoryDomains.cs index 162b39b6c2..375abbd592 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IMemoryDomains.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IMemoryDomains.cs @@ -51,7 +51,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk private byte PeekSystemBus(long addr) { ushort addr2 = (ushort)(addr & 0xFFFF); - return ReadMemory(addr2); + return PeekMemory(addr2); } private void PokeSystemBus(long addr, byte value) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs index 5a4da37c45..61e366435c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs @@ -68,7 +68,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { ReadMemory = ReadMemory, WriteMemory = WriteMemory, - PeekMemory = ReadMemory, + PeekMemory = PeekMemory, DummyReadMemory = ReadMemory, OnExecFetch = ExecFetch }; @@ -138,7 +138,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk audio.Reset(); serialport.Reset(); - cpu.SetCallbacks(ReadMemory, ReadMemory, ReadMemory, WriteMemory); + cpu.SetCallbacks(ReadMemory, PeekMemory, PeekMemory, WriteMemory); _vidbuffer = new int[VirtualWidth * VirtualHeight]; } @@ -184,6 +184,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk case 0xFE: mapper = new MapperHuC3(); mppr = "HuC3"; break; case 0xFF: mapper = new MapperHuC1(); mppr = "HuC1"; break; + // Bootleg mappers + // NOTE: Sachen mapper selection does not account for scrambling, so if another bootleg mapper + // identifies itself as 0x31, this will need to be modified + case 0x31: mapper = new MapperSachen2(); mppr = "Schn2"; break; + case 0x4: case 0x7: case 0xA: @@ -197,6 +202,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk case 0x21: default: // mapper not implemented + Console.WriteLine(header[0x47]); throw new Exception("Mapper not implemented"); break; @@ -236,6 +242,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk break; } + // Sachen maper not known to have RAM + if ((mppr == "Schn1") || (mppr == "Schn2")) + { + cart_RAM = null; + } + // mbc2 carts have built in RAM if (mppr == "MBC2") { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_Sachen_MMC1.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_Sachen_MMC1.cs new file mode 100644 index 0000000000..b178fe1037 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_Sachen_MMC1.cs @@ -0,0 +1,157 @@ +using BizHawk.Common; +using BizHawk.Common.NumberExtensions; +using System; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawk +{ + // Sachen Bootleg Mapper + // NOTE: Normally, locked mode is disabled after 31 rises of A15 + // this occurs when the Boot Rom is loading the nintendo logo into VRAM + // instead of tracking that in the main memory map where it will just slow things down for no reason + // we'll clear the 'locked' flag when the last byte of the logo is read + class MapperSachen1 : MapperBase + { + public int ROM_bank; + public bool locked; + public int ROM_mask; + public int ROM_bank_mask; + public int BASE_ROM_Bank; + public bool reg_access; + + public override void Initialize() + { + ROM_bank = 1; + ROM_mask = Core._rom.Length / 0x4000 - 1; + BASE_ROM_Bank = 0; + ROM_bank_mask = 0xFF; + locked = true; + reg_access = false; + } + + public override byte ReadMemory(ushort addr) + { + if (addr < 0x4000) + { + ushort t_addr = addr; + + // header is scrambled + if ((addr >= 0x100) && (addr < 0x200)) + { + int temp0 = (addr & 1); + int temp1 = (addr & 2); + int temp4 = (addr & 0x10); + int temp6 = (addr & 0x40); + + temp0 = temp0 << 6; + temp1 = temp1 << 3; + temp4 = temp4 >> 3; + temp6 = temp6 >> 6; + + addr &= 0x1AC; + addr |= (ushort)(temp0 | temp1 | temp4 | temp6); + } + + if (locked) { addr |= 0x80; } + + if (t_addr == 0x133) + { + locked = false; + Console.WriteLine("cleared"); + } + + return Core._rom[addr + BASE_ROM_Bank * 0x4000]; + } + else if (addr < 0x8000) + { + return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000]; + } + else + { + return 0xFF; + } + } + + public override byte PeekMemory(ushort addr) + { + if (addr < 0x4000) + { + ushort t_addr = addr; + + // header is scrambled + if ((addr >= 0x100) && (addr < 0x200)) + { + int temp0 = (addr & 1); + int temp1 = (addr & 2); + int temp4 = (addr & 0x10); + int temp6 = (addr & 0x40); + + temp0 = temp0 << 6; + temp1 = temp1 << 3; + temp4 = temp4 >> 3; + temp6 = temp6 >> 6; + + addr &= 0x1AC; + addr |= (ushort)(temp0 | temp1 | temp4 | temp6); + } + + if (locked) { addr |= 0x80; } + + return Core._rom[addr + BASE_ROM_Bank * 0x4000]; + } + else if (addr < 0x8000) + { + return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000]; + } + else + { + return 0xFF; + } + } + + public override void WriteMemory(ushort addr, byte value) + { + if (addr < 0x2000) + { + if (reg_access) + { + BASE_ROM_Bank = value; + } + } + else if (addr < 0x4000) + { + ROM_bank = (value > 0) ? value : 1; + + if ((value & 0x30) == 0x30) + { + reg_access = true; + } + else + { + reg_access = false; + } + } + else if (addr < 0x6000) + { + if (reg_access) + { + ROM_bank_mask = 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("locked", ref locked); + ser.Sync("ROM_bank_mask", ref ROM_bank_mask); + ser.Sync("BASE_ROM_Bank", ref BASE_ROM_Bank); + ser.Sync("reg_access", ref reg_access); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_Sachen_MMC2.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_Sachen_MMC2.cs new file mode 100644 index 0000000000..d43e912cf8 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Mappers/Mapper_Sachen_MMC2.cs @@ -0,0 +1,159 @@ +using BizHawk.Common; +using BizHawk.Common.NumberExtensions; +using System; + +namespace BizHawk.Emulation.Cores.Nintendo.GBHawk +{ + // Sachen Bootleg Mapper + // NOTE: Normally, locked mode is disabled after 31 rises of A15 + // this occurs when the Boot Rom is loading the nintendo logo into VRAM + // instead of tracking that in the main memory map where it will just slow things down for no reason + // we'll clear the 'locked' flag when the last byte of the logo is read + class MapperSachen2 : MapperBase + { + public int ROM_bank; + public bool locked; + public int ROM_mask; + public int ROM_bank_mask; + public int BASE_ROM_Bank; + public bool reg_access; + + public override void Initialize() + { + ROM_bank = 1; + ROM_mask = Core._rom.Length / 0x4000 - 1; + BASE_ROM_Bank = 0; + ROM_bank_mask = 0; + locked = false; + reg_access = false; + } + + public override byte ReadMemory(ushort addr) + { + if (addr < 0x4000) + { + ushort t_addr = addr; + + // header is scrambled + if ((addr >= 0x100) && (addr < 0x200)) + { + int temp0 = (addr & 1); + int temp1 = (addr & 2); + int temp4 = (addr & 0x10); + int temp6 = (addr & 0x40); + + temp0 = temp0 << 6; + temp1 = temp1 << 3; + temp4 = temp4 >> 3; + temp6 = temp6 >> 6; + + addr &= 0x1AC; + addr |= (ushort)(temp0 | temp1 | temp4 | temp6); + } + + if (locked) { addr |= 0x80; } + + if (t_addr == 0x133) + { + if ((Core.GB_bios_register & 0x1) == 0) { locked ^= true; } + } + + return Core._rom[addr + BASE_ROM_Bank * 0x4000]; + } + else if (addr < 0x8000) + { + int temp_bank = (ROM_bank & ~ROM_bank_mask) | (ROM_bank_mask & BASE_ROM_Bank); + temp_bank &= ROM_mask; + + return Core._rom[(addr - 0x4000) + temp_bank * 0x4000]; + } + else + { + return 0xFF; + } + } + + public override byte PeekMemory(ushort addr) + { + if (addr < 0x4000) + { + ushort t_addr = addr; + + // header is scrambled + if ((addr >= 0x100) && (addr < 0x200)) + { + int temp0 = (addr & 1); + int temp1 = (addr & 2); + int temp4 = (addr & 0x10); + int temp6 = (addr & 0x40); + + temp0 = temp0 << 6; + temp1 = temp1 << 3; + temp4 = temp4 >> 3; + temp6 = temp6 >> 6; + + addr &= 0x1AC; + addr |= (ushort)(temp0 | temp1 | temp4 | temp6); + } + + if (locked) { addr |= 0x80; } + + return Core._rom[addr + BASE_ROM_Bank * 0x4000]; + } + else if (addr < 0x8000) + { + return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000]; + } + else + { + return 0xFF; + } + } + + public override void WriteMemory(ushort addr, byte value) + { + if (addr < 0x2000) + { + if (reg_access) + { + BASE_ROM_Bank = value; + } + } + else if (addr < 0x4000) + { + ROM_bank = (value > 0) ? (value) : 1; + + if ((value & 0x30) == 0x30) + { + reg_access = true; + } + else + { + reg_access = false; + } + } + else if (addr < 0x6000) + { + if (reg_access) + { + ROM_bank_mask = 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("locked", ref locked); + ser.Sync("ROM_bank_mask", ref ROM_bank_mask); + ser.Sync("BASE_ROM_Bank", ref BASE_ROM_Bank); + ser.Sync("reg_access", ref reg_access); + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/MemoryMap.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/MemoryMap.cs index 86d436bdde..3564245b4c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/MemoryMap.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/MemoryMap.cs @@ -206,5 +206,96 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk Write_Registers(addr, value); } } + + public byte PeekMemory(ushort addr) + { + if (ppu.DMA_start) + { + if ((addr >= 0xFE00) && (addr < 0xFEA0) && ppu.DMA_OAM_access) + { + return OAM[addr - 0xFE00]; + } + else if ((addr >= 0xFF80)) + { + return ZP_RAM[addr - 0xFF80]; + } + else if ((addr >= 0xE000) && (addr < 0xFE00)) + { + return RAM[addr - 0xE000]; // some of gekkio's tests require this to be accessible during DMA + } + else if (addr < 0x4000) + { + return mapper.PeekMemory(addr); // some of gekkio's tests require this to be accessible during DMA + } + return 0xFF; + } + + if (addr < 0x100) + { + // return Either BIOS ROM or Game ROM + if ((GB_bios_register & 0x1) == 0) + { + return _bios[addr]; // Return BIOS + } + else + { + return mapper.PeekMemory(addr); + } + } + else if (addr < 0x8000) + { + return mapper.PeekMemory(addr); + } + else if (addr < 0x9800) + { + if (ppu.VRAM_access_read) { return CHR_RAM[addr - 0x8000]; } + else { return 0xFF; } + } + else if (addr < 0x9C00) + { + if (ppu.VRAM_access_read) { return BG_map_1[addr - 0x9800]; } + else { return 0xFF; } + } + else if (addr < 0xA000) + { + if (ppu.VRAM_access_read) { return BG_map_2[addr - 0x9C00]; } + else { return 0xFF; } + } + else if (addr < 0xC000) + { + return mapper.PeekMemory(addr); + } + else if (addr < 0xE000) + { + return RAM[addr - 0xC000]; + } + else if (addr < 0xFE00) + { + return RAM[addr - 0xE000]; + } + else if (addr < 0xFEA0) + { + if (ppu.OAM_access_read) { return OAM[addr - 0xFE00]; } + else { return 0xFF; } + } + else if (addr < 0xFF00) + { + // unmapped memory, returns 0xFF + return 0xFF; + } + else if (addr < 0xFF80) + { + return Read_Registers(addr); + } + else if (addr < 0xFFFF) + { + return ZP_RAM[addr - 0xFF80]; + } + else + { + return Read_Registers(addr); + } + + } } }