From 16d68ea813271d8c53d02056db67b90509bb51b9 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Mon, 10 Sep 2018 10:05:49 +0100 Subject: [PATCH] ZXHawk: debug only zx-state snapshot export --- BizHawk.Client.EmuHawk/MainForm.Designer.cs | 40 +- BizHawk.Client.EmuHawk/MainForm.Events.cs | 26 ++ BizHawk.Client.EmuHawk/MainForm.cs | 6 +- .../BizHawk.Emulation.Cores.csproj | 2 + BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs | 2 + .../Hardware/Abstraction/IPSG.cs | 2 + .../Hardware/SoundOuput/AY38912.cs | 17 + .../SinclairSpectrum/Machine/CPUMonitor.cs | 1 + .../Machine/SpectrumBase.Memory.cs | 10 +- .../Machine/SpectrumBase.Port.cs | 4 + .../Machine/ZXSpectrum128K/ZX128.Port.cs | 4 + .../ZXSpectrum128KPlus2a/ZX128Plus2a.Port.cs | 6 + .../ZXSpectrum128KPlus3/ZX128Plus3.Port.cs | 7 + .../Machine/ZXSpectrum48K/ZX48.Port.cs | 2 + .../SinclairSpectrum/Media/MediaConverter.cs | 37 +- .../Media/Snapshot/SZX/SZX.Methods.cs | 425 ++++++++++++++++++ .../Media/Snapshot/SZX/SZX.Objects.cs | 410 +++++++++++++++++ .../SinclairSpectrum/ZXSpectrum.Util.cs | 6 + .../Computers/SinclairSpectrum/ZXSpectrum.cs | 5 +- 19 files changed, 989 insertions(+), 23 deletions(-) create mode 100644 BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Snapshot/SZX/SZX.Methods.cs create mode 100644 BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Media/Snapshot/SZX/SZX.Objects.cs 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;