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;
|
|
|
|
|
|
|
|
|
|
namespace BizHawk.Emulation.Cores.WonderSwan
|
|
|
|
|
{
|
|
|
|
|
[CoreAttributes("Mednafen/Cygne", "Dox", true, false)]
|
|
|
|
|
public class WonderSwan : IEmulator, IVideoProvider, ISyncSoundProvider
|
|
|
|
|
{
|
|
|
|
|
#region Controller
|
|
|
|
|
|
|
|
|
|
public static readonly ControllerDefinition WonderSwanController = new ControllerDefinition
|
|
|
|
|
{
|
|
|
|
|
Name = "WonderSwan Controller",
|
|
|
|
|
BoolButtons = { "Up X, Down X, Left X, Right X, Up Y, Down Y, Left Y, Right Y, Start, B, A, Power" }
|
|
|
|
|
};
|
|
|
|
|
public ControllerDefinition ControllerDefinition { get { return WonderSwanController; } }
|
|
|
|
|
public IController Controller { get; set; }
|
|
|
|
|
|
|
|
|
|
BizSwan.Buttons GetButtons()
|
|
|
|
|
{
|
|
|
|
|
BizSwan.Buttons ret = 0;
|
|
|
|
|
if (Controller["Up X"]) ret |= BizSwan.Buttons.UpX;
|
|
|
|
|
if (Controller["Down X"]) ret |= BizSwan.Buttons.DownX;
|
|
|
|
|
if (Controller["Left X"]) ret |= BizSwan.Buttons.LeftX;
|
|
|
|
|
if (Controller["Right X"]) ret |= BizSwan.Buttons.RightX;
|
|
|
|
|
if (Controller["Up Y"]) ret |= BizSwan.Buttons.UpY;
|
|
|
|
|
if (Controller["Down Y"]) ret |= BizSwan.Buttons.DownY;
|
|
|
|
|
if (Controller["Left Y"]) ret |= BizSwan.Buttons.LeftY;
|
|
|
|
|
if (Controller["Right Y"]) ret |= BizSwan.Buttons.RightY;
|
|
|
|
|
if (Controller["Start"]) ret |= BizSwan.Buttons.Start;
|
|
|
|
|
if (Controller["B"]) ret |= BizSwan.Buttons.B;
|
|
|
|
|
if (Controller["A"]) ret |= BizSwan.Buttons.A;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
public WonderSwan(CoreComm comm, byte[] rom)
|
|
|
|
|
{
|
|
|
|
|
this.CoreComm = comm;
|
|
|
|
|
Core = BizSwan.bizswan_new();
|
|
|
|
|
if (Core == IntPtr.Zero)
|
|
|
|
|
throw new InvalidOperationException("bizswan_new() returned NULL!");
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var ss = new BizSwan.Settings
|
|
|
|
|
{
|
|
|
|
|
sex = BizSwan.Gender.Male,
|
|
|
|
|
blood = BizSwan.Bloodtype.A,
|
|
|
|
|
language = BizSwan.Language.Japanese,
|
|
|
|
|
rotateinput = false, // TODO
|
|
|
|
|
bday = 5,
|
|
|
|
|
bmonth = 12,
|
|
|
|
|
byear = 1968
|
|
|
|
|
};
|
|
|
|
|
ss.SetName("LaForge");
|
|
|
|
|
|
|
|
|
|
if (!BizSwan.bizswan_load(Core, rom, rom.Length, ref ss))
|
|
|
|
|
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 05:09:54 +00:00
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
Dispose();
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
int soundbuffsize = sbuff.Length;
|
|
|
|
|
BizSwan.bizswan_advance(Core, GetButtons(), !render, vbuff, sbuff, ref soundbuffsize);
|
|
|
|
|
if (soundbuffsize == sbuff.Length)
|
|
|
|
|
throw new Exception();
|
|
|
|
|
sbuffcontains = soundbuffsize;
|
|
|
|
|
|
|
|
|
|
IsLagFrame = false; // TODO
|
|
|
|
|
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"; } }
|
|
|
|
|
public bool DeterministicEmulation { get { return true; } }
|
|
|
|
|
public string BoardName { get { return null; } }
|
|
|
|
|
|
|
|
|
|
#region SaveRam
|
|
|
|
|
|
2014-05-30 16:50:58 +00:00
|
|
|
|
byte[] saverambuff;
|
|
|
|
|
|
2014-05-30 05:09:54 +00:00
|
|
|
|
public byte[] ReadSaveRam()
|
|
|
|
|
{
|
2014-05-30 16:50:58 +00:00
|
|
|
|
if (!BizSwan.bizswan_saveramsave(Core, saverambuff, saverambuff.Length))
|
|
|
|
|
throw new InvalidOperationException("bizswan_saveramsave() returned false!");
|
|
|
|
|
return saverambuff;
|
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 void ClearSaveRam()
|
|
|
|
|
{
|
2014-05-30 16:50:58 +00:00
|
|
|
|
throw new InvalidOperationException("A new core starts with a clear saveram. Instantiate a new core if you want this.");
|
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; }
|
|
|
|
|
set { throw new InvalidOperationException(); }
|
2014-05-30 05:09:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Savestates
|
|
|
|
|
|
|
|
|
|
public void SaveStateText(TextWriter writer)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void LoadStateText(TextReader reader)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SaveStateBinary(BinaryWriter writer)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void LoadStateBinary(BinaryReader reader)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public byte[] SaveStateBinary()
|
|
|
|
|
{
|
|
|
|
|
return new byte[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool BinarySaveStatesPreferred
|
|
|
|
|
{
|
|
|
|
|
get { return true; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Debugging
|
|
|
|
|
|
|
|
|
|
public MemoryDomainList MemoryDomains
|
|
|
|
|
{
|
|
|
|
|
get { throw new NotImplementedException(); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Dictionary<string, int> GetCpuFlagsAndRegisters()
|
|
|
|
|
{
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Settings
|
|
|
|
|
|
|
|
|
|
public object GetSettings()
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public object GetSyncSettings()
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool PutSettings(object o)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool PutSyncSettings(object o)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region IVideoProvider
|
|
|
|
|
|
|
|
|
|
public IVideoProvider VideoProvider { get { return this; } }
|
|
|
|
|
|
|
|
|
|
private int[] vbuff = new int[224 * 144];
|
|
|
|
|
|
|
|
|
|
public int[] GetVideoBuffer()
|
|
|
|
|
{
|
|
|
|
|
return vbuff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int VirtualWidth { get { return 224; } }
|
|
|
|
|
public int VirtualHeight { get { return 144; } }
|
|
|
|
|
public int BufferWidth { get { return 224; } }
|
|
|
|
|
public int BufferHeight { get { return 144; } }
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|