[GambatteLink] proper memory callback scopes for each player

This commit is contained in:
CasualPokePlayer 2021-12-01 20:55:35 -08:00
parent 8c6d12e913
commit 0ad79c2cc2
2 changed files with 106 additions and 92 deletions

View File

@ -45,9 +45,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
public long TotalExecutedCycles => Math.Max((long)_cycleCount, (long)callbackCycleCount);
private const string systemBusScope = "System Bus";
private MemoryCallbackSystem _memorycallbacks = new MemoryCallbackSystem(new[] { systemBusScope, "ROM", "VRAM", "SRAM", "WRAM", "OAM", "HRAM" });
private MemoryCallbackSystem _memorycallbacks = new MemoryCallbackSystem(new[] { "System Bus", "ROM", "VRAM", "SRAM", "WRAM", "OAM", "HRAM" });
public IMemoryCallbackSystem MemoryCallbacks => _memorycallbacks;
private LibGambatte.MemoryCallback _readcb;
@ -57,100 +55,103 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
/// <summary>
/// for use in dual core
/// </summary>
internal void ConnectMemoryCallbackSystem(MemoryCallbackSystem mcs)
internal void ConnectMemoryCallbackSystem(MemoryCallbackSystem mcs, int which)
{
_memorycallbacks = mcs;
_readcb = CreateCallback(MemoryCallbackFlags.AccessRead, () => MemoryCallbacks.HasReads, $"P{which + 1} ");
_writecb = CreateCallback(MemoryCallbackFlags.AccessWrite, () => MemoryCallbacks.HasWrites, $"P{which + 1} ");
_execcb = CreateCallback(MemoryCallbackFlags.AccessExecute, () => MemoryCallbacks.HasExecutes, $"P{which + 1} ");
_memorycallbacks.ActiveChanged += SetMemoryCallbacks;
}
private LibGambatte.MemoryCallback CreateCallback(MemoryCallbackFlags flags, Func<bool> getHasCBOfType, string which = "")
{
var rawFlags = (uint)flags;
return (address, cycleOffset) =>
{
callbackCycleCount = _cycleCount + cycleOffset;
if (getHasCBOfType())
{
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, which + "System Bus");
if (address < 0x4000u) // always rom bank 0 for most mbcs (todo: edge mbcs where this doesn't apply)
{
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, which + "ROM");
}
else if (address < 0x8000u) // rom bank x
{
var bank = LibGambatte.gambatte_getrombank(GambatteState); // this will return 1 in case there is no mbc (0 is valid for some mbcs too)
address += (uint)(bank * 0x4000);
address -= 0x4000u;
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, which + "ROM");
}
else if (address < 0xA000u) // vram (may be banked on CGB in CGB enhanced mode)
{
if (IsCGBMode() && !IsCGBDMGMode())
{
var bank = LibGambatte.gambatte_cpuread(GambatteState, 0xFF4F) & 1;
address += (uint)(bank * 0x2000);
}
address -= 0x8000u;
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, which + "VRAM");
}
else if (address < 0xC000u) // sram (may be banked)
{
var bank = LibGambatte.gambatte_getsrambank(GambatteState); // this will return 0 in case there is only one bank
address += (uint)(bank * 0x2000);
address -= 0xA000u;
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, which + "SRAM");
}
else if (address < 0xD000u) // wram bank 0
{
address -= 0xC000u;
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, which + "WRAM");
}
else if (address < 0xE000u) // wram bank x (always one for dmg/cgb in dmg mode)
{
if (IsCGBMode() && !IsCGBDMGMode())
{
var bank = Math.Max(LibGambatte.gambatte_cpuread(GambatteState, 0xFF70) & 7, 1);
address += (uint)(bank * 0x1000);
}
address -= 0xD000u;
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, which + "WRAM");
}
else if (address < 0xFE00u) // echo ram
{
// do we do something here?
}
else if (address < 0xFEA0u) // oam
{
address -= 0xFE00u;
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, which + "OAM");
}
else if (address < 0xFF00u) // "extra" oam
{
// do we do something here?
}
else if (address < 0xFF80u) // mmio
{
// do we do something here?
}
else if (address < 0xFFFF) // hram
{
address -= 0xFF80u;
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, which + "HRAM");
}
else if (address == 0xFFFF) // ie reg
{
// do we do something here?
}
else
{
throw new InvalidOperationException("Core accessed invalid address???");
}
}
};
}
private void InitMemoryCallbacks()
{
LibGambatte.MemoryCallback CreateCallback(MemoryCallbackFlags flags, Func<bool> getHasCBOfType)
{
var rawFlags = (uint)flags;
return (address, cycleOffset) =>
{
callbackCycleCount = _cycleCount + cycleOffset;
if (getHasCBOfType())
{
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, systemBusScope);
if (address < 0x4000u) // always rom bank 0 for most mbcs (todo: edge mbcs where this doesn't apply)
{
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, "ROM");
}
else if (address < 0x8000u) // rom bank x
{
var bank = LibGambatte.gambatte_getrombank(GambatteState); // this will return 1 in case there is no mbc (0 is valid for some mbcs too)
address += (uint)(bank * 0x4000);
address -= 0x4000u;
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, "ROM");
}
else if (address < 0xA000u) // vram (may be banked on CGB in CGB enhanced mode)
{
if (IsCGBMode() && !IsCGBDMGMode())
{
var bank = LibGambatte.gambatte_cpuread(GambatteState, 0xFF4F) & 1;
address += (uint)(bank * 0x2000);
}
address -= 0x8000u;
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, "VRAM");
}
else if (address < 0xC000u) // sram (may be banked)
{
var bank = LibGambatte.gambatte_getsrambank(GambatteState); // this will return 0 in case there is only one bank
address += (uint)(bank * 0x2000);
address -= 0xA000u;
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, "SRAM");
}
else if (address < 0xD000u) // wram bank 0
{
address -= 0xC000u;
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, "WRAM");
}
else if (address < 0xE000u) // wram bank x (always one for dmg/cgb in dmg mode)
{
if (IsCGBMode() && !IsCGBDMGMode())
{
var bank = Math.Max(LibGambatte.gambatte_cpuread(GambatteState, 0xFF70) & 7, 1);
address += (uint)(bank * 0x1000);
}
address -= 0xD000u;
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, "WRAM");
}
else if (address < 0xFE00u) // echo ram
{
// do we do something here?
}
else if (address < 0xFEA0u) // oam
{
address -= 0xFE00u;
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, "OAM");
}
else if (address < 0xFF00u) // "extra" oam
{
// do we do something here?
}
else if (address < 0xFF80u) // mmio
{
// do we do something here?
}
else if (address < 0xFFFF) // hram
{
address -= 0xFF80u;
MemoryCallbacks.CallMemoryCallbacks(address, 0, rawFlags, "HRAM");
}
else if (address == 0xFFFF) // ie reg
{
// do we do something here?
}
else
{
throw new InvalidOperationException("Core accessed invalid address???");
}
}
};
}
_readcb = CreateCallback(MemoryCallbackFlags.AccessRead, () => MemoryCallbacks.HasReads);
_writecb = CreateCallback(MemoryCallbackFlags.AccessWrite, () => MemoryCallbacks.HasWrites);
_execcb = CreateCallback(MemoryCallbackFlags.AccessExecute, () => MemoryCallbacks.HasExecutes);

