Skip to content

Commit

Permalink
Add ISaveRam implementation for AppleII, fix bug which caused DiskIIC…
Browse files Browse the repository at this point in the history
…ontroller to not be correctly stated
  • Loading branch information
CasualPokePlayer committed Apr 5, 2023
1 parent 9ae5f78 commit 8737203
Show file tree
Hide file tree
Showing 11 changed files with 142 additions and 20 deletions.
11 changes: 9 additions & 2 deletions ExternalCoreProjects/Virtu/Disk525.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,28 @@ namespace Jellyfish.Virtu
{
internal abstract class Disk525
{
protected byte[] Data;
protected readonly byte[] Data;
private readonly byte[] Original;
public bool IsWriteProtected;

protected Disk525(byte[] data, bool isWriteProtected)
{
Data = data;
Original = (byte[])data.Clone();
IsWriteProtected = isWriteProtected;
}

public virtual void Sync(IComponentSerializer ser)
{
ser.Sync(nameof(Data), ref Data, false);
ser.SyncDelta("DataDelta", Original, Data);
ser.Sync(nameof(IsWriteProtected), ref IsWriteProtected);
}

public void DeltaUpdate(Action<byte[], byte[]> callback)
{
callback(Data, Original);
}

public static Disk525 CreateDisk(string name, byte[] data, bool isWriteProtected)
{
if (name == null)
Expand Down
12 changes: 9 additions & 3 deletions ExternalCoreProjects/Virtu/DiskIIDrive.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Jellyfish.Virtu
using System;

namespace Jellyfish.Virtu
{
public sealed class DiskIIDrive
{
Expand Down Expand Up @@ -29,8 +31,6 @@ public void Sync(IComponentSerializer ser)
ser.Sync(nameof(_trackNumber), ref _trackNumber);
ser.Sync(nameof(_trackOffset), ref _trackOffset);
ser.Sync(nameof(_trackData), ref _trackData, false);

// TODO: save the delta, this is saving the rom into save states
_disk?.Sync(ser);
}

Expand Down Expand Up @@ -120,5 +120,11 @@ internal void FlushTrack()

private const int TrackNumberMax = 0x44;
private const int PhaseCount = 4;

public void DeltaUpdate(Action<byte[], byte[]> callback)
{
FlushTrack();
_disk.DeltaUpdate(callback);
}
}
}
2 changes: 2 additions & 0 deletions ExternalCoreProjects/Virtu/IComponentSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,7 @@ public interface IComponentSerializer
void Sync(string name, ref byte[] val, bool useNull);
void Sync(string name, ref ushort[] val, bool useNull);
void Sync(string name, ref int[] val, bool useNull);

void SyncDelta<T>(string name, T[] original, T[] current) where T : unmanaged;
}
}
Binary file modified References/Virtu.dll
Binary file not shown.
2 changes: 1 addition & 1 deletion src/BizHawk.Client.Common/config/PathEntryCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ public void ResolveWithDefaults()

CommonEntriesFor(VSystemID.Raw.AmstradCPC, basePath: Path.Combine(".", "AmstradCPC"), omitSaveRAM: true),

CommonEntriesFor(VSystemID.Raw.AppleII, basePath: Path.Combine(".", "Apple II"), omitSaveRAM: true),
CommonEntriesFor(VSystemID.Raw.AppleII, basePath: Path.Combine(".", "Apple II")),

CommonEntriesFor(VSystemID.Raw.Arcade, basePath: Path.Combine(".", "Arcade")),

Expand Down
3 changes: 2 additions & 1 deletion src/BizHawk.Client.EmuHawk/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
using BizHawk.Emulation.Cores;
using BizHawk.Emulation.Cores.Arcades.MAME;
using BizHawk.Emulation.Cores.Calculators.TI83;
using BizHawk.Emulation.Cores.Computers.AppleII;
using BizHawk.Emulation.Cores.Computers.Commodore64;
using BizHawk.Emulation.Cores.Consoles.NEC.PCE;
using BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64;
Expand Down Expand Up @@ -1922,7 +1923,7 @@ private void LoadSaveRam()
byte[] sram;

