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