saturnus: use waterboxcore
This commit is contained in:
parent
c04beea4d0
commit
5a8fad73b9
|
@ -1,104 +1,76 @@
|
|||
using BizHawk.Common.BizInvoke;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
|
||||
{
|
||||
public abstract class LibSaturnus
|
||||
{
|
||||
// some of the internal code uses wizardry by which certain pointers in ss.wbx[.text]
|
||||
// must be greater than or equal to this address, but less than 4GB bigger than it
|
||||
public const ulong StartAddress = 0x36d00000000;
|
||||
|
||||
const CallingConvention CC = CallingConvention.Cdecl;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class TOC
|
||||
{
|
||||
public int FirstTrack;
|
||||
public int LastTrack;
|
||||
public int DiskType;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Track
|
||||
{
|
||||
public int Adr;
|
||||
public int Control;
|
||||
public int Lba;
|
||||
public int Valid;
|
||||
}
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 101)]
|
||||
public Track[] Tracks;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public class FrameAdvanceInfo
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public IntPtr SoundBuf;
|
||||
[FieldOffset(8)]
|
||||
public IntPtr Pixels;
|
||||
[FieldOffset(16)]
|
||||
public IntPtr Controllers;
|
||||
[FieldOffset(24)]
|
||||
public long MasterCycles;
|
||||
[FieldOffset(32)]
|
||||
public int SoundBufMaxSize;
|
||||
[FieldOffset(36)]
|
||||
public int SoundBufSize;
|
||||
[FieldOffset(40)]
|
||||
public int Width;
|
||||
[FieldOffset(44)]
|
||||
public int Height;
|
||||
[FieldOffset(48)]
|
||||
public short ResetPushed;
|
||||
[FieldOffset(50)]
|
||||
public short InputLagged;
|
||||
};
|
||||
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate int FirmwareSizeCallback(string filename);
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate void FirmwareDataCallback(string filename, IntPtr dest);
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate void CDTOCCallback(int disk, [In, Out]TOC toc);
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate void CDSectorCallback(int disk, int lba, IntPtr dest);
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate void InputCallback();
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate void AddMemoryDomainCallback(string name, IntPtr ptr, int size, bool writable);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void SetFirmwareCallbacks(FirmwareSizeCallback sizecallback, FirmwareDataCallback datacallback);
|
||||
[BizImport(CC)]
|
||||
public abstract void SetCDCallbacks(CDTOCCallback toccallback, CDSectorCallback sectorcallback);
|
||||
[BizImport(CC)]
|
||||
public abstract bool Init(
|
||||
int numDisks,
|
||||
Saturnus.SyncSettings.CartType cartType,
|
||||
Saturnus.SyncSettings.RegionType regionDefault,
|
||||
bool regionAutodetect);
|
||||
[BizImport(CC)]
|
||||
public abstract void HardReset();
|
||||
[BizImport(CC)]
|
||||
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);
|
||||
[BizImport(CC)]
|
||||
public abstract void SetInputCallback(InputCallback callback);
|
||||
[BizImport(CC)]
|
||||
public abstract void SetAddMemoryDomainCallback(AddMemoryDomainCallback callback);
|
||||
[BizImport(CC)]
|
||||
public abstract void SetRtc(long ticks, Saturnus.SyncSettings.LanguageType language);
|
||||
[BizImport(CC)]
|
||||
public abstract void SetVideoParameters(bool correctAspect, bool hBlend, bool hOverscan, int sls, int sle);
|
||||
}
|
||||
}
|
||||
using BizHawk.Common.BizInvoke;
|
||||
using BizHawk.Emulation.Cores.Waterbox;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
|
||||
{
|
||||
public abstract class LibSaturnus : LibWaterboxCore
|
||||
{
|
||||
// some of the internal code uses wizardry by which certain pointers in ss.wbx[.text]
|
||||
// must be greater than or equal to this address, but less than 4GB bigger than it
|
||||
public const ulong StartAddress = 0x36d00000000;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class TOC
|
||||
{
|
||||
public int FirstTrack;
|
||||
public int LastTrack;
|
||||
public int DiskType;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Track
|
||||
{
|
||||
public int Adr;
|
||||
public int Control;
|
||||
public int Lba;
|
||||
public int Valid;
|
||||
}
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 101)]
|
||||
public Track[] Tracks;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public new class FrameInfo : LibWaterboxCore.FrameInfo
|
||||
{
|
||||
public int ResetPushed;
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate int FirmwareSizeCallback(string filename);
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate void FirmwareDataCallback(string filename, IntPtr dest);
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate void CDTOCCallback(int disk, [In, Out]TOC toc);
|
||||
[UnmanagedFunctionPointer(CC)]
|
||||
public delegate void CDSectorCallback(int disk, int lba, IntPtr dest);
|
||||
|
||||
[BizImport(CC)]
|
||||
public abstract void SetFirmwareCallbacks(FirmwareSizeCallback sizecallback, FirmwareDataCallback datacallback);
|
||||
[BizImport(CC)]
|
||||
public abstract void SetCDCallbacks(CDTOCCallback toccallback, CDSectorCallback sectorcallback);
|
||||
[BizImport(CC)]
|
||||
public abstract bool Init(
|
||||
int numDisks,
|
||||
Saturnus.SyncSettings.CartType cartType,
|
||||
Saturnus.SyncSettings.RegionType regionDefault,
|
||||
bool regionAutodetect);
|
||||
[BizImport(CC)]
|
||||
public abstract void HardReset();
|
||||
[BizImport(CC)]
|
||||
public abstract void SetDisk(int disk, bool open);
|
||||
[BizImport(CC)]
|
||||
public abstract void SetControllerData(byte[] controllerData);
|
||||
[BizImport(CC)]
|
||||
public abstract void SetupInput(int[] portdevices, int[] multitaps);
|
||||
[BizImport(CC)]
|
||||
public abstract void SetRtc(long ticks, Saturnus.SyncSettings.LanguageType language);
|
||||
[BizImport(CC)]
|
||||
public abstract void SetVideoParameters(bool correctAspect, bool hBlend, bool hOverscan, int sls, int sle);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
|
|||
{
|
||||
[CoreAttributes("Saturnus", "Ryphecha", true, false, "0.9.44.1",
|
||||
"https://mednafen.github.io/releases/", false)]
|
||||
public class Saturnus : IEmulator, IVideoProvider, ISoundProvider,
|
||||
IInputPollable, IDriveLight, IStatable, IRegionable, ISaveRam,
|
||||
public class Saturnus : WaterboxCore,
|
||||
IDriveLight, IRegionable,
|
||||
ISettable<Saturnus.Settings, Saturnus.SyncSettings>
|
||||
{
|
||||
private static readonly DiscSectorReaderPolicy _diskPolicy = new DiscSectorReaderPolicy
|
||||
|
@ -28,7 +28,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
|
|||
DeinterleavedSubcode = false
|
||||
};
|
||||
|
||||
private PeRunner _exe;
|
||||
private LibSaturnus _core;
|
||||
private Disc[] _disks;
|
||||
private DiscSectorReader[] _diskReaders;
|
||||
|
@ -64,9 +63,16 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
|
|||
|
||||
public Saturnus(CoreComm comm, IEnumerable<Disc> disks, bool deterministic, Settings settings,
|
||||
SyncSettings syncSettings)
|
||||
:base(comm, new Configuration
|
||||
{
|
||||
MaxSamples = 8192,
|
||||
DefaultWidth = 320,
|
||||
DefaultHeight = 240,
|
||||
MaxWidth = 1024,
|
||||
MaxHeight = 1024,
|
||||
SystemId = "SAT"
|
||||
})
|
||||
{
|
||||
ServiceProvider = new BasicServiceProvider(this);
|
||||
CoreComm = comm;
|
||||
settings = settings ?? new Settings();
|
||||
syncSettings = syncSettings ?? new SyncSettings();
|
||||
|
||||
|
@ -76,22 +82,20 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
|
|||
throw new InvalidOperationException("Some disks are not valid");
|
||||
InitCallbacks();
|
||||
|
||||
_exe = new PeRunner(new PeRunnerOptions
|
||||
_core = PreInit<LibSaturnus>(new PeRunnerOptions
|
||||
{
|
||||
Path = comm.CoreFileProvider.DllPath(),
|
||||
Filename = "ss.wbx",
|
||||
SbrkHeapSizeKB = 128,
|
||||
SealedHeapSizeKB = 4096, // 512KB of bios, 2MB of kof95/ultraman carts
|
||||
InvisibleHeapSizeKB = 8 * 1024, // 4MB of framebuffer
|
||||
MmapHeapSizeKB = 0, // not used?
|
||||
PlainHeapSizeKB = 24 * 1024, // up to 16MB of cart ram
|
||||
SealedHeapSizeKB = 4096, // 512KB of bios, 2MB of kof95/ultraman carts
|
||||
InvisibleHeapSizeKB = 8 * 1024, // 4MB of framebuffer
|
||||
MmapHeapSizeKB = 0, // not used?
|
||||
PlainHeapSizeKB = 24 * 1024, // up to 16MB of cart ram
|
||||
StartAddress = LibSaturnus.StartAddress
|
||||
});
|
||||
_core = BizInvoker.GetInvoker<LibSaturnus>(_exe, _exe);
|
||||
|
||||
SetFirmwareCallbacks();
|
||||
SetCdCallbacks();
|
||||
_core.SetAddMemoryDomainCallback(_addMemoryDomainCallback);
|
||||
|
||||
if (!_core.Init(_disks.Length, syncSettings.ExpansionCart, syncSettings.Region, syncSettings.RegionAutodetect))
|
||||
throw new InvalidOperationException("Core rejected the disks!");
|
||||
ClearAllCallbacks();
|
||||
|
@ -125,21 +129,16 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
|
|||
_core.SetRtc((long)syncSettings.InitialTime.Subtract(new DateTime(1970, 1, 1)).TotalSeconds,
|
||||
syncSettings.Language);
|
||||
|
||||
_exe.Seal();
|
||||
PostInit();
|
||||
SetCdCallbacks();
|
||||
_core.SetDisk(0, false);
|
||||
(ServiceProvider as BasicServiceProvider).Register<IMemoryDomains>(
|
||||
new MemoryDomainList(_memoryDomains.Values.Cast<MemoryDomain>().ToList())
|
||||
{
|
||||
MainMemory = _memoryDomains["Work Ram Low"]
|
||||
});
|
||||
PutSettings(settings);
|
||||
_syncSettings = syncSettings;
|
||||
DeterministicEmulation = deterministic || !_syncSettings.UseRealTime;
|
||||
}
|
||||
|
||||
public unsafe void FrameAdvance(IController controller, bool render, bool rendersound = true)
|
||||
{
|
||||
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
|
||||
{
|
||||
var prevDiskSignal = controller.IsPressed("Previous Disk");
|
||||
var nextDiskSignal = controller.IsPressed("Next Disk");
|
||||
var newDisk = _activeDisk;
|
||||
|
@ -157,73 +156,25 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
|
|||
{
|
||||
_core.SetDisk(newDisk == -1 ? 0 : newDisk, newDisk == -1);
|
||||
_activeDisk = newDisk;
|
||||
}
|
||||
|
||||
// if not reset, the core will maintain its own deterministic increasing time each frame
|
||||
}
|
||||
|
||||
// if not reset, the core will maintain its own deterministic increasing time each frame
|
||||
if (!DeterministicEmulation)
|
||||
{
|
||||
_core.SetRtc((long)DateTime.Now.Subtract(new DateTime(1970, 1, 1)).TotalSeconds,
|
||||
_syncSettings.Language);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DriveLightOn = false;
|
||||
if (controller.IsPressed("Power"))
|
||||
_core.HardReset();
|
||||
SetInputCallback();
|
||||
|
||||
fixed (short* _sp = _soundBuffer)
|
||||
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,
|
||||
Controllers = (IntPtr)_cp,
|
||||
ResetPushed = (short)(controller.IsPressed("Reset") ? 1 : 0)
|
||||
};
|
||||
|
||||
_core.FrameAdvance(info);
|
||||
Frame++;
|
||||
IsLagFrame = info.InputLagged != 0;
|
||||
if (IsLagFrame)
|
||||
LagCount++;
|
||||
_numSamples = info.SoundBufSize;
|
||||
BufferWidth = info.Width;
|
||||
BufferHeight = info.Height;
|
||||
}
|
||||
}
|
||||
|
||||
private bool _disposed = false;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_exe.Dispose();
|
||||
_exe = null;
|
||||
_core = null;
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public int Frame { get; private set; }
|
||||
public int LagCount { get; set; }
|
||||
public bool IsLagFrame { get; set; }
|
||||
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
Frame = 0;
|
||||
_core.HardReset();
|
||||
|
||||
_core.SetControllerData(_controllerDeck.Poll(controller));
|
||||
|
||||
return new LibSaturnus.FrameInfo { ResetPushed = controller.IsPressed("Reset") ? 1 : 0 };
|
||||
}
|
||||
|
||||
public DisplayType Region => _isPal ? DisplayType.PAL : DisplayType.NTSC;
|
||||
public IEmulatorServiceProvider ServiceProvider { get; private set; }
|
||||
public string SystemId { get { return "SAT"; } }
|
||||
public bool DeterministicEmulation { get; private set; }
|
||||
public CoreComm CoreComm { get; }
|
||||
public ControllerDefinition ControllerDefinition { get; }
|
||||
|
||||
#region ISettable
|
||||
|
||||
|
@ -465,76 +416,26 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
|
|||
var ret = SyncSettings.NeedsReboot(_syncSettings, s);
|
||||
_syncSettings = s;
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IMemoryDomains
|
||||
|
||||
private readonly Dictionary<string, MemoryDomainIntPtrMonitor> _memoryDomains = new Dictionary<string, MemoryDomainIntPtrMonitor>();
|
||||
|
||||
private void AddMemoryDomain(string name, IntPtr ptr, int size, bool writable)
|
||||
{
|
||||
_memoryDomains.Add(name, new MemoryDomainIntPtrMonitor(name, MemoryDomain.Endian.Big, ptr, size, writable, 2, _exe));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region IStatable
|
||||
|
||||
public bool BinarySaveStatesPreferred => true;
|
||||
|
||||
public void SaveStateText(TextWriter writer)
|
||||
{
|
||||
var temp = SaveStateBinary();
|
||||
temp.SaveAsHexFast(writer);
|
||||
// write extra copy of stuff we don't use
|
||||
writer.WriteLine("Frame {0}", Frame);
|
||||
}
|
||||
|
||||
public void LoadStateText(TextReader reader)
|
||||
{
|
||||
string hex = reader.ReadLine();
|
||||
byte[] state = new byte[hex.Length / 2];
|
||||
state.ReadFromHexFast(hex);
|
||||
LoadStateBinary(new BinaryReader(new MemoryStream(state)));
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader reader)
|
||||
{
|
||||
_exe.LoadStateBinary(reader);
|
||||
// other variables
|
||||
Frame = reader.ReadInt32();
|
||||
LagCount = reader.ReadInt32();
|
||||
IsLagFrame = reader.ReadBoolean();
|
||||
_activeDisk = reader.ReadInt32();
|
||||
_prevDiskSignal = reader.ReadBoolean();
|
||||
_nextDiskSignal = reader.ReadBoolean();
|
||||
// any managed pointers that we sent to the core need to be resent now!
|
||||
SetCdCallbacks();
|
||||
_core.SetInputCallback(null);
|
||||
}
|
||||
|
||||
public void SaveStateBinary(BinaryWriter writer)
|
||||
{
|
||||
_exe.SaveStateBinary(writer);
|
||||
// other variables
|
||||
writer.Write(Frame);
|
||||
writer.Write(LagCount);
|
||||
writer.Write(IsLagFrame);
|
||||
|
||||
protected override void SaveStateBinaryInternal(BinaryWriter writer)
|
||||
{
|
||||
writer.Write(_activeDisk);
|
||||
writer.Write(_prevDiskSignal);
|
||||
writer.Write(_nextDiskSignal);
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
var bw = new BinaryWriter(ms);
|
||||
SaveStateBinary(bw);
|
||||
bw.Flush();
|
||||
ms.Close();
|
||||
return ms.ToArray();
|
||||
writer.Write(_nextDiskSignal);
|
||||
}
|
||||
|
||||
protected override void LoadStateBinaryInternal(BinaryReader reader)
|
||||
{
|
||||
_activeDisk = reader.ReadInt32();
|
||||
_prevDiskSignal = reader.ReadBoolean();
|
||||
_nextDiskSignal = reader.ReadBoolean();
|
||||
// any managed pointers that we sent to the core need to be resent now!
|
||||
SetCdCallbacks();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -545,8 +446,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
|
|||
private LibSaturnus.FirmwareDataCallback _firmwareDataCallback;
|
||||
private LibSaturnus.CDTOCCallback _cdTocCallback;
|
||||
private LibSaturnus.CDSectorCallback _cdSectorCallback;
|
||||
private LibSaturnus.InputCallback _inputCallback;
|
||||
private LibSaturnus.AddMemoryDomainCallback _addMemoryDomainCallback;
|
||||
|
||||
private void InitCallbacks()
|
||||
{
|
||||
|
@ -554,8 +453,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
|
|||
_firmwareDataCallback = FirmwareData;
|
||||
_cdTocCallback = CDTOCCallback;
|
||||
_cdSectorCallback = CDSectorCallback;
|
||||
_inputCallback = InputCallbacks.Call;
|
||||
_addMemoryDomainCallback = AddMemoryDomain;
|
||||
}
|
||||
|
||||
private void SetFirmwareCallbacks()
|
||||
|
@ -566,16 +463,11 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
|
|||
{
|
||||
_core.SetCDCallbacks(_cdTocCallback, _cdSectorCallback);
|
||||
}
|
||||
private void SetInputCallback()
|
||||
{
|
||||
_core.SetInputCallback(InputCallbacks.Count > 0 ? _inputCallback : null);
|
||||
}
|
||||
private void ClearAllCallbacks()
|
||||
{
|
||||
_core.SetFirmwareCallbacks(null, null);
|
||||
_core.SetCDCallbacks(null, null);
|
||||
_core.SetInputCallback(null);
|
||||
_core.SetAddMemoryDomainCallback(null);
|
||||
}
|
||||
|
||||
private string TranslateFirmwareName(string filename)
|
||||
|
@ -641,111 +533,11 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn
|
|||
|
||||
#endregion
|
||||
|
||||
#region IVideoProvider
|
||||
|
||||
private int[] _videoBuffer = new int[1024 * 1024];
|
||||
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
return _videoBuffer;
|
||||
}
|
||||
|
||||
private const int PalFpsNum = 1734687500;
|
||||
private const int PalFpsDen = 61 * 455 * 1251;
|
||||
private const int NtscFpsNum = 1746818182; // 1746818181.8
|
||||
private const int NtscFpsDen = 61 * 455 * 1051;
|
||||
|
||||
public int VirtualWidth => BufferWidth; // TODO
|
||||
public int VirtualHeight => BufferHeight; // TODO
|
||||
public int BufferWidth { get; private set; } = 320;
|
||||
public int BufferHeight { get; private set; } = 240;
|
||||
public int VsyncNumerator => _isPal ? PalFpsNum : NtscFpsNum;
|
||||
public int VsyncDenominator => _isPal ? PalFpsDen : NtscFpsDen;
|
||||
public int BackgroundColor => unchecked((int)0xff000000);
|
||||
|
||||
#endregion
|
||||
|
||||
#region ISoundProvider
|
||||
|
||||
private short[] _soundBuffer = new short[16384];
|
||||
private int _numSamples;
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode == SyncSoundMode.Async)
|
||||
{
|
||||
throw new NotSupportedException("Async mode is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
samples = _soundBuffer;
|
||||
nsamp = _numSamples;
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new InvalidOperationException("Async mode is not supported.");
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
}
|
||||
|
||||
public bool CanProvideAsync => false;
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ISaveRam
|
||||
|
||||
private static readonly string[] SaveRamDomains = new[] { "Backup Ram", "Backup Cart" };
|
||||
|
||||
private int SaveRamSize()
|
||||
{
|
||||
return ActiveSaveRamDomains()
|
||||
.Select(m => (int)m.Size)
|
||||
.Sum();
|
||||
}
|
||||
private IEnumerable<MemoryDomainIntPtrMonitor> ActiveSaveRamDomains()
|
||||
{
|
||||
return SaveRamDomains.Where(_memoryDomains.ContainsKey)
|
||||
.Select(s => _memoryDomains[s]);
|
||||
}
|
||||
|
||||
public byte[] CloneSaveRam()
|
||||
{
|
||||
var ret = new byte[SaveRamSize()];
|
||||
var offs = 0;
|
||||
using (_exe.EnterExit())
|
||||
{
|
||||
foreach (var m in ActiveSaveRamDomains())
|
||||
{
|
||||
Marshal.Copy(m.Data, ret, offs, (int)m.Size);
|
||||
offs += (int)m.Size;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void StoreSaveRam(byte[] data)
|
||||
{
|
||||
if (data.Length != SaveRamSize())
|
||||
throw new InvalidOperationException("Saveram was the wrong size!");
|
||||
var offs = 0;
|
||||
using (_exe.EnterExit())
|
||||
{
|
||||
foreach (var m in ActiveSaveRamDomains())
|
||||
{
|
||||
Marshal.Copy(data, offs, m.Data, (int)m.Size);
|
||||
offs += (int)m.Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool SaveRamModified => true;
|
||||
|
||||
#endregion
|
||||
public override int VsyncNumerator => _isPal ? PalFpsNum : NtscFpsNum;
|
||||
public override int VsyncDenominator => _isPal ? PalFpsDen : NtscFpsDen;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,11 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
/// <summary>
|
||||
/// native wordsize. only a hint
|
||||
/// </summary>
|
||||
WordSize8 = 256
|
||||
WordSize8 = 256,
|
||||
/// <summary>
|
||||
/// for a yuge endian domain, if true, bytes are stored word-swapped from their native ordering
|
||||
/// </summary>
|
||||
Swapped = 512,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
|
@ -171,7 +175,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
else
|
||||
throw new InvalidOperationException("Unknown word size for memory domain");
|
||||
_monitor = monitor;
|
||||
if (EndianType == Endian.Big)
|
||||
if ((m.Flags & MemoryDomainFlags.Swapped) != 0 && EndianType == Endian.Big)
|
||||
{
|
||||
_addressMangler = WordSize - 1;
|
||||
}
|
||||
|
|
|
@ -210,7 +210,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
|||
public string SystemId { get; }
|
||||
public bool DeterministicEmulation { get; protected set; } = true;
|
||||
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
|
||||
public abstract ControllerDefinition ControllerDefinition { get; }
|
||||
public virtual ControllerDefinition ControllerDefinition { get; protected set; } = NullController.Instance.Definition;
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
Binary file not shown.
|
@ -33,6 +33,7 @@ typedef struct
|
|||
#define MEMORYAREA_FLAGS_WORDSIZE2 64
|
||||
#define MEMORYAREA_FLAGS_WORDSIZE4 128
|
||||
#define MEMORYAREA_FLAGS_WORDSIZE8 256
|
||||
#define MEMORYAREA_FLAGS_SWAPPED 512
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -1,360 +1,348 @@
|
|||
#include "ss.h"
|
||||
#include "stream/MemoryStream.h"
|
||||
#include <memory>
|
||||
#include "cdrom/cdromif.h"
|
||||
#include "cdb.h"
|
||||
#include "smpc.h"
|
||||
#include "cart.h"
|
||||
#include <ctime>
|
||||
|
||||
#define EXPORT extern "C" ECL_EXPORT
|
||||
using namespace MDFN_IEN_SS;
|
||||
|
||||
int32 (*FirmwareSizeCallback)(const char *filename);
|
||||
void (*FirmwareDataCallback)(const char *filename, uint8 *dest);
|
||||
|
||||
EXPORT void SetFirmwareCallbacks(int32 (*sizecallback)(const char *filename), void (*datacallback)(const char *filename, uint8 *dest))
|
||||
{
|
||||
FirmwareSizeCallback = sizecallback;
|
||||
FirmwareDataCallback = datacallback;
|
||||
}
|
||||
|
||||
struct FrontendTOC
|
||||
{
|
||||
int32 FirstTrack;
|
||||
int32 LastTrack;
|
||||
int32 DiskType;
|
||||
struct
|
||||
{
|
||||
int32 Adr;
|
||||
int32 Control;
|
||||
int32 Lba;
|
||||
int32 Valid;
|
||||
} Tracks[101];
|
||||
};
|
||||
|
||||
static void (*ReadTOCCallback)(int disk, FrontendTOC *dest);
|
||||
static void (*ReadSector2448Callback)(int disk, int lba, uint8 *dest);
|
||||
|
||||
EXPORT void SetCDCallbacks(void (*toccallback)(int disk, FrontendTOC *dest), void (*sectorcallback)(int disk, int lba, uint8 *dest))
|
||||
{
|
||||
ReadTOCCallback = toccallback;
|
||||
ReadSector2448Callback = sectorcallback;
|
||||
}
|
||||
|
||||
class MyCDIF : public CDIF
|
||||
{
|
||||
private:
|
||||
int disk;
|
||||
|
||||
public:
|
||||
MyCDIF(int disk) : disk(disk)
|
||||
{
|
||||
FrontendTOC t;
|
||||
ReadTOCCallback(disk, &t);
|
||||
disc_toc.first_track = t.FirstTrack;
|
||||
disc_toc.last_track = t.LastTrack;
|
||||
disc_toc.disc_type = t.DiskType;
|
||||
for (int i = 0; i < 101; i++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void HintReadSector(int32 lba) {}
|
||||
virtual bool ReadRawSector(uint8 *buf, int32 lba)
|
||||
{
|
||||
ReadSector2448Callback(disk, lba, buf);
|
||||
return true;
|
||||
}
|
||||
virtual bool ReadRawSectorPWOnly(uint8 *pwbuf, int32 lba, bool hint_fullread)
|
||||
{
|
||||
uint8 buff[2448];
|
||||
ReadSector2448Callback(disk, lba, buff);
|
||||
memcpy(pwbuf, buff + 2352, 96);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static std::vector<CDIF *> CDInterfaces;
|
||||
static uint32 *FrameBuffer;
|
||||
static uint8 IsResetPushed; // 1 or 0
|
||||
|
||||
namespace MDFN_IEN_SS
|
||||
{
|
||||
extern bool LoadCD(std::vector<CDIF *> *CDInterfaces);
|
||||
}
|
||||
EXPORT bool Init(int numDisks, int cartType, int regionDefault, int regionAutodetect)
|
||||
{
|
||||
setting_ss_cart = cartType;
|
||||
setting_ss_region_autodetect = regionAutodetect;
|
||||
setting_ss_region_default = regionDefault;
|
||||
|
||||
FrameBuffer = (uint32 *)alloc_invisible(1024 * 1024 * sizeof(*FrameBuffer));
|
||||
for (int i = 0; i < numDisks; i++)
|
||||
CDInterfaces.push_back(new MyCDIF(i));
|
||||
auto ret = LoadCD(&CDInterfaces);
|
||||
if (ret)
|
||||
SMPC_SetInput(12, nullptr, &IsResetPushed);
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT void HardReset()
|
||||
{
|
||||
// soft reset is handled as a normal button
|
||||
SS_Reset(true);
|
||||
}
|
||||
|
||||
EXPORT void SetDisk(int disk, bool open)
|
||||
{
|
||||
CDB_SetDisc(open, disk < 0 ? nullptr : CDInterfaces[disk]);
|
||||
}
|
||||
|
||||
int setting_ss_slstartp = 0;
|
||||
int setting_ss_slendp = 255;
|
||||
int setting_ss_slstart = 0;
|
||||
int setting_ss_slend = 239;
|
||||
int setting_ss_region_default = SMPC_AREA_JP;
|
||||
int setting_ss_cart = CART_NONE;
|
||||
bool setting_ss_correct_aspect = true;
|
||||
bool setting_ss_h_blend = false;
|
||||
bool setting_ss_h_overscan = true;
|
||||
bool setting_ss_region_autodetect = true;
|
||||
bool setting_ss_input_sport1_multitap = false;
|
||||
bool setting_ss_input_sport0_multitap = false;
|
||||
|
||||
namespace MDFN_IEN_SS
|
||||
{
|
||||
extern void Emulate(EmulateSpecStruct *espec_arg);
|
||||
}
|
||||
|
||||
struct FrameAdvanceInfo
|
||||
{
|
||||
int16 *SoundBuf;
|
||||
|
||||
uint32 *Pixels;
|
||||
|
||||
uint8 *Controllers;
|
||||
|
||||
int64 MasterCycles;
|
||||
|
||||
int32 SoundBufMaxSize;
|
||||
int32 SoundBufSize;
|
||||
|
||||
int32 Width;
|
||||
int32 Height;
|
||||
|
||||
int16 ResetPushed;
|
||||
int16 InputLagged;
|
||||
|
||||
// Set by the system emulation code every frame, to denote the horizontal and vertical offsets of the image, and the size
|
||||
// of the image. If the emulated system sets the elements of LineWidths, then the width(w) of this structure
|
||||
// is ignored while drawing the image.
|
||||
// int32 x, y, h;
|
||||
|
||||
// Set(optionally) by emulation code. If InterlaceOn is true, then assume field height is 1/2 DisplayRect.h, and
|
||||
// only every other line in surface (with the start line defined by InterlacedField) has valid data
|
||||
// (it's up to internal Mednafen code to deinterlace it).
|
||||
// bool InterlaceOn;
|
||||
// bool InterlaceField;
|
||||
};
|
||||
|
||||
static uint8 ControllerInput[12 * 32];
|
||||
bool InputLagged;
|
||||
|
||||
EXPORT void FrameAdvance(FrameAdvanceInfo &f)
|
||||
{
|
||||
EmulateSpecStruct e;
|
||||
int32 LineWidths[1024];
|
||||
memset(LineWidths, 0, sizeof(LineWidths));
|
||||
e.pixels = FrameBuffer;
|
||||
e.pitch32 = 1024;
|
||||
e.LineWidths = LineWidths;
|
||||
e.SoundBuf = f.SoundBuf;
|
||||
e.SoundBufMaxSize = f.SoundBufMaxSize;
|
||||
memcpy(ControllerInput, f.Controllers, sizeof(ControllerInput));
|
||||
IsResetPushed = f.ResetPushed;
|
||||
InputLagged = true;
|
||||
Emulate(&e);
|
||||
f.SoundBufSize = e.SoundBufSize;
|
||||
f.MasterCycles = e.MasterCycles;
|
||||
f.InputLagged = InputLagged;
|
||||
|
||||
int w = 256;
|
||||
for (int i = 0; i < e.h; i++)
|
||||
w = std::max(w, LineWidths[i]);
|
||||
|
||||
const uint32 *src = FrameBuffer;
|
||||
uint32 *dst = f.Pixels;
|
||||
const int srcp = 1024;
|
||||
const int dstp = w;
|
||||
src += e.y * srcp + e.x;
|
||||
|
||||
for (int j = 0; j < e.h; j++, src += srcp, dst += dstp)
|
||||
{
|
||||
memcpy(dst, src, LineWidths[j + e.y] * sizeof(*dst));
|
||||
}
|
||||
f.Width = w;
|
||||
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 (*InputCallback)();
|
||||
EXPORT void SetInputCallback(void (*callback)())
|
||||
{
|
||||
InputCallback = callback;
|
||||
}
|
||||
|
||||
void (*AddMemoryDomain)(const char *name, const void *ptr, int size, bool writable);
|
||||
|
||||
EXPORT void SetAddMemoryDomainCallback(void (*callback)(const char *name, const void *ptr, int size, bool writable))
|
||||
{
|
||||
AddMemoryDomain = callback;
|
||||
}
|
||||
|
||||
EXPORT void SetRtc(int64 ticks, int language)
|
||||
{
|
||||
time_t time = ticks;
|
||||
const struct tm *tm = gmtime(&time);
|
||||
SMPC_SetRTC(tm, language);
|
||||
}
|
||||
|
||||
namespace MDFN_IEN_SS
|
||||
{
|
||||
extern bool CorrectAspect;
|
||||
extern bool ShowHOverscan;
|
||||
extern bool DoHBlend;
|
||||
extern int LineVisFirst;
|
||||
extern int LineVisLast;
|
||||
}
|
||||
EXPORT void SetVideoParameters(bool correctAspect, bool hBlend, bool hOverscan, int sls, int sle)
|
||||
{
|
||||
CorrectAspect = correctAspect;
|
||||
ShowHOverscan = hOverscan;
|
||||
DoHBlend = hBlend;
|
||||
LineVisFirst = sls;
|
||||
LineVisLast = sle;
|
||||
}
|
||||
|
||||
// if (BackupRAM_Dirty)SaveBackupRAM();
|
||||
// if (CART_GetClearNVDirty())SaveCartNV();
|
||||
|
||||
/*static MDFN_COLD void CloseGame(void)
|
||||
{
|
||||
try { SaveBackupRAM(); } catch(std::exception& e) { MDFN_PrintError("%s", e.what()); }
|
||||
try { SaveCartNV(); } catch(std::exception& e) { MDFN_PrintError("%s", e.what()); }
|
||||
try { SaveRTC(); } catch(std::exception& e) { MDFN_PrintError("%s", e.what()); }
|
||||
|
||||
Cleanup();
|
||||
}*/
|
||||
|
||||
/*static MDFN_COLD void SaveBackupRAM(void)
|
||||
{
|
||||
FileStream brs(MDFN_MakeFName(MDFNMKF_SAV, 0, "bkr"), FileStream::MODE_WRITE_INPLACE);
|
||||
|
||||
brs.write(BackupRAM, sizeof(BackupRAM));
|
||||
|
||||
brs.close();
|
||||
}
|
||||
|
||||
static MDFN_COLD void LoadBackupRAM(void)
|
||||
{
|
||||
FileStream brs(MDFN_MakeFName(MDFNMKF_SAV, 0, "bkr"), FileStream::MODE_READ);
|
||||
|
||||
brs.read(BackupRAM, sizeof(BackupRAM));
|
||||
}
|
||||
|
||||
static MDFN_COLD void BackupBackupRAM(void)
|
||||
{
|
||||
MDFN_BackupSavFile(10, "bkr");
|
||||
}
|
||||
|
||||
static MDFN_COLD void BackupCartNV(void)
|
||||
{
|
||||
const char* ext = nullptr;
|
||||
void* nv_ptr = nullptr;
|
||||
uint64 nv_size = 0;
|
||||
|
||||
CART_GetNVInfo(&ext, &nv_ptr, &nv_size);
|
||||
|
||||
if(ext)
|
||||
MDFN_BackupSavFile(10, ext);
|
||||
}*/
|
||||
|
||||
/*static MDFN_COLD void LoadCartNV(void)
|
||||
{
|
||||
const char* ext = nullptr;
|
||||
void* nv_ptr = nullptr;
|
||||
uint64 nv_size = 0;
|
||||
|
||||
CART_GetNVInfo(&ext, &nv_ptr, &nv_size);
|
||||
|
||||
if(ext)
|
||||
{
|
||||
//FileStream nvs(MDFN_MakeFName(MDFNMKF_SAV, 0, ext), FileStream::MODE_READ);
|
||||
GZFileStream nvs(MDFN_MakeFName(MDFNMKF_SAV, 0, ext), GZFileStream::MODE::READ);
|
||||
|
||||
nvs.read(nv_ptr, nv_size);
|
||||
}
|
||||
}
|
||||
|
||||
static MDFN_COLD void SaveCartNV(void)
|
||||
{
|
||||
const char* ext = nullptr;
|
||||
void* nv_ptr = nullptr;
|
||||
uint64 nv_size = 0;
|
||||
|
||||
CART_GetNVInfo(&ext, &nv_ptr, &nv_size);
|
||||
|
||||
if(ext)
|
||||
{
|
||||
//FileStream nvs(MDFN_MakeFName(MDFNMKF_SAV, 0, ext), FileStream::MODE_WRITE_INPLACE);
|
||||
GZFileStream nvs(MDFN_MakeFName(MDFNMKF_SAV, 0, ext), GZFileStream::MODE::WRITE);
|
||||
|
||||
nvs.write(nv_ptr, nv_size);
|
||||
|
||||
nvs.close();
|
||||
}
|
||||
}*/
|
||||
|
||||
/*static MDFN_COLD void SaveRTC(void)
|
||||
{
|
||||
FileStream sds(MDFN_MakeFName(MDFNMKF_SAV, 0, "smpc"), FileStream::MODE_WRITE_INPLACE);
|
||||
|
||||
SMPC_SaveNV(&sds);
|
||||
|
||||
sds.close();
|
||||
}
|
||||
|
||||
static MDFN_COLD void LoadRTC(void)
|
||||
{
|
||||
FileStream sds(MDFN_MakeFName(MDFNMKF_SAV, 0, "smpc"), FileStream::MODE_READ);
|
||||
|
||||
SMPC_LoadNV(&sds);
|
||||
}*/
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#include "ss.h"
|
||||
#include "stream/MemoryStream.h"
|
||||
#include <memory>
|
||||
#include "cdrom/cdromif.h"
|
||||
#include "cdb.h"
|
||||
#include "smpc.h"
|
||||
#include "cart.h"
|
||||
#include <ctime>
|
||||
|
||||
#define EXPORT extern "C" ECL_EXPORT
|
||||
using namespace MDFN_IEN_SS;
|
||||
|
||||
int32 (*FirmwareSizeCallback)(const char *filename);
|
||||
void (*FirmwareDataCallback)(const char *filename, uint8 *dest);
|
||||
|
||||
EXPORT void SetFirmwareCallbacks(int32 (*sizecallback)(const char *filename), void (*datacallback)(const char *filename, uint8 *dest))
|
||||
{
|
||||
FirmwareSizeCallback = sizecallback;
|
||||
FirmwareDataCallback = datacallback;
|
||||
}
|
||||
|
||||
struct FrontendTOC
|
||||
{
|
||||
int32 FirstTrack;
|
||||
int32 LastTrack;
|
||||
int32 DiskType;
|
||||
struct
|
||||
{
|
||||
int32 Adr;
|
||||
int32 Control;
|
||||
int32 Lba;
|
||||
int32 Valid;
|
||||
} Tracks[101];
|
||||
};
|
||||
|
||||
static void (*ReadTOCCallback)(int disk, FrontendTOC *dest);
|
||||
static void (*ReadSector2448Callback)(int disk, int lba, uint8 *dest);
|
||||
|
||||
EXPORT void SetCDCallbacks(void (*toccallback)(int disk, FrontendTOC *dest), void (*sectorcallback)(int disk, int lba, uint8 *dest))
|
||||
{
|
||||
ReadTOCCallback = toccallback;
|
||||
ReadSector2448Callback = sectorcallback;
|
||||
}
|
||||
|
||||
class MyCDIF : public CDIF
|
||||
{
|
||||
private:
|
||||
int disk;
|
||||
|
||||
public:
|
||||
MyCDIF(int disk) : disk(disk)
|
||||
{
|
||||
FrontendTOC t;
|
||||
ReadTOCCallback(disk, &t);
|
||||
disc_toc.first_track = t.FirstTrack;
|
||||
disc_toc.last_track = t.LastTrack;
|
||||
disc_toc.disc_type = t.DiskType;
|
||||
for (int i = 0; i < 101; i++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void HintReadSector(int32 lba) {}
|
||||
virtual bool ReadRawSector(uint8 *buf, int32 lba)
|
||||
{
|
||||
ReadSector2448Callback(disk, lba, buf);
|
||||
return true;
|
||||
}
|
||||
virtual bool ReadRawSectorPWOnly(uint8 *pwbuf, int32 lba, bool hint_fullread)
|
||||
{
|
||||
uint8 buff[2448];
|
||||
ReadSector2448Callback(disk, lba, buff);
|
||||
memcpy(pwbuf, buff + 2352, 96);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static std::vector<CDIF *> CDInterfaces;
|
||||
static uint32 *FrameBuffer;
|
||||
static uint8 IsResetPushed; // 1 or 0
|
||||
|
||||
namespace MDFN_IEN_SS
|
||||
{
|
||||
extern bool LoadCD(std::vector<CDIF *> *CDInterfaces);
|
||||
}
|
||||
EXPORT bool Init(int numDisks, int cartType, int regionDefault, int regionAutodetect)
|
||||
{
|
||||
setting_ss_cart = cartType;
|
||||
setting_ss_region_autodetect = regionAutodetect;
|
||||
setting_ss_region_default = regionDefault;
|
||||
|
||||
FrameBuffer = (uint32 *)alloc_invisible(1024 * 1024 * sizeof(*FrameBuffer));
|
||||
for (int i = 0; i < numDisks; i++)
|
||||
CDInterfaces.push_back(new MyCDIF(i));
|
||||
auto ret = LoadCD(&CDInterfaces);
|
||||
if (ret)
|
||||
SMPC_SetInput(12, nullptr, &IsResetPushed);
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT void HardReset()
|
||||
{
|
||||
// soft reset is handled as a normal button
|
||||
SS_Reset(true);
|
||||
}
|
||||
|
||||
EXPORT void SetDisk(int disk, bool open)
|
||||
{
|
||||
CDB_SetDisc(open, disk < 0 ? nullptr : CDInterfaces[disk]);
|
||||
}
|
||||
|
||||
int setting_ss_slstartp = 0;
|
||||
int setting_ss_slendp = 255;
|
||||
int setting_ss_slstart = 0;
|
||||
int setting_ss_slend = 239;
|
||||
int setting_ss_region_default = SMPC_AREA_JP;
|
||||
int setting_ss_cart = CART_NONE;
|
||||
bool setting_ss_correct_aspect = true;
|
||||
bool setting_ss_h_blend = false;
|
||||
bool setting_ss_h_overscan = true;
|
||||
bool setting_ss_region_autodetect = true;
|
||||
bool setting_ss_input_sport1_multitap = false;
|
||||
bool setting_ss_input_sport0_multitap = false;
|
||||
|
||||
namespace MDFN_IEN_SS
|
||||
{
|
||||
extern void Emulate(EmulateSpecStruct *espec_arg);
|
||||
}
|
||||
|
||||
static uint8 ControllerInput[12 * 32];
|
||||
bool InputLagged;
|
||||
|
||||
EXPORT void SetControllerData(const uint8_t* controllerData)
|
||||
{
|
||||
memcpy(ControllerInput, controllerData, sizeof(ControllerInput));
|
||||
}
|
||||
|
||||
struct MyFrameInfo: public FrameInfo
|
||||
{
|
||||
int32_t ResetPushed;
|
||||
};
|
||||
|
||||
EXPORT void FrameAdvance(MyFrameInfo& f)
|
||||
{
|
||||
EmulateSpecStruct e;
|
||||
int32 LineWidths[1024];
|
||||
memset(LineWidths, 0, sizeof(LineWidths));
|
||||
e.pixels = FrameBuffer;
|
||||
e.pitch32 = 1024;
|
||||
e.LineWidths = LineWidths;
|
||||
e.SoundBuf = f.SoundBuffer;
|
||||
e.SoundBufMaxSize = 8192;
|
||||
IsResetPushed = f.ResetPushed;
|
||||
InputLagged = true;
|
||||
Emulate(&e);
|
||||
f.Samples = e.SoundBufSize;
|
||||
f.Cycles = e.MasterCycles;
|
||||
f.Lagged = InputLagged;
|
||||
|
||||
int w = 256;
|
||||
for (int i = 0; i < e.h; i++)
|
||||
w = std::max(w, LineWidths[i]);
|
||||
|
||||
const uint32 *src = FrameBuffer;
|
||||
uint32 *dst = f.VideoBuffer;
|
||||
const int srcp = 1024;
|
||||
const int dstp = w;
|
||||
src += e.y * srcp + e.x;
|
||||
|
||||
for (int j = 0; j < e.h; j++, src += srcp, dst += dstp)
|
||||
{
|
||||
memcpy(dst, src, LineWidths[j + e.y] * sizeof(*dst));
|
||||
}
|
||||
f.Width = w;
|
||||
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 (*InputCallback)();
|
||||
EXPORT void SetInputCallback(void (*callback)())
|
||||
{
|
||||
InputCallback = callback;
|
||||
}
|
||||
|
||||
static std::vector<MemoryArea> MemoryAreas;
|
||||
|
||||
void AddMemoryDomain(const char *name, const void *ptr, int size, int flags)
|
||||
{
|
||||
MemoryArea m;
|
||||
m.Data = (void*)ptr;
|
||||
m.Name = name;
|
||||
m.Size = size;
|
||||
m.Flags = flags;
|
||||
MemoryAreas.push_back(m);
|
||||
}
|
||||
|
||||
EXPORT void GetMemoryAreas(MemoryArea* m)
|
||||
{
|
||||
memcpy(m, MemoryAreas.data(), MemoryAreas.size() * sizeof(MemoryArea));
|
||||
}
|
||||
|
||||
EXPORT void SetRtc(int64 ticks, int language)
|
||||
{
|
||||
time_t time = ticks;
|
||||
const struct tm *tm = gmtime(&time);
|
||||
SMPC_SetRTC(tm, language);
|
||||
}
|
||||
|
||||
namespace MDFN_IEN_SS
|
||||
{
|
||||
extern bool CorrectAspect;
|
||||
extern bool ShowHOverscan;
|
||||
extern bool DoHBlend;
|
||||
extern int LineVisFirst;
|
||||
extern int LineVisLast;
|
||||
}
|
||||
EXPORT void SetVideoParameters(bool correctAspect, bool hBlend, bool hOverscan, int sls, int sle)
|
||||
{
|
||||
CorrectAspect = correctAspect;
|
||||
ShowHOverscan = hOverscan;
|
||||
DoHBlend = hBlend;
|
||||
LineVisFirst = sls;
|
||||
LineVisLast = sle;
|
||||
}
|
||||
|
||||
// if (BackupRAM_Dirty)SaveBackupRAM();
|
||||
// if (CART_GetClearNVDirty())SaveCartNV();
|
||||
|
||||
/*static MDFN_COLD void CloseGame(void)
|
||||
{
|
||||
try { SaveBackupRAM(); } catch(std::exception& e) { MDFN_PrintError("%s", e.what()); }
|
||||
try { SaveCartNV(); } catch(std::exception& e) { MDFN_PrintError("%s", e.what()); }
|
||||
try { SaveRTC(); } catch(std::exception& e) { MDFN_PrintError("%s", e.what()); }
|
||||
|
||||
Cleanup();
|
||||
}*/
|
||||
|
||||
/*static MDFN_COLD void SaveBackupRAM(void)
|
||||
{
|
||||
FileStream brs(MDFN_MakeFName(MDFNMKF_SAV, 0, "bkr"), FileStream::MODE_WRITE_INPLACE);
|
||||
|
||||
brs.write(BackupRAM, sizeof(BackupRAM));
|
||||
|
||||
brs.close();
|
||||
}
|
||||
|
||||
static MDFN_COLD void LoadBackupRAM(void)
|
||||
{
|
||||
FileStream brs(MDFN_MakeFName(MDFNMKF_SAV, 0, "bkr"), FileStream::MODE_READ);
|
||||
|
||||
brs.read(BackupRAM, sizeof(BackupRAM));
|
||||
}
|
||||
|
||||
static MDFN_COLD void BackupBackupRAM(void)
|
||||
{
|
||||
MDFN_BackupSavFile(10, "bkr");
|
||||
}
|
||||
|
||||
static MDFN_COLD void BackupCartNV(void)
|
||||
{
|
||||
const char* ext = nullptr;
|
||||
void* nv_ptr = nullptr;
|
||||
uint64 nv_size = 0;
|
||||
|
||||
CART_GetNVInfo(&ext, &nv_ptr, &nv_size);
|
||||
|
||||
if(ext)
|
||||
MDFN_BackupSavFile(10, ext);
|
||||
}*/
|
||||
|
||||
/*static MDFN_COLD void LoadCartNV(void)
|
||||
{
|
||||
const char* ext = nullptr;
|
||||
void* nv_ptr = nullptr;
|
||||
uint64 nv_size = 0;
|
||||
|
||||
CART_GetNVInfo(&ext, &nv_ptr, &nv_size);
|
||||
|
||||
if(ext)
|
||||
{
|
||||
//FileStream nvs(MDFN_MakeFName(MDFNMKF_SAV, 0, ext), FileStream::MODE_READ);
|
||||
GZFileStream nvs(MDFN_MakeFName(MDFNMKF_SAV, 0, ext), GZFileStream::MODE::READ);
|
||||
|
||||
nvs.read(nv_ptr, nv_size);
|
||||
}
|
||||
}
|
||||
|
||||
static MDFN_COLD void SaveCartNV(void)
|
||||
{
|
||||
const char* ext = nullptr;
|
||||
void* nv_ptr = nullptr;
|
||||
uint64 nv_size = 0;
|
||||
|
||||
CART_GetNVInfo(&ext, &nv_ptr, &nv_size);
|
||||
|
||||
if(ext)
|
||||
{
|
||||
//FileStream nvs(MDFN_MakeFName(MDFNMKF_SAV, 0, ext), FileStream::MODE_WRITE_INPLACE);
|
||||
GZFileStream nvs(MDFN_MakeFName(MDFNMKF_SAV, 0, ext), GZFileStream::MODE::WRITE);
|
||||
|
||||
nvs.write(nv_ptr, nv_size);
|
||||
|
||||
nvs.close();
|
||||
}
|
||||
}*/
|
||||
|
||||
/*static MDFN_COLD void SaveRTC(void)
|
||||
{
|
||||
FileStream sds(MDFN_MakeFName(MDFNMKF_SAV, 0, "smpc"), FileStream::MODE_WRITE_INPLACE);
|
||||
|
||||
SMPC_SaveNV(&sds);
|
||||
|
||||
sds.close();
|
||||
}
|
||||
|
||||
static MDFN_COLD void LoadRTC(void)
|
||||
{
|
||||
FileStream sds(MDFN_MakeFName(MDFNMKF_SAV, 0, "smpc"), FileStream::MODE_READ);
|
||||
|
||||
SMPC_LoadNV(&sds);
|
||||
}*/
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,91 +1,91 @@
|
|||
/******************************************************************************/
|
||||
/* Mednafen Sega Saturn Emulation Module */
|
||||
/******************************************************************************/
|
||||
/* backup.cpp - Backup memory(512KiB) cart emulation
|
||||
** Copyright (C) 2016-2017 Mednafen Team
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU General Public License
|
||||
** as published by the Free Software Foundation; either version 2
|
||||
** of the License, or (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "backup.h"
|
||||
|
||||
namespace MDFN_IEN_SS
|
||||
{
|
||||
|
||||
static uint8 *ExtBackupRAM;
|
||||
static bool ExtBackupRAM_Dirty;
|
||||
|
||||
// TODO: Check mirroring.
|
||||
template <typename T, bool IsWrite>
|
||||
static MDFN_HOT void ExtBackupRAM_RW_DB(uint32 A, uint16 *DB)
|
||||
{
|
||||
uint8 *const ptr = ExtBackupRAM + ((A >> 1) & 0x7FFFF);
|
||||
|
||||
if (IsWrite)
|
||||
{
|
||||
if (A & 1)
|
||||
{
|
||||
ExtBackupRAM_Dirty = true;
|
||||
*ptr = *DB;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*DB = (*ptr << 0) | 0xFF00;
|
||||
|
||||
if ((A & ~1) == 0x04FFFFFE)
|
||||
*DB = 0x21;
|
||||
}
|
||||
}
|
||||
|
||||
static MDFN_COLD bool GetClearNVDirty(void)
|
||||
{
|
||||
bool ret = ExtBackupRAM_Dirty;
|
||||
|
||||
ExtBackupRAM_Dirty = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static MDFN_COLD void GetNVInfo(const char **ext, void **nv_ptr, uint64 *nv_size)
|
||||
{
|
||||
*ext = "bcr";
|
||||
*nv_ptr = ExtBackupRAM;
|
||||
*nv_size = 524288;
|
||||
}
|
||||
|
||||
void CART_Backup_Init(CartInfo *c)
|
||||
{
|
||||
static const uint8 init[0x10] = {0x42, 0x61, 0x63, 0x6B, 0x55, 0x70, 0x52, 0x61, 0x6D, 0x20, 0x46, 0x6F, 0x72, 0x6D, 0x61, 0x74};
|
||||
|
||||
ExtBackupRAM = (uint8 *)alloc_plain(524288);
|
||||
memset(ExtBackupRAM, 0x00, 524288);
|
||||
for (unsigned i = 0; i < 0x200; i += 0x10)
|
||||
memcpy(ExtBackupRAM + i, init, 0x10);
|
||||
|
||||
ExtBackupRAM_Dirty = false;
|
||||
|
||||
c->CS01_SetRW8W16(0x04000000, 0x04FFFFFF,
|
||||
ExtBackupRAM_RW_DB<uint16, false>,
|
||||
ExtBackupRAM_RW_DB<uint8, true>,
|
||||
ExtBackupRAM_RW_DB<uint16, true>);
|
||||
|
||||
c->GetClearNVDirty = GetClearNVDirty;
|
||||
c->GetNVInfo = GetNVInfo;
|
||||
|
||||
AddMemoryDomain("Backup Cart", ExtBackupRAM, 524288, true);
|
||||
}
|
||||
}
|
||||
/******************************************************************************/
|
||||
/* Mednafen Sega Saturn Emulation Module */
|
||||
/******************************************************************************/
|
||||
/* backup.cpp - Backup memory(512KiB) cart emulation
|
||||
** Copyright (C) 2016-2017 Mednafen Team
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU General Public License
|
||||
** as published by the Free Software Foundation; either version 2
|
||||
** of the License, or (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "backup.h"
|
||||
|
||||
namespace MDFN_IEN_SS
|
||||
{
|
||||
|
||||
static uint8 *ExtBackupRAM;
|
||||
static bool ExtBackupRAM_Dirty;
|
||||
|
||||
// TODO: Check mirroring.
|
||||
template <typename T, bool IsWrite>
|
||||
static MDFN_HOT void ExtBackupRAM_RW_DB(uint32 A, uint16 *DB)
|
||||
{
|
||||
uint8 *const ptr = ExtBackupRAM + ((A >> 1) & 0x7FFFF);
|
||||
|
||||
if (IsWrite)
|
||||
{
|
||||
if (A & 1)
|
||||
{
|
||||
ExtBackupRAM_Dirty = true;
|
||||
*ptr = *DB;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*DB = (*ptr << 0) | 0xFF00;
|
||||
|
||||
if ((A & ~1) == 0x04FFFFFE)
|
||||
*DB = 0x21;
|
||||
}
|
||||
}
|
||||
|
||||
static MDFN_COLD bool GetClearNVDirty(void)
|
||||
{
|
||||
bool ret = ExtBackupRAM_Dirty;
|
||||
|
||||
ExtBackupRAM_Dirty = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static MDFN_COLD void GetNVInfo(const char **ext, void **nv_ptr, uint64 *nv_size)
|
||||
{
|
||||
*ext = "bcr";
|
||||
*nv_ptr = ExtBackupRAM;
|
||||
*nv_size = 524288;
|
||||
}
|
||||
|
||||
void CART_Backup_Init(CartInfo *c)
|
||||
{
|
||||
static const uint8 init[0x10] = {0x42, 0x61, 0x63, 0x6B, 0x55, 0x70, 0x52, 0x61, 0x6D, 0x20, 0x46, 0x6F, 0x72, 0x6D, 0x61, 0x74};
|
||||
|
||||
ExtBackupRAM = (uint8 *)alloc_plain(524288);
|
||||
memset(ExtBackupRAM, 0x00, 524288);
|
||||
for (unsigned i = 0; i < 0x200; i += 0x10)
|
||||
memcpy(ExtBackupRAM + i, init, 0x10);
|
||||
|
||||
ExtBackupRAM_Dirty = false;
|
||||
|
||||
c->CS01_SetRW8W16(0x04000000, 0x04FFFFFF,
|
||||
ExtBackupRAM_RW_DB<uint16, false>,
|
||||
ExtBackupRAM_RW_DB<uint8, true>,
|
||||
ExtBackupRAM_RW_DB<uint16, true>);
|
||||
|
||||
c->GetClearNVDirty = GetClearNVDirty;
|
||||
c->GetNVInfo = GetNVInfo;
|
||||
|
||||
AddMemoryDomain("Backup Cart", ExtBackupRAM, 524288, MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_SAVERAMMABLE | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_WORDSIZE2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,60 +1,60 @@
|
|||
/******************************************************************************/
|
||||
/* Mednafen Sega Saturn Emulation Module */
|
||||
/******************************************************************************/
|
||||
/* cs1ram.cpp - CS1 RAM(16MiB) cart emulation
|
||||
** Copyright (C) 2017 Mednafen Team
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU General Public License
|
||||
** as published by the Free Software Foundation; either version 2
|
||||
** of the License, or (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "cs1ram.h"
|
||||
|
||||
namespace MDFN_IEN_SS
|
||||
{
|
||||
static uint16 *CS1RAM = nullptr;
|
||||
|
||||
template <typename T, bool IsWrite>
|
||||
static MDFN_HOT void CS1RAM_RW_DB(uint32 A, uint16 *DB)
|
||||
{
|
||||
const uint32 mask = (sizeof(T) == 2) ? 0xFFFF : (0xFF << (((A & 1) ^ 1) << 3));
|
||||
uint16 *const ptr = (uint16 *)((uint8 *)CS1RAM + (A & 0x00FFFFFE));
|
||||
|
||||
if (IsWrite)
|
||||
*ptr = (*ptr & ~mask) | (*DB & mask);
|
||||
else
|
||||
*DB = *ptr;
|
||||
}
|
||||
|
||||
static MDFN_COLD void Reset(bool powering_up)
|
||||
{
|
||||
if (powering_up)
|
||||
memset(CS1RAM, 0, 0x1000000);
|
||||
}
|
||||
|
||||
void CART_CS1RAM_Init(CartInfo *c)
|
||||
{
|
||||
CS1RAM = (uint16 *)alloc_plain(0x1000000);
|
||||
|
||||
SS_SetPhysMemMap(0x04000000, 0x04FFFFFF, CS1RAM, 0x1000000, true);
|
||||
c->CS01_SetRW8W16(0x04000000, 0x04FFFFFF,
|
||||
CS1RAM_RW_DB<uint16, false>,
|
||||
CS1RAM_RW_DB<uint8, true>,
|
||||
CS1RAM_RW_DB<uint16, true>);
|
||||
|
||||
c->Reset = Reset;
|
||||
AddMemoryDomain("CS1 Cart", CS1RAM, 0x1000000, true);
|
||||
}
|
||||
}
|
||||
/******************************************************************************/
|
||||
/* Mednafen Sega Saturn Emulation Module */
|
||||
/******************************************************************************/
|
||||
/* cs1ram.cpp - CS1 RAM(16MiB) cart emulation
|
||||
** Copyright (C) 2017 Mednafen Team
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU General Public License
|
||||
** as published by the Free Software Foundation; either version 2
|
||||
** of the License, or (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "cs1ram.h"
|
||||
|
||||
namespace MDFN_IEN_SS
|
||||
{
|
||||
static uint16 *CS1RAM = nullptr;
|
||||
|
||||
template <typename T, bool IsWrite>
|
||||
static MDFN_HOT void CS1RAM_RW_DB(uint32 A, uint16 *DB)
|
||||
{
|
||||
const uint32 mask = (sizeof(T) == 2) ? 0xFFFF : (0xFF << (((A & 1) ^ 1) << 3));
|
||||
uint16 *const ptr = (uint16 *)((uint8 *)CS1RAM + (A & 0x00FFFFFE));
|
||||
|
||||
if (IsWrite)
|
||||
*ptr = (*ptr & ~mask) | (*DB & mask);
|
||||
else
|
||||
*DB = *ptr;
|
||||
}
|
||||
|
||||
static MDFN_COLD void Reset(bool powering_up)
|
||||
{
|
||||
if (powering_up)
|
||||
memset(CS1RAM, 0, 0x1000000);
|
||||
}
|
||||
|
||||
void CART_CS1RAM_Init(CartInfo *c)
|
||||
{
|
||||
CS1RAM = (uint16 *)alloc_plain(0x1000000);
|
||||
|
||||
SS_SetPhysMemMap(0x04000000, 0x04FFFFFF, CS1RAM, 0x1000000, true);
|
||||
c->CS01_SetRW8W16(0x04000000, 0x04FFFFFF,
|
||||
CS1RAM_RW_DB<uint16, false>,
|
||||
CS1RAM_RW_DB<uint8, true>,
|
||||
CS1RAM_RW_DB<uint16, true>);
|
||||
|
||||
c->Reset = Reset;
|
||||
AddMemoryDomain("CS1 Cart", CS1RAM, 0x1000000, MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_WORDSIZE2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,84 +1,84 @@
|
|||
/******************************************************************************/
|
||||
/* Mednafen Sega Saturn Emulation Module */
|
||||
/******************************************************************************/
|
||||
/* extram.cpp - Extended RAM(1MiB and 4MiB) cart emulation
|
||||
** Copyright (C) 2016-2017 Mednafen Team
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU General Public License
|
||||
** as published by the Free Software Foundation; either version 2
|
||||
** of the License, or (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "extram.h"
|
||||
|
||||
namespace MDFN_IEN_SS
|
||||
{
|
||||
static uint16 *ExtRAM; //[0x200000];
|
||||
static size_t ExtRAM_Mask;
|
||||
static uint8 Cart_ID;
|
||||
|
||||
template <typename T, bool IsWrite>
|
||||
static MDFN_HOT void ExtRAM_RW_DB(uint32 A, uint16 *DB)
|
||||
{
|
||||
const uint32 mask = (sizeof(T) == 2) ? 0xFFFF : (0xFF << (((A & 1) ^ 1) << 3));
|
||||
uint16 *const ptr = (uint16 *)((uint8 *)ExtRAM + (A & ExtRAM_Mask));
|
||||
|
||||
//printf("Barf %zu %d: %08x\n", sizeof(T), IsWrite, A);
|
||||
|
||||
if (IsWrite)
|
||||
*ptr = (*ptr & ~mask) | (*DB & mask);
|
||||
else
|
||||
*DB = *ptr;
|
||||
}
|
||||
|
||||
static MDFN_HOT void CartID_Read_DB(uint32 A, uint16 *DB)
|
||||
{
|
||||
if ((A & ~1) == 0x04FFFFFE)
|
||||
*DB = Cart_ID;
|
||||
}
|
||||
|
||||
static MDFN_COLD void Reset(bool powering_up)
|
||||
{
|
||||
if (powering_up)
|
||||
memset(ExtRAM, 0, 0x400000); // TODO: Test.
|
||||
}
|
||||
|
||||
void CART_ExtRAM_Init(CartInfo *c, bool R4MiB)
|
||||
{
|
||||
ExtRAM = (uint16 *)alloc_plain(0x400000);
|
||||
if (R4MiB)
|
||||
{
|
||||
Cart_ID = 0x5C;
|
||||
ExtRAM_Mask = 0x3FFFFE;
|
||||
}
|
||||
else
|
||||
{
|
||||
Cart_ID = 0x5A;
|
||||
ExtRAM_Mask = 0x27FFFE;
|
||||
}
|
||||
|
||||
SS_SetPhysMemMap(0x02400000, 0x025FFFFF, ExtRAM + (0x000000 / sizeof(uint16)), (R4MiB ? 0x200000 : 0x080000), true);
|
||||
SS_SetPhysMemMap(0x02600000, 0x027FFFFF, ExtRAM + (0x200000 / sizeof(uint16)), (R4MiB ? 0x200000 : 0x080000), true);
|
||||
|
||||
c->CS01_SetRW8W16(0x02400000, 0x027FFFFF,
|
||||
ExtRAM_RW_DB<uint16, false>,
|
||||
ExtRAM_RW_DB<uint8, true>,
|
||||
ExtRAM_RW_DB<uint16, true>);
|
||||
|
||||
c->CS01_SetRW8W16(/*0x04FFFFFE*/ 0x04F00000, 0x04FFFFFF, CartID_Read_DB);
|
||||
|
||||
c->Reset = Reset;
|
||||
AddMemoryDomain("Ram Cart", ExtRAM, 0x400000, true);
|
||||
}
|
||||
}
|
||||
/******************************************************************************/
|
||||
/* Mednafen Sega Saturn Emulation Module */
|
||||
/******************************************************************************/
|
||||
/* extram.cpp - Extended RAM(1MiB and 4MiB) cart emulation
|
||||
** Copyright (C) 2016-2017 Mednafen Team
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU General Public License
|
||||
** as published by the Free Software Foundation; either version 2
|
||||
** of the License, or (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "extram.h"
|
||||
|
||||
namespace MDFN_IEN_SS
|
||||
{
|
||||
static uint16 *ExtRAM; //[0x200000];
|
||||
static size_t ExtRAM_Mask;
|
||||
static uint8 Cart_ID;
|
||||
|
||||
template <typename T, bool IsWrite>
|
||||
static MDFN_HOT void ExtRAM_RW_DB(uint32 A, uint16 *DB)
|
||||
{
|
||||
const uint32 mask = (sizeof(T) == 2) ? 0xFFFF : (0xFF << (((A & 1) ^ 1) << 3));
|
||||
uint16 *const ptr = (uint16 *)((uint8 *)ExtRAM + (A & ExtRAM_Mask));
|
||||
|
||||
//printf("Barf %zu %d: %08x\n", sizeof(T), IsWrite, A);
|
||||
|
||||
if (IsWrite)
|
||||
*ptr = (*ptr & ~mask) | (*DB & mask);
|
||||
else
|
||||
*DB = *ptr;
|
||||
}
|
||||
|
||||
static MDFN_HOT void CartID_Read_DB(uint32 A, uint16 *DB)
|
||||
{
|
||||
if ((A & ~1) == 0x04FFFFFE)
|
||||
*DB = Cart_ID;
|
||||
}
|
||||
|
||||
static MDFN_COLD void Reset(bool powering_up)
|
||||
{
|
||||
if (powering_up)
|
||||
memset(ExtRAM, 0, 0x400000); // TODO: Test.
|
||||
}
|
||||
|
||||
void CART_ExtRAM_Init(CartInfo *c, bool R4MiB)
|
||||
{
|
||||
ExtRAM = (uint16 *)alloc_plain(0x400000);
|
||||
if (R4MiB)
|
||||
{
|
||||
Cart_ID = 0x5C;
|
||||
ExtRAM_Mask = 0x3FFFFE;
|
||||
}
|
||||
else
|
||||
{
|
||||
Cart_ID = 0x5A;
|
||||
ExtRAM_Mask = 0x27FFFE;
|
||||
}
|
||||
|
||||
SS_SetPhysMemMap(0x02400000, 0x025FFFFF, ExtRAM + (0x000000 / sizeof(uint16)), (R4MiB ? 0x200000 : 0x080000), true);
|
||||
SS_SetPhysMemMap(0x02600000, 0x027FFFFF, ExtRAM + (0x200000 / sizeof(uint16)), (R4MiB ? 0x200000 : 0x080000), true);
|
||||
|
||||
c->CS01_SetRW8W16(0x02400000, 0x027FFFFF,
|
||||
ExtRAM_RW_DB<uint16, false>,
|
||||
ExtRAM_RW_DB<uint8, true>,
|
||||
ExtRAM_RW_DB<uint16, true>);
|
||||
|
||||
c->CS01_SetRW8W16(/*0x04FFFFFE*/ 0x04F00000, 0x04FFFFFF, CartID_Read_DB);
|
||||
|
||||
c->Reset = Reset;
|
||||
AddMemoryDomain("Ram Cart", ExtRAM, 0x400000, MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_WORDSIZE2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,53 +1,53 @@
|
|||
/******************************************************************************/
|
||||
/* Mednafen Sega Saturn Emulation Module */
|
||||
/******************************************************************************/
|
||||
/* rom.cpp - ROM cart emulation
|
||||
** Copyright (C) 2016-2017 Mednafen Team
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU General Public License
|
||||
** as published by the Free Software Foundation; either version 2
|
||||
** of the License, or (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "rom.h"
|
||||
|
||||
namespace MDFN_IEN_SS
|
||||
{
|
||||
|
||||
static uint16 *ROM; //[0x100000];
|
||||
|
||||
static MDFN_HOT void ROM_Read(uint32 A, uint16 *DB)
|
||||
{
|
||||
// TODO: Check mirroring.
|
||||
//printf("ROM: %08x\n", A);
|
||||
*DB = *(uint16 *)((uint8 *)ROM + (A & 0x1FFFFE));
|
||||
}
|
||||
|
||||
void CART_ROM_Init(CartInfo *c, const char *filename)
|
||||
{
|
||||
if (FirmwareSizeCallback(filename) != 0x200000)
|
||||
abort();
|
||||
ROM = (uint16 *)alloc_sealed(0x200000);
|
||||
FirmwareDataCallback(filename, (uint8 *)ROM);
|
||||
|
||||
for (unsigned i = 0; i < 0x100000; i++)
|
||||
{
|
||||
ROM[i] = MDFN_de16msb<true>(&ROM[i]);
|
||||
}
|
||||
|
||||
SS_SetPhysMemMap(0x02000000, 0x03FFFFFF, ROM, 0x200000, false);
|
||||
c->CS01_SetRW8W16(0x02000000, 0x03FFFFFF, ROM_Read);
|
||||
AddMemoryDomain("Rom Cart", ROM, 0x200000, false);
|
||||
}
|
||||
}
|
||||
/******************************************************************************/
|
||||
/* Mednafen Sega Saturn Emulation Module */
|
||||
/******************************************************************************/
|
||||
/* rom.cpp - ROM cart emulation
|
||||
** Copyright (C) 2016-2017 Mednafen Team
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU General Public License
|
||||
** as published by the Free Software Foundation; either version 2
|
||||
** of the License, or (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "rom.h"
|
||||
|
||||
namespace MDFN_IEN_SS
|
||||
{
|
||||
|
||||
static uint16 *ROM; //[0x100000];
|
||||
|
||||
static MDFN_HOT void ROM_Read(uint32 A, uint16 *DB)
|
||||
{
|
||||
// TODO: Check mirroring.
|
||||
//printf("ROM: %08x\n", A);
|
||||
*DB = *(uint16 *)((uint8 *)ROM + (A & 0x1FFFFE));
|
||||
}
|
||||
|
||||
void CART_ROM_Init(CartInfo *c, const char *filename)
|
||||
{
|
||||
if (FirmwareSizeCallback(filename) != 0x200000)
|
||||
abort();
|
||||
ROM = (uint16 *)alloc_sealed(0x200000);
|
||||
FirmwareDataCallback(filename, (uint8 *)ROM);
|
||||
|
||||
for (unsigned i = 0; i < 0x100000; i++)
|
||||
{
|
||||
ROM[i] = MDFN_de16msb<true>(&ROM[i]);
|
||||
}
|
||||
|
||||
SS_SetPhysMemMap(0x02000000, 0x03FFFFFF, ROM, 0x200000, false);
|
||||
c->CS01_SetRW8W16(0x02000000, 0x03FFFFFF, ROM_Read);
|
||||
AddMemoryDomain("Rom Cart", ROM, 0x200000, MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_WORDSIZE2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,322 +1,323 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
|
||||
#define MDFN_FASTCALL
|
||||
#define INLINE inline
|
||||
#define MDFN_COLD
|
||||
#define MDFN_HOT
|
||||
#define NO_INLINE
|
||||
#define NO_CLONE
|
||||
#define MDFN_UNLIKELY(p) (p)
|
||||
#define MDFN_LIKELY(p) (p)
|
||||
//#define MDFN_ASSUME_ALIGNED(p, align) ((decltype(p))__builtin_assume_aligned((p), (align)))
|
||||
#define MDFN_ASSUME_ALIGNED(p, align) (p)
|
||||
#define trio_snprintf snprintf
|
||||
#define trio_vprintf vprintf
|
||||
#define trio_printf printf
|
||||
#define trio_sprintf sprintf
|
||||
#define TRUE true
|
||||
#define FALSE false
|
||||
#ifndef __alignas_is_defined
|
||||
#define alignas(p)
|
||||
#endif
|
||||
#define override // remove for gcc 4.7
|
||||
#define final
|
||||
#define gettext_noop(s) (s)
|
||||
#define MDFN_MASTERCLOCK_FIXED(n) ((int64)((double)(n) * (1LL << 32)))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Pitch(32-bit) must be equal to width and >= the "fb_width" specified in the MDFNGI struct for the emulated system.
|
||||
// Height must be >= to the "fb_height" specified in the MDFNGI struct for the emulated system.
|
||||
// The framebuffer pointed to by surface->pixels is written to by the system emulation code.
|
||||
uint32 *pixels;
|
||||
int pitch32;
|
||||
|
||||
// Pointer to an array of int32, number of elements = fb_height, set by the driver code. Individual elements written
|
||||
// to by system emulation code. If the emulated system doesn't support multiple screen widths per frame, or if you handle
|
||||
// such a situation by outputting at a constant width-per-frame that is the least-common-multiple of the screen widths, then
|
||||
// you can ignore this. If you do wish to use this, you must set all elements every frame.
|
||||
int32 *LineWidths;
|
||||
|
||||
// Pointer to sound buffer, set by the driver code, that the emulation code should render sound to.
|
||||
int16 *SoundBuf;
|
||||
|
||||
// Number of cycles that this frame consumed, using MDFNGI::MasterClock as a time base.
|
||||
// Set by emulation code.
|
||||
int64 MasterCycles;
|
||||
|
||||
// Maximum size of the sound buffer, in frames. Set by the driver code.
|
||||
int32 SoundBufMaxSize;
|
||||
|
||||
// Number of frames currently in internal sound buffer. Set by the system emulation code, to be read by the driver code.
|
||||
int32 SoundBufSize;
|
||||
|
||||
// Set by the system emulation code every frame, to denote the horizontal and vertical offsets of the image, and the size
|
||||
// of the image. If the emulated system sets the elements of LineWidths, then the width(w) of this structure
|
||||
// is ignored while drawing the image.
|
||||
int32 x, y, h;
|
||||
|
||||
// Set(optionally) by emulation code. If InterlaceOn is true, then assume field height is 1/2 DisplayRect.h, and
|
||||
// only every other line in surface (with the start line defined by InterlacedField) has valid data
|
||||
// (it's up to internal Mednafen code to deinterlace it).
|
||||
bool InterlaceOn;
|
||||
bool InterlaceField;
|
||||
} EmulateSpecStruct;
|
||||
|
||||
#define MDFN_printf(...)
|
||||
#define MDFN_PrintError(...)
|
||||
#define MDFN_FORMATSTR(...)
|
||||
#define require assert
|
||||
|
||||
enum InputDeviceInputType : uint8
|
||||
{
|
||||
IDIT_BUTTON, // 1-bit
|
||||
IDIT_BUTTON_CAN_RAPID, // 1-bit
|
||||
|
||||
IDIT_SWITCH, // ceil(log2(n))-bit
|
||||
// Current switch position(default 0).
|
||||
// Persistent, and bidirectional communication(can be modified driver side, and Mednafen core and emulation module side)
|
||||
|
||||
IDIT_STATUS, // ceil(log2(n))-bit
|
||||
// emulation module->driver communication
|
||||
|
||||
IDIT_X_AXIS, // (mouse) 16-bits, signed - in-screen/window range: [0.0, nominal_width)
|
||||
IDIT_Y_AXIS, // (mouse) 16-bits, signed - in-screen/window range: [0.0, nominal_height)
|
||||
|
||||
IDIT_X_AXIS_REL, // (mouse) 32-bits, signed
|
||||
IDIT_Y_AXIS_REL, // (mouse) 32-bits, signed
|
||||
|
||||
IDIT_BYTE_SPECIAL,
|
||||
|
||||
IDIT_RESET_BUTTON, // 1-bit
|
||||
|
||||
IDIT_BUTTON_ANALOG, // 16-bits, 0 - 32767
|
||||
|
||||
IDIT_RUMBLE, // 16-bits, lower 8 bits are weak rumble(0-255), next 8 bits are strong rumble(0-255), 0=no rumble, 255=max rumble. Somewhat subjective, too...
|
||||
// It's a rather special case of game module->driver code communication.
|
||||
};
|
||||
|
||||
#define IDIT_BUTTON_ANALOG_FLAG_SQLR 0x00000001 // Denotes analog data that may need to be scaled to ensure a more squareish logical range(for emulated
|
||||
// analog sticks).
|
||||
struct IDIIS_StatusState
|
||||
{
|
||||
const char *ShortName;
|
||||
const char *Name;
|
||||
int32 Color; // (msb)0RGB(lsb), -1 for unused.
|
||||
};
|
||||
struct InputDeviceInputInfoStruct
|
||||
{
|
||||
const char *SettingName; // No spaces, shouldbe all a-z0-9 and _. Definitely no ~!
|
||||
const char *Name;
|
||||
int ConfigOrder; // Configuration order during in-game config process, -1 for no config.
|
||||
InputDeviceInputType Type;
|
||||
const char *ExcludeName; // SettingName of a button that can't be pressed at the same time as this button
|
||||
// due to physical limitations.
|
||||
uint8 Flags;
|
||||
uint8 BitSize;
|
||||
uint16 BitOffset;
|
||||
|
||||
union {
|
||||
struct
|
||||
{
|
||||
const char *const *SwitchPosName; //
|
||||
uint32 SwitchNumPos;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
const IDIIS_StatusState *StatusStates;
|
||||
uint32 StatusNumStates;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
struct IDIISG : public std::vector<InputDeviceInputInfoStruct>
|
||||
{
|
||||
IDIISG()
|
||||
{
|
||||
InputByteSize = 0;
|
||||
}
|
||||
|
||||
IDIISG(std::initializer_list<InputDeviceInputInfoStruct> l) : std::vector<InputDeviceInputInfoStruct>(l)
|
||||
{
|
||||
size_t bit_offset = 0;
|
||||
|
||||
for (auto &idii : *this)
|
||||
{
|
||||
size_t bit_size = 0;
|
||||
size_t bit_align = 1;
|
||||
|
||||
switch (idii.Type)
|
||||
{
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
|
||||
case IDIT_BUTTON:
|
||||
case IDIT_BUTTON_CAN_RAPID:
|
||||
case IDIT_RESET_BUTTON:
|
||||
bit_size = 1;
|
||||
break;
|
||||
|
||||
case IDIT_SWITCH:
|
||||
bit_size = ceil(log2(idii.SwitchNumPos));
|
||||
break;
|
||||
|
||||
case IDIT_STATUS:
|
||||
bit_size = ceil(log2(idii.StatusNumStates));
|
||||
break;
|
||||
|
||||
case IDIT_X_AXIS:
|
||||
case IDIT_Y_AXIS:
|
||||
bit_size = 16;
|
||||
bit_align = 8;
|
||||
break;
|
||||
|
||||
case IDIT_X_AXIS_REL:
|
||||
case IDIT_Y_AXIS_REL:
|
||||
bit_size = 32;
|
||||
bit_align = 8;
|
||||
break;
|
||||
|
||||
case IDIT_BYTE_SPECIAL:
|
||||
bit_size = 8;
|
||||
bit_align = 8;
|
||||
break;
|
||||
|
||||
case IDIT_BUTTON_ANALOG:
|
||||
bit_size = 16;
|
||||
bit_align = 8;
|
||||
break;
|
||||
|
||||
case IDIT_RUMBLE:
|
||||
bit_size = 16;
|
||||
bit_align = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
bit_offset = (bit_offset + (bit_align - 1)) & ~(bit_align - 1);
|
||||
|
||||
// printf("%s, %zu(%zu)\n", idii.SettingName, bit_offset, bit_offset / 8);
|
||||
|
||||
idii.BitSize = bit_size;
|
||||
idii.BitOffset = bit_offset;
|
||||
|
||||
assert(idii.BitSize == bit_size);
|
||||
assert(idii.BitOffset == bit_offset);
|
||||
|
||||
bit_offset += bit_size;
|
||||
}
|
||||
|
||||
InputByteSize = (bit_offset + 7) / 8;
|
||||
}
|
||||
uint32 InputByteSize;
|
||||
};
|
||||
|
||||
struct IDIIS_Switch : public InputDeviceInputInfoStruct
|
||||
{
|
||||
IDIIS_Switch(const char *sname, const char *name, int co, const char *const *spn, const uint32 spn_num)
|
||||
{
|
||||
SettingName = sname;
|
||||
Name = name;
|
||||
ConfigOrder = co;
|
||||
Type = IDIT_SWITCH;
|
||||
|
||||
ExcludeName = NULL;
|
||||
Flags = 0;
|
||||
SwitchPosName = spn;
|
||||
SwitchNumPos = spn_num;
|
||||
}
|
||||
};
|
||||
|
||||
struct IDIIS_Status : public InputDeviceInputInfoStruct
|
||||
{
|
||||
IDIIS_Status(const char *sname, const char *name, const IDIIS_StatusState *ss, const uint32 ss_num)
|
||||
{
|
||||
SettingName = sname;
|
||||
Name = name;
|
||||
ConfigOrder = -1;
|
||||
Type = IDIT_STATUS;
|
||||
|
||||
ExcludeName = NULL;
|
||||
Flags = 0;
|
||||
StatusStates = ss;
|
||||
StatusNumStates = ss_num;
|
||||
}
|
||||
};
|
||||
|
||||
struct InputDeviceInfoStruct
|
||||
{
|
||||
const char *ShortName;
|
||||
const char *FullName;
|
||||
const char *Description;
|
||||
|
||||
const IDIISG &IDII;
|
||||
|
||||
unsigned Flags;
|
||||
|
||||
enum
|
||||
{
|
||||
FLAG_KEYBOARD = (1U << 0)
|
||||
};
|
||||
};
|
||||
|
||||
struct InputPortInfoStruct
|
||||
{
|
||||
const char *ShortName;
|
||||
const char *FullName;
|
||||
const std::vector<InputDeviceInfoStruct> &DeviceInfo;
|
||||
const char *DefaultDevice; // Default device for this port.
|
||||
};
|
||||
|
||||
#include "endian.h"
|
||||
|
||||
inline char *strdup(const char *p)
|
||||
{
|
||||
char *ret = (char *)malloc(strlen(p) + 1);
|
||||
if (ret)
|
||||
strcpy(ret, p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#include "stream/Stream.h"
|
||||
#include "stream/MemoryStream.h"
|
||||
#include "math_ops.h"
|
||||
|
||||
#include <emulibc.h>
|
||||
|
||||
extern int32 (*FirmwareSizeCallback)(const char *filename);
|
||||
extern void (*FirmwareDataCallback)(const char *filename, uint8 *dest);
|
||||
|
||||
extern int setting_ss_slstartp;
|
||||
extern int setting_ss_slendp;
|
||||
extern int setting_ss_slstart;
|
||||
extern int setting_ss_slend;
|
||||
extern int setting_ss_region_default;
|
||||
extern int setting_ss_cart;
|
||||
extern bool setting_ss_correct_aspect;
|
||||
extern bool setting_ss_h_overscan;
|
||||
extern bool setting_ss_h_blend;
|
||||
extern bool setting_ss_region_autodetect;
|
||||
|
||||
extern bool InputLagged;
|
||||
extern void (*InputCallback)();
|
||||
|
||||
extern void (*AddMemoryDomain)(const char* name, const void* ptr, int size, bool writable);
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
|
||||
#define MDFN_FASTCALL
|
||||
#define INLINE inline
|
||||
#define MDFN_COLD
|
||||
#define MDFN_HOT
|
||||
#define NO_INLINE
|
||||
#define NO_CLONE
|
||||
#define MDFN_UNLIKELY(p) (p)
|
||||
#define MDFN_LIKELY(p) (p)
|
||||
//#define MDFN_ASSUME_ALIGNED(p, align) ((decltype(p))__builtin_assume_aligned((p), (align)))
|
||||
#define MDFN_ASSUME_ALIGNED(p, align) (p)
|
||||
#define trio_snprintf snprintf
|
||||
#define trio_vprintf vprintf
|
||||
#define trio_printf printf
|
||||
#define trio_sprintf sprintf
|
||||
#define TRUE true
|
||||
#define FALSE false
|
||||
#ifndef __alignas_is_defined
|
||||
#define alignas(p)
|
||||
#endif
|
||||
#define override // remove for gcc 4.7
|
||||
#define final
|
||||
#define gettext_noop(s) (s)
|
||||
#define MDFN_MASTERCLOCK_FIXED(n) ((int64)((double)(n) * (1LL << 32)))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Pitch(32-bit) must be equal to width and >= the "fb_width" specified in the MDFNGI struct for the emulated system.
|
||||
// Height must be >= to the "fb_height" specified in the MDFNGI struct for the emulated system.
|
||||
// The framebuffer pointed to by surface->pixels is written to by the system emulation code.
|
||||
uint32 *pixels;
|
||||
int pitch32;
|
||||
|
||||
// Pointer to an array of int32, number of elements = fb_height, set by the driver code. Individual elements written
|
||||
// to by system emulation code. If the emulated system doesn't support multiple screen widths per frame, or if you handle
|
||||
// such a situation by outputting at a constant width-per-frame that is the least-common-multiple of the screen widths, then
|
||||
// you can ignore this. If you do wish to use this, you must set all elements every frame.
|
||||
int32 *LineWidths;
|
||||
|
||||
// Pointer to sound buffer, set by the driver code, that the emulation code should render sound to.
|
||||
int16 *SoundBuf;
|
||||
|
||||
// Number of cycles that this frame consumed, using MDFNGI::MasterClock as a time base.
|
||||
// Set by emulation code.
|
||||
int64 MasterCycles;
|
||||
|
||||
// Maximum size of the sound buffer, in frames. Set by the driver code.
|
||||
int32 SoundBufMaxSize;
|
||||
|
||||
// Number of frames currently in internal sound buffer. Set by the system emulation code, to be read by the driver code.
|
||||
int32 SoundBufSize;
|
||||
|
||||
// Set by the system emulation code every frame, to denote the horizontal and vertical offsets of the image, and the size
|
||||
// of the image. If the emulated system sets the elements of LineWidths, then the width(w) of this structure
|
||||
// is ignored while drawing the image.
|
||||
int32 x, y, h;
|
||||
|
||||
// Set(optionally) by emulation code. If InterlaceOn is true, then assume field height is 1/2 DisplayRect.h, and
|
||||
// only every other line in surface (with the start line defined by InterlacedField) has valid data
|
||||
// (it's up to internal Mednafen code to deinterlace it).
|
||||
bool InterlaceOn;
|
||||
bool InterlaceField;
|
||||
} EmulateSpecStruct;
|
||||
|
||||
#define MDFN_printf(...)
|
||||
#define MDFN_PrintError(...)
|
||||
#define MDFN_FORMATSTR(...)
|
||||
#define require assert
|
||||
|
||||
enum InputDeviceInputType : uint8
|
||||
{
|
||||
IDIT_BUTTON, // 1-bit
|
||||
IDIT_BUTTON_CAN_RAPID, // 1-bit
|
||||
|
||||
IDIT_SWITCH, // ceil(log2(n))-bit
|
||||
// Current switch position(default 0).
|
||||
// Persistent, and bidirectional communication(can be modified driver side, and Mednafen core and emulation module side)
|
||||
|
||||
IDIT_STATUS, // ceil(log2(n))-bit
|
||||
// emulation module->driver communication
|
||||
|
||||
IDIT_X_AXIS, // (mouse) 16-bits, signed - in-screen/window range: [0.0, nominal_width)
|
||||
IDIT_Y_AXIS, // (mouse) 16-bits, signed - in-screen/window range: [0.0, nominal_height)
|
||||
|
||||
IDIT_X_AXIS_REL, // (mouse) 32-bits, signed
|
||||
IDIT_Y_AXIS_REL, // (mouse) 32-bits, signed
|
||||
|
||||
IDIT_BYTE_SPECIAL,
|
||||
|
||||
IDIT_RESET_BUTTON, // 1-bit
|
||||
|
||||
IDIT_BUTTON_ANALOG, // 16-bits, 0 - 32767
|
||||
|
||||
IDIT_RUMBLE, // 16-bits, lower 8 bits are weak rumble(0-255), next 8 bits are strong rumble(0-255), 0=no rumble, 255=max rumble. Somewhat subjective, too...
|
||||
// It's a rather special case of game module->driver code communication.
|
||||
};
|
||||
|
||||
#define IDIT_BUTTON_ANALOG_FLAG_SQLR 0x00000001 // Denotes analog data that may need to be scaled to ensure a more squareish logical range(for emulated
|
||||
// analog sticks).
|
||||
struct IDIIS_StatusState
|
||||
{
|
||||
const char *ShortName;
|
||||
const char *Name;
|
||||
int32 Color; // (msb)0RGB(lsb), -1 for unused.
|
||||
};
|
||||
struct InputDeviceInputInfoStruct
|
||||
{
|
||||
const char *SettingName; // No spaces, shouldbe all a-z0-9 and _. Definitely no ~!
|
||||
const char *Name;
|
||||
int ConfigOrder; // Configuration order during in-game config process, -1 for no config.
|
||||
InputDeviceInputType Type;
|
||||
const char *ExcludeName; // SettingName of a button that can't be pressed at the same time as this button
|
||||
// due to physical limitations.
|
||||
uint8 Flags;
|
||||
uint8 BitSize;
|
||||
uint16 BitOffset;
|
||||
|
||||
union {
|
||||
struct
|
||||
{
|
||||
const char *const *SwitchPosName; //
|
||||
uint32 SwitchNumPos;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
const IDIIS_StatusState *StatusStates;
|
||||
uint32 StatusNumStates;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
struct IDIISG : public std::vector<InputDeviceInputInfoStruct>
|
||||
{
|
||||
IDIISG()
|
||||
{
|
||||
InputByteSize = 0;
|
||||
}
|
||||
|
||||
IDIISG(std::initializer_list<InputDeviceInputInfoStruct> l) : std::vector<InputDeviceInputInfoStruct>(l)
|
||||
{
|
||||
size_t bit_offset = 0;
|
||||
|
||||
for (auto &idii : *this)
|
||||
{
|
||||
size_t bit_size = 0;
|
||||
size_t bit_align = 1;
|
||||
|
||||
switch (idii.Type)
|
||||
{
|
||||
default:
|
||||
abort();
|
||||
break;
|
||||
|
||||
case IDIT_BUTTON:
|
||||
case IDIT_BUTTON_CAN_RAPID:
|
||||
case IDIT_RESET_BUTTON:
|
||||
bit_size = 1;
|
||||
break;
|
||||
|
||||
case IDIT_SWITCH:
|
||||
bit_size = ceil(log2(idii.SwitchNumPos));
|
||||
break;
|
||||
|
||||
case IDIT_STATUS:
|
||||
bit_size = ceil(log2(idii.StatusNumStates));
|
||||
break;
|
||||
|
||||
case IDIT_X_AXIS:
|
||||
case IDIT_Y_AXIS:
|
||||
bit_size = 16;
|
||||
bit_align = 8;
|
||||
break;
|
||||
|
||||
case IDIT_X_AXIS_REL:
|
||||
case IDIT_Y_AXIS_REL:
|
||||
bit_size = 32;
|
||||
bit_align = 8;
|
||||
break;
|
||||
|
||||
case IDIT_BYTE_SPECIAL:
|
||||
bit_size = 8;
|
||||
bit_align = 8;
|
||||
break;
|
||||
|
||||
case IDIT_BUTTON_ANALOG:
|
||||
bit_size = 16;
|
||||
bit_align = 8;
|
||||
break;
|
||||
|
||||
case IDIT_RUMBLE:
|
||||
bit_size = 16;
|
||||
bit_align = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
bit_offset = (bit_offset + (bit_align - 1)) & ~(bit_align - 1);
|
||||
|
||||
// printf("%s, %zu(%zu)\n", idii.SettingName, bit_offset, bit_offset / 8);
|
||||
|
||||
idii.BitSize = bit_size;
|
||||
idii.BitOffset = bit_offset;
|
||||
|
||||
assert(idii.BitSize == bit_size);
|
||||
assert(idii.BitOffset == bit_offset);
|
||||
|
||||
bit_offset += bit_size;
|
||||
}
|
||||
|
||||
InputByteSize = (bit_offset + 7) / 8;
|
||||
}
|
||||
uint32 InputByteSize;
|
||||
};
|
||||
|
||||
struct IDIIS_Switch : public InputDeviceInputInfoStruct
|
||||
{
|
||||
IDIIS_Switch(const char *sname, const char *name, int co, const char *const *spn, const uint32 spn_num)
|
||||
{
|
||||
SettingName = sname;
|
||||
Name = name;
|
||||
ConfigOrder = co;
|
||||
Type = IDIT_SWITCH;
|
||||
|
||||
ExcludeName = NULL;
|
||||
Flags = 0;
|
||||
SwitchPosName = spn;
|
||||
SwitchNumPos = spn_num;
|
||||
}
|
||||
};
|
||||
|
||||
struct IDIIS_Status : public InputDeviceInputInfoStruct
|
||||
{
|
||||
IDIIS_Status(const char *sname, const char *name, const IDIIS_StatusState *ss, const uint32 ss_num)
|
||||
{
|
||||
SettingName = sname;
|
||||
Name = name;
|
||||
ConfigOrder = -1;
|
||||
Type = IDIT_STATUS;
|
||||
|
||||
ExcludeName = NULL;
|
||||
Flags = 0;
|
||||
StatusStates = ss;
|
||||
StatusNumStates = ss_num;
|
||||
}
|
||||
};
|
||||
|
||||
struct InputDeviceInfoStruct
|
||||
{
|
||||
const char *ShortName;
|
||||
const char *FullName;
|
||||
const char *Description;
|
||||
|
||||
const IDIISG &IDII;
|
||||
|
||||
unsigned Flags;
|
||||
|
||||
enum
|
||||
{
|
||||
FLAG_KEYBOARD = (1U << 0)
|
||||
};
|
||||
};
|
||||
|
||||
struct InputPortInfoStruct
|
||||
{
|
||||
const char *ShortName;
|
||||
const char *FullName;
|
||||
const std::vector<InputDeviceInfoStruct> &DeviceInfo;
|
||||
const char *DefaultDevice; // Default device for this port.
|
||||
};
|
||||
|
||||
#include "endian.h"
|
||||
|
||||
inline char *strdup(const char *p)
|
||||
{
|
||||
char *ret = (char *)malloc(strlen(p) + 1);
|
||||
if (ret)
|
||||
strcpy(ret, p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#include "stream/Stream.h"
|
||||
#include "stream/MemoryStream.h"
|
||||
#include "math_ops.h"
|
||||
|
||||
#include "../emulibc/emulibc.h"
|
||||
#include "../emulibc/waterboxcore.h"
|
||||
|
||||
extern int32 (*FirmwareSizeCallback)(const char *filename);
|
||||
extern void (*FirmwareDataCallback)(const char *filename, uint8 *dest);
|
||||
|
||||
extern int setting_ss_slstartp;
|
||||
extern int setting_ss_slendp;
|
||||
extern int setting_ss_slstart;
|
||||
extern int setting_ss_slend;
|
||||
extern int setting_ss_region_default;
|
||||
extern int setting_ss_cart;
|
||||
extern bool setting_ss_correct_aspect;
|
||||
extern bool setting_ss_h_overscan;
|
||||
extern bool setting_ss_h_blend;
|
||||
extern bool setting_ss_region_autodetect;
|
||||
|
||||
extern bool InputLagged;
|
||||
extern void (*InputCallback)();
|
||||
|
||||
void AddMemoryDomain(const char* name, const void* ptr, int size, int flags);
|
||||
|
|
|
@ -1,358 +1,358 @@
|
|||
/******************************************************************************/
|
||||
/* Mednafen Sega Saturn Emulation Module */
|
||||
/******************************************************************************/
|
||||
/* sound.cpp - Sound Emulation
|
||||
** Copyright (C) 2015-2016 Mednafen Team
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU General Public License
|
||||
** as published by the Free Software Foundation; either version 2
|
||||
** of the License, or (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// TODO: Bus between SCU and SCSP looks to be 8-bit, maybe implement that, but
|
||||
// first test to see how the bus access cycle(s) work with respect to reading from
|
||||
// registers whose values may change between the individual byte reads.
|
||||
// (May not be worth emulating if it could possibly trigger problems in games)
|
||||
|
||||
#include "ss.h"
|
||||
#include "sound.h"
|
||||
#include "scu.h"
|
||||
#include "cdb.h"
|
||||
|
||||
#include "m68k/m68k.h"
|
||||
|
||||
namespace MDFN_IEN_SS
|
||||
{
|
||||
|
||||
#include "scsp.h"
|
||||
|
||||
static SS_SCSP SCSP;
|
||||
|
||||
static M68K SoundCPU(true);
|
||||
static int64 run_until_time; // 32.32
|
||||
static int32 next_scsp_time;
|
||||
|
||||
static uint32 clock_ratio;
|
||||
static sscpu_timestamp_t lastts;
|
||||
|
||||
static int16 IBuffer[1024][2];
|
||||
static uint32 IBufferCount;
|
||||
static int last_rate;
|
||||
static uint32 last_quality;
|
||||
|
||||
static INLINE void SCSP_SoundIntChanged(unsigned level)
|
||||
{
|
||||
SoundCPU.SetIPL(level);
|
||||
}
|
||||
|
||||
static INLINE void SCSP_MainIntChanged(bool state)
|
||||
{
|
||||
#ifndef MDFN_SSFPLAY_COMPILE
|
||||
SCU_SetInt(SCU_INT_SCSP, state);
|
||||
#endif
|
||||
}
|
||||
|
||||
#include "scsp.inc"
|
||||
|
||||
//
|
||||
//
|
||||
template <typename T>
|
||||
static MDFN_FASTCALL T SoundCPU_BusRead(uint32 A);
|
||||
|
||||
static MDFN_FASTCALL uint16 SoundCPU_BusReadInstr(uint32 A);
|
||||
|
||||
template <typename T>
|
||||
static MDFN_FASTCALL void SoundCPU_BusWrite(uint32 A, T V);
|
||||
|
||||
static MDFN_FASTCALL void SoundCPU_BusRMW(uint32 A, uint8(MDFN_FASTCALL *cb)(M68K *, uint8));
|
||||
static MDFN_FASTCALL unsigned SoundCPU_BusIntAck(uint8 level);
|
||||
static MDFN_FASTCALL void SoundCPU_BusRESET(bool state);
|
||||
//
|
||||
//
|
||||
|
||||
void SOUND_Init(void)
|
||||
{
|
||||
memset(IBuffer, 0, sizeof(IBuffer));
|
||||
IBufferCount = 0;
|
||||
|
||||
last_rate = -1;
|
||||
last_quality = ~0U;
|
||||
|
||||
run_until_time = 0;
|
||||
next_scsp_time = 0;
|
||||
lastts = 0;
|
||||
|
||||
SoundCPU.BusRead8 = SoundCPU_BusRead<uint8>;
|
||||
SoundCPU.BusRead16 = SoundCPU_BusRead<uint16>;
|
||||
|
||||
SoundCPU.BusWrite8 = SoundCPU_BusWrite<uint8>;
|
||||
SoundCPU.BusWrite16 = SoundCPU_BusWrite<uint16>;
|
||||
|
||||
SoundCPU.BusReadInstr = SoundCPU_BusReadInstr;
|
||||
|
||||
SoundCPU.BusRMW = SoundCPU_BusRMW;
|
||||
|
||||
SoundCPU.BusIntAck = SoundCPU_BusIntAck;
|
||||
SoundCPU.BusRESET = SoundCPU_BusRESET;
|
||||
|
||||
#ifndef MDFN_SSFPLAY_COMPILE
|
||||
SoundCPU.DBG_Warning = SS_DBG_Wrap<SS_DBG_WARNING | SS_DBG_M68K>;
|
||||
SoundCPU.DBG_Verbose = SS_DBG_Wrap<SS_DBG_M68K>;
|
||||
#endif
|
||||
|
||||
SS_SetPhysMemMap(0x05A00000, 0x05A7FFFF, SCSP.GetRAMPtr(), 0x80000, true);
|
||||
// TODO: MEM4B: SS_SetPhysMemMap(0x05A00000, 0x05AFFFFF, SCSP.GetRAMPtr(), 0x40000, true);
|
||||
AddMemoryDomain("Sound Ram", SCSP.GetRAMPtr(), 0x100000, true);
|
||||
}
|
||||
|
||||
uint8 SOUND_PeekRAM(uint32 A)
|
||||
{
|
||||
return ne16_rbo_be<uint8>(SCSP.GetRAMPtr(), A & 0x7FFFF);
|
||||
}
|
||||
|
||||
void SOUND_PokeRAM(uint32 A, uint8 V)
|
||||
{
|
||||
ne16_wbo_be<uint8>(SCSP.GetRAMPtr(), A & 0x7FFFF, V);
|
||||
}
|
||||
|
||||
void SOUND_ResetTS(void)
|
||||
{
|
||||
next_scsp_time -= SoundCPU.timestamp;
|
||||
run_until_time -= (int64)SoundCPU.timestamp << 32;
|
||||
SoundCPU.timestamp = 0;
|
||||
|
||||
lastts = 0;
|
||||
}
|
||||
|
||||
void SOUND_Reset(bool powering_up)
|
||||
{
|
||||
SCSP.Reset(powering_up);
|
||||
SoundCPU.Reset(powering_up);
|
||||
}
|
||||
|
||||
void SOUND_Reset68K(void)
|
||||
{
|
||||
SoundCPU.Reset(false);
|
||||
}
|
||||
|
||||
void SOUND_Set68KActive(bool active)
|
||||
{
|
||||
SoundCPU.SetExtHalted(!active);
|
||||
}
|
||||
|
||||
uint16 SOUND_Read16(uint32 A)
|
||||
{
|
||||
uint16 ret;
|
||||
|
||||
SCSP.RW<uint16, false>(A, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SOUND_Write8(uint32 A, uint8 V)
|
||||
{
|
||||
SCSP.RW<uint8, true>(A, V);
|
||||
}
|
||||
|
||||
void SOUND_Write16(uint32 A, uint16 V)
|
||||
{
|
||||
SCSP.RW<uint16, true>(A, V);
|
||||
}
|
||||
|
||||
static NO_INLINE void RunSCSP(void)
|
||||
{
|
||||
CDB_GetCDDA(SCSP.GetEXTSPtr());
|
||||
//
|
||||
//
|
||||
int16 *const bp = IBuffer[IBufferCount];
|
||||
SCSP.RunSample(bp);
|
||||
//bp[0] = rand();
|
||||
//bp[1] = rand();
|
||||
bp[0] = (bp[0] * 27 + 16) >> 5;
|
||||
bp[1] = (bp[1] * 27 + 16) >> 5;
|
||||
|
||||
IBufferCount = (IBufferCount + 1) & 1023;
|
||||
next_scsp_time += 256;
|
||||
}
|
||||
|
||||
// Ratio between SH-2 clock and 68K clock (sound clock / 2)
|
||||
void SOUND_SetClockRatio(uint32 ratio)
|
||||
{
|
||||
clock_ratio = ratio;
|
||||
}
|
||||
|
||||
sscpu_timestamp_t SOUND_Update(sscpu_timestamp_t timestamp)
|
||||
{
|
||||
run_until_time += ((uint64)(timestamp - lastts) * clock_ratio);
|
||||
lastts = timestamp;
|
||||
//
|
||||
//
|
||||
if (MDFN_LIKELY(SoundCPU.timestamp < (run_until_time >> 32)))
|
||||
{
|
||||
do
|
||||
{
|
||||
int32 next_time = std::min<int32>(next_scsp_time, run_until_time >> 32);
|
||||
|
||||
SoundCPU.Run(next_time);
|
||||
|
||||
if (SoundCPU.timestamp >= next_scsp_time)
|
||||
RunSCSP();
|
||||
} while (MDFN_LIKELY(SoundCPU.timestamp < (run_until_time >> 32)));
|
||||
}
|
||||
else
|
||||
{
|
||||
while (next_scsp_time < (run_until_time >> 32))
|
||||
RunSCSP();
|
||||
}
|
||||
|
||||
return timestamp + 128; // FIXME
|
||||
}
|
||||
|
||||
void SOUND_StartFrame(double rate, uint32 quality)
|
||||
{
|
||||
if ((int)rate != last_rate || quality != last_quality)
|
||||
{
|
||||
int err = 0;
|
||||
last_rate = (int)rate;
|
||||
last_quality = quality;
|
||||
}
|
||||
}
|
||||
|
||||
int32 SOUND_FlushOutput(int16 *SoundBuf, const int32 SoundBufMaxSize, const bool reverse)
|
||||
{
|
||||
if (SoundBuf && reverse)
|
||||
{
|
||||
for (unsigned lr = 0; lr < 2; lr++)
|
||||
{
|
||||
int16 *p0 = &IBuffer[0][lr];
|
||||
int16 *p1 = &IBuffer[IBufferCount - 1][lr];
|
||||
unsigned count = IBufferCount >> 1;
|
||||
|
||||
while (MDFN_LIKELY(count--))
|
||||
{
|
||||
std::swap(*p0, *p1);
|
||||
|
||||
p0 += 2;
|
||||
p1 -= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (last_rate == 44100)
|
||||
{
|
||||
int32 ret = IBufferCount;
|
||||
|
||||
memcpy(SoundBuf, IBuffer, IBufferCount * 2 * sizeof(int16));
|
||||
IBufferCount = 0;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
IBufferCount = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// TODO: test masks.
|
||||
//
|
||||
template <typename T>
|
||||
static MDFN_FASTCALL T SoundCPU_BusRead(uint32 A)
|
||||
{
|
||||
T ret;
|
||||
|
||||
SoundCPU.timestamp += 4;
|
||||
|
||||
if (MDFN_UNLIKELY(SoundCPU.timestamp >= next_scsp_time))
|
||||
RunSCSP();
|
||||
|
||||
SCSP.RW<T, false>(A & 0x1FFFFF, ret);
|
||||
|
||||
SoundCPU.timestamp += 2;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static MDFN_FASTCALL uint16 SoundCPU_BusReadInstr(uint32 A)
|
||||
{
|
||||
uint16 ret;
|
||||
|
||||
SoundCPU.timestamp += 4;
|
||||
|
||||
//if(MDFN_UNLIKELY(SoundCPU.timestamp >= next_scsp_time))
|
||||
// RunSCSP();
|
||||
|
||||
SCSP.RW<uint16, false>(A & 0x1FFFFF, ret);
|
||||
|
||||
SoundCPU.timestamp += 2;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static MDFN_FASTCALL void SoundCPU_BusWrite(uint32 A, T V)
|
||||
{
|
||||
if (MDFN_UNLIKELY(SoundCPU.timestamp >= next_scsp_time))
|
||||
RunSCSP();
|
||||
|
||||
SoundCPU.timestamp += 2;
|
||||
SCSP.RW<T, true>(A & 0x1FFFFF, V);
|
||||
SoundCPU.timestamp += 2;
|
||||
}
|
||||
|
||||
static MDFN_FASTCALL void SoundCPU_BusRMW(uint32 A, uint8(MDFN_FASTCALL *cb)(M68K *, uint8))
|
||||
{
|
||||
uint8 tmp;
|
||||
|
||||
SoundCPU.timestamp += 4;
|
||||
|
||||
if (MDFN_UNLIKELY(SoundCPU.timestamp >= next_scsp_time))
|
||||
RunSCSP();
|
||||
|
||||
SCSP.RW<uint8, false>(A & 0x1FFFFF, tmp);
|
||||
|
||||
tmp = cb(&SoundCPU, tmp);
|
||||
|
||||
SoundCPU.timestamp += 6;
|
||||
|
||||
SCSP.RW<uint8, true>(A & 0x1FFFFF, tmp);
|
||||
|
||||
SoundCPU.timestamp += 2;
|
||||
}
|
||||
|
||||
static MDFN_FASTCALL unsigned SoundCPU_BusIntAck(uint8 level)
|
||||
{
|
||||
return M68K::BUS_INT_ACK_AUTO;
|
||||
}
|
||||
|
||||
static MDFN_FASTCALL void SoundCPU_BusRESET(bool state)
|
||||
{
|
||||
//SS_DBG(SS_DBG_WARNING, "[M68K] RESET: %d @ time %d\n", state, SoundCPU.timestamp);
|
||||
if (state)
|
||||
{
|
||||
SoundCPU.Reset(false);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 SOUND_GetSCSPRegister(const unsigned id, char *const special, const uint32 special_len)
|
||||
{
|
||||
return SCSP.GetRegister(id, special, special_len);
|
||||
}
|
||||
|
||||
void SOUND_SetSCSPRegister(const unsigned id, const uint32 value)
|
||||
{
|
||||
SCSP.SetRegister(id, value);
|
||||
}
|
||||
}
|
||||
/******************************************************************************/
|
||||
/* Mednafen Sega Saturn Emulation Module */
|
||||
/******************************************************************************/
|
||||
/* sound.cpp - Sound Emulation
|
||||
** Copyright (C) 2015-2016 Mednafen Team
|
||||
**
|
||||
** This program is free software; you can redistribute it and/or
|
||||
** modify it under the terms of the GNU General Public License
|
||||
** as published by the Free Software Foundation; either version 2
|
||||
** of the License, or (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
// TODO: Bus between SCU and SCSP looks to be 8-bit, maybe implement that, but
|
||||
// first test to see how the bus access cycle(s) work with respect to reading from
|
||||
// registers whose values may change between the individual byte reads.
|
||||
// (May not be worth emulating if it could possibly trigger problems in games)
|
||||
|
||||
#include "ss.h"
|
||||
#include "sound.h"
|
||||
#include "scu.h"
|
||||
#include "cdb.h"
|
||||
|
||||
#include "m68k/m68k.h"
|
||||
|
||||
namespace MDFN_IEN_SS
|
||||
{
|
||||
|
||||
#include "scsp.h"
|
||||
|
||||
static SS_SCSP SCSP;
|
||||
|
||||
static M68K SoundCPU(true);
|
||||
static int64 run_until_time; // 32.32
|
||||
static int32 next_scsp_time;
|
||||
|
||||
static uint32 clock_ratio;
|
||||
static sscpu_timestamp_t lastts;
|
||||
|
||||
static int16 IBuffer[1024][2];
|
||||
static uint32 IBufferCount;
|
||||
static int last_rate;
|
||||
static uint32 last_quality;
|
||||
|
||||
static INLINE void SCSP_SoundIntChanged(unsigned level)
|
||||
{
|
||||
SoundCPU.SetIPL(level);
|
||||
}
|
||||
|
||||
static INLINE void SCSP_MainIntChanged(bool state)
|
||||
{
|
||||
#ifndef MDFN_SSFPLAY_COMPILE
|
||||
SCU_SetInt(SCU_INT_SCSP, state);
|
||||
#endif
|
||||
}
|
||||
|
||||
#include "scsp.inc"
|
||||
|
||||
//
|
||||
//
|
||||
template <typename T>
|
||||
static MDFN_FASTCALL T SoundCPU_BusRead(uint32 A);
|
||||
|
||||
static MDFN_FASTCALL uint16 SoundCPU_BusReadInstr(uint32 A);
|
||||
|
||||
template <typename T>
|
||||
static MDFN_FASTCALL void SoundCPU_BusWrite(uint32 A, T V);
|
||||
|
||||
static MDFN_FASTCALL void SoundCPU_BusRMW(uint32 A, uint8(MDFN_FASTCALL *cb)(M68K *, uint8));
|
||||
static MDFN_FASTCALL unsigned SoundCPU_BusIntAck(uint8 level);
|
||||
static MDFN_FASTCALL void SoundCPU_BusRESET(bool state);
|
||||
//
|
||||
//
|
||||
|
||||
void SOUND_Init(void)
|
||||
{
|
||||
memset(IBuffer, 0, sizeof(IBuffer));
|
||||
IBufferCount = 0;
|
||||
|
||||
last_rate = -1;
|
||||
last_quality = ~0U;
|
||||
|
||||
run_until_time = 0;
|
||||
next_scsp_time = 0;
|
||||
lastts = 0;
|
||||
|
||||
SoundCPU.BusRead8 = SoundCPU_BusRead<uint8>;
|
||||
SoundCPU.BusRead16 = SoundCPU_BusRead<uint16>;
|
||||
|
||||
SoundCPU.BusWrite8 = SoundCPU_BusWrite<uint8>;
|
||||
SoundCPU.BusWrite16 = SoundCPU_BusWrite<uint16>;
|
||||
|
||||
SoundCPU.BusReadInstr = SoundCPU_BusReadInstr;
|
||||
|
||||
SoundCPU.BusRMW = SoundCPU_BusRMW;
|
||||
|
||||
SoundCPU.BusIntAck = SoundCPU_BusIntAck;
|
||||
SoundCPU.BusRESET = SoundCPU_BusRESET;
|
||||
|
||||
#ifndef MDFN_SSFPLAY_COMPILE
|
||||
SoundCPU.DBG_Warning = SS_DBG_Wrap<SS_DBG_WARNING | SS_DBG_M68K>;
|
||||
SoundCPU.DBG_Verbose = SS_DBG_Wrap<SS_DBG_M68K>;
|
||||
#endif
|
||||
|
||||
SS_SetPhysMemMap(0x05A00000, 0x05A7FFFF, SCSP.GetRAMPtr(), 0x80000, true);
|
||||
// TODO: MEM4B: SS_SetPhysMemMap(0x05A00000, 0x05AFFFFF, SCSP.GetRAMPtr(), 0x40000, true);
|
||||
AddMemoryDomain("Sound Ram", SCSP.GetRAMPtr(), 0x100000, MEMORYAREA_FLAGS_WRITABLE | MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_WORDSIZE2);
|
||||
}
|
||||
|
||||
uint8 SOUND_PeekRAM(uint32 A)
|
||||
{
|
||||
return ne16_rbo_be<uint8>(SCSP.GetRAMPtr(), A & 0x7FFFF);
|
||||
}
|
||||
|
||||
void SOUND_PokeRAM(uint32 A, uint8 V)
|
||||
{
|
||||
ne16_wbo_be<uint8>(SCSP.GetRAMPtr(), A & 0x7FFFF, V);
|
||||
}
|
||||
|
||||
void SOUND_ResetTS(void)
|
||||
{
|
||||
next_scsp_time -= SoundCPU.timestamp;
|
||||
run_until_time -= (int64)SoundCPU.timestamp << 32;
|
||||
SoundCPU.timestamp = 0;
|
||||
|
||||
lastts = 0;
|
||||
}
|
||||
|
||||
void SOUND_Reset(bool powering_up)
|
||||
{
|
||||
SCSP.Reset(powering_up);
|
||||
SoundCPU.Reset(powering_up);
|
||||
}
|
||||
|
||||
void SOUND_Reset68K(void)
|
||||
{
|
||||
SoundCPU.Reset(false);
|
||||
}
|
||||
|
||||
void SOUND_Set68KActive(bool active)
|
||||
{
|
||||
SoundCPU.SetExtHalted(!active);
|
||||
}
|
||||
|
||||
uint16 SOUND_Read16(uint32 A)
|
||||
{
|
||||
uint16 ret;
|
||||
|
||||
SCSP.RW<uint16, false>(A, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SOUND_Write8(uint32 A, uint8 V)
|
||||
{
|
||||
SCSP.RW<uint8, true>(A, V);
|
||||
}
|
||||
|
||||
void SOUND_Write16(uint32 A, uint16 V)
|
||||
{
|
||||
SCSP.RW<uint16, true>(A, V);
|
||||
}
|
||||
|
||||
static NO_INLINE void RunSCSP(void)
|
||||
{
|
||||
CDB_GetCDDA(SCSP.GetEXTSPtr());
|
||||
//
|
||||
//
|
||||
int16 *const bp = IBuffer[IBufferCount];
|
||||
SCSP.RunSample(bp);
|
||||
//bp[0] = rand();
|
||||
//bp[1] = rand();
|
||||
bp[0] = (bp[0] * 27 + 16) >> 5;
|
||||
bp[1] = (bp[1] * 27 + 16) >> 5;
|
||||
|
||||
IBufferCount = (IBufferCount + 1) & 1023;
|
||||
next_scsp_time += 256;
|
||||
}
|
||||
|
||||
// Ratio between SH-2 clock and 68K clock (sound clock / 2)
|
||||
void SOUND_SetClockRatio(uint32 ratio)
|
||||
{
|
||||
clock_ratio = ratio;
|
||||
}
|
||||
|
||||
sscpu_timestamp_t SOUND_Update(sscpu_timestamp_t timestamp)
|
||||
{
|
||||
run_until_time += ((uint64)(timestamp - lastts) * clock_ratio);
|
||||
lastts = timestamp;
|
||||
//
|
||||
//
|
||||
if (MDFN_LIKELY(SoundCPU.timestamp < (run_until_time >> 32)))
|
||||
{
|
||||
do
|
||||
{
|
||||
int32 next_time = std::min<int32>(next_scsp_time, run_until_time >> 32);
|
||||
|
||||
SoundCPU.Run(next_time);
|
||||
|
||||
if (SoundCPU.timestamp >= next_scsp_time)
|
||||
RunSCSP();
|
||||
} while (MDFN_LIKELY(SoundCPU.timestamp < (run_until_time >> 32)));
|
||||
}
|
||||
else
|
||||
{
|
||||
while (next_scsp_time < (run_until_time >> 32))
|
||||
RunSCSP();
|
||||
}
|
||||
|
||||
return timestamp + 128; // FIXME
|
||||
}
|
||||
|
||||
void SOUND_StartFrame(double rate, uint32 quality)
|
||||
{
|
||||
if ((int)rate != last_rate || quality != last_quality)
|
||||
{
|
||||
int err = 0;
|
||||
last_rate = (int)rate;
|
||||
last_quality = quality;
|
||||
}
|
||||
}
|
||||
|
||||
int32 SOUND_FlushOutput(int16 *SoundBuf, const int32 SoundBufMaxSize, const bool reverse)
|
||||
{
|
||||
if (SoundBuf && reverse)
|
||||
{
|
||||
for (unsigned lr = 0; lr < 2; lr++)
|
||||
{
|
||||
int16 *p0 = &IBuffer[0][lr];
|
||||
int16 *p1 = &IBuffer[IBufferCount - 1][lr];
|
||||
unsigned count = IBufferCount >> 1;
|
||||
|
||||
while (MDFN_LIKELY(count--))
|
||||
{
|
||||
std::swap(*p0, *p1);
|
||||
|
||||
p0 += 2;
|
||||
p1 -= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (last_rate == 44100)
|
||||
{
|
||||
int32 ret = IBufferCount;
|
||||
|
||||
memcpy(SoundBuf, IBuffer, IBufferCount * 2 * sizeof(int16));
|
||||
IBufferCount = 0;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
IBufferCount = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// TODO: test masks.
|
||||
//
|
||||
template <typename T>
|
||||
static MDFN_FASTCALL T SoundCPU_BusRead(uint32 A)
|
||||
{
|
||||
T ret;
|
||||
|
||||
SoundCPU.timestamp += 4;
|
||||
|
||||
if (MDFN_UNLIKELY(SoundCPU.timestamp >= next_scsp_time))
|
||||
RunSCSP();
|
||||
|
||||
SCSP.RW<T, false>(A & 0x1FFFFF, ret);
|
||||
|
||||
SoundCPU.timestamp += 2;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static MDFN_FASTCALL uint16 SoundCPU_BusReadInstr(uint32 A)
|
||||
{
|
||||
uint16 ret;
|
||||
|
||||
SoundCPU.timestamp += 4;
|
||||
|
||||
//if(MDFN_UNLIKELY(SoundCPU.timestamp >= next_scsp_time))
|
||||
// RunSCSP();
|
||||
|
||||
SCSP.RW<uint16, false>(A & 0x1FFFFF, ret);
|
||||
|
||||
SoundCPU.timestamp += 2;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static MDFN_FASTCALL void SoundCPU_BusWrite(uint32 A, T V)
|
||||
{
|
||||
if (MDFN_UNLIKELY(SoundCPU.timestamp >= next_scsp_time))
|
||||
RunSCSP();
|
||||
|
||||
SoundCPU.timestamp += 2;
|
||||
SCSP.RW<T, true>(A & 0x1FFFFF, V);
|
||||
SoundCPU.timestamp += 2;
|
||||
}
|
||||
|
||||
static MDFN_FASTCALL void SoundCPU_BusRMW(uint32 A, uint8(MDFN_FASTCALL *cb)(M68K *, uint8))
|
||||
{
|
||||
uint8 tmp;
|
||||
|
||||
SoundCPU.timestamp += 4;
|
||||
|
||||
if (MDFN_UNLIKELY(SoundCPU.timestamp >= next_scsp_time))
|
||||
RunSCSP();
|
||||
|
||||
SCSP.RW<uint8, false>(A & 0x1FFFFF, tmp);
|
||||
|
||||
tmp = cb(&SoundCPU, tmp);
|
||||
|
||||
SoundCPU.timestamp += 6;
|
||||
|
||||
SCSP.RW<uint8, true>(A & 0x1FFFFF, tmp);
|
||||
|
||||
SoundCPU.timestamp += 2;
|
||||
}
|
||||
|
||||
static MDFN_FASTCALL unsigned SoundCPU_BusIntAck(uint8 level)
|
||||
{
|
||||
return M68K::BUS_INT_ACK_AUTO;
|
||||
}
|
||||
|
||||
static MDFN_FASTCALL void SoundCPU_BusRESET(bool state)
|
||||
{
|
||||
//SS_DBG(SS_DBG_WARNING, "[M68K] RESET: %d @ time %d\n", state, SoundCPU.timestamp);
|
||||
if (state)
|
||||
{
|
||||
SoundCPU.Reset(false);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 SOUND_GetSCSPRegister(const unsigned id, char *const special, const uint32 special_len)
|
||||
{
|
||||
return SCSP.GetRegister(id, special, special_len);
|
||||
}
|
||||
|
||||
void SOUND_SetSCSPRegister(const unsigned id, const uint32 value)
|
||||
{
|
||||
SCSP.SetRegister(id, value);
|
||||
}
|
||||
}
|
||||
|
|
2572
waterbox/ss/ss.cpp
2572
waterbox/ss/ss.cpp
File diff suppressed because it is too large
Load Diff
1778
waterbox/ss/vdp1.cpp
1778
waterbox/ss/vdp1.cpp
File diff suppressed because it is too large
Load Diff
1860
waterbox/ss/vdp2.cpp
1860
waterbox/ss/vdp2.cpp
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue