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();