diff --git a/src/BizHawk.Emulation.Cores/Computers/Commodore64/Media/Disk.cs b/src/BizHawk.Emulation.Cores/Computers/Commodore64/Media/Disk.cs
index d148d1971e..173a22afbf 100644
--- a/src/BizHawk.Emulation.Cores/Computers/Commodore64/Media/Disk.cs
+++ b/src/BizHawk.Emulation.Cores/Computers/Commodore64/Media/Disk.cs
@@ -10,7 +10,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
public const int FluxBitsPerTrack = 16000000 / 5;
public const int FluxEntriesPerTrack = FluxBitsPerTrack / FluxBitsPerEntry;
private readonly DiskTrack[] _tracks;
- private bool[] _usedTracks;
public bool Valid;
public bool WriteProtected;
@@ -21,7 +20,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
{
WriteProtected = false;
_tracks = new DiskTrack[trackCount];
- _usedTracks = new bool[trackCount];
FillMissingTracks();
Valid = true;
}
@@ -37,7 +35,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
{
WriteProtected = true;
_tracks = new DiskTrack[trackCapacity];
- _usedTracks = new bool[trackCapacity];
for (var i = 0; i < trackData.Count; i++)
{
var track = new DiskTrack();
@@ -67,24 +64,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
}
}
- ///
- /// Generic update of the deltas stored in Drive1541's ISaveRam implementation.
- /// deltaUpdateCallback will be called for each track which has been possibly dirtied
- ///
- /// callback
- public void DeltaUpdate(Action deltaUpdateCallback)
- {
- for (var i = 0; i < _tracks.Length; i++)
- {
- if (_usedTracks[i])
- {
- deltaUpdateCallback(i, _tracks[i]);
- }
- }
- }
-
- public DiskTrack GetTrack(int trackNumber)
- => _tracks[trackNumber];
+ public IReadOnlyList Tracks
+ => _tracks;
public void SyncState(Serializer ser)
{
diff --git a/src/BizHawk.Emulation.Cores/Computers/Commodore64/Media/DiskTrack.cs b/src/BizHawk.Emulation.Cores/Computers/Commodore64/Media/DiskTrack.cs
index 6484f23726..b6a6f11c0b 100644
--- a/src/BizHawk.Emulation.Cores/Computers/Commodore64/Media/DiskTrack.cs
+++ b/src/BizHawk.Emulation.Cores/Computers/Commodore64/Media/DiskTrack.cs
@@ -1,7 +1,5 @@
using System.Buffers;
-using BizHawk.Common;
-
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media;
///
@@ -23,7 +21,7 @@ public sealed class DiskTrack
///
/// Number of bits contained in a single value of the Bits array.
///
- private const int FluxBitsPerEntry = BytesPerEntry * 8;
+ public const int FluxBitsPerEntry = BytesPerEntry * 8;
///
/// The number of flux transition bits stored for each track.
@@ -35,42 +33,19 @@ public sealed class DiskTrack
///
private const int FluxEntriesPerTrack = FluxBitsPerTrack / FluxBitsPerEntry;
- ///
- /// The number of bytes contained in the cached delta, for use with save states.
- ///
- private const int DeltaBytesPerTrack = FluxEntriesPerTrack * BytesPerEntry + 4;
-
private int[] _bits = new int[FluxEntriesPerTrack];
private int[] _original = new int[FluxEntriesPerTrack];
- private byte[] _delta = new byte[DeltaBytesPerTrack];
- private bool _dirty = true;
- private bool _modified = false;
///
/// Current state of the disk, which may be changed from the original media.
///
- public ReadOnlySpan Bits => _bits;
+ public Span Bits => _bits;
///
/// Fixed state of the original media, from which deltas will be calculated.
///
public ReadOnlySpan Original => _original;
- ///
- /// The compressed difference between
- ///
- public byte[] Delta => _delta;
-
- ///
- /// If true, the delta needs to be recalculated.
- ///
- public bool IsDirty => _dirty;
-
- ///
- /// If true, the track data has been modified.
- ///
- public bool IsModified => _modified;
-
///
/// Create a clone of the DiskTrack.
///
@@ -86,42 +61,13 @@ public sealed class DiskTrack
}
///
- /// Prepare the property.
+ /// Check to see if the original bits and current bits are equivalent.
///
///
- /// The new value of .
+ /// True only if the content differs.
///
- private bool CheckModified()
- => _modified = !_original.AsSpan().SequenceEqual(_bits);
-
- ///
- /// Apply a compressed delta over the original media.
- ///
- ///
- /// Compressed delta data.
- ///
- public void ApplyDelta(ReadOnlySpan delta)
- {
- DeltaSerializer.ApplyDelta(_original, _bits, delta);
- _delta = delta.ToArray();
- _dirty = false;
- CheckModified();
- }
-
- ///
- /// Updates the delta for this track.
- ///
- ///
- /// True if the delta has updated, false otherwise.
- ///
- public bool UpdateDelta()
- {
- if (!_dirty) return false;
-
- _delta = DeltaSerializer.GetDelta(_original, _bits).ToArray();
- _dirty = false;
- return true;
- }
+ public bool IsModified()
+ => !_original.AsSpan().SequenceEqual(_bits);
///
/// Resets this track to the state of the original media.
@@ -129,29 +75,28 @@ public sealed class DiskTrack
public void Reset()
{
_original.CopyTo(_bits.AsSpan());
- _delta = Array.Empty();
- _dirty = false;
}
///
- /// Synchronize state.
+ /// Write an entry to .
///
- ///
- /// Serializer with which to synchronize.
+ ///
+ /// Index of the entry to write.
///
- public void SyncState(Serializer ser, string deltaId)
- {
- ser.Sync(deltaId, ref _delta, useNull: true);
- }
-
- public void Write(int index, int bits)
+ ///
+ /// The new content of the entry.
+ ///
+ ///
+ /// True only if data in has been altered.
+ ///
+ public bool Write(int index, int bits)
{
// We only need to update delta if the bits actually changed.
- if (_bits[index] == bits) return;
+ if (_bits[index] == bits) return false;
_bits[index] = bits;
- _dirty = true;
+ return true;
}
public void ReadFromGCR(int density, ReadOnlySpan bytes, int fluxBitOffset)
@@ -213,5 +158,7 @@ public sealed class DiskTrack
break;
}
}
+
+ _bits.CopyTo(_original.AsSpan());
}
}
diff --git a/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.FluxTransitions.cs b/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.FluxTransitions.cs
index 1bf4bc397b..837d85afcb 100644
--- a/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.FluxTransitions.cs
+++ b/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.FluxTransitions.cs
@@ -38,8 +38,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
private void ExecuteFlux()
{
- var track = _disk.GetTrack(_trackNumber);
- var bits = track.Bits;
+ var track = _disk?.Tracks[_trackNumber];
+ var bits = track == null ? Span.Empty : track.Bits;
// This actually executes the main 16mhz clock
while (_clocks > 0)
@@ -58,8 +58,10 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
{
if (_diskBitsLeft <= 0)
{
- if (_diskWriteEnabled)
- track.Write(_diskByteOffset, _diskOutputBits);
+ if (_diskWriteEnabled && track.Write(_diskByteOffset, _diskOutputBits))
+ {
+ _dirtyDiskTracks[_getCurrentDiskNumber()][_trackNumber] = true;
+ }
_diskByteOffset++;
@@ -70,7 +72,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
_diskBits = bits[_diskByteOffset];
_diskOutputBits = 0;
- _diskBitsLeft = Disk.FluxBitsPerEntry;
+ _diskBitsLeft = DiskTrack.FluxBitsPerEntry;
}
}
_diskOutputBits >>= 1;
@@ -200,8 +202,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
_diskDensityCounter++;
_diskCycle = (_diskCycle + 1) & 0xF;
}
-
- if (_diskWriteEnabled && track.UpdateDelta()) SaveDelta(_trackNumber, track.Delta);
}
}
}
diff --git a/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.SaveRam.cs b/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.SaveRam.cs
index 2ca4cb2f32..214b9fb074 100644
--- a/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.SaveRam.cs
+++ b/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.SaveRam.cs
@@ -13,29 +13,34 @@ public sealed partial class Drive1541 : ISaveRam
// we keep it here for all disks as we need to remember it when swapping disks around
// _usedDiskTracks.Length also doubles as a way to remember the disk count
private bool[][] _usedDiskTracks;
+ private bool[][] _dirtyDiskTracks;
private readonly Func _getCurrentDiskNumber;
+ private int _diskCount;
public void InitSaveRam(int diskCount)
{
+ _diskCount = diskCount;
_usedDiskTracks = new bool[diskCount][];
+ _dirtyDiskTracks = new bool[diskCount][];
_diskDeltas = new byte[diskCount][][];
- for (var i = 0; i < diskCount; i++)
+ for (var diskNumber = 0; diskNumber < diskCount; diskNumber++)
{
- _usedDiskTracks[i] = new bool[84];
- _diskDeltas[i] = new byte[84][];
- for (var j = 0; j < 84; j++)
+ _usedDiskTracks[diskNumber] = new bool[84];
+ _diskDeltas[diskNumber] = new byte[84][];
+ _dirtyDiskTracks[diskNumber] = new bool[84];
+ for (var trackNumber = 0; trackNumber < 84; trackNumber++)
{
- _diskDeltas[i][j] = Array.Empty();
+ _diskDeltas[diskNumber][trackNumber] = Array.Empty();
}
}
+
+ SaveRamModified = false;
}
public bool SaveRamModified { get; private set; } = false;
public byte[] CloneSaveRam()
{
- SaveDeltas(); // update the current deltas
-
using var ms = new MemoryStream();
using var bw = new BinaryWriter(ms);
bw.Write(_usedDiskTracks.Length);
@@ -49,6 +54,7 @@ public sealed partial class Drive1541 : ISaveRam
}
}
+ SaveRamModified = false;
return ms.ToArray();
}
@@ -63,8 +69,6 @@ public sealed partial class Drive1541 : ISaveRam
throw new InvalidOperationException("Disk count mismatch!");
}
- ResetDeltas();
-
for (var i = 0; i < _usedDiskTracks.Length; i++)
{
_usedDiskTracks[i] = br.ReadByteBuffer(returnNull: false)!.ToBoolBuffer();
@@ -74,50 +78,82 @@ public sealed partial class Drive1541 : ISaveRam
}
}
- LoadDeltas(); // load up new deltas
- _usedDiskTracks[_getCurrentDiskNumber()][_trackNumber] = true; // make sure this gets set to true now
+ LoadDeltas();
+ SaveRamModified = false;
}
+ ///
+ /// Clear all cached deltas.
+ ///
+ public void ResetDeltas()
+ {
+ for (var i = 0; i < _diskCount; i++)
+ {
+ for (var j = 0; j < 84; j++)
+ {
+ _diskDeltas[i][j] = Array.Empty();
+ _usedDiskTracks[i][j] = false;
+ }
+ }
+ }
+
+ ///
+ /// Calculate and cache the deltas for each track on the current disk.
+ ///
public void SaveDeltas()
{
- _disk?.DeltaUpdate((tracknum, track) =>
+ if (_disk == null) return;
+
+ var diskNumber = _getCurrentDiskNumber();
+ var deltas = _diskDeltas[diskNumber];
+
+ for (var trackNumber = 0; trackNumber < 84; trackNumber++)
{
- SaveDelta(tracknum, track.Delta);
- });
+ var track = _disk.Tracks[trackNumber];
+ var isModified = track.IsModified();
+
+ _usedDiskTracks[diskNumber][trackNumber] = isModified;
+
+ if (_dirtyDiskTracks[diskNumber][trackNumber])
+ {
+ SaveRamModified = true;
+
+ deltas[trackNumber] = isModified
+ ? DeltaSerializer.GetDelta(track.Original, track.Bits).ToArray()
+ : Array.Empty();
+
+ _dirtyDiskTracks[diskNumber][trackNumber] = false;
+ }
+ }
}
+ ///
+ /// Apply new deltas for each track on the current disk.
+ ///
public void LoadDeltas()
{
- _disk?.DeltaUpdate((tracknum, track) =>
+ if (_disk == null) return;
+
+ var diskNumber = _getCurrentDiskNumber();
+ var deltas = _diskDeltas[diskNumber];
+
+ for (var trackNumber = 0; trackNumber < 84; trackNumber++)
{
- LoadDelta(tracknum, track.Delta);
- });
- }
+ var track = _disk.Tracks[trackNumber];
+ var delta = deltas[trackNumber];
- private void ResetDeltas()
- {
- _disk?.DeltaUpdate(static (_, track) =>
- {
- track.Reset();
- });
- }
+ if (delta == null || delta.Length == 0)
+ {
+ track.Reset();
+ }
+ else
+ {
+ DeltaSerializer.ApplyDelta(track.Original, track.Bits, delta);
+ SaveRamModified = true;
+ }
- private void SaveDelta(int trackNumber, byte[] delta)
- {
- SaveRamModified = true;
- _diskDeltas[_getCurrentDiskNumber()][trackNumber] = delta;
- }
-
- private void LoadDelta(int trackNumber, byte[] delta)
- {
- _diskDeltas[_getCurrentDiskNumber()][trackNumber] = delta;
- _disk.GetTrack(trackNumber).ApplyDelta(delta);
- }
-
- private void ResetDelta(int trackNumber)
- {
- SaveRamModified = true;
- _diskDeltas[_getCurrentDiskNumber()][trackNumber] = Array.Empty();
- _disk.GetTrack(trackNumber).Reset();
+ _usedDiskTracks[diskNumber][trackNumber] = track.IsModified();
+ _dirtyDiskTracks[diskNumber][trackNumber] = false;
+ }
}
}
diff --git a/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.cs b/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.cs
index c78a532163..b7b4e085fa 100644
--- a/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.cs
+++ b/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.cs
@@ -195,11 +195,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
Via0.HardReset();
Via1.HardReset();
_trackNumber = 34;
- for (var i = 0; i < _ram.Length; i++)
- {
- _ram[i] = 0x00;
- }
-
+ _ram.AsSpan().Fill(0);
_diskDensity = 0;
_diskFluxReversalDetected = false;
_diskByteOffset = 0;
@@ -232,8 +228,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
{
if (_disk != null)
{
- var track = _disk.GetTrack(_trackNumber);
- _diskBits = track.Bits[_diskByteOffset] >> (Disk.FluxBitsPerEntry - _diskBitsLeft);
+ var track = _disk.Tracks[_trackNumber];
+ _diskBits = track.Bits[_diskByteOffset] >> (DiskTrack.FluxBitsPerEntry - _diskBitsLeft);
_diskWriteProtected = _disk.WriteProtected;
}
else