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:
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);
break;
case C64.VicType.Pal:
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);
break;
case C64.VicType.NtscOld:
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);
break;
case C64.VicType.Drean:
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);
break;
}

View File

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

View File

@ -286,8 +286,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
public override void SyncState(Serializer ser)
{
SaveState.SyncDeltaBytes("MediaStateA", ser, _originalMediaA, ref _banksA);
SaveState.SyncDeltaBytes("MediaStateB", ser, _originalMediaB, ref _banksB);
SaveState.SyncDelta("MediaStateA", ser, _originalMediaA, ref _banksA);
SaveState.SyncDelta("MediaStateB", ser, _originalMediaB, ref _banksB);
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)
{

View File

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

View File

@ -87,7 +87,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
_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);
}

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 FluxBitsPerTrack = 16000000 / 5;
[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] public bool Valid;
@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
/// </summary>
public Disk(int trackCapacity)
{
_tracks = new List<int[]>(trackCapacity);
_tracks = new int[trackCapacity][];
FillMissingTracks();
_originalMedia = SerializeTracks(_tracks);
Valid = true;
@ -35,7 +35,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
/// <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)
{
_tracks = Enumerable.Repeat<int[]>(null, trackCapacity).ToList();
_tracks = new int[trackCapacity][];
for (var i = 0; i < trackData.Count; i++)
{
_tracks[trackNumbers[i]] = ConvertToFluxTransitions(trackDensities[i], trackData[i], 0);
@ -82,7 +82,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
private void FillMissingTracks()
{
for (var i = 0; i < _tracks.Count; i++)
for (var i = 0; i < _tracks.Length; i++)
{
if (_tracks[i] == null)
{
@ -99,36 +99,44 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
/// <summary>
/// Combine the tracks into a single bitstream.
/// </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>
/// Split a bitstream into tracks.
/// </summary>
private IEnumerable<int[]> DeserializeTracks(int[] data)
private int[][] DeserializeTracks(int[] data)
{
var trackCount = data.Length/FluxEntriesPerTrack;
var result = new int[trackCount][];
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)
{
if (ser.IsReader)
{
var mediaState = new int[_originalMedia.Length];
SaveState.SyncDeltaInts("MediaState", ser, _originalMedia, ref mediaState);
_tracks.Clear();
_tracks.AddRange(DeserializeTracks(mediaState));
SaveState.SyncDelta("MediaState", ser, _originalMedia, ref mediaState);
_tracks = DeserializeTracks(mediaState);
}
else if (ser.IsWriter)
{
var mediaState = SerializeTracks(_tracks);
SaveState.SyncDeltaInts("MediaState", ser, _originalMedia, ref mediaState);
SaveState.SyncDelta("MediaState", ser, _originalMedia, ref mediaState);
}
SaveState.SyncObject(ser, this);
}

View File

@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Text;
@ -38,31 +40,72 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
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;
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);
if (ser.IsReader && delta != null)
{
data = GetDelta(source, delta.Select(d => (int)d).ToArray());
}
}
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);
data = GetDelta(source, DecompressInts(delta));
}
}