start of dngp linkup. It works enough for KOF2 to think a cable is there, but not enough to run anything
This commit is contained in:
parent
3a4de4a6ca
commit
034337c51d
|
@ -1,10 +1,16 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Common.BizInvoke;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Sound;
|
||||
using BizHawk.Emulation.Cores.Waterbox;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.SNK
|
||||
|
@ -19,13 +25,20 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK
|
|||
private bool _disposed = false;
|
||||
private readonly DualSyncSound _soundProvider;
|
||||
private readonly SideBySideVideo _videoProvider;
|
||||
private readonly LinkInterop _leftEnd;
|
||||
private readonly LinkInterop _rightEnd;
|
||||
private readonly LinkCable _linkCable;
|
||||
|
||||
[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);
|
||||
_left = new NeoGeoPort(comm, rom, new NeoGeoPort.SyncSettings { Language = LibNeoGeoPort.Language.English }, deterministic, PeRunner.CanonicalStart);
|
||||
_right = new NeoGeoPort(comm, rom, new NeoGeoPort.SyncSettings { Language = LibNeoGeoPort.Language.English }, deterministic, PeRunner.AlternateStart);
|
||||
_linkCable = new LinkCable();
|
||||
_leftEnd = new LinkInterop(_left, _linkCable.LeftIn, _linkCable.LeftOut);
|
||||
_rightEnd = new LinkInterop(_right, _linkCable.RightIn, _linkCable.RightOut);
|
||||
|
||||
|
||||
_serviceProvider = new BasicServiceProvider(this);
|
||||
_soundProvider = new DualSyncSound(_left, _right);
|
||||
|
@ -36,13 +49,217 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK
|
|||
|
||||
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);
|
||||
var t1 = Task.Run(() =>
|
||||
{
|
||||
_left.FrameAdvance(new PrefixController(controller, "P1 "), render, rendersound);
|
||||
_leftEnd.SignalEndOfFrame();
|
||||
});
|
||||
var t2 = Task.Run(() =>
|
||||
{
|
||||
_right.FrameAdvance(new PrefixController(controller, "P2 "), render, rendersound);
|
||||
_rightEnd.SignalEndOfFrame();
|
||||
});
|
||||
var t3 = Task.Run(() =>
|
||||
{
|
||||
_linkCable.RunFrame();
|
||||
});
|
||||
Task.WaitAll(t1, t2, t3);
|
||||
Frame++;
|
||||
_soundProvider.Fetch();
|
||||
_videoProvider.Fetch();
|
||||
}
|
||||
|
||||
#region link cable
|
||||
|
||||
private class LinkCable
|
||||
{
|
||||
public readonly BlockingCollection<LinkRequest> LeftIn = new BlockingCollection<LinkRequest>();
|
||||
public readonly BlockingCollection<LinkResult> LeftOut = new BlockingCollection<LinkResult>();
|
||||
public readonly BlockingCollection<LinkRequest> RightIn = new BlockingCollection<LinkRequest>();
|
||||
public readonly BlockingCollection<LinkResult> RightOut = new BlockingCollection<LinkResult>();
|
||||
|
||||
private readonly Queue<byte> _leftData = new Queue<byte>();
|
||||
private readonly Queue<byte> _rightData = new Queue<byte>();
|
||||
|
||||
public void RunFrame()
|
||||
{
|
||||
LinkRequest l = LeftIn.Take();
|
||||
LinkRequest r = RightIn.Take();
|
||||
while (true)
|
||||
{
|
||||
switch (l.RequestType)
|
||||
{
|
||||
case LinkRequest.RequestTypes.EndOfFrame:
|
||||
if (r.RequestType == LinkRequest.RequestTypes.EndOfFrame)
|
||||
return;
|
||||
break;
|
||||
case LinkRequest.RequestTypes.Write:
|
||||
_leftData.Enqueue(l.Data);
|
||||
l = LeftIn.Take();
|
||||
continue;
|
||||
case LinkRequest.RequestTypes.Read:
|
||||
case LinkRequest.RequestTypes.Poll:
|
||||
if (_rightData.Count > 0)
|
||||
{
|
||||
LeftOut.Add(new LinkResult
|
||||
{
|
||||
Data = l.RequestType == LinkRequest.RequestTypes.Read ? _rightData.Dequeue() : _rightData.Peek(),
|
||||
Return = true
|
||||
});
|
||||
l = LeftIn.Take();
|
||||
continue;
|
||||
}
|
||||
else if (r.RequestType != LinkRequest.RequestTypes.Write)
|
||||
{
|
||||
LeftOut.Add(new LinkResult
|
||||
{
|
||||
Data = l.Data,
|
||||
Return = false
|
||||
});
|
||||
l = LeftIn.Take();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (r.RequestType)
|
||||
{
|
||||
case LinkRequest.RequestTypes.Write:
|
||||
_rightData.Enqueue(r.Data);
|
||||
r = RightIn.Take();
|
||||
continue;
|
||||
case LinkRequest.RequestTypes.Read:
|
||||
case LinkRequest.RequestTypes.Poll:
|
||||
if (_leftData.Count > 0)
|
||||
{
|
||||
RightOut.Add(new LinkResult
|
||||
{
|
||||
Data = r.RequestType == LinkRequest.RequestTypes.Read ? _leftData.Dequeue() : _leftData.Peek(),
|
||||
Return = true
|
||||
});
|
||||
r = RightIn.Take();
|
||||
continue;
|
||||
}
|
||||
else if (l.RequestType != LinkRequest.RequestTypes.Write)
|
||||
{
|
||||
RightOut.Add(new LinkResult
|
||||
{
|
||||
Data = r.Data,
|
||||
Return = false
|
||||
});
|
||||
r = RightIn.Take();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct LinkRequest
|
||||
{
|
||||
public enum RequestTypes : byte
|
||||
{
|
||||
Read,
|
||||
Poll,
|
||||
Write,
|
||||
EndOfFrame
|
||||
}
|
||||
public RequestTypes RequestType;
|
||||
public byte Data;
|
||||
}
|
||||
public struct LinkResult
|
||||
{
|
||||
public byte Data;
|
||||
public bool Return;
|
||||
}
|
||||
|
||||
private unsafe class LinkInterop
|
||||
{
|
||||
private readonly BlockingCollection<LinkRequest> _push;
|
||||
private readonly BlockingCollection<LinkResult> _pull;
|
||||
private NeoGeoPort _core;
|
||||
private readonly IntPtr _readcb;
|
||||
private readonly IntPtr _pollcb;
|
||||
private readonly IntPtr _writecb;
|
||||
private readonly IImportResolver _exporter;
|
||||
|
||||
public LinkInterop(NeoGeoPort core, BlockingCollection<LinkRequest> push, BlockingCollection<LinkResult> pull)
|
||||
{
|
||||
_core = core;
|
||||
_push = push;
|
||||
_pull = pull;
|
||||
_exporter = BizExvoker.GetExvoker(this);
|
||||
_readcb = _exporter.SafeResolve("CommsReadCallback");
|
||||
_pollcb = _exporter.SafeResolve("CommsPollCallback");
|
||||
_writecb = _exporter.SafeResolve("CommsWriteCallback");
|
||||
ConnectPointers();
|
||||
}
|
||||
|
||||
private void ConnectPointers()
|
||||
{
|
||||
_core._neopop.SetCommsCallbacks(_readcb, _pollcb, _writecb);
|
||||
}
|
||||
|
||||
[BizExport(CallingConvention.Cdecl)]
|
||||
public bool CommsReadCallback(byte* buffer)
|
||||
{
|
||||
if (buffer == null)
|
||||
return true;
|
||||
_push.Add(new LinkRequest
|
||||
{
|
||||
RequestType = LinkRequest.RequestTypes.Read,
|
||||
Data = *buffer
|
||||
});
|
||||
var r = _pull.Take();
|
||||
*buffer = r.Data;
|
||||
return r.Return;
|
||||
}
|
||||
[BizExport(CallingConvention.Cdecl)]
|
||||
public bool CommsPollCallback(byte* buffer)
|
||||
{
|
||||
if (buffer == null)
|
||||
return true;
|
||||
_push.Add(new LinkRequest
|
||||
{
|
||||
RequestType = LinkRequest.RequestTypes.Poll,
|
||||
Data = *buffer
|
||||
});
|
||||
var r = _pull.Take();
|
||||
*buffer = r.Data;
|
||||
return r.Return;
|
||||
}
|
||||
[BizExport(CallingConvention.Cdecl)]
|
||||
public void CommsWriteCallback(byte data)
|
||||
{
|
||||
_push.Add(new LinkRequest
|
||||
{
|
||||
RequestType = LinkRequest.RequestTypes.Write,
|
||||
Data = data
|
||||
});
|
||||
}
|
||||
|
||||
public void SignalEndOfFrame()
|
||||
{
|
||||
_push.Add(new LinkRequest
|
||||
{
|
||||
RequestType = LinkRequest.RequestTypes.EndOfFrame
|
||||
});
|
||||
}
|
||||
|
||||
public void PostLoadState()
|
||||
{
|
||||
ConnectPointers();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private class PrefixController : IController
|
||||
{
|
||||
public PrefixController(IController controller, string prefix)
|
||||
|
|
|
@ -44,5 +44,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK
|
|||
public abstract void SetInputCallback(InputCallback callback);
|
||||
[BizImport(CC)]
|
||||
public abstract void GetMemoryArea(int which, ref IntPtr ptr, ref int size, ref bool writable);
|
||||
[BizImport(CC)]
|
||||
public abstract void SetCommsCallbacks(IntPtr readcb, IntPtr pollcb, IntPtr writecb);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,28 +4,31 @@ using BizHawk.Common.BufferExtensions;
|
|||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Waterbox;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.SNK
|
||||
{
|
||||
[CoreAttributes("NeoPop", "Thomas Klausner", true, false, "0.9.44.1",
|
||||
[CoreAttributes("NeoPop", "Thomas Klausner", true, false, "0.9.44.1",
|
||||
"https://mednafen.github.io/releases/", false)]
|
||||
public class NeoGeoPort : IEmulator, IVideoProvider, ISoundProvider, IStatable, IInputPollable,
|
||||
ISettable<object, NeoGeoPort.SyncSettings>
|
||||
{
|
||||
private PeRunner _exe;
|
||||
private LibNeoGeoPort _neopop;
|
||||
internal LibNeoGeoPort _neopop;
|
||||
private long _clockTime;
|
||||
private int _clockDen;
|
||||
|
||||
[CoreConstructor("NGP")]
|
||||
public NeoGeoPort(CoreComm comm, byte[] rom, SyncSettings syncSettings, bool deterministic)
|
||||
:this(comm, rom, syncSettings, deterministic, PeRunner.CanonicalStart)
|
||||
: this(comm, rom, syncSettings, deterministic, PeRunner.CanonicalStart)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace BizHawk.Emulation.Cores
|
|||
{
|
||||
_l = l;
|
||||
_r = r;
|
||||
_buff = new int[BufferWidth * BufferHeight];
|
||||
}
|
||||
|
||||
private static unsafe void Blit(int* src, int srcp, int* dst, int dstp, int w, int h)
|
||||
|
@ -31,8 +32,6 @@ namespace BizHawk.Emulation.Cores
|
|||
{
|
||||
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)
|
||||
{
|
||||
|
@ -42,7 +41,7 @@ namespace BizHawk.Emulation.Cores
|
|||
}
|
||||
private readonly IVideoProvider _l;
|
||||
private readonly IVideoProvider _r;
|
||||
private int[] _buff = new int[0];
|
||||
private int[] _buff;
|
||||
public int BackgroundColor => _l.BackgroundColor;
|
||||
public int BufferHeight => _l.BufferHeight;
|
||||
public int BufferWidth => _l.BufferWidth * 2;
|
||||
|
|
Binary file not shown.
|
@ -41,19 +41,30 @@ uint8 NGPJoyLatch;
|
|||
uint8 settings_language;
|
||||
time_t frontend_time;
|
||||
|
||||
int (*comms_read_cb)(uint8* buffer);
|
||||
int (*comms_poll_cb)(uint8* buffer);
|
||||
void (*comms_write_cb)(uint8 data);
|
||||
|
||||
bool system_comms_read(uint8 *buffer)
|
||||
{
|
||||
return (0);
|
||||
if (comms_read_cb)
|
||||
return comms_read_cb(buffer);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool system_comms_poll(uint8 *buffer)
|
||||
{
|
||||
return (0);
|
||||
if (comms_poll_cb)
|
||||
return comms_poll_cb(buffer);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void system_comms_write(uint8 data)
|
||||
{
|
||||
return;
|
||||
if (comms_write_cb)
|
||||
comms_write_cb(data);
|
||||
}
|
||||
|
||||
void instruction_error(char *vaMessage, ...)
|
||||
|
@ -195,6 +206,13 @@ EXPORT void SetInputCallback(void (*callback)())
|
|||
inputcallback = callback;
|
||||
}
|
||||
|
||||
EXPORT void SetCommsCallbacks(int (*read_cb)(uint8* buffer), int (*poll_cb)(uint8* buffer), void (*write_cb)(uint8 data))
|
||||
{
|
||||
comms_read_cb = read_cb;
|
||||
comms_poll_cb = poll_cb;
|
||||
comms_write_cb = write_cb;
|
||||
}
|
||||
|
||||
EXPORT void GetMemoryArea(int which, void **ptr, int *size, int *writable)
|
||||
{
|
||||
switch (which)
|
||||
|
|
Loading…
Reference in New Issue