diff --git a/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/BizHawk.Client.EmuHawk/MainForm.Designer.cs
index 57df31fabc..8f65f44499 100644
--- a/BizHawk.Client.EmuHawk/MainForm.Designer.cs
+++ b/BizHawk.Client.EmuHawk/MainForm.Designer.cs
@@ -389,7 +389,9 @@
this.ZXSpectrumPokeMemoryMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.ZXSpectrumMediaMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.ZXSpectrumTapesSubMenu = new System.Windows.Forms.ToolStripMenuItem();
+ this.zxt1ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.ZXSpectrumDisksSubMenu = new System.Windows.Forms.ToolStripMenuItem();
+ this.zxt2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.Atari7800HawkCoreMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.MainStatusBar = new StatusStripEx();
this.DumpStatusButton = new System.Windows.Forms.ToolStripDropDownButton();
@@ -462,8 +464,7 @@
this.ShowMenuContextMenuSeparator = new System.Windows.Forms.ToolStripSeparator();
this.ShowMenuContextMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.timerMouseIdle = new System.Windows.Forms.Timer(this.components);
- this.zxt1ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
- this.zxt2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.ZXSpectrumExportSnapshotMenuItemMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.MainformMenu.SuspendLayout();
this.MainStatusBar.SuspendLayout();
this.MainFormContextMenu.SuspendLayout();
@@ -3454,7 +3455,8 @@
//
this.ZXSpectrumMediaMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.ZXSpectrumTapesSubMenu,
- this.ZXSpectrumDisksSubMenu});
+ this.ZXSpectrumDisksSubMenu,
+ this.ZXSpectrumExportSnapshotMenuItemMenuItem});
this.ZXSpectrumMediaMenuItem.Name = "ZXSpectrumMediaMenuItem";
this.ZXSpectrumMediaMenuItem.Size = new System.Drawing.Size(201, 22);
this.ZXSpectrumMediaMenuItem.Text = "Media";
@@ -3465,19 +3467,31 @@
this.ZXSpectrumTapesSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.zxt1ToolStripMenuItem});
this.ZXSpectrumTapesSubMenu.Name = "ZXSpectrumTapesSubMenu";
- this.ZXSpectrumTapesSubMenu.Size = new System.Drawing.Size(152, 22);
+ this.ZXSpectrumTapesSubMenu.Size = new System.Drawing.Size(159, 22);
this.ZXSpectrumTapesSubMenu.Text = "Tapes";
this.ZXSpectrumTapesSubMenu.DropDownOpened += new System.EventHandler(this.ZXSpectrumTapesSubMenu_DropDownOpened);
//
+ // zxt1ToolStripMenuItem
+ //
+ this.zxt1ToolStripMenuItem.Name = "zxt1ToolStripMenuItem";
+ this.zxt1ToolStripMenuItem.Size = new System.Drawing.Size(94, 22);
+ this.zxt1ToolStripMenuItem.Text = "zxt1";
+ //
// ZXSpectrumDisksSubMenu
//
this.ZXSpectrumDisksSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.zxt2ToolStripMenuItem});
this.ZXSpectrumDisksSubMenu.Name = "ZXSpectrumDisksSubMenu";
- this.ZXSpectrumDisksSubMenu.Size = new System.Drawing.Size(152, 22);
+ this.ZXSpectrumDisksSubMenu.Size = new System.Drawing.Size(159, 22);
this.ZXSpectrumDisksSubMenu.Text = "Disks";
this.ZXSpectrumDisksSubMenu.DropDownOpened += new System.EventHandler(this.ZXSpectrumDisksSubMenu_DropDownOpened);
//
+ // zxt2ToolStripMenuItem
+ //
+ this.zxt2ToolStripMenuItem.Name = "zxt2ToolStripMenuItem";
+ this.zxt2ToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
+ this.zxt2ToolStripMenuItem.Text = "zxt2";
+ //
// Atari7800HawkCoreMenuItem
//
this.Atari7800HawkCoreMenuItem.Name = "Atari7800HawkCoreMenuItem";
@@ -4104,17 +4118,12 @@
this.timerMouseIdle.Interval = 2000;
this.timerMouseIdle.Tick += new System.EventHandler(this.TimerMouseIdle_Tick);
//
- // zxt1ToolStripMenuItem
+ // ZXSpectrumExportSnapshotMenuItemMenuItem
//
- this.zxt1ToolStripMenuItem.Name = "zxt1ToolStripMenuItem";
- this.zxt1ToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
- this.zxt1ToolStripMenuItem.Text = "zxt1";
- //
- // zxt2ToolStripMenuItem
- //
- this.zxt2ToolStripMenuItem.Name = "zxt2ToolStripMenuItem";
- this.zxt2ToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
- this.zxt2ToolStripMenuItem.Text = "zxt2";
+ this.ZXSpectrumExportSnapshotMenuItemMenuItem.Name = "ZXSpectrumExportSnapshotMenuItemMenuItem";
+ this.ZXSpectrumExportSnapshotMenuItemMenuItem.Size = new System.Drawing.Size(159, 22);
+ this.ZXSpectrumExportSnapshotMenuItemMenuItem.Text = "Export Snapshot";
+ this.ZXSpectrumExportSnapshotMenuItemMenuItem.Click += new System.EventHandler(this.ZXSpectrumExportSnapshotMenuItemMenuItem_Click);
//
// MainForm
//
@@ -4591,5 +4600,6 @@
private System.Windows.Forms.ToolStripMenuItem ZXSpectrumDisksSubMenu;
private System.Windows.Forms.ToolStripMenuItem zxt1ToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem zxt2ToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem ZXSpectrumExportSnapshotMenuItemMenuItem;
}
}
diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs
index e9048cab55..fd66d105c8 100644
--- a/BizHawk.Client.EmuHawk/MainForm.Events.cs
+++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs
@@ -2564,6 +2564,32 @@ namespace BizHawk.Client.EmuHawk
}
}
+ private void ZXSpectrumExportSnapshotMenuItemMenuItem_Click(object sender, EventArgs e)
+ {
+ SaveFileDialog zxSnapExpDialog = new SaveFileDialog();
+ zxSnapExpDialog.RestoreDirectory = true;
+ zxSnapExpDialog.Title = "EXPERIMENTAL - Export 3rd party snapshot formats";
+ zxSnapExpDialog.DefaultExt = "szx";
+ zxSnapExpDialog.Filter = "ZX-State files (*.szx)|*.szx";
+ zxSnapExpDialog.SupportMultiDottedExtensions = true;
+
+ try
+ {
+ var res = zxSnapExpDialog.ShowDialog();
+ if (res == DialogResult.OK)
+ {
+ var speccy = (ZXSpectrum)Emulator;
+ var snap = speccy.GetSZXSnapshot();
+ File.WriteAllBytes(zxSnapExpDialog.FileName, snap);
+ //File.WriteAllText(zxSnapExpDialog.FileName, snap);
+ }
+ }
+ catch (Exception ex)
+ {
+ var ee = ex;
+ }
+ }
+
#endregion
#region Help
diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs
index a989739283..5055177fc3 100644
--- a/BizHawk.Client.EmuHawk/MainForm.cs
+++ b/BizHawk.Client.EmuHawk/MainForm.cs
@@ -1834,6 +1834,11 @@ namespace BizHawk.Client.EmuHawk
break;
case "ZXSpectrum":
zXSpectrumToolStripMenuItem.Visible = true;
+#if DEBUG
+ ZXSpectrumExportSnapshotMenuItemMenuItem.Visible = true;
+#else
+ ZXSpectrumExportSnapshotMenuItemMenuItem.Visible = false;
+#endif
break;
}
}
@@ -4368,7 +4373,6 @@ namespace BizHawk.Client.EmuHawk
{
GenericCoreConfig.DoDialog(this, "PC-FX Settings");
}
-
private bool Rewind(ref bool runFrame, long currentTimestamp, out bool returnToRecording)
{
diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
index b18b0865c8..3f9c29fb35 100644
--- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
+++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj
@@ -293,6 +293,8 @@
+
+
diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs
index 318ef27300..bd5a4928f0 100644
--- a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs
+++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs
@@ -7,6 +7,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80A
public long TotalExecutedCycles;
private int EI_pending;
+ // ZXHawk needs to be able to read this for zx-state snapshot export
+ public int EIPending { get { return EI_pending; } }
public const ushort CBpre = 0;
public const ushort EXTDpre = 1;
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IPSG.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IPSG.cs
index f3cde8c900..0d54d6a97c 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IPSG.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Abstraction/IPSG.cs
@@ -19,6 +19,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
/// Activates a register
///
int SelectedRegister { get; set; }
+
+ int[] ExportRegisters();
///
/// Writes to the PSG
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/SoundOuput/AY38912.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/SoundOuput/AY38912.cs
index 394c18875b..9ed0a069b9 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/SoundOuput/AY38912.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/SoundOuput/AY38912.cs
@@ -167,6 +167,15 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
}
}
+ ///
+ /// Used for snapshot generation
+ ///
+ ///
+ public int[] ExportRegisters()
+ {
+ return _registers;
+ }
+
#endregion
#region Public Methods
@@ -176,6 +185,14 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
///
public void Reset()
{
+ for (int i = 0; i < 16; i++)
+ {
+ if (i == 6)
+ _registers[i] = 0xff;
+ else
+ _registers[i] = 0;
+ }
+
/*
_noiseVal = 0x0FFFF;
_outABC = 0;
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs
index 10a1728cb9..fec2b5c606 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/CPUMonitor.cs
@@ -389,6 +389,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
// fetch instruction without incrementing pc
//_cpu.FetchInstruction(_cpu.FetchMemory(firstByte));
+
}
#endregion
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs
index 383e7ea8aa..7c39525cdf 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs
@@ -34,7 +34,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
/// Signs that the shadow screen is now displaying
/// Note: normal screen memory in RAM5 is not altered, the ULA just outputs Screen1 instead (RAM7)
///
- protected bool SHADOWPaged;
+ public bool SHADOWPaged;
///
/// Index of the current RAM page
@@ -66,22 +66,22 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
///
/// High bit of the ROM selection (in normal paging mode)
///
- protected bool ROMhigh = false;
+ public bool ROMhigh = false;
///
/// Low bit of the ROM selection (in normal paging mode)
///
- protected bool ROMlow = false;
+ public bool ROMlow = false;
///
/// Signs that the +2a/+3 special paging mode is activated
///
- protected bool SpecialPagingMode;
+ public bool SpecialPagingMode;
///
/// Index of the current special paging mode (0-3)
///
- protected int PagingConfiguration;
+ public int PagingConfiguration;
///
/// The last byte that was read after contended cycles
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Port.cs
index 2d15f3f2fa..d1c0f29271 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Port.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Port.cs
@@ -17,6 +17,10 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
set { LastULAOutByte = value; }
}
+ public byte Last7ffd;
+ public byte LastFe;
+ public byte Last1ffd;
+
///
/// Reads a byte of data from a specified port address
///
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs
index 6b33600bcc..1ec92a69f6 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128K/ZX128.Port.cs
@@ -96,6 +96,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
// but it is only partially decoded so it actually responds to any port with bits 1 and 15 reset
if (portBits[1] == false && portBits[15] == false)
{
+ Last7ffd = value;
+
// if paging is disabled then all writes to this port are ignored until the next reboot
if (!PagingDisabled)
{
@@ -136,6 +138,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
// Only even addresses address the ULA
if (lowBitReset)
{
+ LastFe = value;
+
// store the last OUT byte
LastULAOutByte = value;
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs
index 9e97b56867..7d6a6a53a4 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs
@@ -77,6 +77,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
// port 0x7ffd - hardware should only respond when bits 1 & 15 are reset and bit 14 is set
if (!portBits[1] && !portBits[15] && portBits[14])
{
+ Last7ffd = value;
+
if (!PagingDisabled)
{
// bits 0, 1, 2 select the RAM page
@@ -97,6 +99,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
// port 0x1ffd - hardware should only respond when bits 1, 13, 14 & 15 are reset and bit 12 is set
if (!portBits[1] && portBits[12] && !portBits[13] && !portBits[14] && !portBits[15])
{
+ Last1ffd = value;
+
if (!PagingDisabled)
{
if (!bits[0])
@@ -134,6 +138,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
// Only even addresses address the ULA
if (lowBitReset)
{
+ LastFe = value;
+
// store the last OUT byte
LastULAOutByte = value;
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs
index e9c8494fff..ac662665d3 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum128KPlus3/ZX128Plus3.Port.cs
@@ -68,6 +68,13 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
///
public override void WritePort(ushort port, byte value)
{
+ if (port == 0x7ffd)
+ Last7ffd = value;
+ else if (port == 0x1ffd)
+ Last1ffd = value;
+ else if ((port & 0x01) == 0)
+ LastFe = value;
+
// get a BitArray of the port
BitArray portBits = new BitArray(BitConverter.GetBytes(port));
// get a BitArray of the value byte
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs
index 019b82e666..b6d175028b 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Port.cs
@@ -71,6 +71,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
if ((port & 0x0001) != 0)
return;
+ LastFe = value;
+
// store the last OUT byte
LastULAOutByte = value;
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/MediaConverter.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/MediaConverter.cs
index f9059c7e10..fde6bdf130 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/MediaConverter.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/MediaConverter.cs
@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.IO.Compression;
+using System.Runtime.InteropServices;
namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
{
@@ -89,11 +90,22 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
///
///
///
- public static int GetInt32(byte[] buf, int offsetIndex)
+ public static int GetInt32(byte[] buf, int offsetIndex)
{
return buf[offsetIndex] | buf[offsetIndex + 1] << 8 | buf[offsetIndex + 2] << 16 | buf[offsetIndex + 3] << 24;
}
+ ///
+ /// Returns an int32 from a byte array based on offset
+ ///
+ ///
+ ///
+ ///
+ public static uint GetUInt32(byte[] buf, int offsetIndex)
+ {
+ return (uint)(buf[offsetIndex] | buf[offsetIndex + 1] << 8 | buf[offsetIndex + 2] << 16 | buf[offsetIndex + 3] << 24);
+ }
+
///
/// Returns an uint16 from a byte array based on offset
///
@@ -148,6 +160,29 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
ds.Read(destBuffer, 0, destBuffer.Length);
}
+
+ public static byte[] SerializeRaw(object obj)
+ {
+ int rSize = Marshal.SizeOf(obj);
+ IntPtr buff = Marshal.AllocHGlobal(rSize);
+ Marshal.StructureToPtr(obj, buff, false);
+ byte[] rData = new byte[rSize];
+ Marshal.Copy(buff, rData, 0, rSize);
+ return rData;
+ }
+
+ public static T DeserializeRaw(byte[] rData, int pos)
+ {
+ int rSize = Marshal.SizeOf(typeof(T));
+ if (rSize > rData.Length - pos)
+ throw new Exception();
+ IntPtr buff = Marshal.AllocHGlobal(rSize);
+ Marshal.Copy(rData, pos, buff, rSize);
+ T rObj = (T)Marshal.PtrToStructure(buff, typeof(T));
+ Marshal.FreeHGlobal(buff);
+ return rObj;
+ }
+
#endregion
}
}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Snapshot/SZX/SZX.Methods.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Snapshot/SZX/SZX.Methods.cs
new file mode 100644
index 0000000000..0c812b9e0d
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Snapshot/SZX/SZX.Methods.cs
@@ -0,0 +1,425 @@
+using BizHawk.Common.NumberExtensions;
+using BizHawk.Emulation.Cores.Components.Z80A;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
+{
+ ///
+ /// SZX Methods
+ /// Based on the work done by ArjunNair in ZERO spectrum emulator: https://github.com/ArjunNair/Zero-Emulator/blob/master/Ziggy/Peripherals/SZXFile.cs
+ ///
+ public partial class SZX
+ {
+ private SpectrumBase _machine;
+
+ private Z80A _cpu => _machine.CPU;
+
+ private SZX(SpectrumBase machine)
+ {
+ _machine = machine;
+ }
+
+ ///
+ /// Exports state information to a byte array in ZX-State format
+ ///
+ ///
+ ///
+ public static byte[] ExportSZX(SpectrumBase machine)
+ {
+ var s = new SZX(machine);
+
+ byte[] result = null;
+
+ using (MemoryStream ms = new MemoryStream())
+ {
+ using (BinaryWriter r = new BinaryWriter(ms))
+ {
+ // temp buffer
+ byte[] buff;
+ // working block
+ ZXSTBLOCK block = new ZXSTBLOCK();
+
+ // header
+ ZXSTHEADER header = new ZXSTHEADER();
+ header.dwMagic = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("ZXST"), 0);
+ header.chMajorVersion = 1;
+ header.chMinorVersion = 4;
+ header.chFlags = 0;
+ switch (s._machine.Spectrum.MachineType)
+ {
+ case MachineType.ZXSpectrum16: header.chMachineId = (int)MachineIdentifier.ZXSTMID_16K; break;
+ case MachineType.ZXSpectrum48: header.chMachineId = (int)MachineIdentifier.ZXSTMID_48K; break;
+ case MachineType.ZXSpectrum128: header.chMachineId = (int)MachineIdentifier.ZXSTMID_128K; break;
+ case MachineType.ZXSpectrum128Plus2: header.chMachineId = (int)MachineIdentifier.ZXSTMID_PLUS2; break;
+ case MachineType.ZXSpectrum128Plus2a: header.chMachineId = (int)MachineIdentifier.ZXSTMID_PLUS2A; break;
+ case MachineType.ZXSpectrum128Plus3: header.chMachineId = (int)MachineIdentifier.ZXSTMID_PLUS3; break;
+ }
+ buff = MediaConverter.SerializeRaw(header);
+ r.Write(buff);
+
+ // ZXSTCREATOR
+ var bStruct = s.GetZXSTCREATOR();
+ block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("CRTR"), 0);
+ block.dwSize = (uint)Marshal.SizeOf(bStruct);
+ buff = MediaConverter.SerializeRaw(block);
+ r.Write(buff);
+ buff = MediaConverter.SerializeRaw(bStruct);
+ r.Write(buff);
+
+ // ZXSTZ80REGS
+ var cStruct = s.GetZXSTZ80REGS();
+ block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("Z80R"), 0);
+ block.dwSize = (uint)Marshal.SizeOf(cStruct);
+ buff = MediaConverter.SerializeRaw(block);
+ r.Write(buff);
+ buff = MediaConverter.SerializeRaw(cStruct);
+ r.Write(buff);
+
+ // ZXSTSPECREGS
+ var dStruct = s.GetZXSTSPECREGS();
+ block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("SPCR"), 0);
+ block.dwSize = (uint)Marshal.SizeOf(dStruct);
+ buff = MediaConverter.SerializeRaw(block);
+ r.Write(buff);
+ buff = MediaConverter.SerializeRaw(dStruct);
+ r.Write(buff);
+
+ // ZXSTKEYBOARD
+ var eStruct = s.GetZXSTKEYBOARD();
+ block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("KEYB"), 0);
+ block.dwSize = (uint)Marshal.SizeOf(eStruct);
+ buff = MediaConverter.SerializeRaw(block);
+ r.Write(buff);
+ buff = MediaConverter.SerializeRaw(eStruct);
+ r.Write(buff);
+
+ // ZXSTJOYSTICK
+ var fStruct = s.GetZXSTJOYSTICK();
+ block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("JOY\0"), 0);
+ block.dwSize = (uint)Marshal.SizeOf(fStruct);
+ buff = MediaConverter.SerializeRaw(block);
+ r.Write(buff);
+ buff = MediaConverter.SerializeRaw(fStruct);
+ r.Write(buff);
+
+
+ // ZXSTAYBLOCK
+ if (s._machine.Spectrum.MachineType != MachineType.ZXSpectrum16 && s._machine.Spectrum.MachineType != MachineType.ZXSpectrum48)
+ {
+ var gStruct = s.GetZXSTAYBLOCK();
+ block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("AY\0\0"), 0);
+ block.dwSize = (uint)Marshal.SizeOf(gStruct);
+ buff = MediaConverter.SerializeRaw(block);
+ r.Write(buff);
+ buff = MediaConverter.SerializeRaw(gStruct);
+ r.Write(buff);
+ }
+
+ // ZXSTRAMPAGE
+ switch (s._machine.Spectrum.MachineType)
+ {
+ // For 16k Spectrums, only page 5 (0x4000 - 0x7fff) is saved.
+ case MachineType.ZXSpectrum16:
+ block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("RAMP"), 0);
+ var rp16 = s.GetZXSTRAMPAGE(5, s._machine.RAM0);
+ block.dwSize = (uint)Marshal.SizeOf(rp16);
+ buff = MediaConverter.SerializeRaw(block);
+ r.Write(buff);
+ buff = MediaConverter.SerializeRaw(rp16);
+ r.Write(buff);
+ break;
+ // For 48k Spectrums and Timex TS/TC models, pages 5, 2 (0x8000 - 0xbfff) and 0 (0xc000 - 0xffff) are saved.
+ case MachineType.ZXSpectrum48:
+ block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("RAMP"), 0);
+ var rp48_0 = s.GetZXSTRAMPAGE(5, s._machine.RAM0);
+ block.dwSize = (uint)Marshal.SizeOf(rp48_0);
+ buff = MediaConverter.SerializeRaw(block);
+ r.Write(buff);
+ buff = MediaConverter.SerializeRaw(rp48_0);
+ r.Write(buff);
+
+ block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("RAMP"), 0);
+ var rp48_1 = s.GetZXSTRAMPAGE(5, s._machine.RAM1);
+ block.dwSize = (uint)Marshal.SizeOf(rp48_1);
+ buff = MediaConverter.SerializeRaw(block);
+ r.Write(buff);
+ buff = MediaConverter.SerializeRaw(rp48_1);
+ r.Write(buff);
+
+ block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("RAMP"), 0);
+ var rp48_2 = s.GetZXSTRAMPAGE(5, s._machine.RAM2);
+ block.dwSize = (uint)Marshal.SizeOf(rp48_2);
+ buff = MediaConverter.SerializeRaw(block);
+ r.Write(buff);
+ buff = MediaConverter.SerializeRaw(rp48_2);
+ r.Write(buff);
+ break;
+ // For 128k Spectrums and the Pentagon 128, all pages (0-7) are saved.
+ case MachineType.ZXSpectrum128:
+ case MachineType.ZXSpectrum128Plus2:
+ case MachineType.ZXSpectrum128Plus2a:
+ case MachineType.ZXSpectrum128Plus3:
+ List rams = new List
+ {
+ s._machine.RAM0, s._machine.RAM1, s._machine.RAM2, s._machine.RAM3,
+ s._machine.RAM4, s._machine.RAM5, s._machine.RAM6, s._machine.RAM7
+ };
+ for (byte i = 0; i < 8; i++)
+ {
+ block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("RAMP"), 0);
+ var rp = s.GetZXSTRAMPAGE(i, rams[i]);
+ block.dwSize = (uint)Marshal.SizeOf(rp);
+ buff = MediaConverter.SerializeRaw(block);
+ r.Write(buff);
+ buff = MediaConverter.SerializeRaw(rp);
+ r.Write(buff);
+ }
+ break;
+ }
+ /*
+ // ZXSTPLUS3
+ if (s._machine.Spectrum.MachineType == MachineType.ZXSpectrum128Plus3)
+ {
+ var iStruct = s.GetZXSTPLUS3();
+ block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("+3\0\0"), 0);
+ block.dwSize = (uint)Marshal.SizeOf(iStruct);
+ buff = MediaConverter.SerializeRaw(block);
+ r.Write(buff);
+ buff = MediaConverter.SerializeRaw(iStruct);
+ r.Write(buff);
+
+ // ZXSTDSKFILE
+ if (s._machine.diskImages.Count() > 0)
+ {
+ var jStruct = s.GetZXSTDSKFILE();
+ block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("DSK\0"), 0);
+ block.dwSize = (uint)Marshal.SizeOf(jStruct);
+ buff = MediaConverter.SerializeRaw(block);
+ r.Write(buff);
+ buff = MediaConverter.SerializeRaw(jStruct);
+ r.Write(buff);
+ }
+ }
+
+ // ZXSTTAPE
+ if (s._machine.tapeImages.Count() > 0)
+ {
+ var hStruct = s.GetZXSTTAPE();
+ var tapeData = s._machine.tapeImages[s._machine.TapeMediaIndex];
+ block.dwId = MediaConverter.GetUInt32(Encoding.UTF8.GetBytes("TAPE"), 0);
+ block.dwSize = (uint)Marshal.SizeOf(hStruct) + (uint)tapeData.Length;
+ buff = MediaConverter.SerializeRaw(block);
+ r.Write(buff);
+ buff = MediaConverter.SerializeRaw(hStruct);
+ r.Write(buff);
+ buff = MediaConverter.SerializeRaw(tapeData);
+ r.Write(buff);
+ char[] terminator = "\0".ToCharArray();
+ r.Write(terminator);
+ }
+ */
+
+ }
+
+ result = ms.ToArray();
+ }
+
+ return result;
+ }
+
+ private ZXSTRAMPAGE GetZXSTRAMPAGE(byte page, byte[] RAM)
+ {
+ var s = new ZXSTRAMPAGE();
+ s.wFlags = 0; // uncompressed only at the moment
+ s.chPageNo = page;
+ s.ramPage = RAM;
+ return s;
+ }
+
+ private ZXSTCREATOR GetZXSTCREATOR()
+ {
+ var s = new ZXSTCREATOR();
+ var str = "BIZHAWK EMULATOR".ToCharArray();
+ s.szCreator = new char[32];
+ for (int i = 0; i < str.Length; i++)
+ s.szCreator[i] = str[i];
+ s.chMajorVersion = 1;
+ s.chMinorVersion = 4;
+
+ return s;
+ }
+
+ private ZXSTZ80REGS GetZXSTZ80REGS()
+ {
+ var s = new ZXSTZ80REGS();
+ s.AF = (ushort)_machine.Spectrum.GetCpuFlagsAndRegisters()["AF"].Value;
+ s.BC = (ushort)_machine.Spectrum.GetCpuFlagsAndRegisters()["BC"].Value;
+ s.DE = (ushort)_machine.Spectrum.GetCpuFlagsAndRegisters()["DE"].Value;
+ s.HL = (ushort)_machine.Spectrum.GetCpuFlagsAndRegisters()["HL"].Value;
+ s.AF1 = (ushort)_machine.Spectrum.GetCpuFlagsAndRegisters()["Shadow AF"].Value;
+ s.BC1 = (ushort)_machine.Spectrum.GetCpuFlagsAndRegisters()["Shadow BC"].Value;
+ s.DE1 = (ushort)_machine.Spectrum.GetCpuFlagsAndRegisters()["Shadow DE"].Value;
+ s.HL1 = (ushort)_machine.Spectrum.GetCpuFlagsAndRegisters()["Shadow HL"].Value;
+ s.IX = (ushort)_machine.Spectrum.GetCpuFlagsAndRegisters()["IX"].Value;
+ s.IY = (ushort)_machine.Spectrum.GetCpuFlagsAndRegisters()["IY"].Value;
+ s.SP = (ushort)_machine.Spectrum.GetCpuFlagsAndRegisters()["SP"].Value;
+ s.PC = (ushort)_machine.Spectrum.GetCpuFlagsAndRegisters()["PC"].Value;
+ s.I = (byte)_machine.CPU.Regs[_machine.CPU.I];
+ s.R = (byte)_machine.CPU.Regs[_machine.CPU.R];
+ s.IFF1 = (byte)(_machine.CPU.IFF1 ? 1 : 0);
+ s.IFF2 = (byte)(_machine.CPU.IFF2 ? 1 : 0);
+ s.IM = (byte)_machine.CPU.InterruptMode;
+ s.dwCyclesStart = (uint)(_machine.CurrentFrameCycle + _machine.ULADevice.InterruptStartTime);
+ s.wMemPtr = (ushort)(_machine.CPU.Regs[_machine.CPU.Z] + (_machine.CPU.Regs[_machine.CPU.W] << 8));
+ //s.chHoldIntReqCycles = ?
+
+ if (_machine.CPU.EIPending > 0)
+ {
+ s.chFlags |= ZXSTZF_EILAST;
+ }
+ else if (_machine.CPU.halted)
+ {
+ s.chFlags |= ZXSTZF_HALTED;
+ }
+
+ return s;
+ }
+
+ private ZXSTSPECREGS GetZXSTSPECREGS()
+ {
+ var s = new ZXSTSPECREGS();
+ s.chBorder = _machine.ULADevice.BorderColor > 7 ? (byte)0 : (byte)_machine.ULADevice.BorderColor;
+ s.chFe = _machine.LastFe;
+ byte x7ffd = (byte)_machine.RAMPaged;
+ byte x1ffd = 0;
+ switch (_machine.Spectrum.MachineType)
+ {
+ case MachineType.ZXSpectrum16:
+ case MachineType.ZXSpectrum48:
+ s.ch7ffd = 0;
+ s.unionPage = 0;
+ break;
+
+ case MachineType.ZXSpectrum128:
+ case MachineType.ZXSpectrum128Plus2:
+ // 7FFD
+ if (_machine._ROMpaged == 1)
+ x7ffd |= 0x10;
+ if (_machine.SHADOWPaged)
+ x7ffd |= 0x08;
+ if (_machine.PagingDisabled)
+ x7ffd |= 0x20;
+ break;
+
+ case MachineType.ZXSpectrum128Plus2a:
+ case MachineType.ZXSpectrum128Plus3:
+ if (_machine.UPDDiskDevice.FDD_FLAG_MOTOR)
+ x1ffd |= 0x08;
+ if (_machine.SpecialPagingMode)
+ {
+ x1ffd |= 0x01;
+ switch (_machine.PagingConfiguration)
+ {
+ case 1:
+ x1ffd |= 0x02;
+ break;
+ case 2:
+ x1ffd |= 0x04;
+ break;
+ case 3:
+ x1ffd |= 0x02;
+ x1ffd |= 0x04;
+ break;
+ }
+ }
+ else
+ {
+ if (_machine.ROMhigh)
+ x1ffd |= 0x04;
+ }
+ if (_machine.ROMlow)
+ x7ffd |= 0x10;
+ if (_machine.SHADOWPaged)
+ x7ffd |= 0x08;
+ if (_machine.PagingDisabled)
+ x7ffd |= 0x20;
+ break;
+ }
+
+ s.ch7ffd = x7ffd;
+ s.unionPage = x1ffd;
+ return s;
+ }
+
+ private ZXSTKEYBOARD GetZXSTKEYBOARD()
+ {
+ var s = new ZXSTKEYBOARD();
+ s.dwFlags = 0; //no issue 2 emulation
+ s.chKeyboardJoystick |= (byte)JoystickTypes.ZXSTKJT_NONE;
+ return s;
+ }
+
+ private ZXSTJOYSTICK GetZXSTJOYSTICK()
+ {
+ var s = new ZXSTJOYSTICK();
+ s.dwFlags = 0; //depreciated
+ s.chTypePlayer1 |= (byte)JoystickTypes.ZXSTKJT_KEMPSTON;
+ s.chTypePlayer2 |= (byte)JoystickTypes.ZXSTKJT_SINCLAIR1;
+ return s;
+ }
+
+ private ZXSTAYBLOCK GetZXSTAYBLOCK()
+ {
+ var s = new ZXSTAYBLOCK();
+ s.cFlags = 0; // no external units
+ s.chCurrentRegister = (byte)_machine.AYDevice.SelectedRegister;
+ var regs = _machine.AYDevice.ExportRegisters();
+ s.chAyRegs = new byte[16];
+ for (int i = 0; i < 16; i++)
+ {
+ s.chAyRegs[i] = (byte)regs[i];
+ }
+ return s;
+ }
+
+ private ZXSTTAPE GetZXSTTAPE()
+ {
+ var s = new ZXSTTAPE();
+ s.wFlags |= (int)CassetteRecorderState.ZXSTTP_EMBEDDED;
+ s.wCurrentBlockNo = (ushort)_machine.TapeDevice.CurrentDataBlockIndex;
+ s.dwCompressedSize = _machine.tapeImages[_machine.TapeDevice.CurrentDataBlockIndex].Length;
+ s.dwUncompressedSize = _machine.tapeImages[_machine.TapeDevice.CurrentDataBlockIndex].Length;
+ char[] ext = "tzx".ToCharArray();
+ s.szFileExtension = new char[16];
+ for (int f = 1; f < ext.Length; f++)
+ {
+ s.szFileExtension[f - 1] = ext[f];
+ }
+ return s;
+ }
+
+ private ZXSTPLUS3 GetZXSTPLUS3()
+ {
+ var s = new ZXSTPLUS3();
+ s.chNumDrives = 1;
+ s.fMotorOn = _machine.UPDDiskDevice.FDD_FLAG_MOTOR ? (byte)1 : (byte)0;
+ return s;
+ }
+
+ private ZXSTDSKFILE GetZXSTDSKFILE()
+ {
+ var s = new ZXSTDSKFILE();
+ s.wFlags = 0;
+ s.chDriveNum = 0;
+ s.dwUncompressedSize = 0;
+ return s;
+ }
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Snapshot/SZX/SZX.Objects.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Snapshot/SZX/SZX.Objects.cs
new file mode 100644
index 0000000000..3bbe9acead
--- /dev/null
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Snapshot/SZX/SZX.Objects.cs
@@ -0,0 +1,410 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
+{
+ ///
+ /// Structs, Constants and Enums
+ /// http://www.spectaculator.com/docs/zx-state/intro.shtml
+ ///
+ public partial class SZX
+ {
+ #region ZX-State Header
+
+ public enum MachineIdentifier : byte
+ {
+ ZXSTMID_16K = 0,
+ ZXSTMID_48K = 1,
+ ZXSTMID_128K = 2,
+ ZXSTMID_PLUS2 = 3,
+ ZXSTMID_PLUS2A = 4,
+ ZXSTMID_PLUS3 = 5,
+ ZXSTMID_PLUS3E = 6,
+ ZXSTMID_PENTAGON128 = 7,
+ ZXSTMID_TC2048 = 8,
+ ZXSTMID_TC2068 = 9,
+ ZXSTMID_SCORPION = 10,
+ ZXSTMID_SE = 11,
+ ZXSTMID_TS2068 = 12,
+ ZXSTMID_PENTAGON512 = 13,
+ ZXSTMID_PENTAGON1024 = 14,
+ ZXSTMID_NTSC48K = 15,
+ ZXSTMID_128KE = 16
+ }
+
+ ///
+ /// If set, the emulated Spectrum uses alternate timings (one cycle later than normal timings). If reset, the emulated Spectrum uses standard timings.
+ /// This flag is only applicable for the ZXSTMID_16K, ZXSTMID_48K and ZXSTMID_128K models.
+ ///
+ public const int ZXSTMF_ALTERNATETIMINGS = 1;
+
+ ///
+ /// The zx-state header appears right at the start of a zx-state (.szx) file.
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ZXSTHEADER
+ {
+ public uint dwMagic;
+ public byte chMajorVersion;
+ public byte chMinorVersion;
+ public byte chMachineId;
+ public byte chFlags;
+ }
+
+ #endregion
+
+ #region ZXSTBLOCK Header
+
+ ///
+ /// Block Header. Each real block starts with this header.
+ ///
+ public struct ZXSTBLOCK
+ {
+ public uint dwId;
+ public uint dwSize;
+ }
+
+ #endregion
+
+ #region ZXSTCREATOR
+
+ ///
+ /// This block identifies the program that created this zx-state file.
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ZXSTCREATOR
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
+ public char[] szCreator;
+ public short chMajorVersion;
+ public short chMinorVersion;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
+ public byte[] chData;
+ }
+
+ #endregion
+
+ #region ZXSTZ80REGS
+
+ ///
+ /// The last instruction executed was an EI instruction or an invalid $DD or $FD prefix.
+ ///
+ public const int ZXSTZF_EILAST = 1;
+ ///
+ /// The last instruction executed was a HALT instruction. The CPU is currently executing NOPs and will continue to do so until the next interrupt occurs.
+ /// This flag is mutually exclusive with ZXSTZF_EILAST.
+ ///
+ public const int ZXSTZF_HALTED = 2;
+
+ ///
+ /// Contains the Z80 registers and other internal state values. It does not contain any specific model registers.
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ZXSTZ80REGS
+ {
+ public ushort AF, BC, DE, HL;
+ public ushort AF1, BC1, DE1, HL1;
+ public ushort IX, IY, SP, PC;
+ public byte I;
+ public byte R;
+ public byte IFF1, IFF2;
+ public byte IM;
+ public uint dwCyclesStart;
+ public byte chHoldIntReqCycles;
+ public byte chFlags;
+ public ushort wMemPtr;
+ }
+
+ #endregion
+
+ #region ZXSTSPECREGS
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ZXSTSPECREGS
+ {
+ public byte chBorder;
+ public byte ch7ffd;
+ public byte unionPage;
+ public byte chFe;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
+ public byte[] chReserved;
+ }
+
+ #endregion
+
+ #region ZXSTAYBLOCK
+
+ ///
+ /// Fuller Box emulation
+ ///
+ public const int ZXSTAYF_FULLERBOX = 1;
+ ///
+ /// Melodik Soundbox emulation.
+ /// This is essentially an AY chip for older Spectrums that uses the same ports as that found in 128k Spectrums
+ ///
+ public const int ZXSTAYF_128AY = 2;
+
+ ///
+ /// The state of the AY chip found in all 128k Spectrums, Pentagons, Scorpions and Timex machines.
+ /// This block may also be present for 16k/48k Spectrums if Fuller Box or Melodik emulation is enabled.
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ZXSTAYBLOCK
+ {
+ public byte cFlags;
+ public byte chCurrentRegister;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+ public byte[] chAyRegs;
+ }
+
+ #endregion
+
+ #region ZXSTRAMPAGE
+
+ ///
+ /// Ram pages are compressed using Zlib
+ ///
+ public const int ZXSTRF_COMPRESSED = 1;
+
+ ///
+ /// zx-state files will contain a number of 16KB RAM page blocks, depending on the specific Spectrum model.
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ZXSTRAMPAGE
+ {
+ public ushort wFlags;
+ public byte chPageNo;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4000)]
+ public byte[] ramPage;
+ }
+
+ #endregion
+
+ #region ZXSTKEYBOARD
+
+ ///
+ /// Keyboard state
+ ///
+ public const int ZXSTKF_ISSUE2 = 1;
+
+ ///
+ /// Supported joystick types
+ ///
+ public enum JoystickTypes
+ {
+ ZXSTKJT_KEMPSTON = 0,
+ ZXSTKJT_FULLER = 1,
+ ZXSTKJT_CURSOR = 2,
+ ZXSTKJT_SINCLAIR1 = 3,
+ ZXSTKJT_SINCLAIR2 = 4,
+ ZXSTKJT_SPECTRUMPLUS = 5,
+ ZXSTKJT_TIMEX1 = 6,
+ ZXSTKJT_TIMEX2 = 7,
+ ZXSTKJT_NONE = 8
+ }
+
+ ///
+ /// The state of the Spectrum keyboard and any keyboard joystick emulation.
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ZXSTKEYBOARD
+ {
+ public uint dwFlags;
+ public byte chKeyboardJoystick;
+ }
+
+ #endregion
+
+ #region ZXSTJOYSTICK
+
+ ///
+ /// Joystick setup for both players.
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ZXSTJOYSTICK
+ {
+ public uint dwFlags;
+ public byte chTypePlayer1;
+ public byte chTypePlayer2;
+ }
+
+ #endregion
+
+ #region ZXSTTAPE
+
+ ///
+ /// Cassette Recorder state
+ ///
+ public enum CassetteRecorderState
+ {
+ ZXSTTP_EMBEDDED = 1,
+ ZXSTTP_COMPRESSED = 2
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ZXSTTAPE
+ {
+ public ushort wCurrentBlockNo;
+ public ushort wFlags;
+ public int dwUncompressedSize;
+ public int dwCompressedSize;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+ public char[] szFileExtension;
+ }
+
+ #endregion
+
+ #region ZXSTPLUS3
+
+ ///
+ /// The number of drives connected to the Spectrum +3 and whether their motors are turned on.
+ /// Any blocks specifying which disk files are in which drive will follow this one.
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ZXSTPLUS3
+ {
+ public byte chNumDrives;
+ public byte fMotorOn;
+ }
+
+ #endregion
+
+ #region ZXSTDSKFILE
+
+ ///
+ /// Not implemented. All disk images are currently links to external .dsk or .ipf files
+ ///
+ public const int ZXSTDSKF_COMPRESSED = 1;
+ ///
+ /// Not implemented. All disk images are currently links to external .dsk or .ipf files
+ ///
+ public const int ZXSTDSKF_EMBEDDED = 2;
+ ///
+ /// When a double-sided disk is inserted into a single-sided drive, specifies the side being read from/written to.
+ /// If set, Side B is the active side, otherwise it is Side A.
+ ///
+ public const int ZXSTDSKF_SIDEB = 3;
+
+ ///
+ /// Each +3 disk drive that has a disk inserted in it will have one of these blocks.
+ /// They follow the ZXSTPLUS3 block which identifies the number of drives.
+ ///
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ZXSTDSKFILE
+ {
+ public ushort wFlags;
+ public byte chDriveNum;
+ public int dwUncompressedSize;
+ }
+
+ #endregion
+
+ #region Not Yet Implemented
+
+ #region ZXSTATASP
+
+ #endregion
+
+ #region ZXSTATARAM
+
+ #endregion
+
+ #region ZXSTCF
+
+ #endregion
+
+ #region ZXSTCFRAM
+
+ #endregion
+
+ #region ZXSTCOVOX
+
+ #endregion
+
+ #region ZXSTBETA128
+
+ #endregion
+
+ #region ZXSTBETADISK
+
+ #endregion
+
+ #region ZXSTDOCK
+
+ #endregion
+
+ #region ZXSTGS
+
+ #endregion
+
+ #region ZXSTGSRAMPAGE
+
+ #endregion
+
+ #region ZXSTIF1
+
+ #endregion
+
+ #region ZXSTIF2ROM
+
+ #endregion
+
+ #region ZXSTMCART
+
+ #endregion
+
+ #region ZXSTMOUSE
+
+ #endregion
+
+ #region ZXSTMULTIFACE
+
+ #endregion
+
+ #region ZXSTOPUS
+
+ #endregion
+
+ #region ZXSTOPUSDISK
+
+ #endregion
+
+ #region ZXSTPLUSD
+
+ #endregion
+
+ #region ZXSTPLUSDDISK
+
+ #endregion
+
+ #region ZXSTROM
+
+ #endregion
+
+ #region ZXSTSCLDREGS
+
+ #endregion
+
+ #region ZXSTSIDE
+
+ #endregion
+
+ #region ZXSTSPECDRUM
+
+ #endregion
+
+ #region ZXSTUSPEECH
+
+ #endregion
+
+ #region ZXSTZXPRINTER
+
+ #endregion
+
+ #endregion
+ }
+}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs
index 8423f50e1f..6b85d7136f 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Util.cs
@@ -62,5 +62,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
return m;
}
+
+ public byte[] GetSZXSnapshot()
+ {
+ return SZX.ExportSZX(_machine);
+ //return System.Text.Encoding.Default.GetString(data);
+ }
}
}
diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs
index f630d6e257..1f6ddb0008 100644
--- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs
+++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.cs
@@ -62,7 +62,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
deterministicEmulation = deterministic.Value;
}
- switch (SyncSettings.MachineType)
+ MachineType = SyncSettings.MachineType;
+
+ switch (MachineType)
{
case MachineType.ZXSpectrum16:
ControllerDefinition = ZXSpectrumControllerDefinition;
@@ -146,6 +148,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum
private readonly TraceBuffer _tracer;
public IController _controller;
public SpectrumBase _machine;
+ public MachineType MachineType;
public List _gameInfo;