// some cores might not know how big the saveram ought to be, so just send it the whole file
if (Emulator is C64 or MGBAHawk or NeoGeoPort or NES { BoardName: "FDS" })
if (Emulator is AppleII or C64 or MGBAHawk or NeoGeoPort or NES { BoardName: "FDS" })
{
sram = File.ReadAllBytes(saveRamPath);
}
Expand Down
1 change: 1 addition & 0 deletions src/BizHawk.Emulation.Common/Database/Database.cs
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ public static GameInfo GetGameInfo(byte[] romData, string fileName)

case ".PO":
case ".DO":
case ".NIB":
game.System = VSystemID.Raw.AppleII;
break;

Expand Down
78 changes: 78 additions & 0 deletions src/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.ISaveRam.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System;
using System.IO;

using BizHawk.Common;
using BizHawk.Emulation.Common;

namespace BizHawk.Emulation.Cores.Computers.AppleII
{
public partial class AppleII : ISaveRam
{
private byte[][] _diskDeltas;

private void InitSaveRam()
{
_diskDeltas = new byte[DiskCount][];
}

public bool SaveRamModified => true;

public byte[] CloneSaveRam()
{
using var ms = new MemoryStream();
using var bw = new BinaryWriter(ms);

SaveDelta();
bw.Write(DiskCount);
for (var i = 0; i < DiskCount; i++)
{
bw.WriteByteBuffer(_diskDeltas[i]);
}

return ms.ToArray();
}

public void StoreSaveRam(byte[] data)
{
using var ms = new MemoryStream(data, false);
using var br = new BinaryReader(ms);

var ndisks = br.ReadInt32();

if (ndisks != DiskCount)
{
throw new InvalidOperationException("Disk count mismatch!");
}

for (var i = 0; i < DiskCount; i++)
{
_diskDeltas[i] = br.ReadByteBuffer(returnNull: true);
}

LoadDelta(true);
}

private void SaveDelta()
{
_machine.DiskIIController.Drive1.DeltaUpdate((original, current) =>
{
_diskDeltas[CurrentDisk] = DeltaSerializer.GetDelta<byte>(original, current).ToArray();
});
}

private void LoadDelta(bool maybeDifferent)
{
_machine.DiskIIController.Drive1.DeltaUpdate((original, current) =>
{
if (_diskDeltas[CurrentDisk] is not null)
{
DeltaSerializer.ApplyDelta<byte>(original, current, _diskDeltas[CurrentDisk]);
}
else if (maybeDifferent)
{
original.AsSpan().CopyTo(current);
}
});
}
}
}
18 changes: 18 additions & 0 deletions src/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IStatable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public void LoadStateBinary(BinaryReader reader)
private void SyncState(AppleSerializer ser)
{
int version = 2;
var oldCurrentDisk = CurrentDisk;
ser.BeginSection(nameof(AppleII));
ser.Sync(nameof(version), ref version);
ser.Sync("Frame", ref _frame);
Expand Down Expand Up @@ -66,10 +67,27 @@ private void SyncState(AppleSerializer ser)
_machine.NoSlotClock.Sync(ser);
ser.EndSection();

// disk change, we need to swap disks so SyncDelta works later
if (CurrentDisk != oldCurrentDisk)
{
_machine.DiskIIController.Drive1.InsertDisk("junk" + _romSet[CurrentDisk].Extension, (byte[])_romSet[CurrentDisk].Data.Clone(), false);
}

ser.BeginSection("DiskIIController");
_machine.DiskIIController.Sync(ser);
ser.EndSection();

ser.BeginSection("InactiveDisks");
for (var i = 0; i < DiskCount; i++)
{
// the current disk is handled in DiskIIController
if (i != CurrentDisk)
{
ser.Sync($"DiskDelta{i}", ref _diskDeltas[i], useNull: true);
}
}
ser.EndSection();

ser.EndSection();
}

