some prelim roughin for dual ngp
This commit is contained in:
parent
4a088ba3ff
commit
3a4de4a6ca
|
@ -98,6 +98,7 @@ namespace BizHawk.Client.ApiHawk
|
|||
|
||||
case "VB":
|
||||
case "NGP":
|
||||
case "DNGP":
|
||||
return 0; // like I give a shit
|
||||
|
||||
default:
|
||||
|
|
|
@ -338,7 +338,7 @@ namespace BizHawk.Emulation.Common
|
|||
|
||||
case ".NGP":
|
||||
case ".NGC":
|
||||
game.System = "NGP";
|
||||
game.System = "DNGP";
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue