From e2a212a0b8ec64832802a0be1b25c67f9a542c85 Mon Sep 17 00:00:00 2001 From: Asnivor Date: Mon, 5 Mar 2018 16:12:19 +0000 Subject: [PATCH] Added tape trap auto-load option --- .../Hardware/Datacorder/DatacorderDevice.cs | 161 ++++++++++++++++-- .../Machine/SpectrumBase.Memory.cs | 2 +- .../SinclairSpectrum/Machine/SpectrumBase.cs | 15 +- .../SinclairSpectrum/ZXSpectrum.ISettable.cs | 12 +- .../SinclairSpectrum/ZXSpectrum.Messaging.cs | 48 +++++- 5 files changed, 216 insertions(+), 22 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs index eb37c02cf4..4bdc9aca30 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Hardware/Datacorder/DatacorderDevice.cs @@ -2,6 +2,7 @@ using BizHawk.Emulation.Cores.Components.Z80A; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -123,6 +124,88 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum #endregion + #region Emulator + + /// + /// This is the address the that ROM will jump to when the spectrum has quit tape playing + /// + public const ushort ERROR_ROM_ADDRESS = 0x0008; + + Stopwatch sw = new Stopwatch(); + + /// + /// Should be fired at the end of every frame + /// Primary purpose is to detect tape traps and manage auto play (if/when this is ever implemented) + /// + public void EndFrame() + { + if (TapeIsPlaying) + { + + // check whether we need to auto-stop the tape + if (IsMachineAtErrorAddress()) + { + _machine.Spectrum.OSD_TapeStoppedAuto(); + Stop(); + } + + } + else + { + // the tape is not playing - check to see if we need to autostart the tape + if (IsMachineInLoadMode()) + { + _machine.Spectrum.OSD_TapePlayingAuto(); + Play(); + //sw.Start(); + } + } + /* + if (TapeIsPlaying && sw.IsRunning) + { + if (!IsMachineInLoadMode() && sw.ElapsedMilliseconds == 2000) + { + sw.Stop(); + sw.Reset(); + _machine.Spectrum.OSD_TapeStoppedAuto(); + Stop(); + } + } + */ + } + + /// + /// Checks whether the machine is in a state that is waiting to load tape content + /// + /// + public bool IsMachineInLoadMode() + { + if (!_machine.Spectrum.Settings.AutoLoadTape) + return false; + + if (_cpu.RegPC == 1523) + return true; + + return false; + } + + /// + /// Checks whether the machine has reached the error rom address (and the tape needs to be stopped) + /// + /// + private bool IsMachineAtErrorAddress() + { + //if (!_machine.Spectrum.Settings.AutoLoadTape) + //return false; + + if (_cpu.RegPC == 64464) // 40620) // ERROR_ROM_ADDRESS) + return true; + else + return false; + } + + #endregion + #region Tape Controls /// @@ -277,6 +360,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum #region Tape Device Methods + private bool initialBlockPlayed = false; + /// /// Simulates the spectrum 'EAR' input reading data from the tape /// @@ -284,6 +369,8 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum /// public bool GetEarBit(long cpuCycle) { + + // decide how many cycles worth of data we are capturing long cycles = cpuCycle - _lastCycle; @@ -312,6 +399,28 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // flip the current state currentState = !currentState; + if (_position == 0) + { + // start of block + // notify about the current block + + var bl = _dataBlocks[_currentDataBlockIndex]; + + StringBuilder sbd = new StringBuilder(); + sbd.Append("("); + sbd.Append((_currentDataBlockIndex + 1) + " of " + _dataBlocks.Count()); + sbd.Append(") : "); + //sbd.Append("ID" + bl.BlockID.ToString("X2") + " - "); + sbd.Append(bl.BlockDescription); + if (bl.MetaData.Count > 0) + { + sbd.Append(" - "); + sbd.Append(bl.MetaData.First().Key + ": " + bl.MetaData.First().Value); + } + _machine.Spectrum.OSD_TapePlayingBlockInfo(sbd.ToString()); + } + + // increment the current period position _position++; @@ -327,6 +436,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // Stop the tape command found - if this is the end of the tape RTZ // otherwise just STOP and move to the next block case TapeCommand.STOP_THE_TAPE: + + _machine.Spectrum.OSD_TapeStoppedAuto(); + if (_currentDataBlockIndex >= _dataBlocks.Count()) RTZ(); else @@ -335,18 +447,50 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum } break; case TapeCommand.STOP_THE_TAPE_48K: - if (_currentDataBlockIndex >= _dataBlocks.Count()) - RTZ(); - else + + if ((_machine.GetType() != typeof(ZX128) && + _machine.GetType() != typeof(ZX128Plus2) && + _machine.GetType() != typeof(ZX128Plus3)) || + (_machine.GetType() == typeof(ZX128) || + _machine.GetType() != typeof(ZX128Plus2) || + _machine.GetType() != typeof(ZX128Plus3)) && + _machine._ROMpaged == 1) { - Stop(); + _machine.Spectrum.OSD_TapeStoppedAuto(); + + if (_currentDataBlockIndex >= _dataBlocks.Count()) + RTZ(); + else + { + Stop(); + } + } break; } + if (_dataBlocks[_currentDataBlockIndex].DataPeriods.Count() == 0) + { + // notify about the current block (we are skipping it because its empty) + var bl = _dataBlocks[_currentDataBlockIndex]; + StringBuilder sbd = new StringBuilder(); + sbd.Append("("); + sbd.Append((_currentDataBlockIndex + 1) + " of " + _dataBlocks.Count()); + sbd.Append(") : "); + //sbd.Append("ID" + bl.BlockID.ToString("X2") + " - "); + sbd.Append(bl.BlockDescription); + if (bl.MetaData.Count > 0) + { + sbd.Append(" - "); + sbd.Append(bl.MetaData.First().Key + ": " + bl.MetaData.First().Value); + } + _machine.Spectrum.OSD_TapePlayingSkipBlockInfo(sbd.ToString()); + + } + // skip any empty blocks while (_position >= _dataBlocks[_currentDataBlockIndex].DataPeriods.Count()) - { + { _position = 0; _currentDataBlockIndex++; if (_currentDataBlockIndex >= _dataBlocks.Count()) @@ -378,12 +522,6 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum return currentState; } - #endregion - - #region Media Serialization - - - #endregion #region State Serialization @@ -403,6 +541,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum ser.Sync("_tapeIsPlaying", ref _tapeIsPlaying); ser.Sync("_lastCycle", ref _lastCycle); ser.Sync("_waitEdge", ref _waitEdge); + //ser.Sync("_initialBlockPlayed", ref initialBlockPlayed); ser.Sync("currentState", ref currentState); //_dataBlocks diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs index 81ee1c819f..0d750bc64c 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.Memory.cs @@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public byte[] ROM1 = new byte[0x4000]; public byte[] ROM2 = new byte[0x4000]; public byte[] ROM3 = new byte[0x4000]; - + /// /// RAM Banks /// diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs index 38594c7670..9d4ec84a10 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/SpectrumBase.cs @@ -12,7 +12,17 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public abstract partial class SpectrumBase { // 128 and up only - protected int ROMPaged = 0; + //protected int ROMPaged = 0; + + protected int ROMPaged; + + public int _ROMpaged + { + get { return ROMPaged; } + set { ROMPaged = value; } + } + + protected bool SHADOWPaged; public int RAMPaged; protected bool PagingDisabled; @@ -151,6 +161,9 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum // setup for next frame ULADevice.ResetInterrupt(); + + TapeDevice.EndFrame(); + FrameCompleted = true; } diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.ISettable.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.ISettable.cs index f964d6f43d..182cedd7a4 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.ISettable.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.ISettable.cs @@ -43,6 +43,11 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public class ZXSpectrumSettings { + [DisplayName("Auto-load/stop tape")] + [Description("Auto or manual tape operation. Auto will attempt to detect CPU tape traps and automatically Stop/Start the tape")] + [DefaultValue(true)] + public bool AutoLoadTape { get; set; } + [DisplayName("Stereo Sound")] [Description("Turn stereo sound on or off")] [DefaultValue(true)] @@ -80,12 +85,7 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum [DisplayName("Tape Load Speed")] [Description("Select how fast the spectrum loads the game from tape")] [DefaultValue(TapeLoadSpeed.Accurate)] - public TapeLoadSpeed TapeLoadSpeed { get; set; } - - [DisplayName("Auto-load tape")] - [Description("Auto or manual tape operation")] - [DefaultValue(true)] - public bool AutoLoadTape { get; set; } + public TapeLoadSpeed TapeLoadSpeed { get; set; } public ZXSpectrumSyncSettings Clone() { diff --git a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Messaging.cs b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Messaging.cs index 2d83819f95..5b7b29b3d6 100644 --- a/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Messaging.cs +++ b/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/ZXSpectrum.Messaging.cs @@ -129,15 +129,57 @@ namespace BizHawk.Emulation.Cores.Computers.SinclairSpectrum public void OSD_TapeStoppedAuto() { StringBuilder sb = new StringBuilder(); - sb.Append("STOPPED (Auto Tape Trap) (" + _machine.TapeMediaIndex + ": " + _gameInfo[_machine.TapeMediaIndex].Name + ")"); + sb.Append("STOPPED (Auto Tape Trap Detected)"); + + SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); + } + + /// + /// Tape message that is fired when a tape is started automatically + /// + public void OSD_TapePlayingAuto() + { + StringBuilder sb = new StringBuilder(); + sb.Append("PLAYING (Auto Tape Trap Detected)"); + + SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); + } + + /// + /// Tape message that is fired when a new block starts playing + /// + public void OSD_TapePlayingBlockInfo(string blockinfo) + { + StringBuilder sb = new StringBuilder(); + sb.Append("...Starting Block "+ blockinfo); + + SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); + } + + /// + /// Tape message that is fired when a tape block is skipped (because it is empty) + /// + public void OSD_TapePlayingSkipBlockInfo(string blockinfo) + { + StringBuilder sb = new StringBuilder(); + sb.Append("...Skipping Empty Block " + blockinfo); + + SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); + } + + /// + /// Tape message that is fired when a tape is started automatically + /// + public void OSD_TapeEndDetected(string blockinfo) + { + StringBuilder sb = new StringBuilder(); + sb.Append("...Skipping Empty Block " + blockinfo); SendMessage(sb.ToString().TrimEnd('\n'), MessageCategory.Tape); } #endregion - - /// /// Checks whether message category is allowed to be sent ///