BizHawk/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs

243 lines
6.5 KiB
C#
Raw Normal View History

2014-05-30 05:09:54 +00:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using System.IO;
using Newtonsoft.Json;
using System.Runtime.InteropServices;
2014-05-30 05:09:54 +00:00
namespace BizHawk.Emulation.Cores.WonderSwan
{
[CoreAttributes("Cygne/Mednafen", "Dox", true, true, "0.9.36.5", "http://mednafen.sourceforge.net/")]
[ServiceNotApplicable(typeof(IDriveLight), typeof(IRegionable))]
public partial class WonderSwan : IEmulator, IVideoProvider, ISyncSoundProvider,
IInputPollable, IDebuggable
2014-05-30 05:09:54 +00:00
{
[CoreConstructor("WSWAN")]
public WonderSwan(CoreComm comm, byte[] file, bool deterministic, object Settings, object SyncSettings)
2014-05-30 05:09:54 +00:00
{
ServiceProvider = new BasicServiceProvider(this);
CoreComm = comm;
_Settings = (Settings)Settings ?? new Settings();
_SyncSettings = (SyncSettings)SyncSettings ?? new SyncSettings();
DeterministicEmulation = deterministic; // when true, remember to force the RTC flag!
2014-05-30 05:09:54 +00:00
Core = BizSwan.bizswan_new();
if (Core == IntPtr.Zero)
throw new InvalidOperationException("bizswan_new() returned NULL!");
try
{
var ss = _SyncSettings.GetNativeSettings();
if (deterministic)
2014-05-31 05:57:18 +00:00
ss.userealtime = false;
2014-05-30 05:09:54 +00:00
bool rotate = false;
if (!BizSwan.bizswan_load(Core, file, file.Length, ref ss, ref rotate))
2014-05-30 05:09:54 +00:00
throw new InvalidOperationException("bizswan_load() returned FALSE!");
CoreComm.VsyncNum = 3072000; // master CPU clock, also pixel clock
CoreComm.VsyncDen = (144 + 15) * (224 + 32); // 144 vislines, 15 vblank lines; 224 vispixels, 32 hblank pixels
2014-05-30 16:50:58 +00:00
InitISaveRam();
InitVideo(rotate);
PutSettings(_Settings);
InitIMemoryDomains();
2014-06-19 15:57:07 +00:00
InitIStatable();
2014-06-19 15:57:07 +00:00
InitDebugCallbacks();
2014-05-30 05:09:54 +00:00
}
catch
{
Dispose();
throw;
}
}
public IEmulatorServiceProvider ServiceProvider { get; private set; }
2014-05-30 05:09:54 +00:00
public void Dispose()
{
if (Core != IntPtr.Zero)
{
BizSwan.bizswan_delete(Core);
Core = IntPtr.Zero;
}
}
public void FrameAdvance(bool render, bool rendersound = true)
{
Frame++;
IsLagFrame = true;
if (Controller["Power"])
BizSwan.bizswan_reset(Core);
bool rotate = false;
2014-05-30 05:09:54 +00:00
int soundbuffsize = sbuff.Length;
IsLagFrame = BizSwan.bizswan_advance(Core, GetButtons(), !render, vbuff, sbuff, ref soundbuffsize, ref rotate);
2014-05-30 05:09:54 +00:00
if (soundbuffsize == sbuff.Length)
throw new Exception();
sbuffcontains = soundbuffsize;
InitVideo(rotate);
2014-05-30 05:09:54 +00:00
if (IsLagFrame)
LagCount++;
}
2014-05-30 16:50:58 +00:00
public CoreComm CoreComm { get; private set; }
public void ResetCounters()
{
Frame = 0;
IsLagFrame = false;
LagCount = 0;
}
2014-05-30 05:09:54 +00:00
IntPtr Core;
public int Frame { get; private set; }
public int LagCount { get; set; }
2014-05-30 05:09:54 +00:00
public bool IsLagFrame { get; private set; }
public string SystemId { get { return "WSWAN"; } }
2014-05-30 18:10:39 +00:00
public bool DeterministicEmulation { get; private set; }
2014-05-30 05:09:54 +00:00
public string BoardName { get { return null; } }
#region Debugging
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
public IInputCallbackSystem InputCallbacks { get { return _inputCallbacks; } }
private readonly MemoryCallbackSystem _memorycallbacks = new MemoryCallbackSystem();
public IMemoryCallbackSystem MemoryCallbacks { get { return _memorycallbacks; } }
2014-12-20 13:16:15 +00:00
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
2014-05-30 05:09:54 +00:00
{
2014-12-20 13:16:15 +00:00
var ret = new Dictionary<string, RegisterValue>();
for (int i = (int)BizSwan.NecRegsMin; i <= (int)BizSwan.NecRegsMax; i++)
{
BizSwan.NecRegs en = (BizSwan.NecRegs)i;
uint val = BizSwan.bizswan_getnecreg(Core, en);
ret[Enum.GetName(typeof(BizSwan.NecRegs), en)] = (ushort)val;
}
return ret;
2014-05-30 05:09:54 +00:00
}
[FeatureNotImplemented]
public void SetCpuRegister(string register, int value)
{
throw new NotImplementedException();
}
public bool CanStep(StepType type) { return false; }
[FeatureNotImplemented]
public void Step(StepType type) { throw new NotImplementedException(); }
2014-06-19 15:57:07 +00:00
BizSwan.MemoryCallback ReadCallbackD;
BizSwan.MemoryCallback WriteCallbackD;
BizSwan.MemoryCallback ExecCallbackD;
BizSwan.ButtonCallback ButtonCallbackD;
void ReadCallback(uint addr)
{
MemoryCallbacks.CallReads(addr);
2014-06-19 15:57:07 +00:00
}
void WriteCallback(uint addr)
{
MemoryCallbacks.CallWrites(addr);
2014-06-19 15:57:07 +00:00
}
void ExecCallback(uint addr)
{
MemoryCallbacks.CallExecutes(addr);
2014-06-19 15:57:07 +00:00
}
void ButtonCallback()
{
InputCallbacks.Call();
2014-06-19 15:57:07 +00:00
}
void InitDebugCallbacks()
{
ReadCallbackD = new BizSwan.MemoryCallback(ReadCallback);
WriteCallbackD = new BizSwan.MemoryCallback(WriteCallback);
ExecCallbackD = new BizSwan.MemoryCallback(ExecCallback);
ButtonCallbackD = new BizSwan.ButtonCallback(ButtonCallback);
_inputCallbacks.ActiveChanged += SetInputCallback;
_memorycallbacks.ActiveChanged += SetMemoryCallbacks;
}
void SetInputCallback()
{
BizSwan.bizswan_setbuttoncallback(Core, InputCallbacks.Any() ? ButtonCallbackD : null);
2014-06-19 15:57:07 +00:00
}
void SetMemoryCallbacks()
2014-06-19 15:57:07 +00:00
{
BizSwan.bizswan_setmemorycallbacks(Core,
MemoryCallbacks.HasReads ? ReadCallbackD : null,
MemoryCallbacks.HasWrites ? WriteCallbackD : null,
MemoryCallbacks.HasExecutes ? ExecCallbackD : null);
2014-06-19 15:57:07 +00:00
}
2014-05-30 05:09:54 +00:00
#endregion
#region IVideoProvider
void InitVideo(bool rotate)
{
if (rotate)
{
BufferWidth = 144;
BufferHeight = 224;
}
else
{
BufferWidth = 224;
BufferHeight = 144;
}
}
2014-05-30 05:09:54 +00:00
private int[] vbuff = new int[224 * 144];
public int[] GetVideoBuffer()
{
return vbuff;
}
public int VirtualWidth { get { return BufferWidth; } }
public int VirtualHeight { get { return BufferHeight; } }
public int BufferWidth { get; private set; }
public int BufferHeight { get; private set; }
2014-05-30 05:09:54 +00:00
public int BackgroundColor { get { return unchecked((int)0xff000000); } }
#endregion
#region ISoundProvider
private short[] sbuff = new short[1536];
private int sbuffcontains = 0;
public ISoundProvider SoundProvider { get { throw new InvalidOperationException(); } }
public ISyncSoundProvider SyncSoundProvider { get { return this; } }
public bool StartAsyncSound() { return false; }
public void EndAsyncSound() { }
public void GetSamples(out short[] samples, out int nsamp)
{
samples = sbuff;
nsamp = sbuffcontains;
}
public void DiscardSamples()
{
sbuffcontains = 0;
}
#endregion
}
}