C64: Faster loading savestates. Also fix input not working after loading state.

This commit is contained in:
Anthony Konzel 2016-03-01 16:03:20 -06:00
parent 43ac625a95
commit a06dd5f768
8 changed files with 120 additions and 55 deletions

View File

@ -102,22 +102,22 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
{ {
case C64.VicType.Ntsc: case C64.VicType.Ntsc:
Vic = Chip6567R8.Create(borderType); Vic = Chip6567R8.Create(borderType);
Cia0 = Chip6526.Create(C64.CiaType.Ntsc, _keyboardPressed, _joystickPressed); Cia0 = Chip6526.Create(C64.CiaType.Ntsc, Input_ReadKeyboard, Input_ReadJoysticks);
Cia1 = Chip6526.Create(C64.CiaType.Ntsc, Cia1_ReadPortA); Cia1 = Chip6526.Create(C64.CiaType.Ntsc, Cia1_ReadPortA);
break; break;
case C64.VicType.Pal: case C64.VicType.Pal:
Vic = Chip6569.Create(borderType); Vic = Chip6569.Create(borderType);
Cia0 = Chip6526.Create(C64.CiaType.Pal, _keyboardPressed, _joystickPressed); Cia0 = Chip6526.Create(C64.CiaType.Pal, Input_ReadKeyboard, Input_ReadJoysticks);
Cia1 = Chip6526.Create(C64.CiaType.Pal, Cia1_ReadPortA); Cia1 = Chip6526.Create(C64.CiaType.Pal, Cia1_ReadPortA);
break; break;
case C64.VicType.NtscOld: case C64.VicType.NtscOld:
Vic = Chip6567R56A.Create(borderType); Vic = Chip6567R56A.Create(borderType);
Cia0 = Chip6526.Create(C64.CiaType.NtscRevA, _keyboardPressed, _joystickPressed); Cia0 = Chip6526.Create(C64.CiaType.NtscRevA, Input_ReadKeyboard, Input_ReadJoysticks);
Cia1 = Chip6526.Create(C64.CiaType.NtscRevA, Cia1_ReadPortA); Cia1 = Chip6526.Create(C64.CiaType.NtscRevA, Cia1_ReadPortA);
break; break;
case C64.VicType.Drean: case C64.VicType.Drean:
Vic = Chip6572.Create(borderType); Vic = Chip6572.Create(borderType);
Cia0 = Chip6526.Create(C64.CiaType.Pal, _keyboardPressed, _joystickPressed); Cia0 = Chip6526.Create(C64.CiaType.Pal, Input_ReadKeyboard, Input_ReadJoysticks);
Cia1 = Chip6526.Create(C64.CiaType.Pal, Cia1_ReadPortA); Cia1 = Chip6526.Create(C64.CiaType.Pal, Cia1_ReadPortA);
break; break;
} }

View File

@ -89,6 +89,16 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
return !_restorePressed && Cia1.ReadIrq() && CartPort.ReadNmi(); return !_restorePressed && Cia1.ReadIrq() && CartPort.ReadNmi();
} }
private bool[] Input_ReadJoysticks()
{
return _joystickPressed;
}
private bool[] Input_ReadKeyboard()
{
return _keyboardPressed;
}
private bool Pla_ReadCharen() private bool Pla_ReadCharen()
{ {
return (Cpu.PortData & 0x04) != 0; return (Cpu.PortData & 0x04) != 0;

View File

@ -286,8 +286,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
public override void SyncState(Serializer ser) public override void SyncState(Serializer ser)
{ {
SaveState.SyncDeltaBytes("MediaStateA", ser, _originalMediaA, ref _banksA); SaveState.SyncDelta("MediaStateA", ser, _originalMediaA, ref _banksA);
SaveState.SyncDeltaBytes("MediaStateB", ser, _originalMediaB, ref _banksB); SaveState.SyncDelta("MediaStateB", ser, _originalMediaB, ref _banksB);
base.SyncState(ser); base.SyncState(ser);
} }
} }

