diff --git a/BizHawk.Emulation.Common/Interfaces/Services/IMemoryDomains.cs b/BizHawk.Emulation.Common/Interfaces/Services/IMemoryDomains.cs index 2635458e0b..a8cc3e8fd0 100644 --- a/BizHawk.Emulation.Common/Interfaces/Services/IMemoryDomains.cs +++ b/BizHawk.Emulation.Common/Interfaces/Services/IMemoryDomains.cs @@ -4,14 +4,14 @@ namespace BizHawk.Emulation.Common { /// /// This service manages the ability for a client to read/write to memory regions of the core, - /// It is a list of all avaialble memory domains - /// A memory domain is a byte array that respresents the memory of a distinct part of the emulated system. - /// All cores sould implement a SystemBus that represents the standard cpu bus range used for cheats for that system, + /// It is a list of all available memory domains + /// A memory domain is a byte array that represents the memory of a distinct part of the emulated system. + /// All cores should implement a SystemBus that represents the standard CPU bus range used for cheats for that system, /// In order to have a cheat system available for the core /// All domains should implement both peek and poke. However, /// if a domain does not implement poke, it should throw NotImplementedException rather than silently fail /// If this service is available the client will expose many RAM related tools such as the Hex Editor, RAM Search/Watch, and Cheats - /// In addition, this is an essential service for effective lua scripting, and many other tools + /// In addition, this is an essential service for effective LUA scripting, and many other tools /// public interface IMemoryDomains : IEnumerable, IEmulatorService { diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 2306ec5157..1d91932851 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -908,11 +908,14 @@ LibsnesCore.cs - LibsnesCore.cs + LibsnesCore.cs LibsnesCore.cs + + LibsnesCore.cs + LibsnesCore.cs diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.ICodeDataLogger.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.ICodeDataLogger.cs index 64d72acc24..c5ff4a376c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.ICodeDataLogger.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.ICodeDataLogger.cs @@ -17,15 +17,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES public void NewCDL(ICodeDataLog cdl) { - cdl["CARTROM"] = new byte[MemoryDomains["CARTROM"].Size]; + cdl["CARTROM"] = new byte[_memoryDomains["CARTROM"].Size]; - if (MemoryDomains.Has("CARTRAM")) + if (_memoryDomains.Has("CARTRAM")) { - cdl["CARTRAM"] = new byte[MemoryDomains["CARTRAM"].Size]; + cdl["CARTRAM"] = new byte[_memoryDomains["CARTRAM"].Size]; } - cdl["WRAM"] = new byte[MemoryDomains["WRAM"].Size]; - cdl["APURAM"] = new byte[MemoryDomains["APURAM"].Size]; + cdl["WRAM"] = new byte[_memoryDomains["WRAM"].Size]; + cdl["APURAM"] = new byte[_memoryDomains["APURAM"].Size]; cdl.SubType = "SNES"; cdl.SubVer = 0; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IMemoryDomains.cs new file mode 100644 index 0000000000..a109c107ad --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IMemoryDomains.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; + +using BizHawk.Common; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.SNES +{ + public partial class LibsnesCore + { + private readonly List _memoryDomainList = new List(); + private IMemoryDomains _memoryDomains; + + private void SetupMemoryDomains(byte[] romData, byte[] sgbRomData) + { + // lets just do this entirely differently for SGB + if (IsSGB) + { + // NOTE: CGB has 32K of wram, and DMG has 8KB of wram. Not sure how to control this right now.. bsnes might not have any ready way of doign that? I couldnt spot it. + // You wouldnt expect a DMG game to access excess wram, but what if it tried to? maybe an oversight in bsnes? + MakeMemoryDomain("SGB WRAM", LibsnesApi.SNES_MEMORY.SGB_WRAM, MemoryDomain.Endian.Little); + + var romDomain = new MemoryDomainByteArray("SGB CARTROM", MemoryDomain.Endian.Little, romData, true, 1); + _memoryDomainList.Add(romDomain); + + // the last 1 byte of this is special.. its an interrupt enable register, instead of ram. weird. maybe its actually ram and just getting specially used? + MakeMemoryDomain("SGB HRAM", LibsnesApi.SNES_MEMORY.SGB_HRAM, MemoryDomain.Endian.Little); + + MakeMemoryDomain("SGB CARTRAM", LibsnesApi.SNES_MEMORY.SGB_CARTRAM, MemoryDomain.Endian.Little); + + MakeMemoryDomain("WRAM", LibsnesApi.SNES_MEMORY.WRAM, MemoryDomain.Endian.Little); + + var sgbromDomain = new MemoryDomainByteArray("SGB.SFC ROM", MemoryDomain.Endian.Little, sgbRomData, true, 1); + _memoryDomainList.Add(sgbromDomain); + } + else + { + MakeMemoryDomain("WRAM", LibsnesApi.SNES_MEMORY.WRAM, MemoryDomain.Endian.Little); + + MakeMemoryDomain("CARTROM", LibsnesApi.SNES_MEMORY.CARTRIDGE_ROM, MemoryDomain.Endian.Little, byteSize: 2); + MakeMemoryDomain("CARTRAM", LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM, MemoryDomain.Endian.Little, byteSize: 2); + MakeMemoryDomain("VRAM", LibsnesApi.SNES_MEMORY.VRAM, MemoryDomain.Endian.Little, byteSize: 2); + MakeMemoryDomain("OAM", LibsnesApi.SNES_MEMORY.OAM, MemoryDomain.Endian.Little, byteSize: 2); + MakeMemoryDomain("CGRAM", LibsnesApi.SNES_MEMORY.CGRAM, MemoryDomain.Endian.Little, byteSize: 2); + MakeMemoryDomain("APURAM", LibsnesApi.SNES_MEMORY.APURAM, MemoryDomain.Endian.Little, byteSize: 2); + + if (!DeterministicEmulation) + { + _memoryDomainList.Add(new MemoryDomainDelegate( + "System Bus", + 0x1000000, + MemoryDomain.Endian.Little, + addr => api.QUERY_peek(LibsnesApi.SNES_MEMORY.SYSBUS, (uint)addr), + (addr, val) => api.QUERY_poke(LibsnesApi.SNES_MEMORY.SYSBUS, (uint)addr, val), wordSize: 2)); + } + else + { + // limited function bus + MakeFakeBus(); + } + } + + _memoryDomains = new MemoryDomainList(_memoryDomainList); + (ServiceProvider as BasicServiceProvider).Register(_memoryDomains); + } + + private unsafe void MakeMemoryDomain(string name, LibsnesApi.SNES_MEMORY id, MemoryDomain.Endian endian, int byteSize = 1) + { + int size = api.QUERY_get_memory_size(id); + int mask = size - 1; + bool pow2 = Util.IsPowerOfTwo(size); + + // if this type of memory isnt available, dont make the memory domain (most commonly save ram) + if (size == 0) + { + return; + } + + byte* blockptr = api.QUERY_get_memory_data(id); + + MemoryDomain md; + + if (id == LibsnesApi.SNES_MEMORY.OAM) + { + // OAM is actually two differently sized banks of memory which arent truly considered adjacent. + // maybe a better way to visualize it is with an empty bus and adjacent banks + // so, we just throw away everything above its size of 544 bytes + if (size != 544) + { + throw new InvalidOperationException("oam size isnt 544 bytes.. wtf?"); + } + + md = new MemoryDomainDelegate( + name, + size, + endian, + addr => addr < 544 ? blockptr[addr] : (byte)0x00, + (addr, value) => { if (addr < 544) { blockptr[addr] = value; } }, + byteSize); + } + else if (pow2) + { + md = new MemoryDomainDelegate( + name, + size, + endian, + addr => blockptr[addr & mask], + (addr, value) => blockptr[addr & mask] = value, + byteSize); + } + else + { + md = new MemoryDomainDelegate( + name, + size, + endian, + addr => blockptr[addr % size], + (addr, value) => blockptr[addr % size] = value, + byteSize); + } + + _memoryDomainList.Add(md); + } + + private unsafe void MakeFakeBus() + { + int size = api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.WRAM); + if (size != 0x20000) + { + throw new InvalidOperationException(); + } + + byte* blockptr = api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.WRAM); + + var md = new MemoryDomainDelegate("System Bus", 0x1000000, MemoryDomain.Endian.Little, + addr => + { + var a = FakeBusMap((int)addr); + if (a.HasValue) + { + return blockptr[a.Value]; + } + + return FakeBusRead((int)addr); + }, + (addr, val) => + { + var a = FakeBusMap((int)addr); + if (a.HasValue) + blockptr[a.Value] = val; + }, wordSize: 2); + _memoryDomainList.Add(md); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs index 23b0c0b5b5..fdbdf74a24 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs @@ -709,128 +709,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES return 0; } - unsafe void MakeFakeBus() - { - int size = api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.WRAM); - if (size != 0x20000) - throw new InvalidOperationException(); - - byte* blockptr = api.QUERY_get_memory_data(LibsnesApi.SNES_MEMORY.WRAM); - - var md = new MemoryDomainDelegate("System Bus", 0x1000000, MemoryDomain.Endian.Little, - (addr) => - { - var a = FakeBusMap((int)addr); - if (a.HasValue) - return blockptr[a.Value]; - else - return FakeBusRead((int)addr); - }, - (addr, val) => - { - var a = FakeBusMap((int)addr); - if (a.HasValue) - blockptr[a.Value] = val; - }, wordSize: 2); - _memoryDomains.Add(md); - } - - - // ----- Client Debugging API stuff ----- - unsafe MemoryDomain MakeMemoryDomain(string name, LibsnesApi.SNES_MEMORY id, MemoryDomain.Endian endian, int byteSize = 1) - { - int size = api.QUERY_get_memory_size(id); - int mask = size - 1; - bool pow2 = Util.IsPowerOfTwo(size); - - //if this type of memory isnt available, dont make the memory domain (most commonly save ram) - if (size == 0) - return null; - - byte* blockptr = api.QUERY_get_memory_data(id); - - MemoryDomain md; - - if(id == LibsnesApi.SNES_MEMORY.OAM) - { - //OAM is actually two differently sized banks of memory which arent truly considered adjacent. - //maybe a better way to visualize it is with an empty bus and adjacent banks - //so, we just throw away everything above its size of 544 bytes - if (size != 544) throw new InvalidOperationException("oam size isnt 544 bytes.. wtf?"); - md = new MemoryDomainDelegate(name, size, endian, - (addr) => (addr < 544) ? blockptr[addr] : (byte)0x00, - (addr, value) => { if (addr < 544) blockptr[addr] = value; }, - byteSize); - } - else if(pow2) - md = new MemoryDomainDelegate(name, size, endian, - (addr) => blockptr[addr & mask], - (addr, value) => blockptr[addr & mask] = value, byteSize); - else - md = new MemoryDomainDelegate(name, size, endian, - (addr) => blockptr[addr % size], - (addr, value) => blockptr[addr % size] = value, byteSize); - - _memoryDomains.Add(md); - - return md; - } - - void SetupMemoryDomains(byte[] romData, byte[] sgbRomData) - { - //lets just do this entirely differently for SGB - if (IsSGB) - { - //NOTE: CGB has 32K of wram, and DMG has 8KB of wram. Not sure how to control this right now.. bsnes might not have any ready way of doign that? I couldnt spot it. - //You wouldnt expect a DMG game to access excess wram, but what if it tried to? maybe an oversight in bsnes? - MakeMemoryDomain("SGB WRAM", LibsnesApi.SNES_MEMORY.SGB_WRAM, MemoryDomain.Endian.Little); - - var romDomain = new MemoryDomainByteArray("SGB CARTROM", MemoryDomain.Endian.Little, romData, true, 1); - _memoryDomains.Add(romDomain); - - //the last 1 byte of this is special.. its an interrupt enable register, instead of ram. weird. maybe its actually ram and just getting specially used? - MakeMemoryDomain("SGB HRAM", LibsnesApi.SNES_MEMORY.SGB_HRAM, MemoryDomain.Endian.Little); - - MakeMemoryDomain("SGB CARTRAM", LibsnesApi.SNES_MEMORY.SGB_CARTRAM, MemoryDomain.Endian.Little); - - MainMemory = MakeMemoryDomain("WRAM", LibsnesApi.SNES_MEMORY.WRAM, MemoryDomain.Endian.Little); - - var sgbromDomain = new MemoryDomainByteArray("SGB.SFC ROM", MemoryDomain.Endian.Little, sgbRomData, true, 1); - _memoryDomains.Add(sgbromDomain); - } - else - { - MainMemory = MakeMemoryDomain("WRAM", LibsnesApi.SNES_MEMORY.WRAM, MemoryDomain.Endian.Little); - - - MakeMemoryDomain("CARTROM", LibsnesApi.SNES_MEMORY.CARTRIDGE_ROM, MemoryDomain.Endian.Little, byteSize: 2); - MakeMemoryDomain("CARTRAM", LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM, MemoryDomain.Endian.Little, byteSize: 2); - MakeMemoryDomain("VRAM", LibsnesApi.SNES_MEMORY.VRAM, MemoryDomain.Endian.Little, byteSize: 2); - MakeMemoryDomain("OAM", LibsnesApi.SNES_MEMORY.OAM, MemoryDomain.Endian.Little, byteSize: 2); - MakeMemoryDomain("CGRAM", LibsnesApi.SNES_MEMORY.CGRAM, MemoryDomain.Endian.Little, byteSize: 2); - MakeMemoryDomain("APURAM", LibsnesApi.SNES_MEMORY.APURAM, MemoryDomain.Endian.Little, byteSize: 2); - - if (!DeterministicEmulation) - { - _memoryDomains.Add(new MemoryDomainDelegate("System Bus", 0x1000000, MemoryDomain.Endian.Little, - (addr) => api.QUERY_peek(LibsnesApi.SNES_MEMORY.SYSBUS, (uint)addr), - (addr, val) => api.QUERY_poke(LibsnesApi.SNES_MEMORY.SYSBUS, (uint)addr, val), wordSize: 2)); - } - else - { - // limited function bus - MakeFakeBus(); - } - } - - MemoryDomains = new MemoryDomainList(_memoryDomains); - (ServiceProvider as BasicServiceProvider).Register(MemoryDomains); - } - - private MemoryDomain MainMemory; - private List _memoryDomains = new List(); - private IMemoryDomains MemoryDomains; - #region audio stuff SpeexResampler resampler; @@ -845,7 +723,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES resampler.EnqueueSample((short)left, (short)right); } - #endregion audio stuff void RefreshPalette()