diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.cs b/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.cs index 228d692..7801b62 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; +using Unity.VisualScripting.Dependencies.Sqlite; namespace Essgee.Emulation.Audio { @@ -130,6 +131,24 @@ namespace Essgee.Emulation.Audio channel4ForceEnable = true; } + + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + sampleCycleCount = BitConverter.ToInt32(data.MemberData[nameof(sampleCycleCount)]); + frameCycleCount = BitConverter.ToInt32(data.MemberData[nameof(frameCycleCount)]); + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + data.MemberData[nameof(sampleCycleCount)] = BitConverter.GetBytes(sampleCycleCount); + data.MemberData[nameof(frameCycleCount)] = BitConverter.GetBytes(frameCycleCount); + return data; + } + #endregion + public object GetRuntimeOption(string name) { switch (name) diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Audio/IAudio.cs b/Assets/Plugins/Essgee.Unity/Emulation/Audio/IAudio.cs index c3415d3..7bb06c8 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Audio/IAudio.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Audio/IAudio.cs @@ -3,7 +3,7 @@ using System; namespace Essgee.Emulation.Audio { - interface IAudio + interface IAudio : IAxiStatus { event EventHandler EnqueueSamples; void OnEnqueueSamples(EnqueueSamplesEventArgs e); diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Audio/SN76489.cs b/Assets/Plugins/Essgee.Unity/Emulation/Audio/SN76489.cs index 3596751..6541aad 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Audio/SN76489.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Audio/SN76489.cs @@ -5,7 +5,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; +using UnityEngine.Playables; using static Essgee.Emulation.Utilities; +using static UnityEditor.Experimental.AssetDatabaseExperimental.AssetDatabaseCounters; namespace Essgee.Emulation.Audio { @@ -157,6 +159,46 @@ namespace Essgee.Emulation.Audio channel4ForceEnable = true; } + #region AxiState + + public virtual void LoadAxiStatus(AxiEssgssStatusData data) + { + volumeRegisters = data.MemberData[nameof(volumeRegisters)].ToUShortArray(); + toneRegisters = data.MemberData[nameof(toneRegisters)].ToUShortArray(); + + channelCounters = data.MemberData[nameof(channelCounters)].ToUShortArray(); + channelOutput = data.MemberData[nameof(channelOutput)].ToBoolArray(); + + latchedChannel = data.MemberData[nameof(latchedChannel)].First(); + latchedType = data.MemberData[nameof(latchedType)].First(); + + noiseLfsr = BitConverter.ToUInt16(data.MemberData[nameof(noiseLfsr)]); + + sampleCycleCount = BitConverter.ToInt32(data.MemberData[nameof(sampleCycleCount)]); + frameCycleCount = BitConverter.ToInt32(data.MemberData[nameof(frameCycleCount)]); + dividerCount = BitConverter.ToInt32(data.MemberData[nameof(dividerCount)]); + } + + public virtual AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + data.MemberData[nameof(volumeRegisters)] = volumeRegisters.ToByteArray(); + data.MemberData[nameof(toneRegisters)] = toneRegisters.ToByteArray(); + + data.MemberData[nameof(channelCounters)] = channelCounters.ToByteArray(); + data.MemberData[nameof(channelOutput)] = channelOutput.ToByteArray(); + + data.MemberData[nameof(latchedChannel)] = BitConverter.GetBytes( latchedChannel); + data.MemberData[nameof(latchedType)] = BitConverter.GetBytes(latchedType); + + data.MemberData[nameof(noiseLfsr)] = BitConverter.GetBytes(noiseLfsr); + + data.MemberData[nameof(sampleCycleCount)] = BitConverter.GetBytes(sampleCycleCount); + data.MemberData[nameof(frameCycleCount)] = BitConverter.GetBytes(frameCycleCount); + data.MemberData[nameof(dividerCount)] = BitConverter.GetBytes(dividerCount); + return data; + } + #endregion public object GetRuntimeOption(string name) { switch (name) diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Audio/SegaSMSPSG.cs b/Assets/Plugins/Essgee.Unity/Emulation/Audio/SegaSMSPSG.cs index 8480b47..c6861ea 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Audio/SegaSMSPSG.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Audio/SegaSMSPSG.cs @@ -1,4 +1,7 @@ -namespace Essgee.Emulation.Audio +using static UnityEditor.Experimental.AssetDatabaseExperimental.AssetDatabaseCounters; +using System; + +namespace Essgee.Emulation.Audio { public class SegaSMSPSG : SN76489 { @@ -15,5 +18,20 @@ noiseLfsr = 0x8000; } + + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + base.LoadAxiStatus(data); + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = base.SaveAxiStatus(); + return data; + } + #endregion + } } diff --git a/Assets/Plugins/Essgee.Unity/Emulation/CPU/ICPU.cs b/Assets/Plugins/Essgee.Unity/Emulation/CPU/ICPU.cs index 2193de4..cb099bd 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/CPU/ICPU.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/CPU/ICPU.cs @@ -1,6 +1,6 @@ namespace Essgee.Emulation.CPU { - interface ICPU + interface ICPU: IAxiStatus { void Startup(); void Shutdown(); diff --git a/Assets/Plugins/Essgee.Unity/Emulation/CPU/SM83.Register.cs b/Assets/Plugins/Essgee.Unity/Emulation/CPU/SM83.Register.cs index 873c2d3..8a613c8 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/CPU/SM83.Register.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/CPU/SM83.Register.cs @@ -20,6 +20,10 @@ namespace Essgee.Emulation.CPU [FieldOffset(0)] public ushort Word; + + + [FieldOffset(0)] + public ushort axi_AllData; } } } diff --git a/Assets/Plugins/Essgee.Unity/Emulation/CPU/SM83.cs b/Assets/Plugins/Essgee.Unity/Emulation/CPU/SM83.cs index 5fb6e4b..e522b7c 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/CPU/SM83.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/CPU/SM83.cs @@ -2,6 +2,7 @@ using Essgee.Utilities; using System; using System.Linq; +using Unity.VisualScripting; using static Essgee.Emulation.Utilities; namespace Essgee.Emulation.CPU @@ -74,6 +75,51 @@ namespace Essgee.Emulation.CPU } } + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + af.axi_AllData = BitConverter.ToUInt16(data.MemberData[nameof(af)]); + bc.axi_AllData = BitConverter.ToUInt16(data.MemberData[nameof(bc)]); + de.axi_AllData = BitConverter.ToUInt16(data.MemberData[nameof(de)]); + hl.axi_AllData = BitConverter.ToUInt16(data.MemberData[nameof(hl)]); + + sp = BitConverter.ToUInt16(data.MemberData[nameof(sp)]); + pc = BitConverter.ToUInt16(data.MemberData[nameof(pc)]); + + ime = BitConverter.ToBoolean(data.MemberData[nameof(ime)]); + imeDelay = BitConverter.ToBoolean(data.MemberData[nameof(imeDelay)]); + halt = BitConverter.ToBoolean(data.MemberData[nameof(halt)]); + doHaltBug = BitConverter.ToBoolean(data.MemberData[nameof(doHaltBug)]); + + op = data.MemberData[nameof(op)].First(); + + currentCycles = BitConverter.ToInt32(data.MemberData[nameof(currentCycles)]); + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + + data.MemberData[nameof(af)] = BitConverter.GetBytes(af.axi_AllData); + data.MemberData[nameof(bc)] = BitConverter.GetBytes(bc.axi_AllData); + data.MemberData[nameof(de)] = BitConverter.GetBytes(de.axi_AllData); + data.MemberData[nameof(hl)] = BitConverter.GetBytes(hl.axi_AllData); + + data.MemberData[nameof(sp)] = BitConverter.GetBytes(sp); + data.MemberData[nameof(pc)] = BitConverter.GetBytes(pc); + + data.MemberData[nameof(ime)] = BitConverter.GetBytes(ime); + data.MemberData[nameof(imeDelay)] = BitConverter.GetBytes(imeDelay); + data.MemberData[nameof(halt)] = BitConverter.GetBytes(halt); + data.MemberData[nameof(doHaltBug)] = BitConverter.GetBytes(doHaltBug); + + data.MemberData[nameof(op)] = BitConverter.GetBytes(op); + + data.MemberData[nameof(currentCycles)] = BitConverter.GetBytes(currentCycles); + return data; + } + #endregion public virtual void Startup() { Reset(); diff --git a/Assets/Plugins/Essgee.Unity/Emulation/CPU/Z80A.Register.cs b/Assets/Plugins/Essgee.Unity/Emulation/CPU/Z80A.Register.cs index 26af5c1..73232df 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/CPU/Z80A.Register.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/CPU/Z80A.Register.cs @@ -20,6 +20,10 @@ namespace Essgee.Emulation.CPU [FieldOffset(0)] public ushort Word; + + + [FieldOffset(0)] + public ushort axi_AllData; } } } diff --git a/Assets/Plugins/Essgee.Unity/Emulation/CPU/Z80A.cs b/Assets/Plugins/Essgee.Unity/Emulation/CPU/Z80A.cs index c6066d0..aad6561 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/CPU/Z80A.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/CPU/Z80A.cs @@ -1,6 +1,7 @@ using Essgee.Exceptions; using Essgee.Utilities; using System; +using System.Linq; using static Essgee.Emulation.Utilities; namespace Essgee.Emulation.CPU @@ -71,6 +72,80 @@ namespace Essgee.Emulation.CPU portWriteDelegate = portWrite; } + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + af.axi_AllData = BitConverter.ToUInt16(data.MemberData[nameof(af)]); + bc.axi_AllData = BitConverter.ToUInt16(data.MemberData[nameof(bc)]); + de.axi_AllData = BitConverter.ToUInt16(data.MemberData[nameof(de)]); + hl.axi_AllData = BitConverter.ToUInt16(data.MemberData[nameof(hl)]); + + af_.axi_AllData = BitConverter.ToUInt16(data.MemberData[nameof(af_)]); + bc_.axi_AllData = BitConverter.ToUInt16(data.MemberData[nameof(bc_)]); + de_.axi_AllData = BitConverter.ToUInt16(data.MemberData[nameof(de_)]); + hl_.axi_AllData = BitConverter.ToUInt16(data.MemberData[nameof(hl_)]); + + ix.axi_AllData = BitConverter.ToUInt16(data.MemberData[nameof(ix)]); + iy.axi_AllData = BitConverter.ToUInt16(data.MemberData[nameof(iy)]); + + i = data.MemberData[nameof(i)].First(); + r = data.MemberData[nameof(r)].First(); + + sp = BitConverter.ToUInt16(data.MemberData[nameof(sp)]); + pc = BitConverter.ToUInt16(data.MemberData[nameof(pc)]); + + iff1 = BitConverter.ToBoolean(data.MemberData[nameof(iff1)]); + iff2 = BitConverter.ToBoolean(data.MemberData[nameof(iff2)]); + eiDelay = BitConverter.ToBoolean(data.MemberData[nameof(eiDelay)]); + halt = BitConverter.ToBoolean(data.MemberData[nameof(halt)]); + + im = data.MemberData[nameof(im)].First(); + op = data.MemberData[nameof(op)].First(); + + intState = data.MemberData[nameof(intState)].ToEnum(); + nmiState = data.MemberData[nameof(nmiState)].ToEnum(); + + currentCycles = BitConverter.ToInt32(data.MemberData[nameof(currentCycles)]); + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + + data.MemberData[nameof(af)] = BitConverter.GetBytes(af.axi_AllData); + data.MemberData[nameof(bc)] = BitConverter.GetBytes(bc.axi_AllData); + data.MemberData[nameof(de)] = BitConverter.GetBytes(de.axi_AllData); + data.MemberData[nameof(hl)] = BitConverter.GetBytes(hl.axi_AllData); + + data.MemberData[nameof(af_)] = BitConverter.GetBytes(af_.axi_AllData); + data.MemberData[nameof(bc_)] = BitConverter.GetBytes(bc_.axi_AllData); + data.MemberData[nameof(de_)] = BitConverter.GetBytes(de_.axi_AllData); + data.MemberData[nameof(hl_)] = BitConverter.GetBytes(hl_.axi_AllData); + + data.MemberData[nameof(i)] = BitConverter.GetBytes(i); + data.MemberData[nameof(r)] = BitConverter.GetBytes(r); + + data.MemberData[nameof(ix)] = BitConverter.GetBytes(ix.axi_AllData); + data.MemberData[nameof(iy)] = BitConverter.GetBytes(iy.axi_AllData); + + data.MemberData[nameof(sp)] = BitConverter.GetBytes(sp); + data.MemberData[nameof(pc)] = BitConverter.GetBytes(pc); + + data.MemberData[nameof(iff1)] = BitConverter.GetBytes(iff1); + data.MemberData[nameof(iff2)] = BitConverter.GetBytes(iff2); + data.MemberData[nameof(eiDelay)] = BitConverter.GetBytes(eiDelay); + data.MemberData[nameof(halt)] = BitConverter.GetBytes(halt); + + data.MemberData[nameof(im)] = BitConverter.GetBytes(im); + + data.MemberData[nameof(op)] = BitConverter.GetBytes(op); + data.MemberData[nameof(intState)] = intState.ToByteArray(); + data.MemberData[nameof(nmiState)] = nmiState.ToByteArray(); + data.MemberData[nameof(currentCycles)] = BitConverter.GetBytes(currentCycles); + return data; + } + #endregion public virtual void Startup() { Reset(); diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Coleco/ColecoCartridge.cs b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Coleco/ColecoCartridge.cs index 5278bcf..630520f 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Coleco/ColecoCartridge.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Coleco/ColecoCartridge.cs @@ -8,6 +8,18 @@ namespace Essgee.Emulation.Cartridges.Coleco byte[] romData; + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + return data; + } + #endregion public ColecoCartridge(int romSize, int ramSize) { romData = new byte[romSize]; diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/ICartridge.cs b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/ICartridge.cs index ef38170..afc1357 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/ICartridge.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/ICartridge.cs @@ -1,6 +1,6 @@ namespace Essgee.Emulation.Cartridges { - public interface ICartridge + internal interface ICartridge :IAxiStatus { void LoadRom(byte[] data); void LoadRam(byte[] data); diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/GBCameraCartridge.cs b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/GBCameraCartridge.cs index 62fe396..2a8e8c7 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/GBCameraCartridge.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/GBCameraCartridge.cs @@ -65,6 +65,20 @@ namespace Essgee.Emulation.Cartridges.Nintendo hasBattery = false; } + + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + return data; + } + #endregion + public void LoadRom(byte[] data) { Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length)); diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/IGameBoyCartridge.cs b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/IGameBoyCartridge.cs index 9f039c0..68b2a0c 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/IGameBoyCartridge.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/IGameBoyCartridge.cs @@ -1,6 +1,6 @@ namespace Essgee.Emulation.Cartridges.Nintendo { - public interface IGameBoyCartridge : ICartridge + internal interface IGameBoyCartridge : ICartridge { void SetCartridgeConfig(bool battery, bool rtc, bool rumble); } diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/MBC1Cartridge.cs b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/MBC1Cartridge.cs index 93afc77..fef802d 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/MBC1Cartridge.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/MBC1Cartridge.cs @@ -27,6 +27,18 @@ namespace Essgee.Emulation.Cartridges.Nintendo hasBattery = false; } + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + return data; + } + #endregion public void LoadRom(byte[] data) { Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length)); diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/MBC2Cartridge.cs b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/MBC2Cartridge.cs index c84e692..77b4111 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/MBC2Cartridge.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/MBC2Cartridge.cs @@ -21,6 +21,18 @@ namespace Essgee.Emulation.Cartridges.Nintendo hasBattery = false; } + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + return data; + } + #endregion public void LoadRom(byte[] data) { diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/MBC3Cartridge.cs b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/MBC3Cartridge.cs index 60d7886..9e91d22 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/MBC3Cartridge.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/MBC3Cartridge.cs @@ -32,6 +32,8 @@ namespace Essgee.Emulation.Cartridges.Nintendo IsLatched = false; } + + public void FromSaveData(byte[] ramData) { var rtcOffset = ramData.Length - 0x30; @@ -129,6 +131,18 @@ namespace Essgee.Emulation.Cartridges.Nintendo rtc = new RTC(); } + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + return data; + } + #endregion public void LoadRom(byte[] data) { Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length)); @@ -257,5 +271,6 @@ namespace Essgee.Emulation.Cartridges.Nintendo ramData[(ramBank << 13) | (address & 0x1FFF)] = value; } } + } } diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/MBC5Cartridge.cs b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/MBC5Cartridge.cs index 63889c9..62ff26c 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/MBC5Cartridge.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/MBC5Cartridge.cs @@ -30,6 +30,18 @@ namespace Essgee.Emulation.Cartridges.Nintendo hasRumble = false; } + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + return data; + } + #endregion public void LoadRom(byte[] data) { Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length)); diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/NoMapperCartridge.cs b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/NoMapperCartridge.cs index 68d1a79..fc795ca 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/NoMapperCartridge.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/NoMapperCartridge.cs @@ -13,6 +13,18 @@ namespace Essgee.Emulation.Cartridges.Nintendo ramData = new byte[ramSize]; } + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + return data; + } + #endregion public void LoadRom(byte[] data) { Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length)); diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/SpecializedLoader.cs b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/SpecializedLoader.cs index c6028f2..c11ffe2 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/SpecializedLoader.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Nintendo/SpecializedLoader.cs @@ -5,7 +5,7 @@ namespace Essgee.Emulation.Cartridges.Nintendo { public static class SpecializedLoader { - public static IGameBoyCartridge CreateCartridgeInstance(byte[] romData, byte[] ramData, Type mapperType) + internal static IGameBoyCartridge CreateCartridgeInstance(byte[] romData, byte[] ramData, Type mapperType) { var romSize = -1; switch (romData[0x0148]) diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/CodemastersCartridge.cs b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/CodemastersCartridge.cs index d61c7fd..9a06c89 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/CodemastersCartridge.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/CodemastersCartridge.cs @@ -1,6 +1,7 @@ using Essgee.Exceptions; using Essgee.Utilities; using System; +using System.Linq; namespace Essgee.Emulation.Cartridges.Sega { @@ -11,14 +12,39 @@ namespace Essgee.Emulation.Cartridges.Sega [StateRequired] byte[] ramData; - [StateRequired] - readonly byte[] pagingRegisters; - [StateRequired] - readonly byte bankMask; + [StateRequired]//TODO 感觉不用保存 保留readonly + byte[] pagingRegisters; + //readonly byte[] pagingRegisters; + [StateRequired]//TODO 感觉不用保存 保留readonly + byte bankMask; + //readonly byte bankMask; [StateRequired] bool isRamEnabled; + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + ramData = data.MemberData[nameof(ramData)]; + pagingRegisters = data.MemberData[nameof(pagingRegisters)]; + bankMask = data.MemberData[nameof(bankMask)].First(); + isRamEnabled = BitConverter.ToBoolean( data.MemberData[nameof(isRamEnabled)]); + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + + data.MemberData[nameof(ramData)] = ramData; + data.MemberData[nameof(pagingRegisters)] = pagingRegisters; + data.MemberData[nameof(bankMask)] = BitConverter.GetBytes(bankMask); + data.MemberData[nameof(isRamEnabled)] = BitConverter.GetBytes(isRamEnabled); + + return data; + } + #endregion + public CodemastersCartridge(int romSize, int ramSize) { pagingRegisters = new byte[3]; @@ -116,5 +142,6 @@ namespace Essgee.Emulation.Cartridges.Sega if (isRamEnabled && ((address & 0xF000) == 0xA000 || (address & 0xF000) == 0xB000)) ramData[address & 0x1FFF] = value; } + } } diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/KoreanMSX8kMapperCartridge.cs b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/KoreanMSX8kMapperCartridge.cs index 44477a3..78f5c8d 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/KoreanMSX8kMapperCartridge.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/KoreanMSX8kMapperCartridge.cs @@ -1,6 +1,7 @@ using Essgee.Exceptions; using Essgee.Utilities; using System; +using System.Linq; namespace Essgee.Emulation.Cartridges.Sega { @@ -8,8 +9,10 @@ namespace Essgee.Emulation.Cartridges.Sega { byte[] romData; - [StateRequired] - readonly byte[] pagingRegisters; + + [StateRequired]//TODO 感觉不用保存 保留readonly + byte[] pagingRegisters; + //readonly byte[] pagingRegisters; [StateRequired] byte bankMask; @@ -21,6 +24,25 @@ namespace Essgee.Emulation.Cartridges.Sega romData = new byte[romSize]; } + + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + pagingRegisters = data.MemberData[nameof(pagingRegisters)]; + bankMask = data.MemberData[nameof(bankMask)].First(); + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + + data.MemberData[nameof(pagingRegisters)] = pagingRegisters; + data.MemberData[nameof(bankMask)] = BitConverter.GetBytes(bankMask); + + return data; + } + #endregion public void LoadRom(byte[] data) { Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length)); diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/KoreanMapperCartridge.cs b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/KoreanMapperCartridge.cs index 37a5d00..2cefca1 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/KoreanMapperCartridge.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/KoreanMapperCartridge.cs @@ -1,6 +1,7 @@ using Essgee.Exceptions; using Essgee.Utilities; using System; +using System.Linq; namespace Essgee.Emulation.Cartridges.Sega { @@ -11,6 +12,27 @@ namespace Essgee.Emulation.Cartridges.Sega [StateRequired] byte bankMask, pagingRegister; + + + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + bankMask = data.MemberData[nameof(bankMask)].First(); + pagingRegister = data.MemberData[nameof(pagingRegister)].First(); + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + + data.MemberData[nameof(bankMask)] = BitConverter.GetBytes(bankMask); + data.MemberData[nameof(pagingRegister)] = BitConverter.GetBytes(pagingRegister); + + return data; + } + #endregion + public KoreanMapperCartridge(int romSize, int ramSize) { pagingRegister = 0x02; diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/KoreanSpriteMapperCartridge.cs b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/KoreanSpriteMapperCartridge.cs index 299e19b..01d09ba 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/KoreanSpriteMapperCartridge.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/KoreanSpriteMapperCartridge.cs @@ -1,6 +1,7 @@ using Essgee.Exceptions; using Essgee.Utilities; using System; +using System.Linq; using static Essgee.Emulation.Utilities; namespace Essgee.Emulation.Cartridges.Sega @@ -17,8 +18,10 @@ namespace Essgee.Emulation.Cartridges.Sega [StateRequired] byte[] ramData; - [StateRequired] - readonly byte[] pagingRegisters; + + [StateRequired]//TODO 感觉不用保存 保留readonly + byte[] pagingRegisters; + //readonly byte[] pagingRegisters; [StateRequired] byte romBankMask; @@ -52,6 +55,31 @@ namespace Essgee.Emulation.Cartridges.Sega isBitReverseBank1 = isBitReverseBank2 = false; } + + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + ramData = data.MemberData[nameof(ramData)]; + pagingRegisters = data.MemberData[nameof(pagingRegisters)]; + romBankMask = data.MemberData[nameof(romBankMask)].First(); + hasCartRam = BitConverter.ToBoolean(data.MemberData[nameof(hasCartRam)]); + isBitReverseBank1 = BitConverter.ToBoolean(data.MemberData[nameof(isBitReverseBank1)]); + isBitReverseBank2 = BitConverter.ToBoolean(data.MemberData[nameof(isBitReverseBank2)]); + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + data.MemberData[nameof(ramData)] = ramData; + data.MemberData[nameof(pagingRegisters)] = pagingRegisters; + data.MemberData[nameof(romBankMask)] = BitConverter.GetBytes(romBankMask); + data.MemberData[nameof(hasCartRam)] = BitConverter.GetBytes(hasCartRam); + data.MemberData[nameof(isBitReverseBank1)] = BitConverter.GetBytes(isBitReverseBank1); + data.MemberData[nameof(isBitReverseBank2)] = BitConverter.GetBytes(isBitReverseBank2); + return data; + } + #endregion public void LoadRom(byte[] data) { Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length)); diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/Multicart4PakAllActionCartridge.cs b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/Multicart4PakAllActionCartridge.cs index 33935e0..244f33f 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/Multicart4PakAllActionCartridge.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/Multicart4PakAllActionCartridge.cs @@ -1,6 +1,7 @@ using Essgee.Exceptions; using Essgee.Utilities; using System; +using UnityEngine.Playables; namespace Essgee.Emulation.Cartridges.Sega { @@ -10,8 +11,9 @@ namespace Essgee.Emulation.Cartridges.Sega { byte[] romData; - [StateRequired] - readonly int romMask; + [StateRequired]//TODO 感觉不用保存 保留readonly + int romMask; + //readonly int romMask; [StateRequired] int romBank0, romBank1, romBank2; @@ -27,6 +29,26 @@ namespace Essgee.Emulation.Cartridges.Sega romBank0 = romBank1 = romBank2 = 0; } + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + romMask = BitConverter.ToInt32(data.MemberData[nameof(romMask)]); + romBank0 = BitConverter.ToInt32(data.MemberData[nameof(romBank0)]); + romBank1 = BitConverter.ToInt32(data.MemberData[nameof(romBank1)]); + romBank2 = BitConverter.ToInt32(data.MemberData[nameof(romBank2)]); + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + data.MemberData[nameof(romMask)] = BitConverter.GetBytes(romMask); + data.MemberData[nameof(romBank0)] = BitConverter.GetBytes(romBank0); + data.MemberData[nameof(romBank1)] = BitConverter.GetBytes(romBank1); + data.MemberData[nameof(romBank2)] = BitConverter.GetBytes(romBank2); + return data; + } + #endregion public void LoadRom(byte[] data) { Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length)); diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/SegaMapperCartridge.cs b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/SegaMapperCartridge.cs index 0d987e5..0b80d33 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/SegaMapperCartridge.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/SegaMapperCartridge.cs @@ -1,6 +1,7 @@ using Essgee.Exceptions; using Essgee.Utilities; using System; +using System.Linq; using static Essgee.Emulation.Utilities; namespace Essgee.Emulation.Cartridges.Sega @@ -13,7 +14,7 @@ namespace Essgee.Emulation.Cartridges.Sega byte[] ramData; [StateRequired] - readonly byte[] pagingRegisters; + byte[] pagingRegisters; [StateRequired] byte romBankMask; @@ -27,6 +28,7 @@ namespace Essgee.Emulation.Cartridges.Sega int romBank1 { get { return pagingRegisters[2]; } } int romBank2 { get { return pagingRegisters[3]; } } + public SegaMapperCartridge(int romSize, int ramSize) { pagingRegisters = new byte[0x04]; @@ -44,6 +46,27 @@ namespace Essgee.Emulation.Cartridges.Sega hasCartRam = false; } + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + ramData = data.MemberData[nameof(ramData)]; + pagingRegisters = data.MemberData[nameof(pagingRegisters)]; + romBankMask = data.MemberData[nameof(romBankMask)].First(); + hasCartRam = BitConverter.ToBoolean(data.MemberData[nameof(hasCartRam)]); + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + data.MemberData[nameof(ramData)] = ramData; + data.MemberData[nameof(pagingRegisters)] = pagingRegisters; + data.MemberData[nameof(romBankMask)] = BitConverter.GetBytes(romBankMask); + data.MemberData[nameof(hasCartRam)] = BitConverter.GetBytes(hasCartRam); + return data; + } + #endregion + public void LoadRom(byte[] data) { Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length)); @@ -143,5 +166,6 @@ namespace Essgee.Emulation.Cartridges.Sega /* Otherwise ignore writes to ROM, as some games seem to be doing that? (ex. Gunstar Heroes GG to 0000) */ } + } } diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/SegaSGCartridge.cs b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/SegaSGCartridge.cs index 8849c9f..3eb12cd 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/SegaSGCartridge.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Cartridges/Sega/SegaSGCartridge.cs @@ -1,5 +1,7 @@ using Essgee.Utilities; using System; +using System.Linq; +using UnityEngine.Playables; namespace Essgee.Emulation.Cartridges.Sega { @@ -10,8 +12,9 @@ namespace Essgee.Emulation.Cartridges.Sega [StateRequired] byte[] ramData; - [StateRequired] - readonly int romMask, ramMask; + [StateRequired]//TODO 感觉不用保存 保留readonly + int romMask, ramMask; + //readonly int romMask, ramMask; public SegaSGCartridge(int romSize, int ramSize) { @@ -25,6 +28,25 @@ namespace Essgee.Emulation.Cartridges.Sega ramMask = (ramSize - 1); } + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + ramData = data.MemberData[nameof(romMask)]; + romMask = data.MemberData[nameof(romMask)].First(); + ramMask = data.MemberData[nameof(ramMask)].First(); + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + data.MemberData[nameof(ramData)] = ramData; + data.MemberData[nameof(romMask)] = BitConverter.GetBytes(romMask); + data.MemberData[nameof(ramMask)] = BitConverter.GetBytes(ramMask); + return data; + } + #endregion + public void LoadRom(byte[] data) { Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length)); diff --git a/Assets/Plugins/Essgee.Unity/Emulation/EmulatorHandler.cs b/Assets/Plugins/Essgee.Unity/Emulation/EmulatorHandler.cs index 9b48389..2db6fe3 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/EmulatorHandler.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/EmulatorHandler.cs @@ -255,114 +255,137 @@ namespace Essgee.Emulation } - private void ThreadMainLoop() + //private void ThreadMainLoop() + //{ + // // TODO: rework fps limiter/counter - AGAIN - because the counter is inaccurate at sampleTimespan=0.25 and the limiter CAN cause sound crackling at sampleTimespan>0.25 + // // try this maybe? https://stackoverflow.com/a/34839411 + + // var stopWatch = Stopwatch.StartNew(); + + // TimeSpan accumulatedTime = TimeSpan.Zero, lastStartTime = TimeSpan.Zero, lastEndTime = TimeSpan.Zero; + + // var frameCounter = 0; + // var sampleTimespan = TimeSpan.FromSeconds(0.5); + + // try + // { + // while (true) + // { + // if (!emulationThreadRunning) + // break; + + // if (stateLoadRequested && stateNumber != -1) + // { + // var statePath = GetSaveStateFilename(stateNumber); + // if (File.Exists(statePath)) + // { + // using (var stream = new FileStream(statePath, FileMode.Open)) + // { + // emulator.SetState(SaveStateHandler.Load(stream, emulator.GetType().Name)); + // } + // } + + // stateLoadRequested = false; + // stateNumber = -1; + // } + + // var refreshRate = emulator.RefreshRate; + // var targetElapsedTime = TimeSpan.FromTicks((long)Math.Round(TimeSpan.TicksPerSecond / refreshRate)); + + // var startTime = stopWatch.Elapsed; + + // while (pauseStateChangesRequested.Count > 0) + // { + // var newPauseState = pauseStateChangesRequested.Dequeue(); + // emulationThreadPaused = newPauseState; + + // PauseChanged?.Invoke(this, EventArgs.Empty); + // } + + // if (!emulationThreadPaused) + // { + // if (limitFps) + // { + // var elapsedTime = (startTime - lastStartTime); + // lastStartTime = startTime; + + // if (elapsedTime < targetElapsedTime) + // { + // accumulatedTime += elapsedTime; + + // while (accumulatedTime >= targetElapsedTime) + // { + // emulator.RunFrame(); + // frameCounter++; + + // accumulatedTime -= targetElapsedTime; + // } + // } + // } + // else + // { + // emulator.RunFrame(); + // frameCounter++; + // } + + // if ((stopWatch.Elapsed - lastEndTime) >= sampleTimespan) + // { + // FramesPerSecond = (int)((frameCounter * 1000.0) / sampleTimespan.TotalMilliseconds); + // frameCounter = 0; + // lastEndTime = stopWatch.Elapsed; + // } + // } + // else + // { + // lastEndTime = stopWatch.Elapsed; + // } + + // if (configChangeRequested) + // { + // emulator.SetConfiguration(newConfiguration); + // configChangeRequested = false; + // } + + // if (stateSaveRequested && stateNumber != -1) + // { + // var statePath = GetSaveStateFilename(stateNumber); + // using (var stream = new FileStream(statePath, FileMode.OpenOrCreate)) + // { + // SaveStateHandler.Save(stream, emulator.GetType().Name, emulator.GetState()); + // } + + // stateSaveRequested = false; + // stateNumber = -1; + // } + // } + // } + // catch (Exception ex) when (!AppEnvironment.DebugMode) + // { + // ex.Data.Add("Thread", Thread.CurrentThread.Name); + // exceptionHandler(ex); + // } + //} + + public void mySaveState(int stateNumber) { - // TODO: rework fps limiter/counter - AGAIN - because the counter is inaccurate at sampleTimespan=0.25 and the limiter CAN cause sound crackling at sampleTimespan>0.25 - // try this maybe? https://stackoverflow.com/a/34839411 - - var stopWatch = Stopwatch.StartNew(); - - TimeSpan accumulatedTime = TimeSpan.Zero, lastStartTime = TimeSpan.Zero, lastEndTime = TimeSpan.Zero; - - var frameCounter = 0; - var sampleTimespan = TimeSpan.FromSeconds(0.5); - - try + var statePath = GetSaveStateFilename(stateNumber); + using (var stream = new FileStream(statePath, FileMode.OpenOrCreate)) { - while (true) - { - if (!emulationThreadRunning) - break; - - if (stateLoadRequested && stateNumber != -1) - { - var statePath = GetSaveStateFilename(stateNumber); - if (File.Exists(statePath)) - { - using (var stream = new FileStream(statePath, FileMode.Open)) - { - emulator.SetState(SaveStateHandler.Load(stream, emulator.GetType().Name)); - } - } - - stateLoadRequested = false; - stateNumber = -1; - } - - var refreshRate = emulator.RefreshRate; - var targetElapsedTime = TimeSpan.FromTicks((long)Math.Round(TimeSpan.TicksPerSecond / refreshRate)); - - var startTime = stopWatch.Elapsed; - - while (pauseStateChangesRequested.Count > 0) - { - var newPauseState = pauseStateChangesRequested.Dequeue(); - emulationThreadPaused = newPauseState; - - PauseChanged?.Invoke(this, EventArgs.Empty); - } - - if (!emulationThreadPaused) - { - if (limitFps) - { - var elapsedTime = (startTime - lastStartTime); - lastStartTime = startTime; - - if (elapsedTime < targetElapsedTime) - { - accumulatedTime += elapsedTime; - - while (accumulatedTime >= targetElapsedTime) - { - emulator.RunFrame(); - frameCounter++; - - accumulatedTime -= targetElapsedTime; - } - } - } - else - { - emulator.RunFrame(); - frameCounter++; - } - - if ((stopWatch.Elapsed - lastEndTime) >= sampleTimespan) - { - FramesPerSecond = (int)((frameCounter * 1000.0) / sampleTimespan.TotalMilliseconds); - frameCounter = 0; - lastEndTime = stopWatch.Elapsed; - } - } - else - { - lastEndTime = stopWatch.Elapsed; - } - - if (configChangeRequested) - { - emulator.SetConfiguration(newConfiguration); - configChangeRequested = false; - } - - if (stateSaveRequested && stateNumber != -1) - { - var statePath = GetSaveStateFilename(stateNumber); - using (var stream = new FileStream(statePath, FileMode.OpenOrCreate)) - { - SaveStateHandler.Save(stream, emulator.GetType().Name, emulator.GetState()); - } - - stateSaveRequested = false; - stateNumber = -1; - } - } + //SaveStateHandler.Save(stream, emulator.GetType().Name, emulator.GetState()); + SaveStateHandler.Save(stream, emulator.GetType().Name, emulator.SaveAxiStatus()); } - catch (Exception ex) when (!AppEnvironment.DebugMode) + } + + public void myLoadState(int stateNumber) + { + var statePath = GetSaveStateFilename(stateNumber); + if (File.Exists(statePath)) { - ex.Data.Add("Thread", Thread.CurrentThread.Name); - exceptionHandler(ex); + using (var stream = new FileStream(statePath, FileMode.Open)) + { + //emulator.SetState(SaveStateHandler.Load(stream, emulator.GetType().Name)); + emulator.LoadAxiStatus(SaveStateHandler.LoadAxiStatus(stream, emulator.GetType().Name)); + } } } } diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Machines/ColecoVision.cs b/Assets/Plugins/Essgee.Unity/Emulation/Machines/ColecoVision.cs index 49079a3..def33c1 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Machines/ColecoVision.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Machines/ColecoVision.cs @@ -219,41 +219,76 @@ namespace Essgee.Emulation.Machines } //public void SetState(Dictionary state) - public void SetState(Dictionary state) + //public void SetState(Dictionary state) + //{ + // SaveStateHandler.PerformSetState(cartridge, (Dictionary)state[nameof(cartridge)]); + // wram = (byte[])state[nameof(wram)]; + // SaveStateHandler.PerformSetState(cpu, (Dictionary)state[nameof(cpu)]); + // SaveStateHandler.PerformSetState(vdp, (Dictionary)state[nameof(vdp)]); + // SaveStateHandler.PerformSetState(psg, (Dictionary)state[nameof(psg)]); + + // portControls1 = (ushort)state[nameof(portControls1)]; + // portControls2 = (ushort)state[nameof(portControls2)]; + // controlsReadMode = (byte)state[nameof(controlsReadMode)]; + // isNmi = (bool)state[nameof(isNmi)]; + // isNmiPending = (bool)state[nameof(isNmiPending)]; + + // ReconfigureSystem(); + //} + + //public Dictionary GetState() + //{ + // return new Dictionary + // { + // [nameof(cartridge)] = SaveStateHandler.PerformGetState(cartridge), + // [nameof(wram)] = wram, + // [nameof(cpu)] = SaveStateHandler.PerformGetState(cpu), + // [nameof(vdp)] = SaveStateHandler.PerformGetState(vdp), + // [nameof(psg)] = SaveStateHandler.PerformGetState(psg), + + // [nameof(portControls1)] = portControls1, + // [nameof(portControls2)] = portControls2, + // [nameof(controlsReadMode)] = controlsReadMode, + // [nameof(isNmi)] = isNmi, + // [nameof(isNmiPending)] = isNmiPending + // }; + //} + + #region + public void LoadAxiStatus(AxiEssgssStatusData data) { - SaveStateHandler.PerformSetState(cartridge, (Dictionary)state[nameof(cartridge)]); - wram = (byte[])state[nameof(wram)]; - SaveStateHandler.PerformSetState(cpu, (Dictionary)state[nameof(cpu)]); - SaveStateHandler.PerformSetState(vdp, (Dictionary)state[nameof(vdp)]); - SaveStateHandler.PerformSetState(psg, (Dictionary)state[nameof(psg)]); + cartridge.LoadAxiStatus(data.ClassData[nameof(cartridge)]); + wram = data.MemberData[nameof(wram)]; + cpu.LoadAxiStatus(data.ClassData[nameof(cpu)]); + vdp.LoadAxiStatus(data.ClassData[nameof(vdp)]); + psg.LoadAxiStatus(data.ClassData[nameof(psg)]); - portControls1 = (ushort)state[nameof(portControls1)]; - portControls2 = (ushort)state[nameof(portControls2)]; - controlsReadMode = (byte)state[nameof(controlsReadMode)]; - isNmi = (bool)state[nameof(isNmi)]; - isNmiPending = (bool)state[nameof(isNmiPending)]; - - ReconfigureSystem(); + portControls1 = BitConverter.ToUInt16( data.MemberData[nameof(portControls1)]); + portControls2 = BitConverter.ToUInt16(data.MemberData[nameof(portControls2)]); + controlsReadMode = data.MemberData[nameof(controlsReadMode)].First(); + isNmi = BitConverter.ToBoolean(data.MemberData[nameof(isNmi)]); + isNmiPending = BitConverter.ToBoolean(data.MemberData[nameof(isNmiPending)]); } - public Dictionary GetState() + public AxiEssgssStatusData SaveAxiStatus() { - return new Dictionary - { - [nameof(cartridge)] = SaveStateHandler.PerformGetState(cartridge), - [nameof(wram)] = wram, - [nameof(cpu)] = SaveStateHandler.PerformGetState(cpu), - [nameof(vdp)] = SaveStateHandler.PerformGetState(vdp), - [nameof(psg)] = SaveStateHandler.PerformGetState(psg), + AxiEssgssStatusData data = new AxiEssgssStatusData(); + data.ClassData[nameof(cartridge)] = cartridge.SaveAxiStatus(); + data.MemberData[nameof(wram)] = wram; + data.ClassData[nameof(cpu)] = cpu.SaveAxiStatus(); + data.ClassData[nameof(vdp)] = vdp.SaveAxiStatus(); + data.ClassData[nameof(psg)] = psg.SaveAxiStatus(); + + data.MemberData[nameof(portControls1)] = BitConverter.GetBytes(portControls1); + data.MemberData[nameof(portControls2)] = BitConverter.GetBytes(portControls2); + data.MemberData[nameof(controlsReadMode)] = BitConverter.GetBytes(controlsReadMode); + data.MemberData[nameof(isNmi)] = BitConverter.GetBytes(isNmi); + data.MemberData[nameof(isNmiPending)] = BitConverter.GetBytes(isNmiPending); + + return data; - [nameof(portControls1)] = portControls1, - [nameof(portControls2)] = portControls2, - [nameof(controlsReadMode)] = controlsReadMode, - [nameof(isNmi)] = isNmi, - [nameof(isNmiPending)] = isNmiPending - }; } - + #endregion public Dictionary GetDebugInformation() { var dict = new Dictionary diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Machines/GameBoy.cs b/Assets/Plugins/Essgee.Unity/Emulation/Machines/GameBoy.cs index 983b68e..1ad5db5 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Machines/GameBoy.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Machines/GameBoy.cs @@ -131,6 +131,20 @@ namespace Essgee.Emulation.Machines public GameBoy() { } + + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + return data; + } + #endregion + public void Initialize() { bootstrap = null; diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Machines/GameBoyColor.cs b/Assets/Plugins/Essgee.Unity/Emulation/Machines/GameBoyColor.cs index b97e463..1d1488c 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Machines/GameBoyColor.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Machines/GameBoyColor.cs @@ -162,6 +162,18 @@ namespace Essgee.Emulation.Machines public GameBoyColor() { } + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + return data; + } + #endregion public void Initialize() { bootstrap = null; diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Machines/GameGear.cs b/Assets/Plugins/Essgee.Unity/Emulation/Machines/GameGear.cs index cd43873..2e5e1d6 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Machines/GameGear.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Machines/GameGear.cs @@ -241,59 +241,114 @@ namespace Essgee.Emulation.Machines } //public void SetState(Dictionary state) - public void SetState(Dictionary state) + //public void SetState(Dictionary state) + //{ + // configuration.Region = (Region)state[nameof(configuration.Region)]; + + // SaveStateHandler.PerformSetState(bootstrap, (Dictionary)state[nameof(bootstrap)]); + // SaveStateHandler.PerformSetState(cartridge, (Dictionary)state[nameof(cartridge)]); + // wram = (byte[])state[nameof(wram)]; + // SaveStateHandler.PerformSetState(cpu, (Dictionary)state[nameof(cpu)]); + // SaveStateHandler.PerformSetState(vdp, (Dictionary)state[nameof(vdp)]); + // SaveStateHandler.PerformSetState(psg, (Dictionary)state[nameof(psg)]); + + // portMemoryControl = (byte)state[nameof(portMemoryControl)]; + // portIoControl = (byte)state[nameof(portIoControl)]; + // hCounterLatched = (byte)state[nameof(hCounterLatched)]; + // portIoAB = (byte)state[nameof(portIoAB)]; + // portIoBMisc = (byte)state[nameof(portIoBMisc)]; + + // portIoC = (byte)state[nameof(portIoC)]; + // portParallelData = (byte)state[nameof(portParallelData)]; + // portDataDirNMI = (byte)state[nameof(portDataDirNMI)]; + // portTxBuffer = (byte)state[nameof(portTxBuffer)]; + // portRxBuffer = (byte)state[nameof(portRxBuffer)]; + // portSerialControl = (byte)state[nameof(portSerialControl)]; + + // ReconfigureSystem(); + //} + + //public Dictionary GetState() + //{ + // return new Dictionary + // { + // [nameof(configuration.Region)] = configuration.Region, + + // [nameof(bootstrap)] = SaveStateHandler.PerformGetState(bootstrap), + // [nameof(cartridge)] = SaveStateHandler.PerformGetState(cartridge), + // [nameof(wram)] = wram, + // [nameof(cpu)] = SaveStateHandler.PerformGetState(cpu), + // [nameof(vdp)] = SaveStateHandler.PerformGetState(vdp), + // [nameof(psg)] = SaveStateHandler.PerformGetState(psg), + + // [nameof(portMemoryControl)] = portMemoryControl, + // [nameof(portIoControl)] = portIoControl, + // [nameof(hCounterLatched)] = hCounterLatched, + // [nameof(portIoAB)] = portIoAB, + // [nameof(portIoBMisc)] = portIoBMisc, + + // [nameof(portIoC)] = portIoC, + // [nameof(portParallelData)] = portParallelData, + // [nameof(portDataDirNMI)] = portDataDirNMI, + // [nameof(portTxBuffer)] = portTxBuffer, + // [nameof(portRxBuffer)] = portRxBuffer, + // [nameof(portSerialControl)] = portSerialControl + // }; + //} + + + public void LoadAxiStatus(AxiEssgssStatusData data) { - configuration.Region = (Region)state[nameof(configuration.Region)]; + configuration.Region = data.MemberData[nameof(configuration.Region)].ToEnum(); - SaveStateHandler.PerformSetState(bootstrap, (Dictionary)state[nameof(bootstrap)]); - SaveStateHandler.PerformSetState(cartridge, (Dictionary)state[nameof(cartridge)]); - wram = (byte[])state[nameof(wram)]; - SaveStateHandler.PerformSetState(cpu, (Dictionary)state[nameof(cpu)]); - SaveStateHandler.PerformSetState(vdp, (Dictionary)state[nameof(vdp)]); - SaveStateHandler.PerformSetState(psg, (Dictionary)state[nameof(psg)]); + bootstrap.LoadAxiStatus(data.ClassData[nameof(bootstrap)]); + cartridge.LoadAxiStatus(data.ClassData[nameof(cartridge)]); + wram = data.MemberData[nameof(wram)]; + cpu.LoadAxiStatus(data.ClassData[nameof(cpu)]); + vdp.LoadAxiStatus(data.ClassData[nameof(vdp)]); + psg.LoadAxiStatus(data.ClassData[nameof(psg)]); - portMemoryControl = (byte)state[nameof(portMemoryControl)]; - portIoControl = (byte)state[nameof(portIoControl)]; - hCounterLatched = (byte)state[nameof(hCounterLatched)]; - portIoAB = (byte)state[nameof(portIoAB)]; - portIoBMisc = (byte)state[nameof(portIoBMisc)]; + portMemoryControl = data.MemberData[nameof(portMemoryControl)].First(); + portIoControl = data.MemberData[nameof(portIoControl)].First(); + hCounterLatched = data.MemberData[nameof(hCounterLatched)].First(); + portIoAB = data.MemberData[nameof(portIoAB)].First(); + portIoBMisc = data.MemberData[nameof(portIoBMisc)].First(); - portIoC = (byte)state[nameof(portIoC)]; - portParallelData = (byte)state[nameof(portParallelData)]; - portDataDirNMI = (byte)state[nameof(portDataDirNMI)]; - portTxBuffer = (byte)state[nameof(portTxBuffer)]; - portRxBuffer = (byte)state[nameof(portRxBuffer)]; - portSerialControl = (byte)state[nameof(portSerialControl)]; - - ReconfigureSystem(); + portIoC = data.MemberData[nameof(portIoC)].First(); + portParallelData = data.MemberData[nameof(portParallelData)].First(); + portDataDirNMI = data.MemberData[nameof(portDataDirNMI)].First(); + portTxBuffer = data.MemberData[nameof(portTxBuffer)].First(); + portRxBuffer = data.MemberData[nameof(portRxBuffer)].First(); + portSerialControl = data.MemberData[nameof(portSerialControl)].First(); } - public Dictionary GetState() + public AxiEssgssStatusData SaveAxiStatus() { - return new Dictionary - { - [nameof(configuration.Region)] = configuration.Region, + AxiEssgssStatusData data = new AxiEssgssStatusData(); + data.MemberData[nameof(configuration.Region)] = configuration.Region.ToByteArray(); + + data.ClassData[nameof(bootstrap)] = bootstrap.SaveAxiStatus(); + data.ClassData[nameof(cartridge)] = cartridge.SaveAxiStatus(); + data.MemberData[nameof(wram)] = wram; + data.ClassData[nameof(cpu)] = cpu.SaveAxiStatus(); + data.ClassData[nameof(vdp)] = vdp.SaveAxiStatus(); + data.ClassData[nameof(psg)] = psg.SaveAxiStatus(); + + data.MemberData[nameof(portMemoryControl)] = BitConverter.GetBytes(portMemoryControl); + data.MemberData[nameof(portIoControl)] = BitConverter.GetBytes(portIoControl); + data.MemberData[nameof(hCounterLatched)] = BitConverter.GetBytes(hCounterLatched); + data.MemberData[nameof(portIoAB)] = BitConverter.GetBytes(portIoAB); + data.MemberData[nameof(portIoBMisc)] = BitConverter.GetBytes(portIoBMisc); - [nameof(bootstrap)] = SaveStateHandler.PerformGetState(bootstrap), - [nameof(cartridge)] = SaveStateHandler.PerformGetState(cartridge), - [nameof(wram)] = wram, - [nameof(cpu)] = SaveStateHandler.PerformGetState(cpu), - [nameof(vdp)] = SaveStateHandler.PerformGetState(vdp), - [nameof(psg)] = SaveStateHandler.PerformGetState(psg), + data.MemberData[nameof(portIoC)] = BitConverter.GetBytes(portIoC); + data.MemberData[nameof(portParallelData)] = BitConverter.GetBytes(portParallelData); + data.MemberData[nameof(portDataDirNMI)] = BitConverter.GetBytes(portDataDirNMI); + data.MemberData[nameof(portTxBuffer)] = BitConverter.GetBytes(portTxBuffer); + data.MemberData[nameof(portRxBuffer)] = BitConverter.GetBytes(portRxBuffer); + data.MemberData[nameof(portSerialControl)] = BitConverter.GetBytes(portSerialControl); - [nameof(portMemoryControl)] = portMemoryControl, - [nameof(portIoControl)] = portIoControl, - [nameof(hCounterLatched)] = hCounterLatched, - [nameof(portIoAB)] = portIoAB, - [nameof(portIoBMisc)] = portIoBMisc, + return data; - [nameof(portIoC)] = portIoC, - [nameof(portParallelData)] = portParallelData, - [nameof(portDataDirNMI)] = portDataDirNMI, - [nameof(portTxBuffer)] = portTxBuffer, - [nameof(portRxBuffer)] = portRxBuffer, - [nameof(portSerialControl)] = portSerialControl - }; } public Dictionary GetDebugInformation() @@ -509,5 +564,6 @@ namespace Essgee.Emulation.Machines break; } } + } } diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Machines/IMachine.cs b/Assets/Plugins/Essgee.Unity/Emulation/Machines/IMachine.cs index 677181c..e4450e9 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Machines/IMachine.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Machines/IMachine.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; namespace Essgee.Emulation.Machines { - public interface IMachine + public interface IMachine:IAxiStatus { event EventHandler SendLogMessage; event EventHandler EmulationReset; @@ -38,8 +38,9 @@ namespace Essgee.Emulation.Machines void Reset(); void Shutdown(); - void SetState(Dictionary state); - Dictionary GetState(); + //void SetState(Dictionary state); + //Dictionary GetState(); + void Load(byte[] romData, byte[] ramData, Type mapperType); byte[] GetCartridgeRam(); diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Machines/MasterSystem.cs b/Assets/Plugins/Essgee.Unity/Emulation/Machines/MasterSystem.cs index b0c131c..b5d8ef4 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Machines/MasterSystem.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Machines/MasterSystem.cs @@ -268,49 +268,119 @@ namespace Essgee.Emulation.Machines } //public void SetState(Dictionary state) - public void SetState(Dictionary state) + //public void SetState(Dictionary state) + //{ + // configuration.TVStandard = (TVStandard)state[nameof(configuration.TVStandard)]; + // configuration.Region = (Region)state[nameof(configuration.Region)]; + + // SaveStateHandler.PerformSetState(bootstrap, (Dictionary)state[nameof(bootstrap)]); + // SaveStateHandler.PerformSetState(cartridge, (Dictionary)state[nameof(cartridge)]); + // wram = (byte[])state[nameof(wram)]; + // SaveStateHandler.PerformSetState(cpu, (Dictionary)state[nameof(cpu)]); + // SaveStateHandler.PerformSetState(vdp, (Dictionary)state[nameof(vdp)]); + // SaveStateHandler.PerformSetState(psg, (Dictionary)state[nameof(psg)]); + + // inputDevices = (InputDevice[])state[nameof(inputDevices)]; + // lightgunLatched = (bool)state[nameof(lightgunLatched)]; + + // portMemoryControl = (byte)state[nameof(portMemoryControl)]; + // portIoControl = (byte)state[nameof(portIoControl)]; + // hCounterLatched = (byte)state[nameof(hCounterLatched)]; + + // ReconfigureSystem(); + //} + + public void LoadAxiStatus(AxiEssgssStatusData data) { - configuration.TVStandard = (TVStandard)state[nameof(configuration.TVStandard)]; - configuration.Region = (Region)state[nameof(configuration.Region)]; + configuration.TVStandard = data.MemberData[nameof(configuration.TVStandard)].ToEnum(); + configuration.Region = data.MemberData[nameof(configuration.Region)].ToEnum(); - SaveStateHandler.PerformSetState(bootstrap, (Dictionary)state[nameof(bootstrap)]); - SaveStateHandler.PerformSetState(cartridge, (Dictionary)state[nameof(cartridge)]); - wram = (byte[])state[nameof(wram)]; - SaveStateHandler.PerformSetState(cpu, (Dictionary)state[nameof(cpu)]); - SaveStateHandler.PerformSetState(vdp, (Dictionary)state[nameof(vdp)]); - SaveStateHandler.PerformSetState(psg, (Dictionary)state[nameof(psg)]); + if (data.ClassData.ContainsKey(nameof(bootstrap))) + bootstrap.LoadAxiStatus(data.ClassData[nameof(bootstrap)]); + cartridge.LoadAxiStatus(data.ClassData[nameof(cartridge)]); + wram = data.MemberData[nameof(wram)]; + cpu.LoadAxiStatus(data.ClassData[nameof(cpu)]); + vdp.LoadAxiStatus(data.ClassData[nameof(vdp)]); + psg.LoadAxiStatus(data.ClassData[nameof(psg)]); - inputDevices = (InputDevice[])state[nameof(inputDevices)]; - lightgunLatched = (bool)state[nameof(lightgunLatched)]; + inputDevices = data.MemberData[nameof(inputDevices)].ToEnumArray(); + lightgunLatched = BitConverter.ToBoolean(data.MemberData[nameof(lightgunLatched)]); - portMemoryControl = (byte)state[nameof(portMemoryControl)]; - portIoControl = (byte)state[nameof(portIoControl)]; - hCounterLatched = (byte)state[nameof(hCounterLatched)]; + portMemoryControl = data.MemberData[nameof(portMemoryControl)].First(); + portIoControl = data.MemberData[nameof(portIoControl)].First(); + hCounterLatched = data.MemberData[nameof(hCounterLatched)].First(); ReconfigureSystem(); } - public Dictionary GetState() + //public Dictionary GetState() + //{ + // return new Dictionary + // { + // [nameof(configuration.TVStandard)] = configuration.TVStandard, + // [nameof(configuration.Region)] = configuration.Region, + + // [nameof(bootstrap)] = SaveStateHandler.PerformGetState(bootstrap), + // [nameof(cartridge)] = SaveStateHandler.PerformGetState(cartridge), + // [nameof(wram)] = wram, + // [nameof(cpu)] = SaveStateHandler.PerformGetState(cpu), + // [nameof(vdp)] = SaveStateHandler.PerformGetState(vdp), + // [nameof(psg)] = SaveStateHandler.PerformGetState(psg), + + // [nameof(inputDevices)] = inputDevices, + // [nameof(lightgunLatched)] = lightgunLatched, + + // [nameof(portMemoryControl)] = portMemoryControl, + // [nameof(portIoControl)] = portIoControl, + // [nameof(hCounterLatched)] = hCounterLatched + // }; + //} + + public AxiEssgssStatusData SaveAxiStatus() { - return new Dictionary - { - [nameof(configuration.TVStandard)] = configuration.TVStandard, - [nameof(configuration.Region)] = configuration.Region, + AxiEssgssStatusData data = new AxiEssgssStatusData(); + data.MemberData[nameof(configuration.TVStandard)] = configuration.TVStandard.ToByteArray(); + data.MemberData[nameof(configuration.Region)] = configuration.Region.ToByteArray(); - [nameof(bootstrap)] = SaveStateHandler.PerformGetState(bootstrap), - [nameof(cartridge)] = SaveStateHandler.PerformGetState(cartridge), - [nameof(wram)] = wram, - [nameof(cpu)] = SaveStateHandler.PerformGetState(cpu), - [nameof(vdp)] = SaveStateHandler.PerformGetState(vdp), - [nameof(psg)] = SaveStateHandler.PerformGetState(psg), + if(bootstrap != null) + data.ClassData[nameof(bootstrap)] = bootstrap.SaveAxiStatus(); - [nameof(inputDevices)] = inputDevices, - [nameof(lightgunLatched)] = lightgunLatched, + data.ClassData[nameof(cartridge)] = cartridge.SaveAxiStatus(); + data.MemberData[nameof(wram)] = wram; + data.ClassData[nameof(cpu)] = cpu.SaveAxiStatus(); + data.ClassData[nameof(vdp)] = vdp.SaveAxiStatus(); + data.ClassData[nameof(psg)] = psg.SaveAxiStatus(); - [nameof(portMemoryControl)] = portMemoryControl, - [nameof(portIoControl)] = portIoControl, - [nameof(hCounterLatched)] = hCounterLatched - }; + data.MemberData[nameof(inputDevices)] = inputDevices.ToByteArray(); + data.MemberData[nameof(lightgunLatched)] = BitConverter.GetBytes(lightgunLatched); + + data.MemberData[nameof(portMemoryControl)] = BitConverter.GetBytes((int)portMemoryControl); + data.MemberData[nameof(portIoControl)] = BitConverter.GetBytes((int)portIoControl); + data.MemberData[nameof(hCounterLatched)] = BitConverter.GetBytes(hCounterLatched); + + + return data; + + + //return new Dictionary + //{ + // [nameof(configuration.TVStandard)] = configuration.TVStandard, + // [nameof(configuration.Region)] = configuration.Region, + + // [nameof(bootstrap)] = SaveStateHandler.PerformGetState(bootstrap), + // [nameof(cartridge)] = SaveStateHandler.PerformGetState(cartridge), + // [nameof(wram)] = wram, + // [nameof(cpu)] = SaveStateHandler.PerformGetState(cpu), + // [nameof(vdp)] = SaveStateHandler.PerformGetState(vdp), + // [nameof(psg)] = SaveStateHandler.PerformGetState(psg), + + // [nameof(inputDevices)] = inputDevices, + // [nameof(lightgunLatched)] = lightgunLatched, + + // [nameof(portMemoryControl)] = portMemoryControl, + // [nameof(portIoControl)] = portIoControl, + // [nameof(hCounterLatched)] = hCounterLatched + //}; } public Dictionary GetDebugInformation() diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Machines/SC3000.cs b/Assets/Plugins/Essgee.Unity/Emulation/Machines/SC3000.cs index 0c8756a..ceaf080 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Machines/SC3000.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Machines/SC3000.cs @@ -245,36 +245,71 @@ namespace Essgee.Emulation.Machines psg?.Shutdown(); } - //public void SetState(Dictionary state) - public void SetState(Dictionary state) - { - configuration.TVStandard = (TVStandard)state[nameof(configuration.TVStandard)]; + ////public void SetState(Dictionary state) + //public void SetState(Dictionary state) + //{ + // configuration.TVStandard = (TVStandard)state[nameof(configuration.TVStandard)]; + + // SaveStateHandler.PerformSetState(cartridge, (Dictionary)state[nameof(cartridge)]); + // wram = (byte[])state[nameof(wram)]; + // SaveStateHandler.PerformSetState(cpu, (Dictionary)state[nameof(cpu)]); + // SaveStateHandler.PerformSetState(vdp, (Dictionary)state[nameof(vdp)]); + // SaveStateHandler.PerformSetState(psg, (Dictionary)state[nameof(psg)]); + // SaveStateHandler.PerformSetState(ppi, (Dictionary)state[nameof(ppi)]); + // keyboard = (bool[,])(state[nameof(keyboard)]); + // ReconfigureSystem(); + //} + + //public Dictionary GetState() + //{ + // return new Dictionary + // { + // [nameof(configuration.TVStandard)] = configuration.TVStandard, + + // [nameof(cartridge)] = SaveStateHandler.PerformGetState(cartridge), + // [nameof(wram)] = wram, + // [nameof(cpu)] = SaveStateHandler.PerformGetState(cpu), + // [nameof(vdp)] = SaveStateHandler.PerformGetState(vdp), + // [nameof(psg)] = SaveStateHandler.PerformGetState(psg), + // [nameof(ppi)] = SaveStateHandler.PerformGetState(ppi), + // [nameof(keyboard)] = keyboard + // }; + //} + + #region + public void LoadAxiStatus(AxiEssgssStatusData data) + { + configuration.TVStandard = data.MemberData[nameof(configuration.TVStandard)].ToEnum(); + + cartridge.LoadAxiStatus(data.ClassData[nameof(cartridge)]); + wram = data.MemberData[nameof(wram)]; + cpu.LoadAxiStatus(data.ClassData[nameof(cpu)]); + vdp.LoadAxiStatus(data.ClassData[nameof(vdp)]); + psg.LoadAxiStatus(data.ClassData[nameof(psg)]); + ppi.LoadAxiStatus(data.ClassData[nameof(ppi)]); + //TODO keyboard 怕是不用保存哦 + //keyboard.LoadAxiStatus(data.ClassData[nameof(ppi)]); - SaveStateHandler.PerformSetState(cartridge, (Dictionary)state[nameof(cartridge)]); - wram = (byte[])state[nameof(wram)]; - SaveStateHandler.PerformSetState(cpu, (Dictionary)state[nameof(cpu)]); - SaveStateHandler.PerformSetState(vdp, (Dictionary)state[nameof(vdp)]); - SaveStateHandler.PerformSetState(psg, (Dictionary)state[nameof(psg)]); - SaveStateHandler.PerformSetState(ppi, (Dictionary)state[nameof(ppi)]); - keyboard = (bool[,])(state[nameof(keyboard)]); - ReconfigureSystem(); } - public Dictionary GetState() + public AxiEssgssStatusData SaveAxiStatus() { - return new Dictionary - { - [nameof(configuration.TVStandard)] = configuration.TVStandard, + AxiEssgssStatusData data = new AxiEssgssStatusData(); + data.MemberData[nameof(configuration.TVStandard)] = configuration.TVStandard.ToByteArray(); + + data.ClassData[nameof(cartridge)] = cartridge.SaveAxiStatus(); + data.MemberData[nameof(wram)] = wram; + data.ClassData[nameof(cpu)] = cpu.SaveAxiStatus(); + data.ClassData[nameof(vdp)] = vdp.SaveAxiStatus(); + data.ClassData[nameof(psg)] = psg.SaveAxiStatus(); + data.ClassData[nameof(ppi)] = ppi.SaveAxiStatus(); + //TODO keyboard 怕是不用保存哦 + //keyboard + + return data; - [nameof(cartridge)] = SaveStateHandler.PerformGetState(cartridge), - [nameof(wram)] = wram, - [nameof(cpu)] = SaveStateHandler.PerformGetState(cpu), - [nameof(vdp)] = SaveStateHandler.PerformGetState(vdp), - [nameof(psg)] = SaveStateHandler.PerformGetState(psg), - [nameof(ppi)] = SaveStateHandler.PerformGetState(ppi), - [nameof(keyboard)] = keyboard - }; } + #endregion public Dictionary GetDebugInformation() { diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Machines/SG1000.cs b/Assets/Plugins/Essgee.Unity/Emulation/Machines/SG1000.cs index da6a7a1..e8f9457 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Machines/SG1000.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Machines/SG1000.cs @@ -221,33 +221,62 @@ namespace Essgee.Emulation.Machines psg?.Shutdown(); } - //public void SetState(Dictionary state) - public void SetState(Dictionary state) + ////public void SetState(Dictionary state) + //public void SetState(Dictionary state) + //{ + // configuration.TVStandard = (TVStandard)state[nameof(configuration.TVStandard)]; + + // SaveStateHandler.PerformSetState(cartridge, (Dictionary)state[nameof(cartridge)]); + // wram = (byte[])state[nameof(wram)]; + // SaveStateHandler.PerformSetState(cpu, (Dictionary)state[nameof(cpu)]); + // SaveStateHandler.PerformSetState(vdp, (Dictionary)state[nameof(vdp)]); + // SaveStateHandler.PerformSetState(psg, (Dictionary)state[nameof(psg)]); + + // ReconfigureSystem(); + //} + + //public Dictionary GetState() + //{ + // return new Dictionary + // { + // [nameof(configuration.TVStandard)] = configuration.TVStandard, + + // [nameof(cartridge)] = SaveStateHandler.PerformGetState(cartridge), + // [nameof(wram)] = wram, + // [nameof(cpu)] = SaveStateHandler.PerformGetState(cpu), + // [nameof(vdp)] = SaveStateHandler.PerformGetState(vdp), + // [nameof(psg)] = SaveStateHandler.PerformGetState(psg) + // }; + //} + + #region + public void LoadAxiStatus(AxiEssgssStatusData data) { - configuration.TVStandard = (TVStandard)state[nameof(configuration.TVStandard)]; + configuration.TVStandard = data.MemberData[nameof(configuration.TVStandard)].ToEnum(); - SaveStateHandler.PerformSetState(cartridge, (Dictionary)state[nameof(cartridge)]); - wram = (byte[])state[nameof(wram)]; - SaveStateHandler.PerformSetState(cpu, (Dictionary)state[nameof(cpu)]); - SaveStateHandler.PerformSetState(vdp, (Dictionary)state[nameof(vdp)]); - SaveStateHandler.PerformSetState(psg, (Dictionary)state[nameof(psg)]); + cartridge.LoadAxiStatus(data.ClassData[nameof(cartridge)]); + wram = data.MemberData[nameof(wram)]; + cpu.LoadAxiStatus(data.ClassData[nameof(cpu)]); + vdp.LoadAxiStatus(data.ClassData[nameof(vdp)]); + psg.LoadAxiStatus(data.ClassData[nameof(psg)]); - ReconfigureSystem(); } - public Dictionary GetState() + public AxiEssgssStatusData SaveAxiStatus() { - return new Dictionary - { - [nameof(configuration.TVStandard)] = configuration.TVStandard, + AxiEssgssStatusData data = new AxiEssgssStatusData(); + data.MemberData[nameof(configuration.TVStandard)] = configuration.TVStandard.ToByteArray(); + + data.ClassData[nameof(cartridge)] = cartridge.SaveAxiStatus(); + data.MemberData[nameof(wram)] = wram; + data.ClassData[nameof(cpu)] = cpu.SaveAxiStatus(); + data.ClassData[nameof(vdp)] = vdp.SaveAxiStatus(); + data.ClassData[nameof(psg)] = psg.SaveAxiStatus(); + + return data; - [nameof(cartridge)] = SaveStateHandler.PerformGetState(cartridge), - [nameof(wram)] = wram, - [nameof(cpu)] = SaveStateHandler.PerformGetState(cpu), - [nameof(vdp)] = SaveStateHandler.PerformGetState(vdp), - [nameof(psg)] = SaveStateHandler.PerformGetState(psg) - }; } + #endregion public Dictionary GetDebugInformation() { diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Peripherals/IPeripheral.cs b/Assets/Plugins/Essgee.Unity/Emulation/Peripherals/IPeripheral.cs index b4431e2..a653d71 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Peripherals/IPeripheral.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Peripherals/IPeripheral.cs @@ -1,6 +1,6 @@ namespace Essgee.Emulation.Peripherals { - interface IPeripheral + interface IPeripheral : IAxiStatus { void Startup(); void Shutdown(); diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Peripherals/Intel8255.cs b/Assets/Plugins/Essgee.Unity/Emulation/Peripherals/Intel8255.cs index b3d30eb..1cfaa4d 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Peripherals/Intel8255.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Peripherals/Intel8255.cs @@ -1,5 +1,7 @@ using Essgee.Exceptions; using Essgee.Utilities; +using System; +using System.Linq; namespace Essgee.Emulation.Peripherals { @@ -32,6 +34,39 @@ namespace Essgee.Emulation.Peripherals public Intel8255() { } + + #region AxiState + + public virtual void LoadAxiStatus(AxiEssgssStatusData data) + { + PortAInput = data.MemberData[nameof(PortAInput)].First(); + PortBInput = data.MemberData[nameof(PortBInput)].First(); + PortCInput = data.MemberData[nameof(PortCInput)].First(); + PortAOutput = data.MemberData[nameof(PortAOutput)].First(); + PortBOutput = data.MemberData[nameof(PortBOutput)].First(); + PortCOutput = data.MemberData[nameof(PortCOutput)].First(); + configByte = data.MemberData[nameof(configByte)].First(); + setResetControlByte = data.MemberData[nameof(setResetControlByte)].First(); + } + + public virtual AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + PortAInput = data.MemberData[nameof(PortAInput)].First(); + PortBInput = data.MemberData[nameof(PortBInput)].First(); + PortCInput = data.MemberData[nameof(PortCInput)].First(); + data.MemberData[nameof(PortAInput)] = BitConverter.GetBytes(PortAInput); + data.MemberData[nameof(PortBInput)] = BitConverter.GetBytes(PortBInput); + data.MemberData[nameof(PortCInput)] = BitConverter.GetBytes(PortCInput); + data.MemberData[nameof(PortAOutput)] = BitConverter.GetBytes(PortAOutput); + data.MemberData[nameof(PortBOutput)] = BitConverter.GetBytes(PortBOutput); + data.MemberData[nameof(PortCOutput)] = BitConverter.GetBytes(PortCOutput); + data.MemberData[nameof(configByte)] = BitConverter.GetBytes(configByte); + data.MemberData[nameof(setResetControlByte)] = BitConverter.GetBytes(setResetControlByte); + return data; + } + #endregion + public void Startup() { // diff --git a/Assets/Plugins/Essgee.Unity/Emulation/SaveStateHandler.cs b/Assets/Plugins/Essgee.Unity/Emulation/SaveStateHandler.cs index aa659db..2fc94d0 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/SaveStateHandler.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/SaveStateHandler.cs @@ -1,149 +1,159 @@ -using Essgee.Exceptions; -using Essgee.Utilities; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.Serialization.Formatters.Binary; -using System.Text; +using System.IO; namespace Essgee.Emulation { public static class SaveStateHandler { - public static string ExpectedVersion = $"ESGST{new Version(EmuStandInfo.ProductVersion).Major:D3}"; + //public static string ExpectedVersion = $"ESGST{new Version(EmuStandInfo.ProductVersion).Major:D3}"; - public static Dictionary Load(Stream stream, string machineName) + //public static Dictionary Load(Stream stream, string machineName) + //{ + // stream.Position = 0; + + // using (var reader = new BinaryReader(stream)) + // { + // /* Read and check version string */ + // var version = Encoding.ASCII.GetString(reader.ReadBytes(ExpectedVersion.Length)); + // if (version != ExpectedVersion) throw new EmulationException("Unsupported savestate version"); + + // /* Read and check filesize */ + // var filesize = reader.ReadUInt32(); + // if (filesize != reader.BaseStream.Length) throw new EmulationException("Savestate filesize mismatch"); + + // /* Read CRC32 */ + // var crc32 = reader.ReadUInt32(); + + // /* Read and check machine ID */ + // var machineId = Encoding.ASCII.GetString(reader.ReadBytes(16)); + // if (machineId != GenerateMachineIdString(machineName)) throw new EmulationException("Savestate machine mismatch"); + + // /* Check CRC32 */ + // using (var stateStream = new MemoryStream()) + // { + // reader.BaseStream.CopyTo(stateStream); + // stateStream.Position = 0; + // var expectedCrc32 = Crc32.Calculate(stateStream); + // if (crc32 != expectedCrc32) throw new EmulationException("Savestate checksum error"); + + // /* Read state data */ + // var binaryFormatter = new BinaryFormatter(); + // return (binaryFormatter.Deserialize(stateStream) as Dictionary); + // } + // } + //} + + public static AxiEssgssStatusData LoadAxiStatus(Stream stream, string machineName) { - stream.Position = 0; - using (var reader = new BinaryReader(stream)) { - /* Read and check version string */ - var version = Encoding.ASCII.GetString(reader.ReadBytes(ExpectedVersion.Length)); - if (version != ExpectedVersion) throw new EmulationException("Unsupported savestate version"); - - /* Read and check filesize */ - var filesize = reader.ReadUInt32(); - if (filesize != reader.BaseStream.Length) throw new EmulationException("Savestate filesize mismatch"); - - /* Read CRC32 */ - var crc32 = reader.ReadUInt32(); - - /* Read and check machine ID */ - var machineId = Encoding.ASCII.GetString(reader.ReadBytes(16)); - if (machineId != GenerateMachineIdString(machineName)) throw new EmulationException("Savestate machine mismatch"); - /* Check CRC32 */ using (var stateStream = new MemoryStream()) { reader.BaseStream.CopyTo(stateStream); - stateStream.Position = 0; - var expectedCrc32 = Crc32.Calculate(stateStream); - if (crc32 != expectedCrc32) throw new EmulationException("Savestate checksum error"); - - /* Read state data */ - var binaryFormatter = new BinaryFormatter(); - return (binaryFormatter.Deserialize(stateStream) as Dictionary); + return stateStream.ToArray().ToAxiEssgssStatusData(); } } } - public static void Save(Stream stream, string machineName, Dictionary state) + //public static void Save(Stream stream, string machineName, Dictionary state) + //{ + // using (var writer = new BinaryWriter(new MemoryStream())) + // { + // /* Write version string */ + // writer.Write(Encoding.ASCII.GetBytes(ExpectedVersion)); + + // /* Write filesize placeholder */ + // var filesizePosition = writer.BaseStream.Position; + // writer.Write(uint.MaxValue); + + // /* Write CRC32 placeholder */ + // var crc32Position = writer.BaseStream.Position; + // writer.Write(uint.MaxValue); + + // /* Write machine ID */ + // writer.Write(Encoding.ASCII.GetBytes(GenerateMachineIdString(machineName))); + + // /* Current position is end of header, store for later */ + // var headerSize = writer.BaseStream.Position; + + // /* Write state data */ + // var binaryFormatter = new BinaryFormatter(); + // binaryFormatter.Serialize(writer.BaseStream, state); + + // /* Write filesize */ + // var lastOffset = writer.BaseStream.Position; + // writer.BaseStream.Position = filesizePosition; + // writer.Write((uint)writer.BaseStream.Length); + // writer.BaseStream.Position = lastOffset; + + // /* Calculate CRC32 for state data, then write CRC32 */ + // lastOffset = writer.BaseStream.Position; + + // writer.BaseStream.Position = 0; + // var crc32 = Crc32.Calculate(writer.BaseStream, (int)headerSize, (int)(writer.BaseStream.Length - headerSize)); + + // writer.BaseStream.Position = crc32Position; + // writer.Write(crc32); + // writer.BaseStream.Position = lastOffset; + + // /* Copy to file */ + // writer.BaseStream.Position = 0; + // writer.BaseStream.CopyTo(stream); + // } + //} + + public static void Save(Stream stream, string machineName, AxiEssgssStatusData state) { - using (var writer = new BinaryWriter(new MemoryStream())) - { - /* Write version string */ - writer.Write(Encoding.ASCII.GetBytes(ExpectedVersion)); - - /* Write filesize placeholder */ - var filesizePosition = writer.BaseStream.Position; - writer.Write(uint.MaxValue); - - /* Write CRC32 placeholder */ - var crc32Position = writer.BaseStream.Position; - writer.Write(uint.MaxValue); - - /* Write machine ID */ - writer.Write(Encoding.ASCII.GetBytes(GenerateMachineIdString(machineName))); - - /* Current position is end of header, store for later */ - var headerSize = writer.BaseStream.Position; - - /* Write state data */ - var binaryFormatter = new BinaryFormatter(); - binaryFormatter.Serialize(writer.BaseStream, state); - - /* Write filesize */ - var lastOffset = writer.BaseStream.Position; - writer.BaseStream.Position = filesizePosition; - writer.Write((uint)writer.BaseStream.Length); - writer.BaseStream.Position = lastOffset; - - /* Calculate CRC32 for state data, then write CRC32 */ - lastOffset = writer.BaseStream.Position; - - writer.BaseStream.Position = 0; - var crc32 = Crc32.Calculate(writer.BaseStream, (int)headerSize, (int)(writer.BaseStream.Length - headerSize)); - - writer.BaseStream.Position = crc32Position; - writer.Write(crc32); - writer.BaseStream.Position = lastOffset; - - /* Copy to file */ - writer.BaseStream.Position = 0; - writer.BaseStream.CopyTo(stream); - } + byte[] data = state.ToByteArray(); + stream.Write(data, 0, data.Length); } + //private static string GenerateMachineIdString(string machineId) + //{ + // return machineId.Substring(0, Math.Min(machineId.Length, 16)).PadRight(16); + //} - private static string GenerateMachineIdString(string machineId) - { - return machineId.Substring(0, Math.Min(machineId.Length, 16)).PadRight(16); - } + ////public static void PerformSetState(object obj, Dictionary state) - //public static void PerformSetState(object obj, Dictionary state) + //public static void PerformSetState(object obj, Dictionary state) + //{ + // if (obj != null) + // { + // /* Restore property values from state */ + // foreach (var prop in obj.GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(StateRequiredAttribute), false).Length != 0)) + // { + // prop.SetValue(obj, state[prop.Name]); + // } - public static void PerformSetState(object obj, Dictionary state) - { - if (obj != null) - { - /* Restore property values from state */ - foreach (var prop in obj.GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(StateRequiredAttribute), false).Length != 0)) - { - prop.SetValue(obj, state[prop.Name]); - } + // /* Restore field values from state */ + // foreach (var field in obj.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(StateRequiredAttribute), false).Length != 0)) + // { + // field.SetValue(obj, state[field.Name]); + // } + // } + //} - /* Restore field values from state */ - foreach (var field in obj.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(StateRequiredAttribute), false).Length != 0)) - { - field.SetValue(obj, state[field.Name]); - } - } - } + ////public static Dictionary PerformGetState(object obj) + //public static Dictionary PerformGetState(object obj) + //{ + // //var state = new Dictionary(); + // var state = new Dictionary(); - //public static Dictionary PerformGetState(object obj) - public static Dictionary PerformGetState(object obj) - { - //var state = new Dictionary(); - var state = new Dictionary(); + // if (obj != null) + // { + // /* Copy property values to state */ + // foreach (var prop in obj.GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(StateRequiredAttribute), false).Length != 0)) + // { + // state.Add(prop.Name, prop.GetValue(obj)); + // } - if (obj != null) - { - /* Copy property values to state */ - foreach (var prop in obj.GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(StateRequiredAttribute), false).Length != 0)) - { - state.Add(prop.Name, prop.GetValue(obj)); - } + // /* Copy field values to state */ + // foreach (var field in obj.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(StateRequiredAttribute), false).Length != 0)) + // { + // state.Add(field.Name, field.GetValue(obj)); + // } + // } - /* Copy field values to state */ - foreach (var field in obj.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(StateRequiredAttribute), false).Length != 0)) - { - state.Add(field.Name, field.GetValue(obj)); - } - } - - return state; - } + // return state; + //} } } diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Video/IVideo.cs b/Assets/Plugins/Essgee.Unity/Emulation/Video/IVideo.cs index 47305aa..fcbadd4 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Video/IVideo.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Video/IVideo.cs @@ -3,7 +3,7 @@ using System; namespace Essgee.Emulation.Video { - interface IVideo + interface IVideo : IAxiStatus { (int X, int Y, int Width, int Height) Viewport { get; } diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Video/Nintendo/CGBVideo.cs b/Assets/Plugins/Essgee.Unity/Emulation/Video/Nintendo/CGBVideo.cs index 4c9fc78..51fda27 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Video/Nintendo/CGBVideo.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Video/Nintendo/CGBVideo.cs @@ -64,6 +64,20 @@ namespace Essgee.Emulation.Video.Nintendo objPaletteData = new byte[64]; } + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + base.LoadAxiStatus(data); + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = base.SaveAxiStatus(); + return data; + } + #endregion + public override void Reset() { base.Reset(); @@ -94,6 +108,7 @@ namespace Essgee.Emulation.Video.Nintendo hdmaBytesLeft = 0; } + // protected override void StepHBlank() diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Video/Nintendo/DMGVideo.cs b/Assets/Plugins/Essgee.Unity/Emulation/Video/Nintendo/DMGVideo.cs index a8f738c..f75d4e4 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Video/Nintendo/DMGVideo.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Video/Nintendo/DMGVideo.cs @@ -145,6 +145,22 @@ namespace Essgee.Emulation.Video.Nintendo layerSpritesForceEnable = true; } + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + vram = data.Array2DMemberData[nameof(vram)].Get2DArrayBytesData(); + oam = data.MemberData[nameof(oam)]; + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + data.Array2DMemberData[nameof(vram)] = new AxiEssgssStatusData_2DArray(vram); + data.MemberData[nameof(oam)] = oam; + return data; + } + #endregion public object GetRuntimeOption(string name) { switch (name) diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Video/SegaSMSVDP.cs b/Assets/Plugins/Essgee.Unity/Emulation/Video/SegaSMSVDP.cs index 59af3b6..d99e900 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Video/SegaSMSVDP.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Video/SegaSMSVDP.cs @@ -2,7 +2,10 @@ using Essgee.Utilities; using System; using System.Diagnostics; +using System.Linq; using System.Runtime.InteropServices; +using Unity.Mathematics; +using Unity.VisualScripting; using static Essgee.Emulation.Utilities; namespace Essgee.Emulation.Video @@ -358,6 +361,39 @@ namespace Essgee.Emulation.Video for (int i = 0; i < spriteBuffer.Length; i++) spriteBuffer[i] = new (int Number, int Y, int X, int Pattern, int Attribute)[NumSpritesPerLineMode4]; } + #region AxiState + + public void LoadAxiStatus(AxiEssgssStatusData data) + { + base.LoadAxiStatus(data); + cram_set = data.MemberData[nameof(cram)]; + vCounter = BitConverter.ToInt32(data.MemberData[nameof(vCounter)]); + hCounter = BitConverter.ToInt32(data.MemberData[nameof(hCounter)]); + lineInterruptCounter = BitConverter.ToInt32(data.MemberData[nameof(lineInterruptCounter)]); + isLineInterruptPending = BitConverter.ToBoolean(data.MemberData[nameof(isLineInterruptPending)]); + horizontalScrollLatched = data.MemberData[nameof(horizontalScrollLatched)].First(); + verticalScrollLatched = data.MemberData[nameof(verticalScrollLatched)].First(); + } + + public AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = base.SaveAxiStatus(); + + data.MemberData[nameof(cram)] = cram_src; + data.MemberData[nameof(vCounter)] = BitConverter.GetBytes(vCounter); + data.MemberData[nameof(hCounter)] = BitConverter.GetBytes(hCounter); + + data.MemberData[nameof(lineInterruptCounter)] = BitConverter.GetBytes(lineInterruptCounter); + + data.MemberData[nameof(isLineInterruptPending)] = BitConverter.GetBytes(isLineInterruptPending); + + data.MemberData[nameof(horizontalScrollLatched)] = BitConverter.GetBytes(horizontalScrollLatched); + data.MemberData[nameof(verticalScrollLatched)] = BitConverter.GetBytes(verticalScrollLatched); + + return data; + } + #endregion + public override void Reset() { base.Reset(); diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Video/TMS99xxA.cs b/Assets/Plugins/Essgee.Unity/Emulation/Video/TMS99xxA.cs index 372c421..c0983bd 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Video/TMS99xxA.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Video/TMS99xxA.cs @@ -2,8 +2,10 @@ using Essgee.Utilities; using System; using System.Diagnostics; +using System.Linq; using System.Runtime.InteropServices; using static Essgee.Emulation.Utilities; +using static UnityEditor.Experimental.AssetDatabaseExperimental.AssetDatabaseCounters; namespace Essgee.Emulation.Video { @@ -90,6 +92,82 @@ namespace Essgee.Emulation.Video [StateRequired] protected (int Number, int Y, int X, int Pattern, int Attribute)[][] spriteBuffer; + // 序列化方法 + public byte[] spriteBuffer_Serialize() + { + // 首先,我们需要计算序列化后的总字节数 + int totalBytes = 0; + foreach (var row in spriteBuffer) + { + if (row != null) + { + totalBytes += row.Length * 5 * sizeof(int); // 每个元组有5个int,每个int占4个字节 + } + } + + // 分配一个足够大的字节数组 + byte[] data = new byte[totalBytes]; + int offset = 0; + + // 填充字节数组 + foreach (var row in spriteBuffer) + { + if (row != null) + { + foreach (var tuple in row) + { + Buffer.BlockCopy(BitConverter.GetBytes(tuple.Number), 0, data, offset, sizeof(int)); + offset += sizeof(int); + Buffer.BlockCopy(BitConverter.GetBytes(tuple.Y), 0, data, offset, sizeof(int)); + offset += sizeof(int); + Buffer.BlockCopy(BitConverter.GetBytes(tuple.X), 0, data, offset, sizeof(int)); + offset += sizeof(int); + Buffer.BlockCopy(BitConverter.GetBytes(tuple.Pattern), 0, data, offset, sizeof(int)); + offset += sizeof(int); + Buffer.BlockCopy(BitConverter.GetBytes(tuple.Attribute), 0, data, offset, sizeof(int)); + offset += sizeof(int); + } + } + } + + return data; + } + + // 反序列化方法 + public void spriteBuffer_SetData(byte[] data) + { + // 假设我们已经知道spriteBuffer的维度(这通常需要在序列化时保存并在反序列化时读取) + // 为了简化,这里假设维度是已知的,并且与原始spriteBuffer相同 + int rowCount = spriteBuffer.Length; + int[] columnCounts = new int[rowCount]; + for (int i = 0; i < rowCount; i++) + { + if (spriteBuffer[i] != null) + { + columnCounts[i] = spriteBuffer[i].Length; + } + } + + int offset = 0; + spriteBuffer = new (int, int, int, int, int)[rowCount][]; + + for (int i = 0; i < rowCount; i++) + { + spriteBuffer[i] = new (int, int, int, int, int)[columnCounts[i]]; + for (int j = 0; j < columnCounts[i]; j++) + { + spriteBuffer[i][j] = ( + BitConverter.ToInt32(data, offset), + BitConverter.ToInt32(data, offset + sizeof(int)), + BitConverter.ToInt32(data, offset + 2 * sizeof(int)), + BitConverter.ToInt32(data, offset + 3 * sizeof(int)), + BitConverter.ToInt32(data, offset + 4 * sizeof(int)) + ); + offset += 5 * sizeof(int); + } + } + } + //protected ushort vramMask16k => 0x3FFF; //protected ushort vramMask4k => 0x0FFF; protected const ushort vramMask16k = 0x3FFF; @@ -103,7 +181,7 @@ namespace Essgee.Emulation.Video protected byte readBuffer; protected byte codeRegister => (byte)((controlWord >> 14) & 0x03); - + protected ushort addressRegister { get { return (ushort)(controlWord & 0x3FFF); } @@ -246,6 +324,43 @@ namespace Essgee.Emulation.Video layerBordersForceEnable = true; } + + #region AxiState + + public virtual void LoadAxiStatus(AxiEssgssStatusData data) + { + registers_set = data.MemberData[nameof(registers)]; + vram_set = data.MemberData[nameof(vram)]; + spriteBuffer_SetData(data.MemberData[nameof(spriteBuffer)]); + isSecondControlWrite = BitConverter.ToBoolean(data.MemberData[nameof(isSecondControlWrite)]); + controlWord = BitConverter.ToUInt16(data.MemberData[nameof(controlWord)]); + readBuffer = data.MemberData[nameof(readBuffer)].First(); + statusFlags = data.MemberData[nameof(statusFlags)].ToEnum(); + InterruptLine = data.MemberData[nameof(InterruptLine)].ToEnum(); + currentScanline = BitConverter.ToInt32(data.MemberData[nameof(currentScanline)]); + screenUsage = data.MemberData[nameof(screenUsage)]; + cycleCount = BitConverter.ToInt32(data.MemberData[nameof(cycleCount)]); + } + + public virtual AxiEssgssStatusData SaveAxiStatus() + { + AxiEssgssStatusData data = new AxiEssgssStatusData(); + data.MemberData[nameof(registers)] = registers_src; + data.MemberData[nameof(vram)] = vram_src; + data.MemberData[nameof(spriteBuffer)] = spriteBuffer_Serialize(); + data.MemberData[nameof(isSecondControlWrite)] = BitConverter.GetBytes(isSecondControlWrite); + data.MemberData[nameof(controlWord)] = BitConverter.GetBytes(controlWord); + data.MemberData[nameof(readBuffer)] = BitConverter.GetBytes(readBuffer); + data.MemberData[nameof(statusFlags)] = statusFlags.ToByteArray(); + data.MemberData[nameof(InterruptLine)] = InterruptLine.ToByteArray(); + data.MemberData[nameof(currentScanline)] = BitConverter.GetBytes(currentScanline); + data.MemberData[nameof(screenUsage)] = screenUsage; + data.MemberData[nameof(cycleCount)] = BitConverter.GetBytes(cycleCount); + return data; + } + + #endregion + public object GetRuntimeOption(string name) { switch (name) diff --git a/Assets/Plugins/Essgee.Unity/IAxiStatus.cs b/Assets/Plugins/Essgee.Unity/IAxiStatus.cs new file mode 100644 index 0000000..a683da8 --- /dev/null +++ b/Assets/Plugins/Essgee.Unity/IAxiStatus.cs @@ -0,0 +1,224 @@ +using Essgee.Utilities; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; + +[Serializable] +public class AxiEssgssStatusData +{ + public Dictionary MemberData = new Dictionary(); + public Dictionary Array2DMemberData = new Dictionary(); + public Dictionary ClassData = new Dictionary(); +} + +[Serializable] +public class AxiEssgssStatusData_2DArray +{ + public int rows; + public int cols; + public byte[] array1D; + public AxiEssgssStatusData_2DArray(byte[,] data2D) + { + rows = data2D.GetLength(0); + cols = data2D.GetLength(1); + array1D = data2D.FlattenByteArray2D(); + } + + public byte[,] Get2DArrayBytesData() + { + return array1D.CreateByteArray2D(rows, cols); + } +} +public static class AxiEssgssStatusDataExtention +{ + public static byte[] ToByteArray(this AxiEssgssStatusData data) + { + using (MemoryStream ms = new MemoryStream()) + { + BinaryFormatter formatter = new BinaryFormatter(); + formatter.Serialize(ms, data); + return ms.ToArray(); + } + } + + public static AxiEssgssStatusData ToAxiEssgssStatusData(this byte[] byteArray) + { + using (MemoryStream ms = new MemoryStream(byteArray)) + { + BinaryFormatter formatter = new BinaryFormatter(); + return (AxiEssgssStatusData)formatter.Deserialize(ms); + } + } +} +public interface IAxiStatus +{ + public void LoadAxiStatus(AxiEssgssStatusData data); + public AxiEssgssStatusData SaveAxiStatus(); +} + +internal static class AxiStatus +{ + // öתΪbyte[] + public static byte[] ToByteArray(this TEnum[] enumArray) where TEnum : struct, Enum + { + if (!typeof(TEnum).IsEnum) throw new ArgumentException("TEnum must be an enumerated type"); + + // ȡöٵĻͣͨInt32 + Type enumUnderlyingType = Enum.GetUnderlyingType(typeof(TEnum)); + if (enumUnderlyingType != typeof(byte)) // ǷΪbyteǣҪжĴ + { + // ͲbyteҪδǼintתΪbyte飬 + // Ҫע⣬ܻᵼݶʧöֵbyteķΧ + // һȫķʹøͣint[]Ϊмʾ + // Ϊ˼ʾǽöֵ԰ȫתΪbyte + // 棺ܲ + + // ǼintöٻͣǿֱתÿöֵΪint + // ȻǷ԰ȫתΪbyteܣォ׳쳣 + return enumArray.Select(e => + { + int intValue = Convert.ToInt32(e); + if (intValue < byte.MinValue || intValue > byte.MaxValue) + throw new OverflowException($"Enum value {e} ({intValue}) is out of range for byte."); + return (byte)intValue; + }).ToArray(); + } + else + { + // Ѿbyteֱת + return Array.ConvertAll(enumArray, e => Convert.ToByte(e)); + } + } + + // byte[]תΪö + public static TEnum[] ToEnumArray(this byte[] byteArray) where TEnum : struct, Enum + { + if (!typeof(TEnum).IsEnum) throw new ArgumentException("TEnum must be an enumerated type"); + + // ֱתÿbyteΪöֵ + return Array.ConvertAll(byteArray, b => (TEnum)Enum.ToObject(typeof(TEnum), b)); + } + + // öתΪbyte[]ͨת̫Ϊֻһֽڣǻʵ + public static byte[] ToByteArray(this TEnum enumValue) where TEnum : struct, Enum + { + if (!typeof(TEnum).IsEnum) throw new ArgumentException("TEnum must be an enumerated type"); + + // ȡöٵĻ + Type enumUnderlyingType = Enum.GetUnderlyingType(typeof(TEnum)); + + // ǷΪbyteǣתǼ԰ȫתΪbyteͨöٵĻint + if (enumUnderlyingType == typeof(byte)) + { + // Ѿbyteֱӷذֽڵ + return new[] { Convert.ToByte(enumValue) }; + } + else if (enumUnderlyingType == typeof(int)) // öٻ + { + // öֵתΪintȻǷ԰ȫתΪbyte + int intValue = Convert.ToInt32(enumValue); + if (intValue < byte.MinValue || intValue > byte.MaxValue) + throw new OverflowException($"Enum value {enumValue} ({intValue}) is out of range for byte."); + + // ذתֽڵ + return new[] { (byte)intValue }; + } + else + { + // Ͳbyteint׳쳣Ӹͼʹ߼ + throw new NotSupportedException($"The underlying type of the enum {typeof(TEnum).Name} is not supported."); + } + } + + // byte[]תΪö٣byte[]ֻһֽڣ + public static TEnum ToEnum(this byte[] byteArray) where TEnum : struct, Enum + { + if (byteArray == null || byteArray.Length != 1) + throw new ArgumentException("The byte array must contain exactly one byte."); + + // ֱӴֽתΪöֵ + return (TEnum)Enum.ToObject(typeof(TEnum), byteArray[0]); + } + + // ushort[] ת byte[] + public static byte[] ToByteArray(this ushort[] ushortArray) + { + byte[] byteArray = new byte[ushortArray.Length * 2]; + Buffer.BlockCopy(ushortArray, 0, byteArray, 0, byteArray.Length); + return byteArray; + } + + // byte[] ת ushort[] + public static ushort[] ToUShortArray(this byte[] byteArray) + { + if (byteArray.Length % 2 != 0) + throw new ArgumentException("byte鳤ȱż"); + + ushort[] ushortArray = new ushort[byteArray.Length / 2]; + Buffer.BlockCopy(byteArray, 0, ushortArray, 0, byteArray.Length); + return ushortArray; + } + + + + public static byte[] ToByteArray(this bool[] boolArr) + { + byte[] byteArray = new byte[boolArr.Length]; + for (int i = 0; i < byteArray.Length; i++) + { + byteArray[i] = (byte)(boolArr[i] ? 1 : 0); + } + return byteArray; + } + + public static bool[] ToBoolArray(this byte[] byteArray) + { + bool[] boolArr = new bool[byteArray.Length]; + for (int i = 0; i < byteArray.Length; i++) + { + boolArr[i] = byteArray[i] == 0 ? false : true; + } + return boolArr; + } + + public static byte[] FlattenByteArray2D(this byte[,] array2D) + { + int rows = array2D.GetLength(0); + int cols = array2D.GetLength(1); + byte[] array1D = new byte[rows * cols]; + + int index = 0; + for (int i = 0; i < rows; i++) + { + for (int j = 0; j < cols; j++) + { + array1D[index++] = array2D[i, j]; + } + } + + return array1D; + } + public static byte[,] CreateByteArray2D(this byte[] array1D, int rows, int cols) + { + if (array1D.Length != rows * cols) + { + throw new ArgumentException("The length of the 1D array does not match the specified dimensions for the 2D array."); + } + + byte[,] array2D = new byte[rows, cols]; + + int index = 0; + for (int i = 0; i < rows; i++) + { + for (int j = 0; j < cols; j++) + { + array2D[i, j] = array1D[index++]; + } + } + + return array2D; + } +} diff --git a/Assets/Plugins/Essgee.Unity/IAxiStatus.cs.meta b/Assets/Plugins/Essgee.Unity/IAxiStatus.cs.meta new file mode 100644 index 0000000..7febd99 --- /dev/null +++ b/Assets/Plugins/Essgee.Unity/IAxiStatus.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 40ed20a1384827f45b7f187a4ccb4740 \ No newline at end of file diff --git a/Assets/Scripts/UEssgee.cs b/Assets/Scripts/UEssgee.cs index 36ebbbf..0346d7d 100644 --- a/Assets/Scripts/UEssgee.cs +++ b/Assets/Scripts/UEssgee.cs @@ -62,6 +62,15 @@ public class Essgeeinit : MonoBehaviour mUniKeyboard.UpdateInputKey(); emulatorHandler.Update_Frame(); + + if (Input.GetKeyDown(KeyCode.F5)) + { + emulatorHandler.mySaveState(0); + } + if (Input.GetKeyDown(KeyCode.F6)) + { + emulatorHandler.myLoadState(0); + } } void InitAll(IGameMetaReources metaresources,string CustonDataDir) diff --git a/Assets/Scripts/UEssgeeInterface/KeyCodeCore.cs b/Assets/Scripts/UEssgeeInterface/KeyCodeCore.cs index 3ea94e8..1221a8d 100644 --- a/Assets/Scripts/UEssgeeInterface/KeyCodeCore.cs +++ b/Assets/Scripts/UEssgeeInterface/KeyCodeCore.cs @@ -146,6 +146,7 @@ public class KeyCodeCore dictKey2Motion.Add(EssgeeUnityKey.P2_BTN_1, machine.configuration.Joypad2Button1); dictKey2Motion.Add(EssgeeUnityKey.P2_BTN_2, machine.configuration.Joypad2Button2); } + //存档功能待补 else if (Machine is Essgee.Emulation.Machines.GameBoy) { var machine = (Essgee.Emulation.Machines.GameBoy)Machine; @@ -168,6 +169,7 @@ public class KeyCodeCore dictKey2Motion.Add(EssgeeUnityKey.P1_POTION_1, machine.configuration.ControlsStart); dictKey2Motion.Add(EssgeeUnityKey.P1_POTION_2, machine.configuration.ControlsSelect); } + //存档功能待补 else if (Machine is Essgee.Emulation.Machines.GameBoyColor) { var machine = (Essgee.Emulation.Machines.GameBoyColor)Machine;