some prelim roughin for dual ngp

This commit is contained in:
nattthebear 2017-06-01 18:19:30 -04:00
parent 4a088ba3ff
commit 3a4de4a6ca
9 changed files with 296 additions and 13 deletions

View File

@ -98,6 +98,7 @@ namespace BizHawk.Client.ApiHawk
case "VB":
case "NGP":
case "DNGP":
return 0; // like I give a shit
default:

View File

@ -338,7 +338,7 @@ namespace BizHawk.Emulation.Common
case ".NGP":
case ".NGC":
game.System = "NGP";
game.System = "DNGP";
break;
}

View File

@ -229,7 +229,7 @@
<Compile Include="Computers\Commodore64\C64.MotherboardInput.cs" />
<Compile Include="Computers\Commodore64\Cartridge\Mapper0001.cs" />
<Compile Include="Computers\Commodore64\Cartridge\Mapper0005.cs" />
<Compile Include="Computers\Commodore64\Cartridge\Mapper0007.cs" />
<Compile Include="Computers\Commodore64\Cartridge\Mapper0007.cs" />
<Compile Include="Computers\Commodore64\Cartridge\Mapper0008.cs" />
<Compile Include="Computers\Commodore64\Cartridge\Mapper000A.cs" />
<Compile Include="Computers\Commodore64\Cartridge\Mapper000B.cs" />
@ -1210,6 +1210,7 @@
<Compile Include="Consoles\Sega\SMS\VDP.ModeTMS.cs" />
<Compile Include="Consoles\Sega\SMS\VDP.Mode4.cs" />
<Compile Include="Consoles\Sega\SMS\VDP.Tables.cs" />
<Compile Include="Consoles\SNK\DualNeoGeoPort.cs" />
<Compile Include="Consoles\SNK\LibNeoGeoPort.cs" />
<Compile Include="Consoles\SNK\NeoGeoPort.cs" />
<Compile Include="Consoles\Sony\PSP\PPSSPPDll.cs" />
@ -1290,6 +1291,8 @@
<Compile Include="CPUs\Z80\Registers.cs" />
<Compile Include="CPUs\Z80\Tables.cs" />
<Compile Include="CPUs\Z80\Z80A.cs" />
<Compile Include="SideBySideVideo.cs" />
<Compile Include="Sound\DualSyncSound.cs" />
<Compile Include="Waterbox\ElfRunner.cs" />
<Compile Include="FileID.cs" />
<Compile Include="Consoles\PC Engine\MemoryMap.cs" />
@ -1395,4 +1398,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

View File

@ -0,0 +1,109 @@
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Sound;
using BizHawk.Emulation.Cores.Waterbox;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BizHawk.Emulation.Cores.Consoles.SNK
{
[CoreAttributes("Dual NeoPop", "Thomas Klausner and natt", true, false, "0.9.44.1",
"https://mednafen.github.io/releases/", false)]
public class DualNeoGeoPort : IEmulator
{
private NeoGeoPort _left;
private NeoGeoPort _right;
private readonly BasicServiceProvider _serviceProvider;
private bool _disposed = false;
private readonly DualSyncSound _soundProvider;
private readonly SideBySideVideo _videoProvider;
[CoreConstructor("DNGP")]
public DualNeoGeoPort(CoreComm comm, byte[] rom, bool deterministic)
{
CoreComm = comm;
_left = new NeoGeoPort(comm, rom, null, deterministic, PeRunner.CanonicalStart);
_right = new NeoGeoPort(comm, rom, null, deterministic, PeRunner.AlternateStart);
_serviceProvider = new BasicServiceProvider(this);
_soundProvider = new DualSyncSound(_left, _right);
_serviceProvider.Register<ISoundProvider>(_soundProvider);
_videoProvider = new SideBySideVideo(_left, _right);
_serviceProvider.Register<IVideoProvider>(_videoProvider);
}
public void FrameAdvance(IController controller, bool render, bool rendersound = true)
{
_left.FrameAdvance(new PrefixController(controller, "P1 "), render, rendersound);
_right.FrameAdvance(new PrefixController(controller, "P2 "), render, rendersound);
Frame++;
_soundProvider.Fetch();
_videoProvider.Fetch();
}
private class PrefixController : IController
{
public PrefixController(IController controller, string prefix)
{
_controller = controller;
_prefix = prefix;
}
private readonly IController _controller;
private readonly string _prefix;
public ControllerDefinition Definition => null;
public float GetFloat(string name)
{
return _controller.GetFloat(_prefix + name);
}
public bool IsPressed(string button)
{
return _controller.IsPressed(_prefix + button);
}
}
public ControllerDefinition ControllerDefinition => DualNeoGeoPortController;
private static readonly ControllerDefinition DualNeoGeoPortController = new ControllerDefinition
{
BoolButtons =
{
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 A", "P1 B", "P1 Option", "P1 Power",
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 A", "P2 B", "P2 Option", "P2 Power"
},
Name = "Dual NeoGeo Portable Controller"
};
public void ResetCounters()
{
Frame = 0;
}
public int Frame { get; private set; }
public IEmulatorServiceProvider ServiceProvider => _serviceProvider;
public CoreComm CoreComm { get; }
public bool DeterministicEmulation => _left.DeterministicEmulation && _right.DeterministicEmulation;
public string SystemId => "DNGP";
public void Dispose()
{
if (!_disposed)
{
_left.Dispose();
_right.Dispose();
_left = null;
_right = null;
_disposed = true;
}
}
}
}

