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;
|
2014-05-30 22:31:16 +00:00
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using Newtonsoft.Json;
|
2014-05-30 22:59:13 +00:00
|
|
|
|
using System.Runtime.InteropServices;
|
2014-05-30 05:09:54 +00:00
|
|
|
|
|
|
|
|
|
namespace BizHawk.Emulation.Cores.WonderSwan
|
|
|
|
|
{
|
2014-11-10 01:01:01 +00:00
|
|
|
|
[CoreAttributes("Cygne/Mednafen", "Dox", true, true, "0.9.36.5", "http://mednafen.sourceforge.net/")]
|
2014-11-30 16:42:58 +00:00
|
|
|
|
public class WonderSwan : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam, IStatable,
|
2014-11-30 20:29:30 +00:00
|
|
|
|
IInputPollable, IDebuggable, ISettable<WonderSwan.Settings, WonderSwan.SyncSettings>
|
2014-05-30 05:09:54 +00:00
|
|
|
|
{
|
|
|
|
|
#region Controller
|
|
|
|
|
|
|
|
|
|
public static readonly ControllerDefinition WonderSwanController = new ControllerDefinition
|
|
|
|
|
{
|
|
|
|
|
Name = "WonderSwan Controller",
|
2014-06-04 23:26:57 +00:00
|
|
|
|
BoolButtons =
|
|
|
|
|
{
|
2014-06-07 01:26:16 +00:00
|
|
|
|
"P1 X1",
|
|
|
|
|
"P1 X2",
|
|
|
|
|
"P1 X3",
|
|
|
|
|
"P1 X4",
|
|
|
|
|
"P1 Y1",
|
|
|
|
|
"P1 Y2",
|
|
|
|
|
"P1 Y3",
|
|
|
|
|
"P1 Y4",
|
2014-06-04 23:26:57 +00:00
|
|
|
|
"P1 Start",
|
|
|
|
|
"P1 B",
|
|
|
|
|
"P1 A",
|
|
|
|
|
|
2014-06-07 01:26:16 +00:00
|
|
|
|
"P2 X1",
|
|
|
|
|
"P2 X2",
|
|
|
|
|
"P2 X3",
|
|
|
|
|
"P2 X4",
|
|
|
|
|
"P2 Y1",
|
|
|
|
|
"P2 Y2",
|
|
|
|
|
"P2 Y3",
|
|
|
|
|
"P2 Y4",
|
2014-06-04 23:26:57 +00:00
|
|
|
|
"P2 Start",
|
|
|
|
|
"P2 B",
|
|
|
|
|
"P2 A",
|
|
|
|
|
|
|
|
|
|
"Power",
|
|
|
|
|
"Rotate"
|
|
|
|
|
}
|
2014-05-30 05:09:54 +00:00
|
|
|
|
};
|
|
|
|
|
public ControllerDefinition ControllerDefinition { get { return WonderSwanController; } }
|
|
|
|
|
public IController Controller { get; set; }
|
|
|
|
|
|
|
|
|
|
BizSwan.Buttons GetButtons()
|
|
|
|
|
{
|
|
|
|
|
BizSwan.Buttons ret = 0;
|
2014-06-07 01:26:16 +00:00
|
|
|
|
if (Controller["P1 X1"]) ret |= BizSwan.Buttons.X1;
|
|
|
|
|
if (Controller["P1 X2"]) ret |= BizSwan.Buttons.X2;
|
|
|
|
|
if (Controller["P1 X3"]) ret |= BizSwan.Buttons.X3;
|
|
|
|
|
if (Controller["P1 X4"]) ret |= BizSwan.Buttons.X4;
|
|
|
|
|
if (Controller["P1 Y1"]) ret |= BizSwan.Buttons.Y1;
|
|
|
|
|
if (Controller["P1 Y2"]) ret |= BizSwan.Buttons.Y2;
|
|
|
|
|
if (Controller["P1 Y3"]) ret |= BizSwan.Buttons.Y3;
|
|
|
|
|
if (Controller["P1 Y4"]) ret |= BizSwan.Buttons.Y4;
|
2014-06-04 23:26:57 +00:00
|
|
|
|
if (Controller["P1 Start"]) ret |= BizSwan.Buttons.Start;
|
|
|
|
|
if (Controller["P1 B"]) ret |= BizSwan.Buttons.B;
|
|
|
|
|
if (Controller["P1 A"]) ret |= BizSwan.Buttons.A;
|
|
|
|
|
|
2014-06-07 01:26:16 +00:00
|
|
|
|
if (Controller["P2 X1"]) ret |= BizSwan.Buttons.R_X1;
|
|
|
|
|
if (Controller["P2 X2"]) ret |= BizSwan.Buttons.R_X2;
|
|
|
|
|
if (Controller["P2 X3"]) ret |= BizSwan.Buttons.R_X3;
|
|
|
|
|
if (Controller["P2 X4"]) ret |= BizSwan.Buttons.R_X4;
|
|
|
|
|
if (Controller["P2 Y1"]) ret |= BizSwan.Buttons.R_Y1;
|
|
|
|
|
if (Controller["P2 Y2"]) ret |= BizSwan.Buttons.R_Y2;
|
|
|
|
|
if (Controller["P2 Y3"]) ret |= BizSwan.Buttons.R_Y3;
|
|
|
|
|
if (Controller["P2 Y4"]) ret |= BizSwan.Buttons.R_Y4;
|
2014-06-04 23:26:57 +00:00
|
|
|
|
if (Controller["P2 Start"]) ret |= BizSwan.Buttons.R_Start;
|
|
|
|
|
if (Controller["P2 B"]) ret |= BizSwan.Buttons.R_B;
|
|
|
|
|
if (Controller["P2 A"]) ret |= BizSwan.Buttons.R_A;
|
|
|
|
|
|
2014-06-04 02:03:40 +00:00
|
|
|
|
if (Controller["Rotate"]) ret |= BizSwan.Buttons.Rotate;
|
2014-05-30 05:09:54 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2014-08-23 19:06:37 +00:00
|
|
|
|
[CoreConstructor("WSWAN")]
|
2014-09-12 15:39:04 +00:00
|
|
|
|
public WonderSwan(CoreComm comm, byte[] file, bool deterministic, object Settings, object SyncSettings)
|
2014-05-30 05:09:54 +00:00
|
|
|
|
{
|
2014-12-04 03:38:30 +00:00
|
|
|
|
ServiceProvider = new BasicServiceProvider(this);
|
2014-05-30 22:31:16 +00:00
|
|
|
|
CoreComm = comm;
|
|
|
|
|
_Settings = (Settings)Settings ?? new Settings();
|
|
|
|
|
_SyncSettings = (SyncSettings)SyncSettings ?? new SyncSettings();
|
|
|
|
|
|
2014-08-23 19:06:37 +00:00
|
|
|
|
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
|
|
|
|
|
{
|
2014-05-30 22:31:16 +00:00
|
|
|
|
var ss = _SyncSettings.GetNativeSettings();
|
2014-08-23 19:06:37 +00:00
|
|
|
|
if (deterministic)
|
2014-05-31 05:57:18 +00:00
|
|
|
|
ss.userealtime = false;
|
2014-05-30 05:09:54 +00:00
|
|
|
|
|
2014-05-30 20:53:52 +00:00
|
|
|
|
bool rotate = false;
|
|
|
|
|
|
2014-09-12 15:39:04 +00:00
|
|
|
|
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
|
|
|
|
|
|
|
|
|
saverambuff = new byte[BizSwan.bizswan_saveramsize(Core)];
|
2014-05-30 20:53:52 +00:00
|
|
|
|
|
|
|
|
|
InitVideo(rotate);
|
2014-05-30 22:31:16 +00:00
|
|
|
|
PutSettings(_Settings);
|
2014-05-30 22:59:13 +00:00
|
|
|
|
SetMemoryDomains();
|
2014-05-31 05:57:18 +00:00
|
|
|
|
|
|
|
|
|
savebuff = new byte[BizSwan.bizswan_binstatesize(Core)];
|
|
|
|
|
savebuff2 = new byte[savebuff.Length + 13];
|
2014-06-19 15:57:07 +00:00
|
|
|
|
|
|
|
|
|
InitDebugCallbacks();
|
2014-05-30 05:09:54 +00:00
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
Dispose();
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 03:38:30 +00:00
|
|
|
|
public IEmulatorServiceProvider ServiceProvider { get; private set; }
|
|
|
|
|
|
2014-12-05 00:05:40 +00:00
|
|
|
|
public ITracer Tracer
|
|
|
|
|
{
|
|
|
|
|
[FeatureNotImplemented]
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
|
2014-06-04 02:03:40 +00:00
|
|
|
|
bool rotate = false;
|
2014-05-30 05:09:54 +00:00
|
|
|
|
int soundbuffsize = sbuff.Length;
|
2014-06-04 02:03:40 +00:00
|
|
|
|
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;
|
2014-06-04 02:03:40 +00:00
|
|
|
|
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; }
|
|
|
|
|
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 SaveRam
|
|
|
|
|
|
2014-05-30 16:50:58 +00:00
|
|
|
|
byte[] saverambuff;
|
|
|
|
|
|
2014-08-13 17:52:13 +00:00
|
|
|
|
public byte[] CloneSaveRam()
|
2014-05-30 05:09:54 +00:00
|
|
|
|
{
|
2014-05-30 16:50:58 +00:00
|
|
|
|
if (!BizSwan.bizswan_saveramsave(Core, saverambuff, saverambuff.Length))
|
|
|
|
|
throw new InvalidOperationException("bizswan_saveramsave() returned false!");
|
2014-08-13 17:52:13 +00:00
|
|
|
|
return (byte[])saverambuff.Clone();
|
2014-05-30 05:09:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void StoreSaveRam(byte[] data)
|
|
|
|
|
{
|
2014-05-30 16:50:58 +00:00
|
|
|
|
if (!BizSwan.bizswan_saveramload(Core, data, data.Length))
|
|
|
|
|
throw new InvalidOperationException("bizswan_saveramload() returned false!");
|
2014-05-30 05:09:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool SaveRamModified
|
|
|
|
|
{
|
2014-05-30 16:50:58 +00:00
|
|
|
|
get { return BizSwan.bizswan_saveramsize(Core) > 0; }
|
2014-05-30 05:09:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Savestates
|
|
|
|
|
|
2014-05-31 05:57:18 +00:00
|
|
|
|
JsonSerializer ser = new JsonSerializer() { Formatting = Formatting.Indented };
|
|
|
|
|
|
|
|
|
|
class TextStateData
|
|
|
|
|
{
|
|
|
|
|
public int Frame;
|
|
|
|
|
public int LagCount;
|
|
|
|
|
public bool IsLagFrame;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-30 05:09:54 +00:00
|
|
|
|
public void SaveStateText(TextWriter writer)
|
|
|
|
|
{
|
2014-05-31 05:57:18 +00:00
|
|
|
|
var s = new TextState<TextStateData>();
|
|
|
|
|
s.Prepare();
|
2014-06-04 18:53:57 +00:00
|
|
|
|
var ff = s.GetFunctionPointersSave();
|
2014-05-31 05:57:18 +00:00
|
|
|
|
BizSwan.bizswan_txtstatesave(Core, ref ff);
|
|
|
|
|
s.ExtraData.IsLagFrame = IsLagFrame;
|
|
|
|
|
s.ExtraData.LagCount = LagCount;
|
|
|
|
|
s.ExtraData.Frame = Frame;
|
|
|
|
|
|
|
|
|
|
ser.Serialize(writer, s);
|
|
|
|
|
// write extra copy of stuff we don't use
|
|
|
|
|
writer.WriteLine();
|
|
|
|
|
writer.WriteLine("Frame {0}", Frame);
|
2014-05-30 05:09:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void LoadStateText(TextReader reader)
|
|
|
|
|
{
|
2014-05-31 05:57:18 +00:00
|
|
|
|
var s = (TextState<TextStateData>)ser.Deserialize(reader, typeof(TextState<TextStateData>));
|
|
|
|
|
s.Prepare();
|
2014-06-04 18:53:57 +00:00
|
|
|
|
var ff = s.GetFunctionPointersLoad();
|
2014-05-31 05:57:18 +00:00
|
|
|
|
BizSwan.bizswan_txtstateload(Core, ref ff);
|
|
|
|
|
IsLagFrame = s.ExtraData.IsLagFrame;
|
|
|
|
|
LagCount = s.ExtraData.LagCount;
|
|
|
|
|
Frame = s.ExtraData.Frame;
|
2014-05-30 05:09:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-31 05:57:18 +00:00
|
|
|
|
byte[] savebuff;
|
|
|
|
|
byte[] savebuff2;
|
|
|
|
|
|
2014-05-30 05:09:54 +00:00
|
|
|
|
public void SaveStateBinary(BinaryWriter writer)
|
|
|
|
|
{
|
2014-05-31 05:57:18 +00:00
|
|
|
|
if (!BizSwan.bizswan_binstatesave(Core, savebuff, savebuff.Length))
|
|
|
|
|
throw new InvalidOperationException("bizswan_binstatesave() returned false!");
|
|
|
|
|
writer.Write(savebuff.Length);
|
|
|
|
|
writer.Write(savebuff);
|
|
|
|
|
|
|
|
|
|
// other variables
|
|
|
|
|
writer.Write(IsLagFrame);
|
|
|
|
|
writer.Write(LagCount);
|
|
|
|
|
writer.Write(Frame);
|
2014-05-30 05:09:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void LoadStateBinary(BinaryReader reader)
|
|
|
|
|
{
|
2014-05-31 05:57:18 +00:00
|
|
|
|
int length = reader.ReadInt32();
|
|
|
|
|
if (length != savebuff.Length)
|
|
|
|
|
throw new InvalidOperationException("Save buffer size mismatch!");
|
|
|
|
|
reader.Read(savebuff, 0, length);
|
|
|
|
|
if (!BizSwan.bizswan_binstateload(Core, savebuff, savebuff.Length))
|
|
|
|
|
throw new InvalidOperationException("bizswan_binstateload() returned false!");
|
|
|
|
|
|
|
|
|
|
// other variables
|
|
|
|
|
IsLagFrame = reader.ReadBoolean();
|
|
|
|
|
LagCount = reader.ReadInt32();
|
|
|
|
|
Frame = reader.ReadInt32();
|
2014-05-30 05:09:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public byte[] SaveStateBinary()
|
|
|
|
|
{
|
2014-05-31 05:57:18 +00:00
|
|
|
|
var ms = new MemoryStream(savebuff2, true);
|
|
|
|
|
var bw = new BinaryWriter(ms);
|
|
|
|
|
SaveStateBinary(bw);
|
|
|
|
|
bw.Flush();
|
2014-08-08 20:01:09 +00:00
|
|
|
|
if (ms.Position != savebuff2.Length)
|
|
|
|
|
throw new InvalidOperationException();
|
2014-05-31 05:57:18 +00:00
|
|
|
|
ms.Close();
|
|
|
|
|
return savebuff2;
|
2014-05-30 05:09:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool BinarySaveStatesPreferred
|
|
|
|
|
{
|
|
|
|
|
get { return true; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Debugging
|
|
|
|
|
|
2014-05-30 22:59:13 +00:00
|
|
|
|
unsafe void SetMemoryDomains()
|
2014-05-30 05:09:54 +00:00
|
|
|
|
{
|
2014-05-30 22:59:13 +00:00
|
|
|
|
var mmd = new List<MemoryDomain>();
|
|
|
|
|
for (int i = 0; ; i++)
|
|
|
|
|
{
|
|
|
|
|
IntPtr name;
|
|
|
|
|
int size;
|
|
|
|
|
IntPtr data;
|
|
|
|
|
if (!BizSwan.bizswan_getmemoryarea(Core, i, out name, out size, out data))
|
|
|
|
|
break;
|
|
|
|
|
if (size == 0)
|
|
|
|
|
continue;
|
|
|
|
|
string sname = Marshal.PtrToStringAnsi(name);
|
2014-08-15 21:21:17 +00:00
|
|
|
|
mmd.Add(MemoryDomain.FromIntPtr(sname, size, MemoryDomain.Endian.Little, data));
|
2014-05-30 22:59:13 +00:00
|
|
|
|
}
|
|
|
|
|
MemoryDomains = new MemoryDomainList(mmd, 0);
|
2014-05-30 05:09:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-05 02:21:10 +00:00
|
|
|
|
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-05-30 22:59:13 +00:00
|
|
|
|
|
2014-12-05 02:21:10 +00:00
|
|
|
|
public MemoryDomainList MemoryDomains { get; private set; }
|
|
|
|
|
|
2014-11-23 16:22:02 +00:00
|
|
|
|
public IDictionary<string, int> GetCpuFlagsAndRegisters()
|
2014-05-30 05:09:54 +00:00
|
|
|
|
{
|
2014-05-30 22:59:13 +00:00
|
|
|
|
var ret = new Dictionary<string, int>();
|
|
|
|
|
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)] = (int)val;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
2014-05-30 05:09:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-11-24 01:17:05 +00:00
|
|
|
|
[FeatureNotImplemented]
|
2014-05-31 17:03:21 +00:00
|
|
|
|
public void SetCpuRegister(string register, int value)
|
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
2014-12-05 01:56:45 +00:00
|
|
|
|
MemoryCallbacks.CallRead(addr);
|
2014-06-19 15:57:07 +00:00
|
|
|
|
}
|
|
|
|
|
void WriteCallback(uint addr)
|
|
|
|
|
{
|
2014-12-05 01:56:45 +00:00
|
|
|
|
MemoryCallbacks.CallWrite(addr);
|
2014-06-19 15:57:07 +00:00
|
|
|
|
}
|
|
|
|
|
void ExecCallback(uint addr)
|
|
|
|
|
{
|
2014-12-05 01:56:45 +00:00
|
|
|
|
MemoryCallbacks.CallExecute(addr);
|
2014-06-19 15:57:07 +00:00
|
|
|
|
}
|
|
|
|
|
void ButtonCallback()
|
|
|
|
|
{
|
2014-12-04 00:43:12 +00:00
|
|
|
|
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);
|
2014-12-04 01:22:34 +00:00
|
|
|
|
_inputCallbacks.ActiveChanged += SetInputCallback;
|
2014-12-05 02:21:10 +00:00
|
|
|
|
_memorycallbacks.ActiveChanged += SetMemoryCallbacks;
|
2014-12-04 01:22:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SetInputCallback()
|
|
|
|
|
{
|
2014-12-05 02:21:10 +00:00
|
|
|
|
BizSwan.bizswan_setbuttoncallback(Core, InputCallbacks.Any() ? ButtonCallbackD : null);
|
2014-06-19 15:57:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 01:22:34 +00:00
|
|
|
|
void SetMemoryCallbacks()
|
2014-06-19 15:57:07 +00:00
|
|
|
|
{
|
|
|
|
|
BizSwan.bizswan_setmemorycallbacks(Core,
|
2014-12-05 01:56:45 +00:00
|
|
|
|
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 Settings
|
|
|
|
|
|
2014-05-30 22:31:16 +00:00
|
|
|
|
Settings _Settings;
|
|
|
|
|
SyncSettings _SyncSettings;
|
|
|
|
|
|
|
|
|
|
public class Settings
|
|
|
|
|
{
|
2014-07-20 00:56:37 +00:00
|
|
|
|
[DisplayName("Background Layer")]
|
2014-05-30 22:31:16 +00:00
|
|
|
|
[Description("True to display the selected layer.")]
|
|
|
|
|
[DefaultValue(true)]
|
|
|
|
|
public bool EnableBG { get; set; }
|
2014-07-20 00:56:37 +00:00
|
|
|
|
|
|
|
|
|
[DisplayName("Foreground Layer")]
|
2014-05-30 22:31:16 +00:00
|
|
|
|
[Description("True to display the selected layer.")]
|
|
|
|
|
[DefaultValue(true)]
|
|
|
|
|
public bool EnableFG { get; set; }
|
2014-07-20 00:56:37 +00:00
|
|
|
|
|
|
|
|
|
[DisplayName("Sprites Layer")]
|
2014-05-30 22:31:16 +00:00
|
|
|
|
[Description("True to display the selected layer.")]
|
|
|
|
|
[DefaultValue(true)]
|
|
|
|
|
public bool EnableSprites { get; set; }
|
|
|
|
|
|
|
|
|
|
public BizSwan.Settings GetNativeSettings()
|
|
|
|
|
{
|
|
|
|
|
var ret = new BizSwan.Settings();
|
|
|
|
|
if (EnableBG) ret.LayerMask |= BizSwan.LayerFlags.BG;
|
|
|
|
|
if (EnableFG) ret.LayerMask |= BizSwan.LayerFlags.FG;
|
|
|
|
|
if (EnableSprites) ret.LayerMask |= BizSwan.LayerFlags.Sprite;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Settings()
|
|
|
|
|
{
|
|
|
|
|
SettingsUtil.SetDefaultValues(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Settings Clone()
|
|
|
|
|
{
|
|
|
|
|
return (Settings)MemberwiseClone();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class SyncSettings
|
|
|
|
|
{
|
2014-07-20 00:56:37 +00:00
|
|
|
|
[DisplayName("Initial Time")]
|
2014-05-30 22:31:16 +00:00
|
|
|
|
[Description("Initial time of emulation. Only relevant when UseRealTime is false.")]
|
|
|
|
|
[DefaultValue(typeof(DateTime), "2010-01-01")]
|
|
|
|
|
public DateTime InitialTime { get; set; }
|
|
|
|
|
|
|
|
|
|
[Description("Your birthdate. Stored in EEPROM and used by some games.")]
|
|
|
|
|
[DefaultValue(typeof(DateTime), "1968-05-13")]
|
|
|
|
|
public DateTime BirthDate { get; set; }
|
|
|
|
|
|
|
|
|
|
[Description("True to emulate a color system.")]
|
|
|
|
|
[DefaultValue(true)]
|
|
|
|
|
public bool Color { get; set; }
|
|
|
|
|
|
2014-07-20 00:56:37 +00:00
|
|
|
|
[DisplayName("Use RealTime")]
|
2014-05-30 22:31:16 +00:00
|
|
|
|
[Description("If true, RTC clock will be based off of real time instead of emulated time. Ignored (set to false) when recording a movie.")]
|
|
|
|
|
[DefaultValue(false)]
|
|
|
|
|
public bool UseRealTime { get; set; }
|
|
|
|
|
|
|
|
|
|
[Description("Your gender. Stored in EEPROM and used by some games.")]
|
|
|
|
|
[DefaultValue(BizSwan.Gender.Female)]
|
|
|
|
|
public BizSwan.Gender Gender { get; set; }
|
|
|
|
|
|
|
|
|
|
[Description("Language to play games in. Most games ignore this.")]
|
|
|
|
|
[DefaultValue(BizSwan.Language.Japanese)]
|
|
|
|
|
public BizSwan.Language Language { get; set; }
|
|
|
|
|
|
2014-07-20 00:56:37 +00:00
|
|
|
|
[DisplayName("Blood Type")]
|
2014-05-30 22:31:16 +00:00
|
|
|
|
[Description("Your blood type. Stored in EEPROM and used by some games.")]
|
|
|
|
|
[DefaultValue(BizSwan.Bloodtype.AB)]
|
|
|
|
|
public BizSwan.Bloodtype BloodType { get; set; }
|
|
|
|
|
|
|
|
|
|
[Description("Your name. Stored in EEPROM and used by some games. Maximum of 16 characters")]
|
|
|
|
|
[DefaultValue("Lady Ashelia")]
|
|
|
|
|
public string Name { get; set; }
|
|
|
|
|
|
|
|
|
|
public BizSwan.SyncSettings GetNativeSettings()
|
|
|
|
|
{
|
|
|
|
|
var ret = new BizSwan.SyncSettings
|
|
|
|
|
{
|
|
|
|
|
color = Color,
|
|
|
|
|
userealtime = UseRealTime,
|
|
|
|
|
sex = Gender,
|
|
|
|
|
language = Language,
|
|
|
|
|
blood = BloodType
|
|
|
|
|
};
|
|
|
|
|
ret.SetName(Name);
|
|
|
|
|
ret.bday = (uint)BirthDate.Day;
|
|
|
|
|
ret.bmonth = (uint)BirthDate.Month;
|
|
|
|
|
ret.byear = (uint)BirthDate.Year;
|
|
|
|
|
ret.initialtime = (ulong)((InitialTime - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public SyncSettings()
|
|
|
|
|
{
|
|
|
|
|
SettingsUtil.SetDefaultValues(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public SyncSettings Clone()
|
|
|
|
|
{
|
|
|
|
|
return (SyncSettings)MemberwiseClone();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool NeedsReboot(SyncSettings x, SyncSettings y)
|
|
|
|
|
{
|
2014-08-03 21:36:38 +00:00
|
|
|
|
return !DeepEquality.DeepEquals(x, y);
|
2014-05-30 22:31:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-19 01:22:47 +00:00
|
|
|
|
public Settings GetSettings()
|
2014-05-30 05:09:54 +00:00
|
|
|
|
{
|
2014-05-30 22:31:16 +00:00
|
|
|
|
return _Settings.Clone();
|
2014-05-30 05:09:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-10-19 01:22:47 +00:00
|
|
|
|
public SyncSettings GetSyncSettings()
|
2014-05-30 05:09:54 +00:00
|
|
|
|
{
|
2014-05-30 22:31:16 +00:00
|
|
|
|
return _SyncSettings.Clone();
|
2014-05-30 05:09:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-10-19 01:22:47 +00:00
|
|
|
|
public bool PutSettings(Settings o)
|
2014-05-30 05:09:54 +00:00
|
|
|
|
{
|
2014-10-19 01:22:47 +00:00
|
|
|
|
_Settings = o;
|
2014-05-30 22:31:16 +00:00
|
|
|
|
var native = _Settings.GetNativeSettings();
|
|
|
|
|
BizSwan.bizswan_putsettings(Core, ref native);
|
2014-05-30 05:09:54 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-19 01:22:47 +00:00
|
|
|
|
public bool PutSyncSettings(SyncSettings o)
|
2014-05-30 05:09:54 +00:00
|
|
|
|
{
|
2014-10-19 01:22:47 +00:00
|
|
|
|
bool ret = SyncSettings.NeedsReboot(o, _SyncSettings);
|
|
|
|
|
_SyncSettings = o;
|
2014-05-30 22:31:16 +00:00
|
|
|
|
return ret;
|
2014-05-30 05:09:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region IVideoProvider
|
|
|
|
|
|
|
|
|
|
public IVideoProvider VideoProvider { get { return this; } }
|
|
|
|
|
|
2014-05-30 20:53:52 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-30 20:53:52 +00:00
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|