diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
index 2f9f7725f8..1aaf31181b 100644
--- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
+++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
@@ -1150,6 +1150,7 @@
+
Yabause.cs
diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/LibSaturnus.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/LibSaturnus.cs
index 7af3533bd0..4e51d824fb 100644
--- a/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/LibSaturnus.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/LibSaturnus.cs
@@ -26,7 +26,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
[StructLayout(LayoutKind.Sequential)]
public struct Track
{
- public int Address;
+ public int Adr;
public int Control;
public int Lba;
public int Valid;
@@ -44,14 +44,16 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
[FieldOffset(8)]
public IntPtr Pixels;
[FieldOffset(16)]
- public long MasterCycles;
+ public IntPtr Controllers;
[FieldOffset(24)]
- public int SoundBufMaxSize;
- [FieldOffset(28)]
- public int SoundBufSize;
+ public long MasterCycles;
[FieldOffset(32)]
- public int Width;
+ public int SoundBufMaxSize;
[FieldOffset(36)]
+ public int SoundBufSize;
+ [FieldOffset(40)]
+ public int Width;
+ [FieldOffset(44)]
public int Height;
};
@@ -76,5 +78,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
public abstract void SetDisk(int disk, bool open);
[BizImport(CC)]
public abstract void FrameAdvance([In, Out]FrameAdvanceInfo f);
+ [BizImport(CC)]
+ public abstract void SetupInput(int[] portdevices, int[] multitaps);
}
}
diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/Saturnus.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/Saturnus.cs
index c52fb40d5b..66eadc100d 100644
--- a/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/Saturnus.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/Saturnus.cs
@@ -20,6 +20,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
private Disc[] _disks;
private DiscSectorReader[] _diskReaders;
private bool _isPal;
+ private SaturnusControllerDeck _controllerDeck;
public Saturnus(CoreComm comm, IEnumerable disks)
{
@@ -45,10 +46,18 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
SetFirmwareCallbacks();
SetCdCallbacks();
-
if (!_core.Init(_disks.Length))
throw new InvalidOperationException("Core rejected the disks!");
ClearAllCallbacks();
+
+ _controllerDeck = new SaturnusControllerDeck(new[] { false, false },
+ new[] { SaturnusControllerDeck.Device.Gamepad, SaturnusControllerDeck.Device.None },
+ _core);
+ ControllerDefinition = _controllerDeck.Definition;
+ ControllerDefinition.Name = "Saturn Controller";
+ ControllerDefinition.BoolButtons.Add("Power");
+ ControllerDefinition.BoolButtons.Add("Reset"); // not yet hooked up
+
_exe.Seal();
SetCdCallbacks();
_core.SetDisk(0, false);
@@ -56,14 +65,19 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
public unsafe void FrameAdvance(IController controller, bool render, bool rendersound = true)
{
+ if (controller.IsPressed("Power"))
+ _core.HardReset();
+
fixed (short* _sp = _soundBuffer)
- fixed (int* _vp = _videoBuffer)
+ fixed (int* _vp = _videoBuffer)
+ fixed (byte* _cp = _controllerDeck.Poll(controller))
{
var info = new LibSaturnus.FrameAdvanceInfo
{
SoundBuf = (IntPtr)_sp,
SoundBufMaxSize = _soundBuffer.Length / 2,
- Pixels = (IntPtr)_vp
+ Pixels = (IntPtr)_vp,
+ Controllers = (IntPtr)_cp
};
_core.FrameAdvance(info);
@@ -101,7 +115,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
public string SystemId { get { return "SAT"; } }
public bool DeterministicEmulation { get; private set; }
public CoreComm CoreComm { get; }
- public ControllerDefinition ControllerDefinition => NullController.Instance.Definition;
+ public ControllerDefinition ControllerDefinition { get; }
#region Callbacks
@@ -176,7 +190,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
t.DiskType = (int)tin.Session1Format;
for (int i = 0; i < 101; i++)
{
- t.Tracks[i].Address = 1; // ????
+ t.Tracks[i].Adr = 1; // ????
t.Tracks[i].Lba = tin.TOCItems[i].LBA;
t.Tracks[i].Control = (int)tin.TOCItems[i].Control;
t.Tracks[i].Valid = tin.TOCItems[i].Exists ? 1 : 0;
@@ -184,6 +198,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
}
private void CDSectorCallback(int disk, int lba, IntPtr dest)
{
+ Console.WriteLine("servicing " + lba);
var buff = new byte[2448];
_diskReaders[disk].ReadLBA_2448(lba, buff, 0);
Marshal.Copy(buff, 0, dest, 2448);
diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/SaturnusControllerDeck.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/SaturnusControllerDeck.cs
new file mode 100644
index 0000000000..c9a6eceb0d
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/SaturnusControllerDeck.cs
@@ -0,0 +1,140 @@
+using BizHawk.Emulation.Common;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
+{
+ public class SaturnusControllerDeck
+ {
+ private const int DataSize = 32;
+
+ private static readonly Type[] Implementors =
+ {
+ typeof(None),
+ typeof(Gamepad),
+ typeof(None),
+ typeof(None),
+ typeof(None),
+ typeof(None),
+ typeof(None),
+ typeof(None)
+ };
+
+ private readonly IDevice[] _devices;
+ private readonly ControlDefUnMerger[] _unmerger;
+ private readonly byte[] _data;
+
+ public ControllerDefinition Definition { get; }
+
+ public SaturnusControllerDeck(bool[] multitap, Device[] devices, LibSaturnus core)
+ {
+ int count = 2 + multitap.Count(b => b) * 5;
+
+ int[] dev = new int[12];
+ int[] mt = new int[2];
+
+ for (int i = 0; i < 12; i++)
+ dev[i] = (int)(i < count ? devices[i] : Device.None);
+ for (int i = 0; i < 2; i++)
+ mt[i] = multitap[i] ? 1 : 0;
+
+ core.SetupInput(dev, mt);
+
+ _devices = dev.Take(count)
+ .Select(i => Activator.CreateInstance(Implementors[i]))
+ .Cast()
+ .ToArray();
+ _data = new byte[count * DataSize];
+
+ List cdum;
+ Definition = ControllerDefinitionMerger.GetMerged(_devices.Select(d => d.Definition),
+ out cdum);
+ _unmerger = cdum.ToArray();
+ }
+
+ public byte[] Poll(IController controller)
+ {
+ for (int i = 0, offset = 0; i < _devices.Length; i++, offset += DataSize)
+ _devices[i].Update(_unmerger[i].UnMerge(controller), _data, offset);
+ return _data;
+ }
+
+ public enum Device
+ {
+ None,
+ Gamepad,
+ ThreeDeePad,
+ Mouse,
+ Wheel,
+ Mission,
+ DualMission,
+ Keyboard
+ }
+
+ private interface IDevice
+ {
+ void Update(IController controller, byte[] dest, int offset);
+ ControllerDefinition Definition { get; }
+ }
+
+ private class None : IDevice
+ {
+ private static readonly ControllerDefinition NoneDefition = new ControllerDefinition();
+ public ControllerDefinition Definition => NoneDefition;
+ public void Update(IController controller, byte[] dest, int offset)
+ {
+ }
+
+ }
+
+ private abstract class ButtonedDevice : IDevice
+ {
+ protected ButtonedDevice()
+ {
+ Definition = new ControllerDefinition
+ {
+ BoolButtons = ButtonNames.Where(s => s != null).ToList()
+ };
+ }
+
+ protected abstract string[] ButtonNames { get; }
+ public ControllerDefinition Definition { get; }
+
+ public virtual void Update(IController controller, byte[] dest, int offset)
+ {
+ byte data = 0;
+ int pos = 0;
+ int bit = 0;
+ for (int i = 0; i < ButtonNames.Length; i++)
+ {
+ if (ButtonNames[i] != null && controller.IsPressed(ButtonNames[i]))
+ data |= (byte)(1 << bit);
+ if (++bit == 8)
+ {
+ bit = 0;
+ dest[offset + pos++] = data;
+ data = 0;
+ }
+ }
+ if (bit != 0)
+ dest[offset] = data;
+ }
+ }
+
+ private class Gamepad : ButtonedDevice
+ {
+ private static readonly string[] _buttonNames =
+ {
+ "0Z", "0Y", "0X", "0R",
+ "0Up", "0Down", "0Left", "0Right",
+ "0B", "0C", "0A", "0Start",
+ null,null, null, "0L"
+ };
+
+ protected override string[] ButtonNames => _buttonNames;
+ }
+ }
+}
diff --git a/waterbox/ss/bizhawk.cpp b/waterbox/ss/bizhawk.cpp
index b32a7d02e3..7d735ab907 100644
--- a/waterbox/ss/bizhawk.cpp
+++ b/waterbox/ss/bizhawk.cpp
@@ -9,10 +9,10 @@
#define EXPORT extern "C" ECL_EXPORT
using namespace MDFN_IEN_SS;
-static int32 (*FirmwareSizeCallback)(const char* filename);
-static void (*FirmwareDataCallback)(const char* filename, uint8* dest);
+static int32 (*FirmwareSizeCallback)(const char *filename);
+static void (*FirmwareDataCallback)(const char *filename, uint8 *dest);
-std::unique_ptr GetFirmware(const char* filename)
+std::unique_ptr GetFirmware(const char *filename)
{
int32 length = FirmwareSizeCallback(filename);
auto buffer = new uint8[length];
@@ -24,7 +24,7 @@ std::unique_ptr GetFirmware(const char* filename)
return ms;
}
-EXPORT void SetFirmwareCallbacks(int32 (*sizecallback)(const char *filename), void (*datacallback)(const char* filename, uint8* dest))
+EXPORT void SetFirmwareCallbacks(int32 (*sizecallback)(const char *filename), void (*datacallback)(const char *filename, uint8 *dest))
{
FirmwareSizeCallback = sizecallback;
FirmwareDataCallback = datacallback;
@@ -37,7 +37,7 @@ struct FrontendTOC
int32 DiskType;
struct
{
- int32 Address;
+ int32 Adr;
int32 Control;
int32 Lba;
int32 Valid;
@@ -55,7 +55,7 @@ EXPORT void SetCDCallbacks(void (*toccallback)(int disk, FrontendTOC *dest), voi
class MyCDIF : public CDIF
{
- private:
+ private:
int disk;
public:
@@ -68,10 +68,10 @@ class MyCDIF : public CDIF
disc_toc.disc_type = t.DiskType;
for (int i = 0; i < 101; i++)
{
- disc_toc.tracks[i].adr = t.Tracks[i].Address;
+ disc_toc.tracks[i].adr = t.Tracks[i].Adr;
disc_toc.tracks[i].control = t.Tracks[i].Control;
disc_toc.tracks[i].lba = t.Tracks[i].Lba;
- disc_toc.tracks[i].valid = t.Tracks[i].Valid;
+ disc_toc.tracks[i].valid = t.Tracks[i].Valid;
}
}
@@ -91,7 +91,7 @@ class MyCDIF : public CDIF
};
static std::vector CDInterfaces;
-static uint32* FrameBuffer;
+static uint32 *FrameBuffer;
static uint8 IsResetPushed; // 1 or 0
namespace MDFN_IEN_SS
@@ -100,7 +100,7 @@ extern bool LoadCD(std::vector *CDInterfaces);
}
EXPORT bool Init(int numDisks)
{
- FrameBuffer = (uint32*)alloc_invisible(1024 * 1024);
+ FrameBuffer = (uint32 *)alloc_invisible(1024 * 1024);
for (int i = 0; i < numDisks; i++)
CDInterfaces.push_back(new MyCDIF(i));
auto ret = LoadCD(&CDInterfaces);
@@ -140,9 +140,11 @@ extern void Emulate(EmulateSpecStruct *espec_arg);
struct FrameAdvanceInfo
{
- int16* SoundBuf;
+ int16 *SoundBuf;
- uint32* Pixels;
+ uint32 *Pixels;
+
+ uint8* Controllers;
int64 MasterCycles;
@@ -164,7 +166,9 @@ struct FrameAdvanceInfo
// bool InterlaceField;
};
-EXPORT void FrameAdvance(FrameAdvanceInfo& f)
+static uint8 ControllerInput[12 * 32];
+
+EXPORT void FrameAdvance(FrameAdvanceInfo &f)
{
EmulateSpecStruct e;
int32 LineWidths[1024];
@@ -173,6 +177,8 @@ EXPORT void FrameAdvance(FrameAdvanceInfo& f)
e.LineWidths = LineWidths;
e.SoundBuf = f.SoundBuf;
e.SoundBufMaxSize = f.SoundBufMaxSize;
+ memcpy(ControllerInput, f.Controllers, sizeof(ControllerInput));
+
Emulate(&e);
f.SoundBufSize = e.SoundBufSize;
f.MasterCycles = e.MasterCycles;
@@ -181,8 +187,8 @@ EXPORT void FrameAdvance(FrameAdvanceInfo& f)
for (int i = 0; i < e.h; i++)
w = std::max(w, LineWidths[i]);
- const uint32* src = FrameBuffer;
- uint32* dst = f.Pixels;
+ const uint32 *src = FrameBuffer;
+ uint32 *dst = f.Pixels;
const int srcp = 1024;
const int dstp = w;
src += e.y * srcp + e.x;
@@ -195,6 +201,26 @@ EXPORT void FrameAdvance(FrameAdvanceInfo& f)
f.Height = e.h;
}
+static const char *DeviceNames[] =
+{
+ "none",
+ "gamepad",
+ "3dpad",
+ "mouse",
+ "wheel",
+ "mission",
+ "dmission",
+ "keyboard"
+};
+
+EXPORT void SetupInput(const int* portdevices, const int* multitaps)
+{
+ for (int i = 0; i < 2; i++)
+ SMPC_SetMultitap(i, multitaps[i]);
+ for (int i = 0; i < 12; i++)
+ SMPC_SetInput(i, DeviceNames[portdevices[i]], ControllerInput + i * 32);
+}
+
/*void VDP2REND_SetGetVideoParams(MDFNGI* gi, const bool caspect, const int sls, const int sle, const bool show_h_overscan, const bool dohblend)
{
CorrectAspect = caspect;
@@ -241,7 +267,6 @@ void SetGetVideoParams(MDFNGI* gi, const bool caspect, const int sls, const int
VDP2REND_SetGetVideoParams(gi, caspect, sls, sle, show_h_overscan, dohblend);
}*/
-
// if (BackupRAM_Dirty)SaveBackupRAM();
// if (CART_GetClearNVDirty())SaveCartNV();