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
///