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:
nattthebear 2017-06-01 20:44:49 -04:00
parent 3a4de4a6ca
commit 034337c51d
6 changed files with 253 additions and 14 deletions

View File

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

View File

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

View File

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

View File

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

View File

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