View File

@ -25,6 +25,11 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK
[CoreConstructor("NGP")]
public NeoGeoPort(CoreComm comm, byte[] rom, SyncSettings syncSettings, bool deterministic)
:this(comm, rom, syncSettings, deterministic, PeRunner.CanonicalStart)
{
}
internal NeoGeoPort(CoreComm comm, byte[] rom, SyncSettings syncSettings, bool deterministic, ulong startAddress)
{
ServiceProvider = new BasicServiceProvider(this);
CoreComm = comm;
@ -37,7 +42,8 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK
SbrkHeapSizeKB = 256,
SealedHeapSizeKB = 10 * 1024, // must be a bit larger than twice the ROM size
InvisibleHeapSizeKB = 4,
PlainHeapSizeKB = 4
PlainHeapSizeKB = 4,
StartAddress = startAddress
});
_neopop = BizInvoker.GetInvoker<LibNeoGeoPort>(_exe, _exe);

View File

@ -0,0 +1,59 @@
using BizHawk.Emulation.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BizHawk.Emulation.Cores
{
public class SideBySideVideo : IVideoProvider
{
public SideBySideVideo(IVideoProvider l, IVideoProvider r)
{
_l = l;
_r = r;
}
private static unsafe void Blit(int* src, int srcp, int* dst, int dstp, int w, int h)
{
int* srcend = src + h * srcp;
while (src < srcend)
{
for (int j = 0; j < w; j++)
dst[j] = src[j];
src += srcp;
dst += dstp;
}
}
public unsafe void Fetch()
{
int h = BufferHeight;
int w = BufferWidth;
if (_buff.Length < w * h)
_buff = new int[w * h];
fixed(int* _pl = _l.GetVideoBuffer(), _pr = _r.GetVideoBuffer(), _pd = _buff)
{
Blit(_pl, w / 2, _pd, w, w / 2, h);
Blit(_pr, w / 2, _pd + w / 2, w, w / 2, h);
}
}
private readonly IVideoProvider _l;
private readonly IVideoProvider _r;
private int[] _buff = new int[0];
public int BackgroundColor => _l.BackgroundColor;
public int BufferHeight => _l.BufferHeight;
public int BufferWidth => _l.BufferWidth * 2;
public int VirtualHeight => _l.VirtualHeight;
public int VirtualWidth => _l.VirtualWidth * 2;
public int VsyncDenominator => _l.VsyncDenominator;
public int VsyncNumerator => _l.VsyncNumerator;
public int[] GetVideoBuffer()
{
return _buff;
}
}
}

View File

