LibsnesCore - break off memory domain stuff to a separate file

This commit is contained in:
adelikat 2017-04-19 10:51:16 -05:00
parent bc42af0fa6
commit 7ebddc6087
5 changed files with 168 additions and 133 deletions

View File

@ -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
{

View File

@ -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>

View File

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

View File

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

View File

@ -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()