using System; using System.Collections.Generic; using System.Linq; using BizHawk.Emulation.Common; namespace BizHawk.Emulation.Cores.WonderSwan { [Core("Cygne/Mednafen", "Dox, Mednafen Team", true, true, "0.9.36.5", "http://mednafen.sourceforge.net/")] [ServiceNotApplicable(typeof(IDriveLight), typeof(IRegionable))] public partial class WonderSwan : IEmulator, IVideoProvider, ISoundProvider, IInputPollable, IDebuggable { [CoreConstructor("WSWAN")] public WonderSwan(CoreComm comm, byte[] file, bool deterministic, object settings, object syncSettings) { 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! Core = BizSwan.bizswan_new(); if (Core == IntPtr.Zero) throw new InvalidOperationException("bizswan_new() returned NULL!"); try { var ss = _SyncSettings.GetNativeSettings(); if (deterministic) ss.userealtime = false; bool rotate = false; if (!BizSwan.bizswan_load(Core, file, file.Length, ref ss, ref rotate)) throw new InvalidOperationException("bizswan_load() returned FALSE!"); InitISaveRam(); InitVideo(rotate); PutSettings(_Settings); InitIMemoryDomains(); InitIStatable(); InitDebugCallbacks(); } catch { Dispose(); throw; } } public IEmulatorServiceProvider ServiceProvider { get; private set; } public void Dispose() { if (Core != IntPtr.Zero) { BizSwan.bizswan_delete(Core); Core = IntPtr.Zero; } } public void FrameAdvance(IController controller, bool render, bool rendersound = true) { Frame++; IsLagFrame = true; if (controller.IsPressed("Power")) BizSwan.bizswan_reset(Core); bool rotate = false; int soundbuffsize = sbuff.Length; IsLagFrame = BizSwan.bizswan_advance(Core, GetButtons(controller), !render, vbuff, sbuff, ref soundbuffsize, ref rotate); if (soundbuffsize == sbuff.Length) throw new Exception(); sbuffcontains = soundbuffsize; InitVideo(rotate); if (IsLagFrame) LagCount++; } public CoreComm CoreComm { get; private set; } public void ResetCounters() { Frame = 0; IsLagFrame = false; LagCount = 0; } IntPtr Core; public int Frame { get; private set; } public int LagCount { get; set; } public bool IsLagFrame { get; set; } public string SystemId { get { return "WSWAN"; } } public bool DeterministicEmulation { get; private set; } #region Debugging private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem(); public IInputCallbackSystem InputCallbacks { get { return _inputCallbacks; } } private readonly MemoryCallbackSystem _memorycallbacks = new MemoryCallbackSystem(new[] { "System Bus" }); // This isn't an actual memory domain in this core (yet), but there's nothing that enforces that it has to be public IMemoryCallbackSystem MemoryCallbacks { get { return _memorycallbacks; } } public IDictionary GetCpuFlagsAndRegisters() { var ret = new Dictionary(); 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; } [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(); } [FeatureNotImplemented] public long TotalExecutedCycles { get { throw new NotImplementedException(); } } BizSwan.MemoryCallback ReadCallbackD; BizSwan.MemoryCallback WriteCallbackD; BizSwan.MemoryCallback ExecCallbackD; BizSwan.ButtonCallback ButtonCallbackD; void ReadCallback(uint addr) { MemoryCallbacks.CallReads(addr, "System Bus"); } void WriteCallback(uint addr) { MemoryCallbacks.CallWrites(addr, "System Bus"); } void ExecCallback(uint addr) { MemoryCallbacks.CallExecutes(addr, "System Bus"); } void ButtonCallback() { InputCallbacks.Call(); } 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); } void SetMemoryCallbacks() { BizSwan.bizswan_setmemorycallbacks(Core, MemoryCallbacks.HasReads ? ReadCallbackD : null, MemoryCallbacks.HasWrites ? WriteCallbackD : null, MemoryCallbacks.HasExecutes ? ExecCallbackD : null); } #endregion #region IVideoProvider void InitVideo(bool rotate) { if (rotate) { BufferWidth = 144; BufferHeight = 224; } else { BufferWidth = 224; BufferHeight = 144; } } 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; } public int BackgroundColor { get { return unchecked((int)0xff000000); } } public int VsyncNumerator => 3072000; // master CPU clock, also pixel clock public int VsyncDenominator => (144 + 15) * (224 + 32); // 144 vislines, 15 vblank lines; 224 vispixels, 32 hblank pixels #endregion } }