saturnus: use waterboxcore

This commit is contained in:
nattthebear 2017-06-17 15:30:03 -04:00
parent c04beea4d0
commit 5a8fad73b9
16 changed files with 4554 additions and 4796 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff