重写各个平台的保存机制,基本测试通过(即时存档)
This commit is contained in:
parent
ee40681744
commit
1ceb8ef211
@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using Unity.VisualScripting.Dependencies.Sqlite;
|
||||||
|
|
||||||
namespace Essgee.Emulation.Audio
|
namespace Essgee.Emulation.Audio
|
||||||
{
|
{
|
||||||
@ -130,6 +131,24 @@ namespace Essgee.Emulation.Audio
|
|||||||
channel4ForceEnable = true;
|
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)
|
public object GetRuntimeOption(string name)
|
||||||
{
|
{
|
||||||
switch (name)
|
switch (name)
|
||||||
|
@ -3,7 +3,7 @@ using System;
|
|||||||
|
|
||||||
namespace Essgee.Emulation.Audio
|
namespace Essgee.Emulation.Audio
|
||||||
{
|
{
|
||||||
interface IAudio
|
interface IAudio : IAxiStatus
|
||||||
{
|
{
|
||||||
event EventHandler<EnqueueSamplesEventArgs> EnqueueSamples;
|
event EventHandler<EnqueueSamplesEventArgs> EnqueueSamples;
|
||||||
void OnEnqueueSamples(EnqueueSamplesEventArgs e);
|
void OnEnqueueSamples(EnqueueSamplesEventArgs e);
|
||||||
|
@ -5,7 +5,9 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using UnityEngine.Playables;
|
||||||
using static Essgee.Emulation.Utilities;
|
using static Essgee.Emulation.Utilities;
|
||||||
|
using static UnityEditor.Experimental.AssetDatabaseExperimental.AssetDatabaseCounters;
|
||||||
|
|
||||||
namespace Essgee.Emulation.Audio
|
namespace Essgee.Emulation.Audio
|
||||||
{
|
{
|
||||||
@ -157,6 +159,46 @@ namespace Essgee.Emulation.Audio
|
|||||||
channel4ForceEnable = true;
|
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)
|
public object GetRuntimeOption(string name)
|
||||||
{
|
{
|
||||||
switch (name)
|
switch (name)
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
namespace Essgee.Emulation.Audio
|
using static UnityEditor.Experimental.AssetDatabaseExperimental.AssetDatabaseCounters;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Essgee.Emulation.Audio
|
||||||
{
|
{
|
||||||
public class SegaSMSPSG : SN76489
|
public class SegaSMSPSG : SN76489
|
||||||
{
|
{
|
||||||
@ -15,5 +18,20 @@
|
|||||||
|
|
||||||
noiseLfsr = 0x8000;
|
noiseLfsr = 0x8000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region AxiState
|
||||||
|
|
||||||
|
public void LoadAxiStatus(AxiEssgssStatusData data)
|
||||||
|
{
|
||||||
|
base.LoadAxiStatus(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AxiEssgssStatusData SaveAxiStatus()
|
||||||
|
{
|
||||||
|
AxiEssgssStatusData data = base.SaveAxiStatus();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Essgee.Emulation.CPU
|
namespace Essgee.Emulation.CPU
|
||||||
{
|
{
|
||||||
interface ICPU
|
interface ICPU: IAxiStatus
|
||||||
{
|
{
|
||||||
void Startup();
|
void Startup();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
@ -20,6 +20,10 @@ namespace Essgee.Emulation.CPU
|
|||||||
|
|
||||||
[FieldOffset(0)]
|
[FieldOffset(0)]
|
||||||
public ushort Word;
|
public ushort Word;
|
||||||
|
|
||||||
|
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public ushort axi_AllData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using Essgee.Utilities;
|
using Essgee.Utilities;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Unity.VisualScripting;
|
||||||
using static Essgee.Emulation.Utilities;
|
using static Essgee.Emulation.Utilities;
|
||||||
|
|
||||||
namespace Essgee.Emulation.CPU
|
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()
|
public virtual void Startup()
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
|
@ -20,6 +20,10 @@ namespace Essgee.Emulation.CPU
|
|||||||
|
|
||||||
[FieldOffset(0)]
|
[FieldOffset(0)]
|
||||||
public ushort Word;
|
public ushort Word;
|
||||||
|
|
||||||
|
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public ushort axi_AllData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Essgee.Exceptions;
|
using Essgee.Exceptions;
|
||||||
using Essgee.Utilities;
|
using Essgee.Utilities;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using static Essgee.Emulation.Utilities;
|
using static Essgee.Emulation.Utilities;
|
||||||
|
|
||||||
namespace Essgee.Emulation.CPU
|
namespace Essgee.Emulation.CPU
|
||||||
@ -71,6 +72,80 @@ namespace Essgee.Emulation.CPU
|
|||||||
portWriteDelegate = portWrite;
|
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<InterruptState>();
|
||||||
|
nmiState = data.MemberData[nameof(nmiState)].ToEnum<InterruptState>();
|
||||||
|
|
||||||
|
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()
|
public virtual void Startup()
|
||||||
{
|
{
|
||||||
Reset();
|
Reset();
|
||||||
|
@ -8,6 +8,18 @@ namespace Essgee.Emulation.Cartridges.Coleco
|
|||||||
|
|
||||||
byte[] romData;
|
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)
|
public ColecoCartridge(int romSize, int ramSize)
|
||||||
{
|
{
|
||||||
romData = new byte[romSize];
|
romData = new byte[romSize];
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Essgee.Emulation.Cartridges
|
namespace Essgee.Emulation.Cartridges
|
||||||
{
|
{
|
||||||
public interface ICartridge
|
internal interface ICartridge :IAxiStatus
|
||||||
{
|
{
|
||||||
void LoadRom(byte[] data);
|
void LoadRom(byte[] data);
|
||||||
void LoadRam(byte[] data);
|
void LoadRam(byte[] data);
|
||||||
|
@ -65,6 +65,20 @@ namespace Essgee.Emulation.Cartridges.Nintendo
|
|||||||
hasBattery = false;
|
hasBattery = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#region AxiState
|
||||||
|
|
||||||
|
public void LoadAxiStatus(AxiEssgssStatusData data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AxiEssgssStatusData SaveAxiStatus()
|
||||||
|
{
|
||||||
|
AxiEssgssStatusData data = new AxiEssgssStatusData();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
public void LoadRom(byte[] data)
|
public void LoadRom(byte[] data)
|
||||||
{
|
{
|
||||||
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Essgee.Emulation.Cartridges.Nintendo
|
namespace Essgee.Emulation.Cartridges.Nintendo
|
||||||
{
|
{
|
||||||
public interface IGameBoyCartridge : ICartridge
|
internal interface IGameBoyCartridge : ICartridge
|
||||||
{
|
{
|
||||||
void SetCartridgeConfig(bool battery, bool rtc, bool rumble);
|
void SetCartridgeConfig(bool battery, bool rtc, bool rumble);
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,18 @@ namespace Essgee.Emulation.Cartridges.Nintendo
|
|||||||
hasBattery = false;
|
hasBattery = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region AxiState
|
||||||
|
|
||||||
|
public void LoadAxiStatus(AxiEssgssStatusData data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AxiEssgssStatusData SaveAxiStatus()
|
||||||
|
{
|
||||||
|
AxiEssgssStatusData data = new AxiEssgssStatusData();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
public void LoadRom(byte[] data)
|
public void LoadRom(byte[] data)
|
||||||
{
|
{
|
||||||
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
||||||
|
@ -21,6 +21,18 @@ namespace Essgee.Emulation.Cartridges.Nintendo
|
|||||||
|
|
||||||
hasBattery = false;
|
hasBattery = false;
|
||||||
}
|
}
|
||||||
|
#region AxiState
|
||||||
|
|
||||||
|
public void LoadAxiStatus(AxiEssgssStatusData data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AxiEssgssStatusData SaveAxiStatus()
|
||||||
|
{
|
||||||
|
AxiEssgssStatusData data = new AxiEssgssStatusData();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
public void LoadRom(byte[] data)
|
public void LoadRom(byte[] data)
|
||||||
{
|
{
|
||||||
|
@ -32,6 +32,8 @@ namespace Essgee.Emulation.Cartridges.Nintendo
|
|||||||
IsLatched = false;
|
IsLatched = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void FromSaveData(byte[] ramData)
|
public void FromSaveData(byte[] ramData)
|
||||||
{
|
{
|
||||||
var rtcOffset = ramData.Length - 0x30;
|
var rtcOffset = ramData.Length - 0x30;
|
||||||
@ -129,6 +131,18 @@ namespace Essgee.Emulation.Cartridges.Nintendo
|
|||||||
rtc = new RTC();
|
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)
|
public void LoadRom(byte[] data)
|
||||||
{
|
{
|
||||||
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
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;
|
ramData[(ramBank << 13) | (address & 0x1FFF)] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,18 @@ namespace Essgee.Emulation.Cartridges.Nintendo
|
|||||||
hasRumble = false;
|
hasRumble = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region AxiState
|
||||||
|
|
||||||
|
public void LoadAxiStatus(AxiEssgssStatusData data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AxiEssgssStatusData SaveAxiStatus()
|
||||||
|
{
|
||||||
|
AxiEssgssStatusData data = new AxiEssgssStatusData();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
public void LoadRom(byte[] data)
|
public void LoadRom(byte[] data)
|
||||||
{
|
{
|
||||||
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
||||||
|
@ -13,6 +13,18 @@ namespace Essgee.Emulation.Cartridges.Nintendo
|
|||||||
ramData = new byte[ramSize];
|
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)
|
public void LoadRom(byte[] data)
|
||||||
{
|
{
|
||||||
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
||||||
|
@ -5,7 +5,7 @@ namespace Essgee.Emulation.Cartridges.Nintendo
|
|||||||
{
|
{
|
||||||
public static class SpecializedLoader
|
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;
|
var romSize = -1;
|
||||||
switch (romData[0x0148])
|
switch (romData[0x0148])
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Essgee.Exceptions;
|
using Essgee.Exceptions;
|
||||||
using Essgee.Utilities;
|
using Essgee.Utilities;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Essgee.Emulation.Cartridges.Sega
|
namespace Essgee.Emulation.Cartridges.Sega
|
||||||
{
|
{
|
||||||
@ -11,14 +12,39 @@ namespace Essgee.Emulation.Cartridges.Sega
|
|||||||
[StateRequired]
|
[StateRequired]
|
||||||
byte[] ramData;
|
byte[] ramData;
|
||||||
|
|
||||||
[StateRequired]
|
[StateRequired]//TODO 感觉不用保存 保留readonly
|
||||||
readonly byte[] pagingRegisters;
|
byte[] pagingRegisters;
|
||||||
[StateRequired]
|
//readonly byte[] pagingRegisters;
|
||||||
readonly byte bankMask;
|
[StateRequired]//TODO 感觉不用保存 保留readonly
|
||||||
|
byte bankMask;
|
||||||
|
//readonly byte bankMask;
|
||||||
|
|
||||||
[StateRequired]
|
[StateRequired]
|
||||||
bool isRamEnabled;
|
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)
|
public CodemastersCartridge(int romSize, int ramSize)
|
||||||
{
|
{
|
||||||
pagingRegisters = new byte[3];
|
pagingRegisters = new byte[3];
|
||||||
@ -116,5 +142,6 @@ namespace Essgee.Emulation.Cartridges.Sega
|
|||||||
if (isRamEnabled && ((address & 0xF000) == 0xA000 || (address & 0xF000) == 0xB000))
|
if (isRamEnabled && ((address & 0xF000) == 0xA000 || (address & 0xF000) == 0xB000))
|
||||||
ramData[address & 0x1FFF] = value;
|
ramData[address & 0x1FFF] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Essgee.Exceptions;
|
using Essgee.Exceptions;
|
||||||
using Essgee.Utilities;
|
using Essgee.Utilities;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Essgee.Emulation.Cartridges.Sega
|
namespace Essgee.Emulation.Cartridges.Sega
|
||||||
{
|
{
|
||||||
@ -8,8 +9,10 @@ namespace Essgee.Emulation.Cartridges.Sega
|
|||||||
{
|
{
|
||||||
byte[] romData;
|
byte[] romData;
|
||||||
|
|
||||||
[StateRequired]
|
|
||||||
readonly byte[] pagingRegisters;
|
[StateRequired]//TODO 感觉不用保存 保留readonly
|
||||||
|
byte[] pagingRegisters;
|
||||||
|
//readonly byte[] pagingRegisters;
|
||||||
|
|
||||||
[StateRequired]
|
[StateRequired]
|
||||||
byte bankMask;
|
byte bankMask;
|
||||||
@ -21,6 +24,25 @@ namespace Essgee.Emulation.Cartridges.Sega
|
|||||||
romData = new byte[romSize];
|
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)
|
public void LoadRom(byte[] data)
|
||||||
{
|
{
|
||||||
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Essgee.Exceptions;
|
using Essgee.Exceptions;
|
||||||
using Essgee.Utilities;
|
using Essgee.Utilities;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Essgee.Emulation.Cartridges.Sega
|
namespace Essgee.Emulation.Cartridges.Sega
|
||||||
{
|
{
|
||||||
@ -11,6 +12,27 @@ namespace Essgee.Emulation.Cartridges.Sega
|
|||||||
[StateRequired]
|
[StateRequired]
|
||||||
byte bankMask, pagingRegister;
|
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)
|
public KoreanMapperCartridge(int romSize, int ramSize)
|
||||||
{
|
{
|
||||||
pagingRegister = 0x02;
|
pagingRegister = 0x02;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Essgee.Exceptions;
|
using Essgee.Exceptions;
|
||||||
using Essgee.Utilities;
|
using Essgee.Utilities;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using static Essgee.Emulation.Utilities;
|
using static Essgee.Emulation.Utilities;
|
||||||
|
|
||||||
namespace Essgee.Emulation.Cartridges.Sega
|
namespace Essgee.Emulation.Cartridges.Sega
|
||||||
@ -17,8 +18,10 @@ namespace Essgee.Emulation.Cartridges.Sega
|
|||||||
[StateRequired]
|
[StateRequired]
|
||||||
byte[] ramData;
|
byte[] ramData;
|
||||||
|
|
||||||
[StateRequired]
|
|
||||||
readonly byte[] pagingRegisters;
|
[StateRequired]//TODO 感觉不用保存 保留readonly
|
||||||
|
byte[] pagingRegisters;
|
||||||
|
//readonly byte[] pagingRegisters;
|
||||||
|
|
||||||
[StateRequired]
|
[StateRequired]
|
||||||
byte romBankMask;
|
byte romBankMask;
|
||||||
@ -52,6 +55,31 @@ namespace Essgee.Emulation.Cartridges.Sega
|
|||||||
isBitReverseBank1 = isBitReverseBank2 = false;
|
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)
|
public void LoadRom(byte[] data)
|
||||||
{
|
{
|
||||||
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Essgee.Exceptions;
|
using Essgee.Exceptions;
|
||||||
using Essgee.Utilities;
|
using Essgee.Utilities;
|
||||||
using System;
|
using System;
|
||||||
|
using UnityEngine.Playables;
|
||||||
|
|
||||||
namespace Essgee.Emulation.Cartridges.Sega
|
namespace Essgee.Emulation.Cartridges.Sega
|
||||||
{
|
{
|
||||||
@ -10,8 +11,9 @@ namespace Essgee.Emulation.Cartridges.Sega
|
|||||||
{
|
{
|
||||||
byte[] romData;
|
byte[] romData;
|
||||||
|
|
||||||
[StateRequired]
|
[StateRequired]//TODO 感觉不用保存 保留readonly
|
||||||
readonly int romMask;
|
int romMask;
|
||||||
|
//readonly int romMask;
|
||||||
|
|
||||||
[StateRequired]
|
[StateRequired]
|
||||||
int romBank0, romBank1, romBank2;
|
int romBank0, romBank1, romBank2;
|
||||||
@ -27,6 +29,26 @@ namespace Essgee.Emulation.Cartridges.Sega
|
|||||||
romBank0 = romBank1 = romBank2 = 0;
|
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)
|
public void LoadRom(byte[] data)
|
||||||
{
|
{
|
||||||
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Essgee.Exceptions;
|
using Essgee.Exceptions;
|
||||||
using Essgee.Utilities;
|
using Essgee.Utilities;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using static Essgee.Emulation.Utilities;
|
using static Essgee.Emulation.Utilities;
|
||||||
|
|
||||||
namespace Essgee.Emulation.Cartridges.Sega
|
namespace Essgee.Emulation.Cartridges.Sega
|
||||||
@ -13,7 +14,7 @@ namespace Essgee.Emulation.Cartridges.Sega
|
|||||||
byte[] ramData;
|
byte[] ramData;
|
||||||
|
|
||||||
[StateRequired]
|
[StateRequired]
|
||||||
readonly byte[] pagingRegisters;
|
byte[] pagingRegisters;
|
||||||
|
|
||||||
[StateRequired]
|
[StateRequired]
|
||||||
byte romBankMask;
|
byte romBankMask;
|
||||||
@ -27,6 +28,7 @@ namespace Essgee.Emulation.Cartridges.Sega
|
|||||||
int romBank1 { get { return pagingRegisters[2]; } }
|
int romBank1 { get { return pagingRegisters[2]; } }
|
||||||
int romBank2 { get { return pagingRegisters[3]; } }
|
int romBank2 { get { return pagingRegisters[3]; } }
|
||||||
|
|
||||||
|
|
||||||
public SegaMapperCartridge(int romSize, int ramSize)
|
public SegaMapperCartridge(int romSize, int ramSize)
|
||||||
{
|
{
|
||||||
pagingRegisters = new byte[0x04];
|
pagingRegisters = new byte[0x04];
|
||||||
@ -44,6 +46,27 @@ namespace Essgee.Emulation.Cartridges.Sega
|
|||||||
hasCartRam = false;
|
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)
|
public void LoadRom(byte[] data)
|
||||||
{
|
{
|
||||||
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
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) */
|
/* Otherwise ignore writes to ROM, as some games seem to be doing that? (ex. Gunstar Heroes GG to 0000) */
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
using Essgee.Utilities;
|
using Essgee.Utilities;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEngine.Playables;
|
||||||
|
|
||||||
namespace Essgee.Emulation.Cartridges.Sega
|
namespace Essgee.Emulation.Cartridges.Sega
|
||||||
{
|
{
|
||||||
@ -10,8 +12,9 @@ namespace Essgee.Emulation.Cartridges.Sega
|
|||||||
[StateRequired]
|
[StateRequired]
|
||||||
byte[] ramData;
|
byte[] ramData;
|
||||||
|
|
||||||
[StateRequired]
|
[StateRequired]//TODO 感觉不用保存 保留readonly
|
||||||
readonly int romMask, ramMask;
|
int romMask, ramMask;
|
||||||
|
//readonly int romMask, ramMask;
|
||||||
|
|
||||||
public SegaSGCartridge(int romSize, int ramSize)
|
public SegaSGCartridge(int romSize, int ramSize)
|
||||||
{
|
{
|
||||||
@ -25,6 +28,25 @@ namespace Essgee.Emulation.Cartridges.Sega
|
|||||||
ramMask = (ramSize - 1);
|
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)
|
public void LoadRom(byte[] data)
|
||||||
{
|
{
|
||||||
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
Buffer.BlockCopy(data, 0, romData, 0, Math.Min(data.Length, romData.Length));
|
||||||
|
@ -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
|
var statePath = GetSaveStateFilename(stateNumber);
|
||||||
// try this maybe? https://stackoverflow.com/a/34839411
|
using (var stream = new FileStream(statePath, FileMode.OpenOrCreate))
|
||||||
|
|
||||||
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)
|
//SaveStateHandler.Save(stream, emulator.GetType().Name, emulator.GetState());
|
||||||
{
|
SaveStateHandler.Save(stream, emulator.GetType().Name, emulator.SaveAxiStatus());
|
||||||
if (!emulationThreadRunning)
|
}
|
||||||
break;
|
}
|
||||||
|
|
||||||
if (stateLoadRequested && stateNumber != -1)
|
public void myLoadState(int stateNumber)
|
||||||
{
|
{
|
||||||
var statePath = GetSaveStateFilename(stateNumber);
|
var statePath = GetSaveStateFilename(stateNumber);
|
||||||
if (File.Exists(statePath))
|
if (File.Exists(statePath))
|
||||||
{
|
{
|
||||||
using (var stream = new FileStream(statePath, FileMode.Open))
|
using (var stream = new FileStream(statePath, FileMode.Open))
|
||||||
{
|
{
|
||||||
emulator.SetState(SaveStateHandler.Load(stream, emulator.GetType().Name));
|
//emulator.SetState(SaveStateHandler.Load(stream, emulator.GetType().Name));
|
||||||
}
|
emulator.LoadAxiStatus(SaveStateHandler.LoadAxiStatus(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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,41 +219,76 @@ namespace Essgee.Emulation.Machines
|
|||||||
}
|
}
|
||||||
|
|
||||||
//public void SetState(Dictionary<string, dynamic> state)
|
//public void SetState(Dictionary<string, dynamic> state)
|
||||||
public void SetState(Dictionary<string, object> state)
|
//public void SetState(Dictionary<string, object> state)
|
||||||
|
//{
|
||||||
|
// SaveStateHandler.PerformSetState(cartridge, (Dictionary<string, object>)state[nameof(cartridge)]);
|
||||||
|
// wram = (byte[])state[nameof(wram)];
|
||||||
|
// SaveStateHandler.PerformSetState(cpu, (Dictionary<string, object>)state[nameof(cpu)]);
|
||||||
|
// SaveStateHandler.PerformSetState(vdp, (Dictionary<string, object>)state[nameof(vdp)]);
|
||||||
|
// SaveStateHandler.PerformSetState(psg, (Dictionary<string, object>)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<string, object> GetState()
|
||||||
|
//{
|
||||||
|
// return new Dictionary<string, object>
|
||||||
|
// {
|
||||||
|
// [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<string, object>)state[nameof(cartridge)]);
|
cartridge.LoadAxiStatus(data.ClassData[nameof(cartridge)]);
|
||||||
wram = (byte[])state[nameof(wram)];
|
wram = data.MemberData[nameof(wram)];
|
||||||
SaveStateHandler.PerformSetState(cpu, (Dictionary<string, object>)state[nameof(cpu)]);
|
cpu.LoadAxiStatus(data.ClassData[nameof(cpu)]);
|
||||||
SaveStateHandler.PerformSetState(vdp, (Dictionary<string, object>)state[nameof(vdp)]);
|
vdp.LoadAxiStatus(data.ClassData[nameof(vdp)]);
|
||||||
SaveStateHandler.PerformSetState(psg, (Dictionary<string, object>)state[nameof(psg)]);
|
psg.LoadAxiStatus(data.ClassData[nameof(psg)]);
|
||||||
|
|
||||||
portControls1 = (ushort)state[nameof(portControls1)];
|
portControls1 = BitConverter.ToUInt16( data.MemberData[nameof(portControls1)]);
|
||||||
portControls2 = (ushort)state[nameof(portControls2)];
|
portControls2 = BitConverter.ToUInt16(data.MemberData[nameof(portControls2)]);
|
||||||
controlsReadMode = (byte)state[nameof(controlsReadMode)];
|
controlsReadMode = data.MemberData[nameof(controlsReadMode)].First();
|
||||||
isNmi = (bool)state[nameof(isNmi)];
|
isNmi = BitConverter.ToBoolean(data.MemberData[nameof(isNmi)]);
|
||||||
isNmiPending = (bool)state[nameof(isNmiPending)];
|
isNmiPending = BitConverter.ToBoolean(data.MemberData[nameof(isNmiPending)]);
|
||||||
|
|
||||||
ReconfigureSystem();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, object> GetState()
|
public AxiEssgssStatusData SaveAxiStatus()
|
||||||
{
|
{
|
||||||
return new Dictionary<string, object>
|
AxiEssgssStatusData data = new AxiEssgssStatusData();
|
||||||
{
|
data.ClassData[nameof(cartridge)] = cartridge.SaveAxiStatus();
|
||||||
[nameof(cartridge)] = SaveStateHandler.PerformGetState(cartridge),
|
data.MemberData[nameof(wram)] = wram;
|
||||||
[nameof(wram)] = wram,
|
data.ClassData[nameof(cpu)] = cpu.SaveAxiStatus();
|
||||||
[nameof(cpu)] = SaveStateHandler.PerformGetState(cpu),
|
data.ClassData[nameof(vdp)] = vdp.SaveAxiStatus();
|
||||||
[nameof(vdp)] = SaveStateHandler.PerformGetState(vdp),
|
data.ClassData[nameof(psg)] = psg.SaveAxiStatus();
|
||||||
[nameof(psg)] = SaveStateHandler.PerformGetState(psg),
|
|
||||||
|
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<string, object> GetDebugInformation()
|
public Dictionary<string, object> GetDebugInformation()
|
||||||
{
|
{
|
||||||
var dict = new Dictionary<string, object>
|
var dict = new Dictionary<string, object>
|
||||||
|
@ -131,6 +131,20 @@ namespace Essgee.Emulation.Machines
|
|||||||
|
|
||||||
public GameBoy() { }
|
public GameBoy() { }
|
||||||
|
|
||||||
|
|
||||||
|
#region AxiState
|
||||||
|
|
||||||
|
public void LoadAxiStatus(AxiEssgssStatusData data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AxiEssgssStatusData SaveAxiStatus()
|
||||||
|
{
|
||||||
|
AxiEssgssStatusData data = new AxiEssgssStatusData();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
bootstrap = null;
|
bootstrap = null;
|
||||||
|
@ -162,6 +162,18 @@ namespace Essgee.Emulation.Machines
|
|||||||
|
|
||||||
public GameBoyColor() { }
|
public GameBoyColor() { }
|
||||||
|
|
||||||
|
#region AxiState
|
||||||
|
|
||||||
|
public void LoadAxiStatus(AxiEssgssStatusData data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AxiEssgssStatusData SaveAxiStatus()
|
||||||
|
{
|
||||||
|
AxiEssgssStatusData data = new AxiEssgssStatusData();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
bootstrap = null;
|
bootstrap = null;
|
||||||
|
@ -241,59 +241,114 @@ namespace Essgee.Emulation.Machines
|
|||||||
}
|
}
|
||||||
|
|
||||||
//public void SetState(Dictionary<string, dynamic> state)
|
//public void SetState(Dictionary<string, dynamic> state)
|
||||||
public void SetState(Dictionary<string, object> state)
|
//public void SetState(Dictionary<string, object> state)
|
||||||
|
//{
|
||||||
|
// configuration.Region = (Region)state[nameof(configuration.Region)];
|
||||||
|
|
||||||
|
// SaveStateHandler.PerformSetState(bootstrap, (Dictionary<string, object>)state[nameof(bootstrap)]);
|
||||||
|
// SaveStateHandler.PerformSetState(cartridge, (Dictionary<string, object>)state[nameof(cartridge)]);
|
||||||
|
// wram = (byte[])state[nameof(wram)];
|
||||||
|
// SaveStateHandler.PerformSetState(cpu, (Dictionary<string, object>)state[nameof(cpu)]);
|
||||||
|
// SaveStateHandler.PerformSetState(vdp, (Dictionary<string, object>)state[nameof(vdp)]);
|
||||||
|
// SaveStateHandler.PerformSetState(psg, (Dictionary<string, object>)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<string, object> GetState()
|
||||||
|
//{
|
||||||
|
// return new Dictionary<string, object>
|
||||||
|
// {
|
||||||
|
// [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<Region>();
|
||||||
|
|
||||||
SaveStateHandler.PerformSetState(bootstrap, (Dictionary<string, object>)state[nameof(bootstrap)]);
|
bootstrap.LoadAxiStatus(data.ClassData[nameof(bootstrap)]);
|
||||||
SaveStateHandler.PerformSetState(cartridge, (Dictionary<string, object>)state[nameof(cartridge)]);
|
cartridge.LoadAxiStatus(data.ClassData[nameof(cartridge)]);
|
||||||
wram = (byte[])state[nameof(wram)];
|
wram = data.MemberData[nameof(wram)];
|
||||||
SaveStateHandler.PerformSetState(cpu, (Dictionary<string, object>)state[nameof(cpu)]);
|
cpu.LoadAxiStatus(data.ClassData[nameof(cpu)]);
|
||||||
SaveStateHandler.PerformSetState(vdp, (Dictionary<string, object>)state[nameof(vdp)]);
|
vdp.LoadAxiStatus(data.ClassData[nameof(vdp)]);
|
||||||
SaveStateHandler.PerformSetState(psg, (Dictionary<string, object>)state[nameof(psg)]);
|
psg.LoadAxiStatus(data.ClassData[nameof(psg)]);
|
||||||
|
|
||||||
portMemoryControl = (byte)state[nameof(portMemoryControl)];
|
portMemoryControl = data.MemberData[nameof(portMemoryControl)].First();
|
||||||
portIoControl = (byte)state[nameof(portIoControl)];
|
portIoControl = data.MemberData[nameof(portIoControl)].First();
|
||||||
hCounterLatched = (byte)state[nameof(hCounterLatched)];
|
hCounterLatched = data.MemberData[nameof(hCounterLatched)].First();
|
||||||
portIoAB = (byte)state[nameof(portIoAB)];
|
portIoAB = data.MemberData[nameof(portIoAB)].First();
|
||||||
portIoBMisc = (byte)state[nameof(portIoBMisc)];
|
portIoBMisc = data.MemberData[nameof(portIoBMisc)].First();
|
||||||
|
|
||||||
portIoC = (byte)state[nameof(portIoC)];
|
portIoC = data.MemberData[nameof(portIoC)].First();
|
||||||
portParallelData = (byte)state[nameof(portParallelData)];
|
portParallelData = data.MemberData[nameof(portParallelData)].First();
|
||||||
portDataDirNMI = (byte)state[nameof(portDataDirNMI)];
|
portDataDirNMI = data.MemberData[nameof(portDataDirNMI)].First();
|
||||||
portTxBuffer = (byte)state[nameof(portTxBuffer)];
|
portTxBuffer = data.MemberData[nameof(portTxBuffer)].First();
|
||||||
portRxBuffer = (byte)state[nameof(portRxBuffer)];
|
portRxBuffer = data.MemberData[nameof(portRxBuffer)].First();
|
||||||
portSerialControl = (byte)state[nameof(portSerialControl)];
|
portSerialControl = data.MemberData[nameof(portSerialControl)].First();
|
||||||
|
|
||||||
ReconfigureSystem();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, object> GetState()
|
public AxiEssgssStatusData SaveAxiStatus()
|
||||||
{
|
{
|
||||||
return new Dictionary<string, object>
|
AxiEssgssStatusData data = new AxiEssgssStatusData();
|
||||||
{
|
data.MemberData[nameof(configuration.Region)] = configuration.Region.ToByteArray();
|
||||||
[nameof(configuration.Region)] = configuration.Region,
|
|
||||||
|
|
||||||
[nameof(bootstrap)] = SaveStateHandler.PerformGetState(bootstrap),
|
data.ClassData[nameof(bootstrap)] = bootstrap.SaveAxiStatus();
|
||||||
[nameof(cartridge)] = SaveStateHandler.PerformGetState(cartridge),
|
data.ClassData[nameof(cartridge)] = cartridge.SaveAxiStatus();
|
||||||
[nameof(wram)] = wram,
|
data.MemberData[nameof(wram)] = wram;
|
||||||
[nameof(cpu)] = SaveStateHandler.PerformGetState(cpu),
|
data.ClassData[nameof(cpu)] = cpu.SaveAxiStatus();
|
||||||
[nameof(vdp)] = SaveStateHandler.PerformGetState(vdp),
|
data.ClassData[nameof(vdp)] = vdp.SaveAxiStatus();
|
||||||
[nameof(psg)] = SaveStateHandler.PerformGetState(psg),
|
data.ClassData[nameof(psg)] = psg.SaveAxiStatus();
|
||||||
|
|
||||||
[nameof(portMemoryControl)] = portMemoryControl,
|
data.MemberData[nameof(portMemoryControl)] = BitConverter.GetBytes(portMemoryControl);
|
||||||
[nameof(portIoControl)] = portIoControl,
|
data.MemberData[nameof(portIoControl)] = BitConverter.GetBytes(portIoControl);
|
||||||
[nameof(hCounterLatched)] = hCounterLatched,
|
data.MemberData[nameof(hCounterLatched)] = BitConverter.GetBytes(hCounterLatched);
|
||||||
[nameof(portIoAB)] = portIoAB,
|
data.MemberData[nameof(portIoAB)] = BitConverter.GetBytes(portIoAB);
|
||||||
[nameof(portIoBMisc)] = portIoBMisc,
|
data.MemberData[nameof(portIoBMisc)] = BitConverter.GetBytes(portIoBMisc);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
|
||||||
[nameof(portIoC)] = portIoC,
|
|
||||||
[nameof(portParallelData)] = portParallelData,
|
|
||||||
[nameof(portDataDirNMI)] = portDataDirNMI,
|
|
||||||
[nameof(portTxBuffer)] = portTxBuffer,
|
|
||||||
[nameof(portRxBuffer)] = portRxBuffer,
|
|
||||||
[nameof(portSerialControl)] = portSerialControl
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, object> GetDebugInformation()
|
public Dictionary<string, object> GetDebugInformation()
|
||||||
@ -509,5 +564,6 @@ namespace Essgee.Emulation.Machines
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
namespace Essgee.Emulation.Machines
|
namespace Essgee.Emulation.Machines
|
||||||
{
|
{
|
||||||
public interface IMachine
|
public interface IMachine:IAxiStatus
|
||||||
{
|
{
|
||||||
event EventHandler<SendLogMessageEventArgs> SendLogMessage;
|
event EventHandler<SendLogMessageEventArgs> SendLogMessage;
|
||||||
event EventHandler<EventArgs> EmulationReset;
|
event EventHandler<EventArgs> EmulationReset;
|
||||||
@ -38,8 +38,9 @@ namespace Essgee.Emulation.Machines
|
|||||||
void Reset();
|
void Reset();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
void SetState(Dictionary<string, object> state);
|
//void SetState(Dictionary<string, object> state);
|
||||||
Dictionary<string, object> GetState();
|
//Dictionary<string, object> GetState();
|
||||||
|
|
||||||
|
|
||||||
void Load(byte[] romData, byte[] ramData, Type mapperType);
|
void Load(byte[] romData, byte[] ramData, Type mapperType);
|
||||||
byte[] GetCartridgeRam();
|
byte[] GetCartridgeRam();
|
||||||
|
@ -268,49 +268,119 @@ namespace Essgee.Emulation.Machines
|
|||||||
}
|
}
|
||||||
|
|
||||||
//public void SetState(Dictionary<string, dynamic> state)
|
//public void SetState(Dictionary<string, dynamic> state)
|
||||||
public void SetState(Dictionary<string, object> state)
|
//public void SetState(Dictionary<string, object> state)
|
||||||
|
//{
|
||||||
|
// configuration.TVStandard = (TVStandard)state[nameof(configuration.TVStandard)];
|
||||||
|
// configuration.Region = (Region)state[nameof(configuration.Region)];
|
||||||
|
|
||||||
|
// SaveStateHandler.PerformSetState(bootstrap, (Dictionary<string, object>)state[nameof(bootstrap)]);
|
||||||
|
// SaveStateHandler.PerformSetState(cartridge, (Dictionary<string, object>)state[nameof(cartridge)]);
|
||||||
|
// wram = (byte[])state[nameof(wram)];
|
||||||
|
// SaveStateHandler.PerformSetState(cpu, (Dictionary<string, object>)state[nameof(cpu)]);
|
||||||
|
// SaveStateHandler.PerformSetState(vdp, (Dictionary<string, object>)state[nameof(vdp)]);
|
||||||
|
// SaveStateHandler.PerformSetState(psg, (Dictionary<string, object>)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.TVStandard = data.MemberData[nameof(configuration.TVStandard)].ToEnum<TVStandard>();
|
||||||
configuration.Region = (Region)state[nameof(configuration.Region)];
|
configuration.Region = data.MemberData[nameof(configuration.Region)].ToEnum<Region>();
|
||||||
|
|
||||||
SaveStateHandler.PerformSetState(bootstrap, (Dictionary<string, object>)state[nameof(bootstrap)]);
|
if (data.ClassData.ContainsKey(nameof(bootstrap)))
|
||||||
SaveStateHandler.PerformSetState(cartridge, (Dictionary<string, object>)state[nameof(cartridge)]);
|
bootstrap.LoadAxiStatus(data.ClassData[nameof(bootstrap)]);
|
||||||
wram = (byte[])state[nameof(wram)];
|
cartridge.LoadAxiStatus(data.ClassData[nameof(cartridge)]);
|
||||||
SaveStateHandler.PerformSetState(cpu, (Dictionary<string, object>)state[nameof(cpu)]);
|
wram = data.MemberData[nameof(wram)];
|
||||||
SaveStateHandler.PerformSetState(vdp, (Dictionary<string, object>)state[nameof(vdp)]);
|
cpu.LoadAxiStatus(data.ClassData[nameof(cpu)]);
|
||||||
SaveStateHandler.PerformSetState(psg, (Dictionary<string, object>)state[nameof(psg)]);
|
vdp.LoadAxiStatus(data.ClassData[nameof(vdp)]);
|
||||||
|
psg.LoadAxiStatus(data.ClassData[nameof(psg)]);
|
||||||
|
|
||||||
inputDevices = (InputDevice[])state[nameof(inputDevices)];
|
inputDevices = data.MemberData[nameof(inputDevices)].ToEnumArray<InputDevice>();
|
||||||
lightgunLatched = (bool)state[nameof(lightgunLatched)];
|
lightgunLatched = BitConverter.ToBoolean(data.MemberData[nameof(lightgunLatched)]);
|
||||||
|
|
||||||
portMemoryControl = (byte)state[nameof(portMemoryControl)];
|
portMemoryControl = data.MemberData[nameof(portMemoryControl)].First();
|
||||||
portIoControl = (byte)state[nameof(portIoControl)];
|
portIoControl = data.MemberData[nameof(portIoControl)].First();
|
||||||
hCounterLatched = (byte)state[nameof(hCounterLatched)];
|
hCounterLatched = data.MemberData[nameof(hCounterLatched)].First();
|
||||||
|
|
||||||
ReconfigureSystem();
|
ReconfigureSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, object> GetState()
|
//public Dictionary<string, object> GetState()
|
||||||
|
//{
|
||||||
|
// return new Dictionary<string, object>
|
||||||
|
// {
|
||||||
|
// [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<string, object>
|
AxiEssgssStatusData data = new AxiEssgssStatusData();
|
||||||
{
|
data.MemberData[nameof(configuration.TVStandard)] = configuration.TVStandard.ToByteArray();
|
||||||
[nameof(configuration.TVStandard)] = configuration.TVStandard,
|
data.MemberData[nameof(configuration.Region)] = configuration.Region.ToByteArray();
|
||||||
[nameof(configuration.Region)] = configuration.Region,
|
|
||||||
|
|
||||||
[nameof(bootstrap)] = SaveStateHandler.PerformGetState(bootstrap),
|
if(bootstrap != null)
|
||||||
[nameof(cartridge)] = SaveStateHandler.PerformGetState(cartridge),
|
data.ClassData[nameof(bootstrap)] = bootstrap.SaveAxiStatus();
|
||||||
[nameof(wram)] = wram,
|
|
||||||
[nameof(cpu)] = SaveStateHandler.PerformGetState(cpu),
|
|
||||||
[nameof(vdp)] = SaveStateHandler.PerformGetState(vdp),
|
|
||||||
[nameof(psg)] = SaveStateHandler.PerformGetState(psg),
|
|
||||||
|
|
||||||
[nameof(inputDevices)] = inputDevices,
|
data.ClassData[nameof(cartridge)] = cartridge.SaveAxiStatus();
|
||||||
[nameof(lightgunLatched)] = lightgunLatched,
|
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,
|
data.MemberData[nameof(inputDevices)] = inputDevices.ToByteArray();
|
||||||
[nameof(portIoControl)] = portIoControl,
|
data.MemberData[nameof(lightgunLatched)] = BitConverter.GetBytes(lightgunLatched);
|
||||||
[nameof(hCounterLatched)] = hCounterLatched
|
|
||||||
};
|
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<string, object>
|
||||||
|
//{
|
||||||
|
// [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<string, object> GetDebugInformation()
|
public Dictionary<string, object> GetDebugInformation()
|
||||||
|
@ -245,36 +245,71 @@ namespace Essgee.Emulation.Machines
|
|||||||
psg?.Shutdown();
|
psg?.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
//public void SetState(Dictionary<string, dynamic> state)
|
////public void SetState(Dictionary<string, dynamic> state)
|
||||||
public void SetState(Dictionary<string, object> state)
|
//public void SetState(Dictionary<string, object> state)
|
||||||
{
|
//{
|
||||||
configuration.TVStandard = (TVStandard)state[nameof(configuration.TVStandard)];
|
// configuration.TVStandard = (TVStandard)state[nameof(configuration.TVStandard)];
|
||||||
|
|
||||||
|
// SaveStateHandler.PerformSetState(cartridge, (Dictionary<string, object>)state[nameof(cartridge)]);
|
||||||
|
// wram = (byte[])state[nameof(wram)];
|
||||||
|
// SaveStateHandler.PerformSetState(cpu, (Dictionary<string, object>)state[nameof(cpu)]);
|
||||||
|
// SaveStateHandler.PerformSetState(vdp, (Dictionary<string, object>)state[nameof(vdp)]);
|
||||||
|
// SaveStateHandler.PerformSetState(psg, (Dictionary<string, object>)state[nameof(psg)]);
|
||||||
|
// SaveStateHandler.PerformSetState(ppi, (Dictionary<string, object>)state[nameof(ppi)]);
|
||||||
|
// keyboard = (bool[,])(state[nameof(keyboard)]);
|
||||||
|
// ReconfigureSystem();
|
||||||
|
//}
|
||||||
|
|
||||||
|
//public Dictionary<string, object> GetState()
|
||||||
|
//{
|
||||||
|
// return new Dictionary<string, object>
|
||||||
|
// {
|
||||||
|
// [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<TVStandard>();
|
||||||
|
|
||||||
|
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<string, object>)state[nameof(cartridge)]);
|
|
||||||
wram = (byte[])state[nameof(wram)];
|
|
||||||
SaveStateHandler.PerformSetState(cpu, (Dictionary<string, object>)state[nameof(cpu)]);
|
|
||||||
SaveStateHandler.PerformSetState(vdp, (Dictionary<string, object>)state[nameof(vdp)]);
|
|
||||||
SaveStateHandler.PerformSetState(psg, (Dictionary<string, object>)state[nameof(psg)]);
|
|
||||||
SaveStateHandler.PerformSetState(ppi, (Dictionary<string, object>)state[nameof(ppi)]);
|
|
||||||
keyboard = (bool[,])(state[nameof(keyboard)]);
|
|
||||||
ReconfigureSystem();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, object> GetState()
|
public AxiEssgssStatusData SaveAxiStatus()
|
||||||
{
|
{
|
||||||
return new Dictionary<string, object>
|
AxiEssgssStatusData data = new AxiEssgssStatusData();
|
||||||
{
|
data.MemberData[nameof(configuration.TVStandard)] = configuration.TVStandard.ToByteArray();
|
||||||
[nameof(configuration.TVStandard)] = configuration.TVStandard,
|
|
||||||
|
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<string, object> GetDebugInformation()
|
public Dictionary<string, object> GetDebugInformation()
|
||||||
{
|
{
|
||||||
|
@ -221,33 +221,62 @@ namespace Essgee.Emulation.Machines
|
|||||||
psg?.Shutdown();
|
psg?.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
//public void SetState(Dictionary<string, dynamic> state)
|
////public void SetState(Dictionary<string, dynamic> state)
|
||||||
public void SetState(Dictionary<string, object> state)
|
//public void SetState(Dictionary<string, object> state)
|
||||||
|
//{
|
||||||
|
// configuration.TVStandard = (TVStandard)state[nameof(configuration.TVStandard)];
|
||||||
|
|
||||||
|
// SaveStateHandler.PerformSetState(cartridge, (Dictionary<string, object>)state[nameof(cartridge)]);
|
||||||
|
// wram = (byte[])state[nameof(wram)];
|
||||||
|
// SaveStateHandler.PerformSetState(cpu, (Dictionary<string, object>)state[nameof(cpu)]);
|
||||||
|
// SaveStateHandler.PerformSetState(vdp, (Dictionary<string, object>)state[nameof(vdp)]);
|
||||||
|
// SaveStateHandler.PerformSetState(psg, (Dictionary<string, object>)state[nameof(psg)]);
|
||||||
|
|
||||||
|
// ReconfigureSystem();
|
||||||
|
//}
|
||||||
|
|
||||||
|
//public Dictionary<string, object> GetState()
|
||||||
|
//{
|
||||||
|
// return new Dictionary<string, object>
|
||||||
|
// {
|
||||||
|
// [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<TVStandard>();
|
||||||
|
|
||||||
SaveStateHandler.PerformSetState(cartridge, (Dictionary<string, object>)state[nameof(cartridge)]);
|
cartridge.LoadAxiStatus(data.ClassData[nameof(cartridge)]);
|
||||||
wram = (byte[])state[nameof(wram)];
|
wram = data.MemberData[nameof(wram)];
|
||||||
SaveStateHandler.PerformSetState(cpu, (Dictionary<string, object>)state[nameof(cpu)]);
|
cpu.LoadAxiStatus(data.ClassData[nameof(cpu)]);
|
||||||
SaveStateHandler.PerformSetState(vdp, (Dictionary<string, object>)state[nameof(vdp)]);
|
vdp.LoadAxiStatus(data.ClassData[nameof(vdp)]);
|
||||||
SaveStateHandler.PerformSetState(psg, (Dictionary<string, object>)state[nameof(psg)]);
|
psg.LoadAxiStatus(data.ClassData[nameof(psg)]);
|
||||||
|
|
||||||
ReconfigureSystem();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, object> GetState()
|
public AxiEssgssStatusData SaveAxiStatus()
|
||||||
{
|
{
|
||||||
return new Dictionary<string, object>
|
AxiEssgssStatusData data = new AxiEssgssStatusData();
|
||||||
{
|
data.MemberData[nameof(configuration.TVStandard)] = configuration.TVStandard.ToByteArray();
|
||||||
[nameof(configuration.TVStandard)] = configuration.TVStandard,
|
|
||||||
|
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<string, object> GetDebugInformation()
|
public Dictionary<string, object> GetDebugInformation()
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Essgee.Emulation.Peripherals
|
namespace Essgee.Emulation.Peripherals
|
||||||
{
|
{
|
||||||
interface IPeripheral
|
interface IPeripheral : IAxiStatus
|
||||||
{
|
{
|
||||||
void Startup();
|
void Startup();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
using Essgee.Exceptions;
|
using Essgee.Exceptions;
|
||||||
using Essgee.Utilities;
|
using Essgee.Utilities;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Essgee.Emulation.Peripherals
|
namespace Essgee.Emulation.Peripherals
|
||||||
{
|
{
|
||||||
@ -32,6 +34,39 @@ namespace Essgee.Emulation.Peripherals
|
|||||||
|
|
||||||
public Intel8255() { }
|
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()
|
public void Startup()
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
|
@ -1,149 +1,159 @@
|
|||||||
using Essgee.Exceptions;
|
using System.IO;
|
||||||
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;
|
|
||||||
|
|
||||||
namespace Essgee.Emulation
|
namespace Essgee.Emulation
|
||||||
{
|
{
|
||||||
public static class SaveStateHandler
|
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<string, object> Load(Stream stream, string machineName)
|
//public static Dictionary<string, object> 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<string, object>);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
public static AxiEssgssStatusData LoadAxiStatus(Stream stream, string machineName)
|
||||||
{
|
{
|
||||||
stream.Position = 0;
|
|
||||||
|
|
||||||
using (var reader = new BinaryReader(stream))
|
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 */
|
/* Check CRC32 */
|
||||||
using (var stateStream = new MemoryStream())
|
using (var stateStream = new MemoryStream())
|
||||||
{
|
{
|
||||||
reader.BaseStream.CopyTo(stateStream);
|
reader.BaseStream.CopyTo(stateStream);
|
||||||
stateStream.Position = 0;
|
return stateStream.ToArray().ToAxiEssgssStatusData();
|
||||||
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<string, object>);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Save(Stream stream, string machineName, Dictionary<string, object> state)
|
//public static void Save(Stream stream, string machineName, Dictionary<string, object> 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()))
|
byte[] data = state.ToByteArray();
|
||||||
{
|
stream.Write(data, 0, data.Length);
|
||||||
/* Write version string */
|
}
|
||||||
writer.Write(Encoding.ASCII.GetBytes(ExpectedVersion));
|
//private static string GenerateMachineIdString(string machineId)
|
||||||
|
//{
|
||||||
|
// return machineId.Substring(0, Math.Min(machineId.Length, 16)).PadRight(16);
|
||||||
|
//}
|
||||||
|
|
||||||
/* Write filesize placeholder */
|
////public static void PerformSetState(object obj, Dictionary<string, dynamic> state)
|
||||||
var filesizePosition = writer.BaseStream.Position;
|
|
||||||
writer.Write(uint.MaxValue);
|
|
||||||
|
|
||||||
/* Write CRC32 placeholder */
|
//public static void PerformSetState(object obj, Dictionary<string, object> state)
|
||||||
var crc32Position = writer.BaseStream.Position;
|
//{
|
||||||
writer.Write(uint.MaxValue);
|
// 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]);
|
||||||
|
// }
|
||||||
|
|
||||||
/* Write machine ID */
|
// /* Restore field values from state */
|
||||||
writer.Write(Encoding.ASCII.GetBytes(GenerateMachineIdString(machineName)));
|
// 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]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
/* Current position is end of header, store for later */
|
////public static Dictionary<string, dynamic> PerformGetState(object obj)
|
||||||
var headerSize = writer.BaseStream.Position;
|
//public static Dictionary<string, object> PerformGetState(object obj)
|
||||||
|
//{
|
||||||
|
// //var state = new Dictionary<string, dynamic>();
|
||||||
|
// var state = new Dictionary<string, object>();
|
||||||
|
|
||||||
/* Write state data */
|
// if (obj != null)
|
||||||
var binaryFormatter = new BinaryFormatter();
|
// {
|
||||||
binaryFormatter.Serialize(writer.BaseStream, state);
|
// /* 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));
|
||||||
|
// }
|
||||||
|
|
||||||
/* Write filesize */
|
// /* Copy field values to state */
|
||||||
var lastOffset = writer.BaseStream.Position;
|
// foreach (var field in obj.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Where(x => x.GetCustomAttributes(typeof(StateRequiredAttribute), false).Length != 0))
|
||||||
writer.BaseStream.Position = filesizePosition;
|
// {
|
||||||
writer.Write((uint)writer.BaseStream.Length);
|
// state.Add(field.Name, field.GetValue(obj));
|
||||||
writer.BaseStream.Position = lastOffset;
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
/* Calculate CRC32 for state data, then write CRC32 */
|
// return state;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GenerateMachineIdString(string machineId)
|
|
||||||
{
|
|
||||||
return machineId.Substring(0, Math.Min(machineId.Length, 16)).PadRight(16);
|
|
||||||
}
|
|
||||||
|
|
||||||
//public static void PerformSetState(object obj, Dictionary<string, dynamic> state)
|
|
||||||
|
|
||||||
public static void PerformSetState(object obj, Dictionary<string, object> 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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//public static Dictionary<string, dynamic> PerformGetState(object obj)
|
|
||||||
public static Dictionary<string, object> PerformGetState(object obj)
|
|
||||||
{
|
|
||||||
//var state = new Dictionary<string, dynamic>();
|
|
||||||
var state = new Dictionary<string, object>();
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ using System;
|
|||||||
|
|
||||||
namespace Essgee.Emulation.Video
|
namespace Essgee.Emulation.Video
|
||||||
{
|
{
|
||||||
interface IVideo
|
interface IVideo : IAxiStatus
|
||||||
{
|
{
|
||||||
(int X, int Y, int Width, int Height) Viewport { get; }
|
(int X, int Y, int Width, int Height) Viewport { get; }
|
||||||
|
|
||||||
|
@ -64,6 +64,20 @@ namespace Essgee.Emulation.Video.Nintendo
|
|||||||
objPaletteData = new byte[64];
|
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()
|
public override void Reset()
|
||||||
{
|
{
|
||||||
base.Reset();
|
base.Reset();
|
||||||
@ -94,6 +108,7 @@ namespace Essgee.Emulation.Video.Nintendo
|
|||||||
hdmaBytesLeft = 0;
|
hdmaBytesLeft = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
protected override void StepHBlank()
|
protected override void StepHBlank()
|
||||||
|
@ -145,6 +145,22 @@ namespace Essgee.Emulation.Video.Nintendo
|
|||||||
layerSpritesForceEnable = true;
|
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)
|
public object GetRuntimeOption(string name)
|
||||||
{
|
{
|
||||||
switch (name)
|
switch (name)
|
||||||
|
@ -2,7 +2,10 @@
|
|||||||
using Essgee.Utilities;
|
using Essgee.Utilities;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using Unity.Mathematics;
|
||||||
|
using Unity.VisualScripting;
|
||||||
using static Essgee.Emulation.Utilities;
|
using static Essgee.Emulation.Utilities;
|
||||||
|
|
||||||
namespace Essgee.Emulation.Video
|
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];
|
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()
|
public override void Reset()
|
||||||
{
|
{
|
||||||
base.Reset();
|
base.Reset();
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
using Essgee.Utilities;
|
using Essgee.Utilities;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using static Essgee.Emulation.Utilities;
|
using static Essgee.Emulation.Utilities;
|
||||||
|
using static UnityEditor.Experimental.AssetDatabaseExperimental.AssetDatabaseCounters;
|
||||||
|
|
||||||
namespace Essgee.Emulation.Video
|
namespace Essgee.Emulation.Video
|
||||||
{
|
{
|
||||||
@ -90,6 +92,82 @@ namespace Essgee.Emulation.Video
|
|||||||
[StateRequired]
|
[StateRequired]
|
||||||
protected (int Number, int Y, int X, int Pattern, int Attribute)[][] spriteBuffer;
|
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 vramMask16k => 0x3FFF;
|
||||||
//protected ushort vramMask4k => 0x0FFF;
|
//protected ushort vramMask4k => 0x0FFF;
|
||||||
protected const ushort vramMask16k = 0x3FFF;
|
protected const ushort vramMask16k = 0x3FFF;
|
||||||
@ -246,6 +324,43 @@ namespace Essgee.Emulation.Video
|
|||||||
layerBordersForceEnable = true;
|
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<StatusFlags>();
|
||||||
|
InterruptLine = data.MemberData[nameof(InterruptLine)].ToEnum<InterruptState>();
|
||||||
|
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)
|
public object GetRuntimeOption(string name)
|
||||||
{
|
{
|
||||||
switch (name)
|
switch (name)
|
||||||
|
224
Assets/Plugins/Essgee.Unity/IAxiStatus.cs
Normal file
224
Assets/Plugins/Essgee.Unity/IAxiStatus.cs
Normal file
@ -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<string, byte[]> MemberData = new Dictionary<string, byte[]>();
|
||||||
|
public Dictionary<string, AxiEssgssStatusData_2DArray> Array2DMemberData = new Dictionary<string, AxiEssgssStatusData_2DArray>();
|
||||||
|
public Dictionary<string, AxiEssgssStatusData> ClassData = new Dictionary<string, AxiEssgssStatusData>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[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<TEnum>(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<TEnum>(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<TEnum>(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
|
||||||
|
{
|
||||||
|
// 如果基础类型不是byte或int,则抛出异常(或者你可以添加更多的类型检查和处理逻辑)
|
||||||
|
throw new NotSupportedException($"The underlying type of the enum {typeof(TEnum).Name} is not supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从byte[]转换为单个枚举(假设byte[]只有一个字节)
|
||||||
|
public static TEnum ToEnum<TEnum>(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;
|
||||||
|
}
|
||||||
|
}
|
2
Assets/Plugins/Essgee.Unity/IAxiStatus.cs.meta
Normal file
2
Assets/Plugins/Essgee.Unity/IAxiStatus.cs.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 40ed20a1384827f45b7f187a4ccb4740
|
@ -62,6 +62,15 @@ public class Essgeeinit : MonoBehaviour
|
|||||||
mUniKeyboard.UpdateInputKey();
|
mUniKeyboard.UpdateInputKey();
|
||||||
|
|
||||||
emulatorHandler.Update_Frame();
|
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)
|
void InitAll(IGameMetaReources metaresources,string CustonDataDir)
|
||||||
|
@ -146,6 +146,7 @@ public class KeyCodeCore
|
|||||||
dictKey2Motion.Add(EssgeeUnityKey.P2_BTN_1, machine.configuration.Joypad2Button1);
|
dictKey2Motion.Add(EssgeeUnityKey.P2_BTN_1, machine.configuration.Joypad2Button1);
|
||||||
dictKey2Motion.Add(EssgeeUnityKey.P2_BTN_2, machine.configuration.Joypad2Button2);
|
dictKey2Motion.Add(EssgeeUnityKey.P2_BTN_2, machine.configuration.Joypad2Button2);
|
||||||
}
|
}
|
||||||
|
//存档功能待补
|
||||||
else if (Machine is Essgee.Emulation.Machines.GameBoy)
|
else if (Machine is Essgee.Emulation.Machines.GameBoy)
|
||||||
{
|
{
|
||||||
var machine = (Essgee.Emulation.Machines.GameBoy)Machine;
|
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_1, machine.configuration.ControlsStart);
|
||||||
dictKey2Motion.Add(EssgeeUnityKey.P1_POTION_2, machine.configuration.ControlsSelect);
|
dictKey2Motion.Add(EssgeeUnityKey.P1_POTION_2, machine.configuration.ControlsSelect);
|
||||||
}
|
}
|
||||||
|
//存档功能待补
|
||||||
else if (Machine is Essgee.Emulation.Machines.GameBoyColor)
|
else if (Machine is Essgee.Emulation.Machines.GameBoyColor)
|
||||||
{
|
{
|
||||||
var machine = (Essgee.Emulation.Machines.GameBoyColor)Machine;
|
var machine = (Essgee.Emulation.Machines.GameBoyColor)Machine;
|
||||||
|
Loading…
Reference in New Issue
Block a user