View File

@ -40,7 +40,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
} }
} }
public static Cia Create(C64.CiaType type, bool[] keyboard, bool[] joysticks) public static Cia Create(C64.CiaType type, Func<bool[]> keyboard, Func<bool[]> joysticks)
{ {
switch (type) switch (type)
{ {

View File

@ -36,37 +36,40 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
{ {
[SaveState.DoNotSave] private int _ret; [SaveState.DoNotSave] private int _ret;
[SaveState.DoNotSave] private int _tst; [SaveState.DoNotSave] private int _tst;
[SaveState.DoNotSave] private readonly bool[] _joyData; [SaveState.DoNotSave] private readonly Func<bool[]> _readJoyData;
[SaveState.DoNotSave] private readonly bool[] _keyData; [SaveState.DoNotSave] private readonly Func<bool[]> _readKeyData;
public JoystickKeyboardPort(bool[] joyData, bool[] keyData) public JoystickKeyboardPort(Func<bool[]> readJoyData, Func<bool[]> readKeyData)
{ {
_joyData = joyData; _readJoyData = readJoyData;
_keyData = keyData; _readKeyData = readKeyData;
} }
private int GetJoystick1() private int GetJoystick1()
{ {
var joyData = _readJoyData();
return 0xE0 | return 0xE0 |
(_joyData[0] ? 0x00 : 0x01) | (joyData[0] ? 0x00 : 0x01) |
(_joyData[1] ? 0x00 : 0x02) | (joyData[1] ? 0x00 : 0x02) |
(_joyData[2] ? 0x00 : 0x04) | (joyData[2] ? 0x00 : 0x04) |
(_joyData[3] ? 0x00 : 0x08) | (joyData[3] ? 0x00 : 0x08) |
(_joyData[4] ? 0x00 : 0x10); (joyData[4] ? 0x00 : 0x10);
} }
private int GetJoystick2() private int GetJoystick2()
{ {
var joyData = _readJoyData();
return 0xE0 | return 0xE0 |
(_joyData[5] ? 0x00 : 0x01) | (joyData[5] ? 0x00 : 0x01) |
(_joyData[6] ? 0x00 : 0x02) | (joyData[6] ? 0x00 : 0x02) |
(_joyData[7] ? 0x00 : 0x04) | (joyData[7] ? 0x00 : 0x04) |
(_joyData[8] ? 0x00 : 0x08) | (joyData[8] ? 0x00 : 0x08) |
(_joyData[9] ? 0x00 : 0x10); (joyData[9] ? 0x00 : 0x10);
} }
private int GetKeyboardRows(int activeColumns) private int GetKeyboardRows(int activeColumns)
{ {
var keyData = _readKeyData();
var result = 0xFF; var result = 0xFF;
for (var r = 0; r < 8; r++) for (var r = 0; r < 8; r++)
{ {
@ -75,7 +78,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
var i = r << 3; var i = r << 3;
for (var c = 0; c < 8; c++) for (var c = 0; c < 8; c++)
{ {
if (_keyData[i++]) if (keyData[i++])
{ {
result &= ~(1 << c); result &= ~(1 << c);
} }
@ -88,6 +91,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
private int GetKeyboardColumns(int activeRows) private int GetKeyboardColumns(int activeRows)
{ {
var keyData = _readKeyData();
var result = 0xFF; var result = 0xFF;
for (var c = 0; c < 8; c++) for (var c = 0; c < 8; c++)
{ {
@ -96,7 +100,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
var i = c; var i = c;
for (var r = 0; r < 8; r++) for (var r = 0; r < 8; r++)
{ {
if (_keyData[i]) if (keyData[i])
{ {
result &= ~(1 << r); result &= ~(1 << r);
} }

View File

@ -87,7 +87,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
_todDen = todDen; _todDen = todDen;
} }
public Cia(int todNum, int todDen, bool[] keyboard, bool[] joysticks) : this(todNum, todDen) public Cia(int todNum, int todDen, Func<bool[]> keyboard, Func<bool[]> joysticks) : this(todNum, todDen)
{ {
_port = new JoystickKeyboardPort(joysticks, keyboard); _port = new JoystickKeyboardPort(joysticks, keyboard);
} }

View File

@ -10,7 +10,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
[SaveState.DoNotSave] public const int FluxBitsPerEntry = 32; [SaveState.DoNotSave] public const int FluxBitsPerEntry = 32;
[SaveState.DoNotSave] public const int FluxBitsPerTrack = 16000000 / 5; [SaveState.DoNotSave] public const int FluxBitsPerTrack = 16000000 / 5;
[SaveState.DoNotSave] public const int FluxEntriesPerTrack = FluxBitsPerTrack/FluxBitsPerEntry; [SaveState.DoNotSave] public const int FluxEntriesPerTrack = FluxBitsPerTrack/FluxBitsPerEntry;
[SaveState.DoNotSave] private readonly List<int[]> _tracks; [SaveState.DoNotSave] private int[][] _tracks;
[SaveState.DoNotSave] private readonly int[] _originalMedia; [SaveState.DoNotSave] private readonly int[] _originalMedia;
[SaveState.DoNotSave] public bool Valid; [SaveState.DoNotSave] public bool Valid;
@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
/// </summary> /// </summary>
public Disk(int trackCapacity) public Disk(int trackCapacity)
{ {
_tracks = new List<int[]>(trackCapacity); _tracks = new int[trackCapacity][];
FillMissingTracks(); FillMissingTracks();
_originalMedia = SerializeTracks(_tracks); _originalMedia = SerializeTracks(_tracks);
Valid = true; Valid = true;
@ -35,7 +35,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
/// <param name="trackCapacity">Total number of tracks on the media.</param> /// <param name="trackCapacity">Total number of tracks on the media.</param>
public Disk(IList<byte[]> trackData, IList<int> trackNumbers, IList<int> trackDensities, IList<int> trackLengths, int trackCapacity) public Disk(IList<byte[]> trackData, IList<int> trackNumbers, IList<int> trackDensities, IList<int> trackLengths, int trackCapacity)
{ {
_tracks = Enumerable.Repeat<int[]>(null, trackCapacity).ToList(); _tracks = new int[trackCapacity][];
for (var i = 0; i < trackData.Count; i++) for (var i = 0; i < trackData.Count; i++)
{ {
_tracks[trackNumbers[i]] = ConvertToFluxTransitions(trackDensities[i], trackData[i], 0); _tracks[trackNumbers[i]] = ConvertToFluxTransitions(trackDensities[i], trackData[i], 0);
@ -82,7 +82,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
private void FillMissingTracks() private void FillMissingTracks()
{ {
for (var i = 0; i < _tracks.Count; i++) for (var i = 0; i < _tracks.Length; i++)
{ {
if (_tracks[i] == null) if (_tracks[i] == null)
{ {
@ -99,36 +99,44 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
/// <summary> /// <summary>
/// Combine the tracks into a single bitstream. /// Combine the tracks into a single bitstream.
/// </summary> /// </summary>
private int[] SerializeTracks(IEnumerable<int[]> tracks) private int[] SerializeTracks(int[][] tracks)
{ {
return tracks.SelectMany(t => t).ToArray(); var trackCount = tracks.Length;
var result = new int[trackCount * FluxEntriesPerTrack];
for (var i = 0; i < trackCount; i++)
{
Array.Copy(tracks[i], 0, result, i * FluxEntriesPerTrack, FluxEntriesPerTrack);
}
return result;
} }
/// <summary> /// <summary>
/// Split a bitstream into tracks. /// Split a bitstream into tracks.
/// </summary> /// </summary>
private IEnumerable<int[]> DeserializeTracks(int[] data) private int[][] DeserializeTracks(int[] data)
{ {
var trackCount = data.Length/FluxEntriesPerTrack; var trackCount = data.Length/FluxEntriesPerTrack;
var result = new int[trackCount][];
for (var i = 0; i < trackCount; i++) for (var i = 0; i < trackCount; i++)
{ {
yield return data.Skip(i*FluxEntriesPerTrack).Take(FluxEntriesPerTrack).ToArray(); result[i] = new int[FluxEntriesPerTrack];
Array.Copy(data, i * FluxEntriesPerTrack, result[i], 0, FluxEntriesPerTrack);
} }
} return result;
}
public void SyncState(Serializer ser) public void SyncState(Serializer ser)
{ {
if (ser.IsReader) if (ser.IsReader)
{ {
var mediaState = new int[_originalMedia.Length]; var mediaState = new int[_originalMedia.Length];
SaveState.SyncDeltaInts("MediaState", ser, _originalMedia, ref mediaState); SaveState.SyncDelta("MediaState", ser, _originalMedia, ref mediaState);
_tracks.Clear(); _tracks = DeserializeTracks(mediaState);
_tracks.AddRange(DeserializeTracks(mediaState));
} }
else if (ser.IsWriter) else if (ser.IsWriter)
{ {
var mediaState = SerializeTracks(_tracks); var mediaState = SerializeTracks(_tracks);
SaveState.SyncDeltaInts("MediaState", ser, _originalMedia, ref mediaState); SaveState.SyncDelta("MediaState", ser, _originalMedia, ref mediaState);
} }
SaveState.SyncObject(ser, this); SaveState.SyncObject(ser, this);
} }

View File

@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
@ -38,31 +40,72 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
return delta; return delta;
} }
public static void SyncDeltaBytes(string name, Serializer ser, int[] source, ref int[] data) private static byte[] CompressInts(int[] data)
{
unchecked
{
var length = data.Length;
var bytes = new byte[length * 4];
for (int i = 0, j = 0; i < length; i++)
{
var c = data[i];
bytes[j++] = (byte)(c);
bytes[j++] = (byte)(c >> 8);
bytes[j++] = (byte)(c >> 16);
bytes[j++] = (byte)(c >> 24);
}
using (var mem = new MemoryStream())
{
using (var compressor = new DeflateStream(mem, CompressionMode.Compress))
{
var writer = new BinaryWriter(compressor);
writer.Write(bytes.Length);
writer.Write(bytes);
compressor.Flush();
}
mem.Flush();
return mem.ToArray();
}
}
}
private static int[] DecompressInts(byte[] data)
{
unchecked
{
using (var mem = new MemoryStream(data))
{
using (var decompressor = new DeflateStream(mem, CompressionMode.Decompress))
{
var reader = new BinaryReader(decompressor);
var length = reader.ReadInt32();
var bytes = reader.ReadBytes(length);
var result = new int[length >> 2];
for (int i = 0, j = 0; i < length; i++)
{
int d = bytes[i++];
d |= bytes[i++] << 8;
d |= bytes[i++] << 16;
d |= bytes[i] << 24;
result[j++] = d;
}
return result;
}
}
}
}
public static void SyncDelta(string name, Serializer ser, int[] source, ref int[] data)
{ {
byte[] delta = null; byte[] delta = null;
if (ser.IsWriter && data != null) if (ser.IsWriter && data != null)
{ {
delta = GetDelta(source, data).Select(d => unchecked((byte)d)).ToArray(); delta = CompressInts(GetDelta(source, data));
} }
ser.Sync(name, ref delta, false); ser.Sync(name, ref delta, false);
if (ser.IsReader && delta != null) if (ser.IsReader && delta != null)
{ {
data = GetDelta(source, delta.Select(d => (int)d).ToArray()); data = GetDelta(source, DecompressInts(delta));
}
}
public static void SyncDeltaInts(string name, Serializer ser, int[] source, ref int[] data)
{
int[] delta = null;
if (ser.IsWriter && data != null)
{
delta = GetDelta(source, data);
}
ser.Sync(name, ref delta, false);
if (ser.IsReader && delta != null)
{
data = GetDelta(source, delta);
} }
} }