Expand Down
33 changes: 21 additions & 12 deletions src/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,30 @@ static AppleII()
[CoreConstructor(VSystemID.Raw.AppleII)]
public AppleII(CoreLoadParameters<Settings, SyncSettings> lp)
{
_romSet = lp.Roms.Select(r => r.RomData).ToList();
static (byte[], string) GetRomAndExt(IRomAsset romAssert)
{
var ext = romAssert.Extension.ToUpperInvariant();
return ext switch
{
".DSK" or ".PO" or ".DO" or ".NIB" => (romAssert.FileData, ext),
".2mg" => throw new NotSupportedException("Unsupported extension .2mg!"), // TODO: add a way to support this (we have hashes of this format in our db it seems?)
_ => (romAssert.FileData, ".DSK") // no idea, let's assume it's just a .DSK?
};
}

_romSet = lp.Roms.Select(GetRomAndExt).ToList();
var ser = new BasicServiceProvider(this);
ServiceProvider = ser;

const string TRACE_HEADER = "6502: PC, opcode, register (A, X, Y, P, SP, Cy), flags (NVTBDIZC)";
_tracer = new TraceBuffer(TRACE_HEADER);

_disk1 = _romSet[0];

_appleIIRom = lp.Comm.CoreFileProvider.GetFirmwareOrThrow(new(SystemId, "AppleIIe"), "The Apple IIe BIOS firmware is required");
_diskIIRom = lp.Comm.CoreFileProvider.GetFirmwareOrThrow(new(SystemId, "DiskII"), "The DiskII firmware is required");

_machine = new Components(_appleIIRom, _diskIIRom);

// make a writable memory stream cloned from the rom.
// for junk.dsk the .dsk is important because it determines the format from that
InitSaveRam();
InitDisk();

ser.Register<ITraceable>(_tracer);
Expand All @@ -55,11 +63,10 @@ public AppleII(CoreLoadParameters<Settings, SyncSettings> lp)

private static readonly ControllerDefinition AppleIIController;

private readonly List<byte[]> _romSet = new List<byte[]>();
private readonly List<(byte[] Data, string Extension)> _romSet;
private readonly ITraceable _tracer;

private readonly Components _machine;
private byte[] _disk1;
private readonly byte[] _appleIIRom;
private readonly byte[] _diskIIRom;

Expand All @@ -75,12 +82,14 @@ public int CurrentDisk

public void SetDisk(int discNum)
{
SaveDelta();
CurrentDisk = discNum;
InitDisk();
}

private void IncrementDisk()
{
SaveDelta();
CurrentDisk++;
if (CurrentDisk >= _romSet.Count)
{
Expand All @@ -92,6 +101,7 @@ private void IncrementDisk()

private void DecrementDisk()
{
SaveDelta();
CurrentDisk--;
if (CurrentDisk < 0)
{
Expand All @@ -103,11 +113,10 @@ private void DecrementDisk()

private void InitDisk()
{
_disk1 = _romSet[CurrentDisk];

// make a writable memory stream cloned from the rom.
// for junk.dsk the .dsk is important because it determines the format from that
_machine.Memory.DiskIIController.Drive1.InsertDisk("junk.dsk", (byte[])_disk1.Clone(), false);
// the extension is important here because it determines the format from that
_machine.DiskIIController.Drive1.InsertDisk("junk" + _romSet[CurrentDisk].Extension, (byte[])_romSet[CurrentDisk].Data.Clone(), false);
LoadDelta(false);
}

private static readonly List<string> RealButtons = new List<string>(Keyboard.GetKeyNames()
Expand All @@ -120,7 +129,7 @@ private void InitDisk()
};

public bool DriveLightEnabled => true;
public bool DriveLightOn => _machine.Memory.DiskIIController.DriveLight;
public bool DriveLightOn => _machine.DiskIIController.DriveLight;

private bool _nextPressed;
private bool _prevPressed;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public Components(byte[] appleIIe, byte[] diskIIRom)
emptySlot,
emptySlot,
emptySlot,
new DiskIIController(Video, diskIIRom),
DiskIIController,
emptySlot);

Cpu.Reset();
Expand Down

0 comments on commit 8737203

Please sign in to comment.