LibsnesCore - break off memory domain stuff to a separate file
This commit is contained in:
parent
bc42af0fa6
commit
7ebddc6087
|
@ -4,14 +4,14 @@ namespace BizHawk.Emulation.Common
|
|||
{
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// </summary>
|
||||
public interface IMemoryDomains : IEnumerable<MemoryDomain>, IEmulatorService
|
||||
{
|
||||
|
|
|
@ -908,11 +908,14 @@
|
|||
<DependentUpon>LibsnesCore.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\SNES\LibsnesCore.IEmulator.cs">
|
||||
<DependentUpon>LibsnesCore.cs</DependentUpon>
|
||||
<DependentUpon>LibsnesCore.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\SNES\LibsnesCore.IInputPollable.cs">
|
||||
<DependentUpon>LibsnesCore.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\SNES\LibsnesCore.IMemoryDomains.cs">
|
||||
<DependentUpon>LibsnesCore.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Nintendo\SNES\LibsnesCore.IRegionable.cs">
|
||||
<DependentUpon>LibsnesCore.cs</DependentUpon>
|
||||
</Compile>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<MemoryDomain> _memoryDomainList = new List<MemoryDomain>();
|
||||
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<IMemoryDomains>(_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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<IMemoryDomains>(MemoryDomains);
|
||||
}
|
||||
|
||||
private MemoryDomain MainMemory;
|
||||
private List<MemoryDomain> _memoryDomains = new List<MemoryDomain>();
|
||||
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()
|
||||
|
|
Loading…
Reference in New Issue