View File

@ -28,13 +28,26 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
_linkedOverflow = new int[_numCores];
RomDetails = "";
_memoryCallbacks = new MemoryCallbackSystem(new[] { "System Bus", "ROM", "VRAM", "SRAM", "WRAM", "OAM", "HRAM" });
var scopes = new string[_numCores * 7];
for (int i = 0; i < _numCores; i++)
{
scopes[i * 7 + 0] = $"P{i + 1} System Bus";
scopes[i * 7 + 1] = $"P{i + 1} ROM";
scopes[i * 7 + 2] = $"P{i + 1} VRAM";
scopes[i * 7 + 3] = $"P{i + 1} SRAM";
scopes[i * 7 + 4] = $"P{i + 1} WRAM";
scopes[i * 7 + 5] = $"P{i + 1} OAM";
scopes[i * 7 + 6] = $"P{i + 1} HRAM";
}
_memoryCallbacks = new MemoryCallbackSystem(scopes);
for (int i = 0; i < _numCores; i++)
{
_linkedCores[i] = new Gameboy(lp.Comm, lp.Roms[i].Game, lp.Roms[i].RomData, _settings._linkedSettings[i], _syncSettings._linkedSyncSettings[i], lp.DeterministicEmulationRequested);
_linkedCores[i].ConnectInputCallbackSystem(_inputCallbacks);
_linkedCores[i].ConnectMemoryCallbackSystem(_memoryCallbacks);
_linkedCores[i].ConnectMemoryCallbackSystem(_memoryCallbacks, i);
_linkedConts[i] = new SaveController(Gameboy.CreateControllerDefinition(false, false));
_linkedBlips[i] = new BlipBuffer(1024);
_linkedBlips[i].SetRates(2097152 * 2, 44100);