@ -0,0 +1,96 @@
using BizHawk.Emulation.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BizHawk.Emulation.Cores.Sound
{
/// <summary>
/// this thing more or less ASSumes that the two cores input to it both provide the same number of samples in each go
/// </summary>
public class DualSyncSound : ISoundProvider
{
private ISoundProvider _left;
private ISoundProvider _right;
private int _nsamp;
private short[] _samp = new short[0];
private short[] _leftOverflow = new short[32];
private int _leftOverflowCount = 0;
private short[] _rightOverflow = new short[32];
private int _rightOverflowCount = 0;
public DualSyncSound(ISoundProvider left, ISoundProvider right)
{
_left = left;
_right = right;
}
private static short Mix(short[] buff, int idx)
{
int s = buff[idx * 2] + buff[idx * 2 + 1];
if (s > 32767)
s = 32767;
if (s < -32768)
s = -32768;
return (short)s;
}
public void Fetch()
{
int nsampl, nsampr;
short[] sampl, sampr;
_left.GetSamplesSync(out sampl, out nsampl);
_right.GetSamplesSync(out sampr, out nsampr);
int n = Math.Min(nsampl + _leftOverflowCount, nsampr + _rightOverflowCount);
if (_samp.Length < n * 2)
_samp = new short[n * 2];
int i, j;
for (i = 0, j = 0; i < _leftOverflowCount; i++, j++)
_samp[j * 2] = Mix(_leftOverflow, i);
for (i = 0; j < n; i++, j++)
_samp[j * 2] = Mix(sampl, i);
_leftOverflowCount = Math.Min(nsampl - i, 16);
Array.Copy(sampl, i * 2, _leftOverflow, 0, _leftOverflowCount * 2);
for (i = 0, j = 0; i < _rightOverflowCount; i++, j++)
_samp[j * 2 + 1] = Mix(_rightOverflow, i);
for (i = 0; j < n; i++, j++)
_samp[j * 2 + 1] = Mix(sampr, i);
_rightOverflowCount = Math.Min(nsampr - i, 16);
Array.Copy(sampr, i * 2, _rightOverflow, 0, _rightOverflowCount * 2);
_nsamp = n;
}
public bool CanProvideAsync => false;
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
public void DiscardSamples()
{
}
public void GetSamplesAsync(short[] samples)
{
throw new InvalidOperationException();
}
public void GetSamplesSync(out short[] samples, out int nsamp)
{
samples = _samp;
nsamp = _nsamp;
}
public void SetSyncMode(SyncSoundMode mode)
{
if (mode != SyncSoundMode.Sync)
throw new InvalidOperationException();
}
}
}

View File

@ -53,8 +53,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
/// can be 0, but mmap calls will crash.
/// </summary>
public uint MmapHeapSizeKB { get; set; }
}
/// <summary>
/// start address in memory
/// </summary>
public ulong StartAddress { get; set; } = PeRunner.CanonicalStart;
}
public class PeRunner : Swappable, IImportResolver, IBinaryStateable
{
@ -539,8 +543,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
}
// usual starting address for the executable
private static readonly ulong CanonicalStart = 0x0000036f00000000;
/// <summary>
/// usual starting point for the executable
/// </summary>
public const ulong CanonicalStart = 0x0000036f00000000;
public const ulong AlternateStart = 0x0000036e00000000;
/// <summary>
/// the next place where we can put a module or heap
@ -642,6 +650,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
public PeRunner(PeRunnerOptions opt)
{
_nextStart = opt.StartAddress;
Initialize(_nextStart);
using (this.EnterExit())
{

View File

@ -17,7 +17,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
/// <summary>
/// start address
/// </summary>
private ulong _lockkey;
private uint _lockkey;
/// <summary>
/// the the relevant lockinfo for this core
@ -39,17 +39,17 @@ namespace BizHawk.Emulation.Cores.Waterbox
_memoryBlocks = null;
}
protected void Initialize(ulong lockkey)
protected void Initialize(ulong startAddress)
{
// any Swappables in the same 4G range are assumed to conflict
var lockkey = (uint)(startAddress >> 32);
_lockkey = lockkey;
if (lockkey == 0)
throw new NullReferenceException();
_currentLockInfo = LockInfos.GetOrAdd(_lockkey, new LockInfo { Sync = new object() });
}
// any Swappable is assumed to conflict with any other Swappable at the same base address,
// but not any other starting address. so don't put them too close together!
private class LockInfo
{
public object Sync;
@ -70,7 +70,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
}
}
private static readonly ConcurrentDictionary<ulong, LockInfo> LockInfos = new ConcurrentDictionary<ulong, LockInfo>();
private static readonly ConcurrentDictionary<uint, LockInfo> LockInfos = new ConcurrentDictionary<uint, LockInfo>();
/// <summary>
/// acquire lock and swap this into memory