[C64] Fix up implementation of SaveRam
This commit is contained in:
parent
6f7097ee07
commit
0adf2f97d7
|
@ -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
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generic update of the deltas stored in Drive1541's ISaveRam implementation.
|
||||
/// deltaUpdateCallback will be called for each track which has been possibly dirtied
|
||||
/// </summary>
|
||||
/// <param name="deltaUpdateCallback">callback</param>
|
||||
public void DeltaUpdate(Action<int, DiskTrack> 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<DiskTrack> Tracks
|
||||
=> _tracks;
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
using System.Buffers;
|
||||
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media;
|
||||
|
||||
/// <summary>
|
||||
|
@ -23,7 +21,7 @@ public sealed class DiskTrack
|
|||
/// <summary>
|
||||
/// Number of bits contained in a single value of the Bits array.
|
||||
/// </summary>
|
||||
private const int FluxBitsPerEntry = BytesPerEntry * 8;
|
||||
public const int FluxBitsPerEntry = BytesPerEntry * 8;
|
||||
|
||||
/// <summary>
|
||||
/// The number of flux transition bits stored for each track.
|
||||
|
@ -35,42 +33,19 @@ public sealed class DiskTrack
|
|||
/// </summary>
|
||||
private const int FluxEntriesPerTrack = FluxBitsPerTrack / FluxBitsPerEntry;
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes contained in the cached delta, for use with save states.
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Current state of the disk, which may be changed from the original media.
|
||||
/// </summary>
|
||||
public ReadOnlySpan<int> Bits => _bits;
|
||||
public Span<int> Bits => _bits;
|
||||
|
||||
/// <summary>
|
||||
/// Fixed state of the original media, from which deltas will be calculated.
|
||||
/// </summary>
|
||||
public ReadOnlySpan<int> Original => _original;
|
||||
|
||||
/// <summary>
|
||||
/// The compressed difference between
|
||||
/// </summary>
|
||||
public byte[] Delta => _delta;
|
||||
|
||||
/// <summary>
|
||||
/// If true, the delta needs to be recalculated.
|
||||
/// </summary>
|
||||
public bool IsDirty => _dirty;
|
||||
|
||||
/// <summary>
|
||||
/// If true, the track data has been modified.
|
||||
/// </summary>
|
||||
public bool IsModified => _modified;
|
||||
|
||||
/// <summary>
|
||||
/// Create a clone of the DiskTrack.
|
||||
/// </summary>
|
||||
|
@ -86,42 +61,13 @@ public sealed class DiskTrack
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prepare the <see cref="IsModified"/> property.
|
||||
/// Check to see if the original bits and current bits are equivalent.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The new value of <see cref="IsModified"/>.
|
||||
/// True only if the content differs.
|
||||
/// </returns>
|
||||
private bool CheckModified()
|
||||
=> _modified = !_original.AsSpan().SequenceEqual(_bits);
|
||||
|
||||
/// <summary>
|
||||
/// Apply a compressed delta over the original media.
|
||||
/// </summary>
|
||||
/// <param name="delta">
|
||||
/// Compressed delta data.
|
||||
/// </param>
|
||||
public void ApplyDelta(ReadOnlySpan<byte> delta)
|
||||
{
|
||||
DeltaSerializer.ApplyDelta<int>(_original, _bits, delta);
|
||||
_delta = delta.ToArray();
|
||||
_dirty = false;
|
||||
CheckModified();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the delta for this track.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// True if the delta has updated, false otherwise.
|
||||
/// </returns>
|
||||
public bool UpdateDelta()
|
||||
{
|
||||
if (!_dirty) return false;
|
||||
|
||||
_delta = DeltaSerializer.GetDelta<int>(_original, _bits).ToArray();
|
||||
_dirty = false;
|
||||
return true;
|
||||
}
|
||||
public bool IsModified()
|
||||
=> !_original.AsSpan().SequenceEqual(_bits);
|
||||
|
||||
/// <summary>
|
||||
/// 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<byte>();
|
||||
_dirty = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Synchronize state.
|
||||
/// Write an entry to <see cref="Bits"/>.
|
||||
/// </summary>
|
||||
/// <param name="ser">
|
||||
/// Serializer with which to synchronize.
|
||||
/// <param name="index">
|
||||
/// Index of the entry to write.
|
||||
/// </param>
|
||||
public void SyncState(Serializer ser, string deltaId)
|
||||
{
|
||||
ser.Sync(deltaId, ref _delta, useNull: true);
|
||||
}
|
||||
|
||||
public void Write(int index, int bits)
|
||||
/// <param name="bits">
|
||||
/// The new content of the entry.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// True only if data in <see cref="Bits"/> has been altered.
|
||||
/// </returns>
|
||||
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<byte> bytes, int fluxBitOffset)
|
||||
|
@ -213,5 +158,7 @@ public sealed class DiskTrack
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_bits.CopyTo(_original.AsSpan());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<int>.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<int> _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<byte>();
|
||||
_diskDeltas[diskNumber][trackNumber] = Array.Empty<byte>();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all cached deltas.
|
||||
/// </summary>
|
||||
public void ResetDeltas()
|
||||
{
|
||||
for (var i = 0; i < _diskCount; i++)
|
||||
{
|
||||
for (var j = 0; j < 84; j++)
|
||||
{
|
||||
_diskDeltas[i][j] = Array.Empty<byte>();
|
||||
_usedDiskTracks[i][j] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate and cache the deltas for each track on the current disk.
|
||||
/// </summary>
|
||||
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<byte>();
|
||||
|
||||
_dirtyDiskTracks[diskNumber][trackNumber] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply new deltas for each track on the current disk.
|
||||
/// </summary>
|
||||
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<byte>();
|
||||
_disk.GetTrack(trackNumber).Reset();
|
||||
_usedDiskTracks[diskNumber][trackNumber] = track.IsModified();
|
||||
_dirtyDiskTracks[diskNumber][trackNumber] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue