Merge pull request #588 from TASVideos/c64-delta-savestates

C64 delta savestates
This commit is contained in:
Tony Konzel 2016-03-01 20:41:09 -06:00
commit ab74a9274b
25 changed files with 950 additions and 668 deletions

View File

@ -2,23 +2,23 @@
{ {
public sealed partial class Motherboard public sealed partial class Motherboard
{ {
private readonly int[] _joystickPressed = new int[10]; private readonly bool[] _joystickPressed = new bool[10];
private readonly int[] _keyboardPressed = new int[64]; private readonly bool[] _keyboardPressed = new bool[64];
private static readonly string[,] JoystickMatrix = { private static readonly string[][] JoystickMatrix = {
{"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Button"}, new[] {"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Button"},
{"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Button"} new[] {"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Button"}
}; };
private static readonly string[,] KeyboardMatrix = { private static readonly string[][] KeyboardMatrix = {
{ "Key Insert/Delete", "Key Return", "Key Cursor Left/Right", "Key F7", "Key F1", "Key F3", "Key F5", "Key Cursor Up/Down" }, new[] { "Key Insert/Delete", "Key Return", "Key Cursor Left/Right", "Key F7", "Key F1", "Key F3", "Key F5", "Key Cursor Up/Down" },
{ "Key 3", "Key W", "Key A", "Key 4", "Key Z", "Key S", "Key E", "Key Left Shift" }, new[] { "Key 3", "Key W", "Key A", "Key 4", "Key Z", "Key S", "Key E", "Key Left Shift" },
{ "Key 5", "Key R", "Key D", "Key 6", "Key C", "Key F", "Key T", "Key X" }, new[] { "Key 5", "Key R", "Key D", "Key 6", "Key C", "Key F", "Key T", "Key X" },
{ "Key 7", "Key Y", "Key G", "Key 8", "Key B", "Key H", "Key U", "Key V" }, new[] { "Key 7", "Key Y", "Key G", "Key 8", "Key B", "Key H", "Key U", "Key V" },
{ "Key 9", "Key I", "Key J", "Key 0", "Key M", "Key K", "Key O", "Key N" }, new[] { "Key 9", "Key I", "Key J", "Key 0", "Key M", "Key K", "Key O", "Key N" },
{ "Key Plus", "Key P", "Key L", "Key Minus", "Key Period", "Key Colon", "Key At", "Key Comma" }, new[] { "Key Plus", "Key P", "Key L", "Key Minus", "Key Period", "Key Colon", "Key At", "Key Comma" },
{ "Key Pound", "Key Asterisk", "Key Semicolon", "Key Clear/Home", "Key Right Shift", "Key Equal", "Key Up Arrow", "Key Slash" }, new[] { "Key Pound", "Key Asterisk", "Key Semicolon", "Key Clear/Home", "Key Right Shift", "Key Equal", "Key Up Arrow", "Key Slash" },
{ "Key 1", "Key Left Arrow", "Key Control", "Key 2", "Key Space", "Key Commodore", "Key Q", "Key Run/Stop" } new[] { "Key 1", "Key Left Arrow", "Key Control", "Key 2", "Key Space", "Key Commodore", "Key Q", "Key Run/Stop" }
}; };
[SaveState.DoNotSave] int _pollIndex; [SaveState.DoNotSave] int _pollIndex;
@ -33,9 +33,10 @@
{ {
for (var i = 0; i < 5; i++) for (var i = 0; i < 5; i++)
{ {
_joystickPressed[_pollIndex++] = Controller[JoystickMatrix[j, i]] ? -1 : 0; _joystickPressed[_pollIndex] = Controller[JoystickMatrix[j][i]];
_pollIndex++;
} }
} }
// scan keyboard // scan keyboard
_pollIndex = 0; _pollIndex = 0;
@ -43,7 +44,7 @@
{ {
for (var j = 0; j < 8; j++) for (var j = 0; j < 8; j++)
{ {
_keyboardPressed[_pollIndex++] = Controller[KeyboardMatrix[i, j]] ? -1 : 0; _keyboardPressed[_pollIndex++] = Controller[KeyboardMatrix[i][j]];
} }
} }

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

@ -1,268 +1,276 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using BizHawk.Common; using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
{ {
public abstract partial class CartridgeDevice public abstract partial class CartridgeDevice
{ {
// --------------------------------- public static CartridgeDevice Load(byte[] crtFile)
{
public static CartridgeDevice Load(byte[] crtFile) var mem = new MemoryStream(crtFile);
{ var reader = new BinaryReader(mem);
var mem = new MemoryStream(crtFile);
var reader = new BinaryReader(mem); if (new string(reader.ReadChars(16)) != "C64 CARTRIDGE ")
{
if (new string(reader.ReadChars(16)) != "C64 CARTRIDGE ") return null;
{ }
return null;
} var chipAddress = new List<int>();
var chipBank = new List<int>();
var chipAddress = new List<int>(); var chipData = new List<int[]>();
var chipBank = new List<int>(); var chipType = new List<int>();
var chipData = new List<int[]>();
var chipType = new List<int>(); var headerLength = ReadCRTInt(reader);
var version = ReadCRTShort(reader);
var headerLength = ReadCRTInt(reader); var mapper = ReadCRTShort(reader);
var version = ReadCRTShort(reader); var exrom = reader.ReadByte() != 0;
var mapper = ReadCRTShort(reader); var game = reader.ReadByte() != 0;
var exrom = reader.ReadByte() != 0;
var game = reader.ReadByte() != 0; // reserved
reader.ReadBytes(6);
// reserved
reader.ReadBytes(6); // cartridge name
reader.ReadBytes(0x20);
// cartridge name
reader.ReadBytes(0x20); // skip extra header bytes
if (headerLength > 0x40)
// skip extra header bytes {
if (headerLength > 0x40) reader.ReadBytes(headerLength - 0x40);
{ }
reader.ReadBytes(headerLength - 0x40);
} // read chips
while (reader.PeekChar() >= 0)
// read chips {
while (reader.PeekChar() >= 0) if (new string(reader.ReadChars(4)) != "CHIP")
{ {
if (new string(reader.ReadChars(4)) != "CHIP") break;
{ }
break;
} var chipLength = ReadCRTInt(reader);
chipType.Add(ReadCRTShort(reader));
var chipLength = ReadCRTInt(reader); chipBank.Add(ReadCRTShort(reader));
chipType.Add(ReadCRTShort(reader)); chipAddress.Add(ReadCRTShort(reader));
chipBank.Add(ReadCRTShort(reader)); var chipDataLength = ReadCRTShort(reader);
chipAddress.Add(ReadCRTShort(reader)); chipData.Add(reader.ReadBytes(chipDataLength).Select(x => (int)x).ToArray());
var chipDataLength = ReadCRTShort(reader); chipLength -= chipDataLength + 0x10;
chipData.Add(reader.ReadBytes(chipDataLength).Select(x => (int)x).ToArray()); if (chipLength > 0)
chipLength -= chipDataLength + 0x10; reader.ReadBytes(chipLength);
if (chipLength > 0) }
reader.ReadBytes(chipLength);
} if (chipData.Count <= 0)
{
if (chipData.Count <= 0) return null;
{ }
return null;
} CartridgeDevice result;
switch (mapper)
CartridgeDevice result; {
switch (mapper) case 0x0000:
{ result = new Mapper0000(chipAddress, chipData, game, exrom);
case 0x0000: break;
result = new Mapper0000(chipAddress, chipBank, chipData, game, exrom); case 0x0005:
break; result = new Mapper0005(chipAddress, chipBank, chipData);
case 0x0005: break;
result = new Mapper0005(chipAddress, chipBank, chipData); case 0x000B:
break; result = new Mapper000B(chipAddress, chipData);
case 0x000B: break;
result = new Mapper000B(chipAddress, chipBank, chipData); case 0x000F:
break; result = new Mapper000F(chipAddress, chipBank, chipData);
case 0x000F: break;
result = new Mapper000F(chipAddress, chipBank, chipData); case 0x0011:
break; result = new Mapper0011(chipAddress, chipBank, chipData);
case 0x0011: break;
result = new Mapper0011(chipAddress, chipBank, chipData); case 0x0012:
break; result = new Mapper0012(chipAddress, chipBank, chipData);
case 0x0012: break;
result = new Mapper0012(chipAddress, chipBank, chipData); case 0x0013:
break; result = new Mapper0013(chipAddress, chipBank, chipData);
case 0x0013: break;
result = new Mapper0013(chipAddress, chipBank, chipData); case 0x0020:
break; result = new Mapper0020(chipAddress, chipBank, chipData);
case 0x0020: break;
result = new Mapper0020(chipAddress, chipBank, chipData); default:
break; throw new Exception("This cartridge file uses an unrecognized mapper: " + mapper);
default: }
throw new Exception("This cartridge file uses an unrecognized mapper: " + mapper); result.HardReset();
}
result.HardReset(); return result;
}
return result;
} private static int ReadCRTShort(BinaryReader reader)
{
private static int ReadCRTShort(BinaryReader reader) return (reader.ReadByte() << 8) |
{ reader.ReadByte();
return (reader.ReadByte() << 8) | }
reader.ReadByte();
} private static int ReadCRTInt(BinaryReader reader)
{
private static int ReadCRTInt(BinaryReader reader) return (reader.ReadByte() << 24) |
{ (reader.ReadByte() << 16) |
return (reader.ReadByte() << 24) | (reader.ReadByte() << 8) |
(reader.ReadByte() << 16) | reader.ReadByte();
(reader.ReadByte() << 8) | }
reader.ReadByte();
} [SaveState.SaveWithName("ExRom")]
protected bool pinExRom;
// --------------------------------- [SaveState.SaveWithName("Game")]
protected bool pinGame;
protected bool pinExRom; [SaveState.SaveWithName("IRQ")]
protected bool pinGame; protected bool pinIRQ;
protected bool pinIRQ; [SaveState.SaveWithName("NMI")]
protected bool pinNMI; protected bool pinNMI;
protected bool pinReset; [SaveState.SaveWithName("Reset")]
protected bool validCartridge; protected bool pinReset;
[SaveState.DoNotSave]
public virtual void ExecutePhase1() protected bool validCartridge;
{
} public virtual void ExecutePhase1()
{
public virtual void ExecutePhase2() }
{
} public virtual void ExecutePhase2()
{
public bool ExRom }
{
get [SaveState.DoNotSave]
{ public bool ExRom
return pinExRom; {
} get
} {
return pinExRom;
public bool Game }
{ }
get
{ [SaveState.DoNotSave]
return pinGame; public bool Game
} {
} get
{
public virtual void HardReset() return pinGame;
{ }
pinIRQ = true; }
pinNMI = true;
pinReset = true; public virtual void HardReset()
} {
pinIRQ = true;
public bool IRQ pinNMI = true;
{ pinReset = true;
get }
{
return pinIRQ; [SaveState.DoNotSave]
} public bool IRQ
} {
get
public bool NMI {
{ return pinIRQ;
get }
{ }
return pinNMI;
} [SaveState.DoNotSave]
} public bool NMI
{
public virtual int Peek8000(int addr) get
{ {
return 0xFF; return pinNMI;
} }
}
public virtual int PeekA000(int addr)
{ public virtual int Peek8000(int addr)
return 0xFF; {
} return 0xFF;
}
public virtual int PeekDE00(int addr)
{ public virtual int PeekA000(int addr)
return 0xFF; {
} return 0xFF;
}
public virtual int PeekDF00(int addr)
{ public virtual int PeekDE00(int addr)
return 0xFF; {
} return 0xFF;
}
public virtual void Poke8000(int addr, int val)
{ public virtual int PeekDF00(int addr)
} {
return 0xFF;
public virtual void PokeA000(int addr, int val) }
{
} public virtual void Poke8000(int addr, int val)
{
public virtual void PokeDE00(int addr, int val) }
{
} public virtual void PokeA000(int addr, int val)
{
public virtual void PokeDF00(int addr, int val) }
{
} public virtual void PokeDE00(int addr, int val)
{
public virtual int Read8000(int addr) }
{
return 0xFF; public virtual void PokeDF00(int addr, int val)
} {
}
public virtual int ReadA000(int addr)
{ public virtual int Read8000(int addr)
return 0xFF; {
} return 0xFF;
}
public virtual int ReadDE00(int addr)
{ public virtual int ReadA000(int addr)
return 0xFF; {
} return 0xFF;
}
public virtual int ReadDF00(int addr)
{ public virtual int ReadDE00(int addr)
return 0xFF; {
} return 0xFF;
}
public bool Reset
{ public virtual int ReadDF00(int addr)
get {
{ return 0xFF;
return pinReset; }
}
} [SaveState.DoNotSave]
public bool Reset
public virtual void SyncState(Serializer ser) {
{ get
SaveState.SyncObject(ser, this); {
} return pinReset;
}
public bool Valid }
{
get public virtual void SyncState(Serializer ser)
{ {
return validCartridge; SaveState.SyncObject(ser, this);
} }
}
[SaveState.DoNotSave]
public virtual void Write8000(int addr, int val) public bool Valid
{ {
} get
{
public virtual void WriteA000(int addr, int val) return validCartridge;
{ }
} }
public virtual void WriteDE00(int addr, int val) public virtual void Write8000(int addr, int val)
{ {
} }
public virtual void WriteDF00(int addr, int val) public virtual void WriteA000(int addr, int val)
{ {
} }
}
} public virtual void WriteDE00(int addr, int val)
{
}
public virtual void WriteDF00(int addr, int val)
{
}
}
}

View File

@ -8,15 +8,19 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
{ {
private sealed class Mapper0000 : CartridgeDevice private sealed class Mapper0000 : CartridgeDevice
{ {
[SaveState.DoNotSave]
private readonly int[] _romA; private readonly int[] _romA;
[SaveState.SaveWithName("RomMaskA")]
private readonly int _romAMask; private readonly int _romAMask;
[SaveState.DoNotSave]
private readonly int[] _romB; private readonly int[] _romB;
[SaveState.SaveWithName("RomMaskB")]
private readonly int _romBMask; private readonly int _romBMask;
// standard cartridge mapper (Commodore) // standard cartridge mapper (Commodore)
// note that this format also covers Ultimax carts // note that this format also covers Ultimax carts
public Mapper0000(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData, bool game, bool exrom) public Mapper0000(IList<int> newAddresses, IList<int[]> newData, bool game, bool exrom)
{ {
pinGame = game; pinGame = game;
pinExRom = exrom; pinExRom = exrom;

View File

@ -9,12 +9,19 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
{ {
private sealed class Mapper0005 : CartridgeDevice private sealed class Mapper0005 : CartridgeDevice
{ {
[SaveState.DoNotSave]
private readonly int[][] _banksA; //8000 private readonly int[][] _banksA; //8000
[SaveState.DoNotSave]
private readonly int[][] _banksB = new int[0][]; //A000 private readonly int[][] _banksB = new int[0][]; //A000
[SaveState.SaveWithName("BankMask")]
private readonly int _bankMask; private readonly int _bankMask;
[SaveState.SaveWithName("BankNumber")]
private int _bankNumber; private int _bankNumber;
[SaveState.DoNotSave]
private int[] _currentBankA; private int[] _currentBankA;
[SaveState.DoNotSave]
private int[] _currentBankB; private int[] _currentBankB;
[SaveState.DoNotSave]
private readonly int[] _dummyBank; private readonly int[] _dummyBank;
public Mapper0005(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData) public Mapper0005(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)

View File

@ -14,9 +14,10 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
{ {
private sealed class Mapper000B : CartridgeDevice private sealed class Mapper000B : CartridgeDevice
{ {
[SaveState.DoNotSave]
private readonly int[] _rom = new int[0x4000]; private readonly int[] _rom = new int[0x4000];
public Mapper000B(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData) public Mapper000B(IList<int> newAddresses, IList<int[]> newData)
{ {
validCartridge = false; validCartridge = false;

View File

@ -16,9 +16,13 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
{ {
private class Mapper000F : CartridgeDevice private class Mapper000F : CartridgeDevice
{ {
[SaveState.DoNotSave]
private readonly int[][] _banks; //8000 private readonly int[][] _banks; //8000
[SaveState.SaveWithName("BankMask")]
private readonly int _bankMask; private readonly int _bankMask;
[SaveState.SaveWithName("BankNumber")]
private int _bankNumber; private int _bankNumber;
[SaveState.SaveWithName("CurrentBank")]
private int[] _currentBank; private int[] _currentBank;
public Mapper000F(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData) public Mapper000F(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)

View File

@ -8,9 +8,13 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
{ {
private sealed class Mapper0012 : CartridgeDevice private sealed class Mapper0012 : CartridgeDevice
{ {
[SaveState.DoNotSave]
private readonly int[] _bankMain; private readonly int[] _bankMain;
[SaveState.DoNotSave]
private readonly int[][] _bankHigh; private readonly int[][] _bankHigh;
[SaveState.SaveWithName("BankHighSelected")]
private int[] _bankHighSelected; private int[] _bankHighSelected;
[SaveState.SaveWithName("BankIndex")]
private int _bankIndex; private int _bankIndex;
// Zaxxon and Super Zaxxon cartridges // Zaxxon and Super Zaxxon cartridges

View File

@ -16,10 +16,15 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
{ {
private sealed class Mapper0013 : CartridgeDevice private sealed class Mapper0013 : CartridgeDevice
{ {
[SaveState.DoNotSave]
private readonly int[][] _banks; //8000 private readonly int[][] _banks; //8000
[SaveState.SaveWithName("BankMask")]
private readonly int _bankMask; private readonly int _bankMask;
[SaveState.SaveWithName("BankNumber")]
private int _bankNumber; private int _bankNumber;
[SaveState.DoNotSave]
private int[] _currentBank; private int[] _currentBank;
[SaveState.SaveWithName("ROMEnable")]
private bool _romEnable; private bool _romEnable;
public Mapper0013(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData) public Mapper0013(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)

View File

@ -26,15 +26,29 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
{ {
private sealed class Mapper0020 : CartridgeDevice private sealed class Mapper0020 : CartridgeDevice
{ {
[SaveState.SaveWithName("BankOffset")]
private int _bankOffset = 63 << 13; private int _bankOffset = 63 << 13;
private readonly int[] _banksA = new int[64 << 13]; //8000 [SaveState.DoNotSave]
private readonly int[] _banksB = new int[64 << 13]; //A000 private int[] _banksA = new int[64 << 13]; //8000
[SaveState.DoNotSave]
private int[] _banksB = new int[64 << 13]; //A000
[SaveState.DoNotSave]
private readonly int[] _originalMediaA; //8000
[SaveState.DoNotSave]
private readonly int[] _originalMediaB; //A000
[SaveState.SaveWithName("BoardLed")]
private bool _boardLed; private bool _boardLed;
[SaveState.SaveWithName("Jumper")]
private bool _jumper = false; private bool _jumper = false;
[SaveState.SaveWithName("StateBits")]
private int _stateBits; private int _stateBits;
[SaveState.SaveWithName("RAM")]
private readonly int[] _ram = new int[256]; private readonly int[] _ram = new int[256];
[SaveState.SaveWithName("CommandLatch55")]
private bool _commandLatch55; private bool _commandLatch55;
[SaveState.SaveWithName("CommandLatchAA")]
private bool _commandLatchAa; private bool _commandLatchAa;
[SaveState.SaveWithName("InternalROMState")]
private int _internalRomState; private int _internalRomState;
public Mapper0020(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData) public Mapper0020(IList<int> newAddresses, IList<int> newBanks, IList<int[]> newData)
@ -75,6 +89,10 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
_commandLatch55 = false; _commandLatch55 = false;
_commandLatchAa = false; _commandLatchAa = false;
_internalRomState = 0; _internalRomState = 0;
// back up original media
_originalMediaA = _banksA.Select(d => d).ToArray();
_originalMediaB = _banksB.Select(d => d).ToArray();
} }
private void BankSet(int index) private void BankSet(int index)
@ -265,6 +283,13 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge
{ {
_ram[addr] = val & 0xFF; _ram[addr] = val & 0xFF;
} }
public override void SyncState(Serializer ser)
{
SaveState.SyncDelta("MediaStateA", ser, _originalMediaA, ref _banksA);
SaveState.SyncDelta("MediaStateB", ser, _originalMediaB, ref _banksB);
base.SyncState(ser);
}
} }
} }
} }

View File

@ -1,57 +1,62 @@
using System; using System;
using BizHawk.Common; using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cassette namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cassette
{ {
public sealed class CassettePort public sealed class CassettePort
{ {
public Func<bool> ReadDataOutput = () => true; [SaveState.DoNotSave]
public Func<bool> ReadMotor = () => true; public Func<bool> ReadDataOutput = () => true;
private CassettePortDevice _device; [SaveState.DoNotSave]
private bool _connected; public Func<bool> ReadMotor = () => true;
public void HardReset() [SaveState.SaveWithName("Device")]
{ private CassettePortDevice _device;
if (_connected) [SaveState.SaveWithName("Connected")]
{ private bool _connected;
_device.HardReset();
} public void HardReset()
} {
if (_connected)
public void ExecutePhase() {
{ _device.HardReset();
if (_connected) }
{ }
_device.ExecutePhase2();
} public void ExecutePhase()
} {
if (_connected)
public bool ReadDataInputBuffer() {
{ _device.ExecutePhase2();
return !_connected || _device.ReadDataInputBuffer(); }
} }
public bool ReadSenseBuffer() public bool ReadDataInputBuffer()
{ {
return !_connected || _device.ReadSenseBuffer(); return !_connected || _device.ReadDataInputBuffer();
} }
public void SyncState(Serializer ser) public bool ReadSenseBuffer()
{ {
SaveState.SyncObject(ser, this); return !_connected || _device.ReadSenseBuffer();
} }
public void Connect(CassettePortDevice device) public void SyncState(Serializer ser)
{ {
_connected = device != null; SaveState.SyncObject(ser, this);
_device = device; }
if (_device == null)
{ public void Connect(CassettePortDevice device)
return; {
} _connected = device != null;
_device = device;
_device.ReadDataOutput = () => ReadDataOutput(); if (_device == null)
_device.ReadMotor = () => ReadMotor(); {
} return;
} }
}
_device.ReadDataOutput = () => ReadDataOutput();
_device.ReadMotor = () => ReadMotor();
}
}
}

View File

@ -1,34 +1,36 @@
using System; using System;
using BizHawk.Common; using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cassette namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cassette
{ {
public abstract class CassettePortDevice public abstract class CassettePortDevice
{ {
public Func<bool> ReadDataOutput; [SaveState.DoNotSave]
public Func<bool> ReadMotor; public Func<bool> ReadDataOutput;
[SaveState.DoNotSave]
public virtual void ExecutePhase2() public Func<bool> ReadMotor;
{
} public virtual void ExecutePhase2()
{
public virtual void HardReset() }
{
} public virtual void HardReset()
{
public virtual bool ReadDataInputBuffer() }
{
return true; public virtual bool ReadDataInputBuffer()
} {
return true;
public virtual bool ReadSenseBuffer() }
{
return true; public virtual bool ReadSenseBuffer()
} {
return true;
public virtual void SyncState(Serializer ser) }
{
SaveState.SyncObject(ser, this); public virtual void SyncState(Serializer ser)
} {
} SaveState.SyncObject(ser, this);
} }
}
}

View File

@ -1,40 +1,41 @@
using BizHawk.Common; using BizHawk.Common;
using BizHawk.Emulation.Cores.Computers.Commodore64.Media; using BizHawk.Emulation.Cores.Computers.Commodore64.Media;
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cassette namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cassette
{ {
public class TapeDrive : CassettePortDevice public class TapeDrive : CassettePortDevice
{ {
private Tape _tape; [SaveState.SaveWithName("Tape")]
private Tape _tape;
public override void ExecutePhase2()
{ public override void ExecutePhase2()
if (_tape != null && !ReadMotor()) _tape.ExecuteCycle(); {
} if (_tape != null && !ReadMotor()) _tape.ExecuteCycle();
}
public override void HardReset()
{ public override void HardReset()
if (_tape != null) _tape.Rewind(); {
} if (_tape != null) _tape.Rewind();
}
public override bool ReadDataInputBuffer()
{ public override bool ReadDataInputBuffer()
return _tape == null || _tape.Read(); {
} return _tape == null || _tape.Read();
}
public override bool ReadSenseBuffer()
{ public override bool ReadSenseBuffer()
return _tape == null; {
} return _tape == null;
}
public override void SyncState(Serializer ser)
{ public override void SyncState(Serializer ser)
SaveState.SyncObject(ser, this); {
} SaveState.SyncObject(ser, this);
}
public void Insert(Tape tape)
{ public void Insert(Tape tape)
_tape = tape; {
} _tape = tape;
} }
} }
}

View File

@ -40,7 +40,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
} }
} }
public static Cia Create(C64.CiaType type, int[] keyboard, int[] 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 int[] _joyData; [SaveState.DoNotSave] private readonly Func<bool[]> _readJoyData;
[SaveState.DoNotSave] private readonly int[] _keyData; [SaveState.DoNotSave] private readonly Func<bool[]> _readKeyData;
public JoystickKeyboardPort(int[] joyData, int[] 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] == 0 ? 0x01 : 0x00) | (joyData[0] ? 0x00 : 0x01) |
(_joyData[1] == 0 ? 0x02 : 0x00) | (joyData[1] ? 0x00 : 0x02) |
(_joyData[2] == 0 ? 0x04 : 0x00) | (joyData[2] ? 0x00 : 0x04) |
(_joyData[3] == 0 ? 0x08 : 0x00) | (joyData[3] ? 0x00 : 0x08) |
(_joyData[4] == 0 ? 0x10 : 0x00); (joyData[4] ? 0x00 : 0x10);
} }
private int GetJoystick2() private int GetJoystick2()
{ {
var joyData = _readJoyData();
return 0xE0 | return 0xE0 |
(_joyData[5] == 0 ? 0x01 : 0x00) | (joyData[5] ? 0x00 : 0x01) |
(_joyData[6] == 0 ? 0x02 : 0x00) | (joyData[6] ? 0x00 : 0x02) |
(_joyData[7] == 0 ? 0x04 : 0x00) | (joyData[7] ? 0x00 : 0x04) |
(_joyData[8] == 0 ? 0x08 : 0x00) | (joyData[8] ? 0x00 : 0x08) |
(_joyData[9] == 0 ? 0x10 : 0x00); (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++] != 0) 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] != 0) 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, int[] keyboard, int[] 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

@ -7,18 +7,11 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
{ {
public sealed class Disk public sealed class Disk
{ {
public const int FLUX_BITS_PER_ENTRY = 32; [SaveState.DoNotSave] public const int FluxBitsPerEntry = 32;
public const int FLUX_BITS_PER_TRACK = 16000000 / 5; [SaveState.DoNotSave] public const int FluxBitsPerTrack = 16000000 / 5;
public const int FLUX_ENTRIES_PER_TRACK = FLUX_BITS_PER_TRACK/FLUX_BITS_PER_ENTRY; [SaveState.DoNotSave] public const int FluxEntriesPerTrack = FluxBitsPerTrack/FluxBitsPerEntry;
[SaveState.DoNotSave] private int[][] _tracks;
private class Track [SaveState.DoNotSave] private readonly int[] _originalMedia;
{
public int Index;
public bool Present;
public int[] FluxData;
}
[SaveState.DoNotSave] private readonly Track[] _tracks;
[SaveState.DoNotSave] public bool Valid; [SaveState.DoNotSave] public bool Valid;
/// <summary> /// <summary>
@ -26,9 +19,10 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
/// </summary> /// </summary>
public Disk(int trackCapacity) public Disk(int trackCapacity)
{ {
_tracks = new Track[trackCapacity]; _tracks = new int[trackCapacity][];
FillMissingTracks(); FillMissingTracks();
Valid = true; _originalMedia = SerializeTracks(_tracks);
Valid = true;
} }
/// <summary> /// <summary>
@ -41,46 +35,71 @@ 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 = new Track[trackCapacity]; _tracks = new int[trackCapacity][];
for (var i = 0; i < trackData.Count; i++) for (var i = 0; i < trackData.Count; i++)
{ {
var track = new Track _tracks[trackNumbers[i]] = ConvertToFluxTransitions(trackDensities[i], trackData[i], 0);
{
Index = trackNumbers[i],
Present = true,
FluxData = ConvertToFluxTransitions(trackDensities[i], trackData[i], 0)
};
_tracks[trackNumbers[i]] = track;
} }
FillMissingTracks(); FillMissingTracks();
Valid = true; Valid = true;
} _originalMedia = SerializeTracks(_tracks);
}
private int[] ConvertToFluxTransitions(int density, byte[] bytes, int fluxBitOffset) private int[] ConvertToFluxTransitions(int density, byte[] bytes, int fluxBitOffset)
{ {
var result = new int[FLUX_ENTRIES_PER_TRACK]; var paddedLength = bytes.Length;
var length = bytes.Length; switch (density)
var lengthBits = length*8; {
case 3:
paddedLength = Math.Max(bytes.Length, 7692);
break;
case 2:
paddedLength = Math.Max(bytes.Length, 7142);
break;
case 1:
paddedLength = Math.Max(bytes.Length, 6666);
break;
case 0:
paddedLength = Math.Max(bytes.Length, 6250);
break;
}
paddedLength++;
var paddedBytes = new byte[paddedLength];
Array.Copy(bytes, paddedBytes, bytes.Length);
for (var i = bytes.Length; i < paddedLength; i++)
{
paddedBytes[i] = 0xAA;
}
var result = new int[FluxEntriesPerTrack];
var length = paddedLength;
var lengthBits = (paddedLength * 8) - 7;
var offsets = new List<long>(); var offsets = new List<long>();
var remainingBits = lengthBits;
const long bitsNum = FLUX_ENTRIES_PER_TRACK * FLUX_BITS_PER_ENTRY; const long bitsNum = FluxEntriesPerTrack * FluxBitsPerEntry;
long bitsDen = lengthBits; long bitsDen = lengthBits;
for (var i = 0; i < length; i++) for (var i = 0; i < paddedLength; i++)
{ {
var byteData = bytes[i]; var byteData = paddedBytes[i];
for (var j = 0; j < 8; j++) for (var j = 0; j < 8; j++)
{ {
var offset = fluxBitOffset + ((i * 8 + j) * bitsNum / bitsDen); var offset = fluxBitOffset + ((i * 8 + j) * bitsNum / bitsDen);
var byteOffset = (int)(offset / FLUX_BITS_PER_ENTRY); var byteOffset = (int)(offset / FluxBitsPerEntry);
var bitOffset = (int)(offset % FLUX_BITS_PER_ENTRY); var bitOffset = (int)(offset % FluxBitsPerEntry);
offsets.Add(offset); offsets.Add(offset);
result[byteOffset] |= ((byteData & 0x80) != 0 ? 1 : 0) << bitOffset; result[byteOffset] |= ((byteData & 0x80) != 0 ? 1 : 0) << bitOffset;
byteData <<= 1; byteData <<= 1;
} remainingBits--;
} if (remainingBits <= 0)
break;
}
if (remainingBits <= 0)
break;
}
return result; return result;
} }
private void FillMissingTracks() private void FillMissingTracks()
@ -89,27 +108,58 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
{ {
if (_tracks[i] == null) if (_tracks[i] == null)
{ {
_tracks[i] = new Track _tracks[i] = new int[FluxEntriesPerTrack];
{
Index = i,
FluxData = new int[FLUX_ENTRIES_PER_TRACK]
};
} }
} }
} }
public int[] GetDataForTrack(int halftrack) public int[] GetDataForTrack(int halftrack)
{ {
return _tracks[halftrack].FluxData; return _tracks[halftrack];
} }
public IEnumerable<int> GetPresentTracks() /// <summary>
/// Combine the tracks into a single bitstream.
/// </summary>
private int[] SerializeTracks(int[][] tracks)
{ {
return _tracks.Where(t => t.Present).Select(t => t.Index); 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 int[][] DeserializeTracks(int[] data)
{
var trackCount = data.Length/FluxEntriesPerTrack;
var result = new int[trackCount][];
for (var i = 0; i < trackCount; i++)
{
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)
{
var mediaState = new int[_originalMedia.Length];
SaveState.SyncDelta("MediaState", ser, _originalMedia, ref mediaState);
_tracks = DeserializeTracks(mediaState);
}
else if (ser.IsWriter)
{
var mediaState = SerializeTracks(_tracks);
SaveState.SyncDelta("MediaState", ser, _originalMedia, ref mediaState);
}
SaveState.SyncObject(ser, this); SaveState.SyncObject(ser, this);
} }
} }

View File

@ -1,101 +1,103 @@
using System; using System;
using System.Text; using System.Text;
using BizHawk.Common; using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media namespace BizHawk.Emulation.Cores.Computers.Commodore64.Media
{ {
/** public class Tape
* This class represents a tape. Only TAP-style tapes are supported for now. {
*/ [SaveState.DoNotSave] private readonly byte[] _tapeData;
public class Tape [SaveState.DoNotSave] private readonly byte _version;
{ [SaveState.DoNotSave] private readonly int _start;
[SaveState.DoNotSave] private readonly byte[] _tapeData; [SaveState.DoNotSave] private readonly int _end;
[SaveState.DoNotSave] private readonly byte _version;
[SaveState.DoNotSave] private readonly int _start; [SaveState.SaveWithName("Position")]
[SaveState.DoNotSave] private readonly int _end; private int _pos;
private int _pos, _cycle; [SaveState.SaveWithName("Cycle")]
private bool _data; private int _cycle;
[SaveState.SaveWithName("Data")]
public Tape(byte version, byte[] tapeData, int start, int end) private bool _data;
{
_version = version; public Tape(byte version, byte[] tapeData, int start, int end)
_tapeData = tapeData; {
_start = start; _version = version;
_end = end; _tapeData = tapeData;
Rewind(); _start = start;
} _end = end;
Rewind();
public void ExecuteCycle() }
{
if (_cycle == 0) public void ExecuteCycle()
{ {
if (_pos >= _end) if (_cycle == 0)
{ {
_data = true; if (_pos >= _end)
return; {
} _data = true;
return;
_cycle = _tapeData[_pos++] * 8; }
if (_cycle == 0)
{ _cycle = _tapeData[_pos++] * 8;
if (_version == 0) if (_cycle == 0)
{ {
_cycle = 256 * 8; // unspecified overflow condition if (_version == 0)
} {
else _cycle = 256 * 8; // unspecified overflow condition
{ }
_cycle = (int)(BitConverter.ToUInt32(_tapeData, _pos - 1) >> 8); else
_pos += 3; {
if (_cycle == 0) _cycle = (int)(BitConverter.ToUInt32(_tapeData, _pos - 1) >> 8);
{ _pos += 3;
throw new Exception("Bad tape data"); if (_cycle == 0)
} {
} throw new Exception("Bad tape data");
} }
}
_cycle++; }
}
_cycle++;
// Send a single negative pulse at the end of a cycle }
_data = --_cycle != 0;
} // Send a single negative pulse at the end of a cycle
_data = --_cycle != 0;
// Rewinds the tape back to start }
public void Rewind()
{ // Rewinds the tape back to start
_pos = _start; public void Rewind()
_cycle = 0; {
} _pos = _start;
_cycle = 0;
// Reads from tape, this will tell the caller if the flag pin should be raised }
public bool Read()
{ // Reads from tape, this will tell the caller if the flag pin should be raised
return _data; public bool Read()
} {
return _data;
// Try to construct a tape file from file data. Returns null if not a tape file, throws exceptions for bad tape files. }
// (Note that some error conditions aren't caught right here.)
public static Tape Load(byte[] tapeFile) // Try to construct a tape file from file data. Returns null if not a tape file, throws exceptions for bad tape files.
{ // (Note that some error conditions aren't caught right here.)
Tape result = null; public static Tape Load(byte[] tapeFile)
{
if (Encoding.ASCII.GetString(tapeFile, 0, 12) == "C64-TAPE-RAW") Tape result = null;
{
var version = tapeFile[12]; if (Encoding.ASCII.GetString(tapeFile, 0, 12) == "C64-TAPE-RAW")
if (version > 1) throw new Exception("This tape has an unsupported version"); {
var size = BitConverter.ToUInt32(tapeFile, 16); var version = tapeFile[12];
if (size + 20 != tapeFile.Length) if (version > 1) throw new Exception("This tape has an unsupported version");
{ var size = BitConverter.ToUInt32(tapeFile, 16);
throw new Exception("Tape file header specifies a length that doesn't match the file size"); if (size + 20 != tapeFile.Length)
} {
result = new Tape(version, tapeFile, 20, tapeFile.Length); throw new Exception("Tape file header specifies a length that doesn't match the file size");
} }
return result; result = new Tape(version, tapeFile, 20, tapeFile.Length);
} }
return result;
public void SyncState(Serializer ser) }
{
SaveState.SyncObject(ser, this); public void SyncState(Serializer ser)
} {
} SaveState.SyncObject(ser, this);
} }
}
}

View File

@ -1,5 +1,8 @@
using System; using System;
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;
@ -14,9 +17,99 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
{ {
} }
public class SaveWithName : Attribute
{
public string Name { get; set; }
public SaveWithName(string name)
{
Name = name;
}
}
private static readonly Encoding Encoding = Encoding.Unicode; private static readonly Encoding Encoding = Encoding.Unicode;
public static void SyncObject(Serializer ser, object obj) private static int[] GetDelta(IList<int> source, IList<int> data)
{
var length = Math.Min(source.Count, data.Count);
var delta = new int[length];
for (var i = 0; i < length; i++)
{
delta[i] = source[i] ^ data[i];
}
return delta;
}
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)
{
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);
}
}
public static void SyncObject(Serializer ser, object obj)
{ {
const BindingFlags defaultFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy; const BindingFlags defaultFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
var objType = obj.GetType(); var objType = obj.GetType();
@ -29,6 +122,14 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
continue; continue;
} }
var name = member.Name;
var nameAttribute = member.GetCustomAttributes(true).FirstOrDefault(a => a is SaveWithName);
if (nameAttribute != null)
{
name = ((SaveWithName) nameAttribute).Name;
}
object currentValue = null; object currentValue = null;
var fail = false; var fail = false;
var fieldInfo = member as FieldInfo; var fieldInfo = member as FieldInfo;
@ -54,34 +155,35 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
break; break;
case "Bit": case "Bit":
var refBit = (Bit)currentValue; var refBit = (Bit)currentValue;
ser.Sync(member.Name, ref refBit); ser.Sync(name, ref refBit);
currentValue = refBit; currentValue = refBit;
break; break;
case "Boolean": case "Boolean":
var refBool = (bool)currentValue; var refBool = (bool)currentValue;
ser.Sync(member.Name, ref refBool); ser.Sync(name, ref refBool);
currentValue = refBool; currentValue = refBool;
break; break;
case "Boolean[]": case "Boolean[]":
{ {
var tmp = (bool[])currentValue; var tmp = (bool[])currentValue;
ser.Sync(member.Name, ref tmp, false); ser.Sync(name, ref tmp, false);
currentValue = tmp; currentValue = tmp;
} }
break; break;
case "Byte": case "Byte":
var refByte = (byte)currentValue; var refByte = (byte)currentValue;
ser.Sync(member.Name, ref refByte); ser.Sync(name, ref refByte);
currentValue = refByte; currentValue = refByte;
break; break;
case "Byte[]": case "Byte[]":
refByteBuffer = new ByteBuffer((byte[])currentValue); refByteBuffer = new ByteBuffer((byte[])currentValue);
ser.Sync(member.Name, ref refByteBuffer); ser.Sync(name, ref refByteBuffer);
currentValue = refByteBuffer.Arr; currentValue = refByteBuffer.Arr.Select(d => d).ToArray();
refByteBuffer.Dispose();
break; break;
case "ByteBuffer": case "ByteBuffer":
refByteBuffer = (ByteBuffer)currentValue; refByteBuffer = (ByteBuffer)currentValue;
ser.Sync(member.Name, ref refByteBuffer); ser.Sync(name, ref refByteBuffer);
currentValue = refByteBuffer; currentValue = refByteBuffer;
break; break;
case "Func`1": case "Func`1":
@ -89,29 +191,30 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
break; break;
case "Int16": case "Int16":
var refInt16 = (short)currentValue; var refInt16 = (short)currentValue;
ser.Sync(member.Name, ref refInt16); ser.Sync(name, ref refInt16);
currentValue = refInt16; currentValue = refInt16;
break; break;
case "Int32": case "Int32":
refInt32 = (int)currentValue; refInt32 = (int)currentValue;
ser.Sync(member.Name, ref refInt32); ser.Sync(name, ref refInt32);
currentValue = refInt32; currentValue = refInt32;
break; break;
case "Int32[]": case "Int32[]":
refIntBuffer = new IntBuffer((int[])currentValue); refIntBuffer = new IntBuffer((int[])currentValue);
ser.Sync(member.Name, ref refIntBuffer); ser.Sync(name, ref refIntBuffer);
currentValue = refIntBuffer.Arr; currentValue = refIntBuffer.Arr.Select(d => d).ToArray();
refIntBuffer.Dispose();
break; break;
case "IntBuffer": case "IntBuffer":
refIntBuffer = (IntBuffer)currentValue; refIntBuffer = (IntBuffer)currentValue;
ser.Sync(member.Name, ref refIntBuffer); ser.Sync(name, ref refIntBuffer);
currentValue = refIntBuffer; currentValue = refIntBuffer;
break; break;
case "Point": case "Point":
refPointX = ((Point)currentValue).X; refPointX = ((Point)currentValue).X;
refPointY = ((Point)currentValue).Y; refPointY = ((Point)currentValue).Y;
ser.Sync(member.Name + "_X", ref refPointX); ser.Sync(name + "_X", ref refPointX);
ser.Sync(member.Name + "_Y", ref refPointY); ser.Sync(name + "_Y", ref refPointY);
currentValue = new Point(refPointX, refPointY); currentValue = new Point(refPointX, refPointY);
break; break;
case "Rectangle": case "Rectangle":
@ -119,31 +222,32 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
refPointY = ((Rectangle)currentValue).Y; refPointY = ((Rectangle)currentValue).Y;
var refRectWidth = ((Rectangle)currentValue).Width; var refRectWidth = ((Rectangle)currentValue).Width;
var refRectHeight = ((Rectangle)currentValue).Height; var refRectHeight = ((Rectangle)currentValue).Height;
ser.Sync(member.Name + "_X", ref refPointX); ser.Sync(name + "_X", ref refPointX);
ser.Sync(member.Name + "_Y", ref refPointY); ser.Sync(name + "_Y", ref refPointY);
ser.Sync(member.Name + "_Height", ref refRectHeight); ser.Sync(name + "_Height", ref refRectHeight);
ser.Sync(member.Name + "_Width", ref refRectWidth); ser.Sync(name + "_Width", ref refRectWidth);
currentValue = new Rectangle(refPointX, refPointY, refRectWidth, refRectHeight); currentValue = new Rectangle(refPointX, refPointY, refRectWidth, refRectHeight);
break; break;
case "SByte": case "SByte":
var refSByte = (sbyte)currentValue; var refSByte = (sbyte)currentValue;
ser.Sync(member.Name, ref refSByte); ser.Sync(name, ref refSByte);
currentValue = refSByte; currentValue = refSByte;
break; break;
case "String": case "String":
var refString = (string)currentValue; var refString = (string)currentValue;
var refVal = new ByteBuffer(Encoding.GetBytes(refString)); var refVal = new ByteBuffer(Encoding.GetBytes(refString));
ser.Sync(member.Name, ref refVal); ser.Sync(name, ref refVal);
currentValue = Encoding.GetString(refVal.Arr); currentValue = Encoding.GetString(refVal.Arr);
refVal.Dispose();
break; break;
case "UInt16": case "UInt16":
var refUInt16 = (ushort)currentValue; var refUInt16 = (ushort)currentValue;
ser.Sync(member.Name, ref refUInt16); ser.Sync(name, ref refUInt16);
currentValue = refUInt16; currentValue = refUInt16;
break; break;
case "UInt32": case "UInt32":
var refUInt32 = (uint)currentValue; var refUInt32 = (uint)currentValue;
ser.Sync(member.Name, ref refUInt32); ser.Sync(name, ref refUInt32);
currentValue = refUInt32; currentValue = refUInt32;
break; break;
default: default:
@ -151,7 +255,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
if (t.IsEnum) if (t.IsEnum)
{ {
refInt32 = (int)currentValue; refInt32 = (int)currentValue;
ser.Sync(member.Name, ref refInt32); ser.Sync(name, ref refInt32);
currentValue = refInt32; currentValue = refInt32;
} }
else if (t.IsArray) else if (t.IsArray)
@ -159,7 +263,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
var currentValueArray = (Array) currentValue; var currentValueArray = (Array) currentValue;
for (var i = 0; i < currentValueArray.Length; i++) for (var i = 0; i < currentValueArray.Length; i++)
{ {
ser.BeginSection(string.Format("{0}_{1}", member.Name, i)); ser.BeginSection(string.Format("{0}_{1}", name, i));
SyncObject(ser, currentValueArray.GetValue(i)); SyncObject(ser, currentValueArray.GetValue(i));
ser.EndSection(); ser.EndSection();
} }

View File

@ -8,18 +8,29 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
{ {
public sealed partial class Drive1541 public sealed partial class Drive1541
{ {
[SaveState.DoNotSave]
private const long LEHMER_RNG_PRIME = 48271; private const long LEHMER_RNG_PRIME = 48271;
[SaveState.SaveWithName("DiskDensityCounter")]
private int _diskDensityCounter; // density .. 16 private int _diskDensityCounter; // density .. 16
[SaveState.SaveWithName("DiskSupplementaryCounter")]
private int _diskSupplementaryCounter; // 0 .. 16 private int _diskSupplementaryCounter; // 0 .. 16
[SaveState.SaveWithName("DiskFluxReversalDetected")]
private bool _diskFluxReversalDetected; private bool _diskFluxReversalDetected;
[SaveState.SaveWithName("DiskBitsRemainingInDataEntry")]
private int _diskBitsLeft; private int _diskBitsLeft;
[SaveState.SaveWithName("DiskDataEntryIndex")]
private int _diskByteOffset; private int _diskByteOffset;
[SaveState.SaveWithName("DiskDataEntry")]
private int _diskBits; private int _diskBits;
[SaveState.SaveWithName("DiskCurrentCycle")]
private int _diskCycle; private int _diskCycle;
[SaveState.SaveWithName("DiskDensityConfig")]
private int _diskDensity; private int _diskDensity;
[SaveState.SaveWithName("PreviousCA1")]
private bool _previousCa1; private bool _previousCa1;
[SaveState.SaveWithName("CountsBeforeRandomTransition")]
private int _countsBeforeRandomTransition; private int _countsBeforeRandomTransition;
[SaveState.SaveWithName("CurrentRNG")]
private int _rngCurrent; private int _rngCurrent;
// Lehmer RNG // Lehmer RNG
@ -40,12 +51,12 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
if (_diskBitsLeft <= 0) if (_diskBitsLeft <= 0)
{ {
_diskByteOffset++; _diskByteOffset++;
if (_diskByteOffset == Disk.FLUX_ENTRIES_PER_TRACK) if (_diskByteOffset == Disk.FluxEntriesPerTrack)
{ {
_diskByteOffset = 0; _diskByteOffset = 0;
} }
_diskBits = _trackImageData[_diskByteOffset]; _diskBits = _trackImageData[_diskByteOffset];
_diskBitsLeft = Disk.FLUX_BITS_PER_ENTRY; _diskBitsLeft = Disk.FluxBitsPerEntry;
} }
if ((_diskBits & 1) != 0) if ((_diskBits & 1) != 0)
{ {

View File

@ -8,11 +8,13 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
{ {
public sealed partial class Drive1541 : IDisassemblable public sealed partial class Drive1541 : IDisassemblable
{ {
[SaveState.DoNotSave]
IEnumerable<string> IDisassemblable.AvailableCpus IEnumerable<string> IDisassemblable.AvailableCpus
{ {
get { yield return "Disk Drive 6502"; } get { yield return "Disk Drive 6502"; }
} }
[SaveState.DoNotSave]
string IDisassemblable.Cpu string IDisassemblable.Cpu
{ {
get { return "Disk Drive 6502"; } get { return "Disk Drive 6502"; }
@ -21,6 +23,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
} }
} }
[SaveState.DoNotSave]
string IDisassemblable.PCRegisterName string IDisassemblable.PCRegisterName
{ {
get { return "PC"; } get { return "PC"; }

View File

@ -13,28 +13,49 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
{ {
public sealed partial class Drive1541 : SerialPortDevice public sealed partial class Drive1541 : SerialPortDevice
{ {
[SaveState.SaveWithName("Disk")]
private Disk _disk; private Disk _disk;
[SaveState.SaveWithName("BitHistory")]
private int _bitHistory; private int _bitHistory;
[SaveState.SaveWithName("BitsRemainingInLatchedByte")]
private int _bitsRemainingInLatchedByte; private int _bitsRemainingInLatchedByte;
[SaveState.SaveWithName("Sync")]
private bool _sync; private bool _sync;
[SaveState.SaveWithName("ByteReady")]
private bool _byteReady; private bool _byteReady;
[SaveState.DoNotSave] private readonly int _driveCpuClockNum; [SaveState.SaveWithName("DriveCpuClockNumerator")]
private readonly int _driveCpuClockNum;
[SaveState.SaveWithName("TrackNumber")]
private int _trackNumber; private int _trackNumber;
[SaveState.SaveWithName("MotorEnabled")]
private bool _motorEnabled; private bool _motorEnabled;
[SaveState.SaveWithName("LedEnabled")]
private bool _ledEnabled; private bool _ledEnabled;
[SaveState.SaveWithName("MotorStep")]
private int _motorStep; private int _motorStep;
[SaveState.DoNotSave]
private int _via0PortBtemp; private int _via0PortBtemp;
[SaveState.SaveWithName("CPU")]
private readonly MOS6502X _cpu; private readonly MOS6502X _cpu;
[SaveState.SaveWithName("RAM")]
private readonly int[] _ram; private readonly int[] _ram;
[SaveState.SaveWithName("VIA0")]
public readonly Via Via0; public readonly Via Via0;
[SaveState.SaveWithName("VIA1")]
public readonly Via Via1; public readonly Via Via1;
[SaveState.SaveWithName("SystemCpuClockNumerator")]
private readonly int _cpuClockNum; private readonly int _cpuClockNum;
[SaveState.SaveWithName("SystemDriveCpuRatioDifference")]
private int _ratioDifference; private int _ratioDifference;
[SaveState.SaveWithName("DriveLightOffTime")]
private int _driveLightOffTime; private int _driveLightOffTime;
[SaveState.DoNotSave] private int[] _trackImageData = new int[1]; [SaveState.DoNotSave]
private int[] _trackImageData = new int[1];
[SaveState.DoNotSave]
public Func<int> ReadIec = () => 0xFF; public Func<int> ReadIec = () => 0xFF;
[SaveState.DoNotSave]
public Action DebuggerStep; public Action DebuggerStep;
[SaveState.DoNotSave]
public readonly Chip23128 DriveRom; public readonly Chip23128 DriveRom;
public Drive1541(int clockNum, int clockDen) public Drive1541(int clockNum, int clockDen)
@ -191,7 +212,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
if (_disk != null) if (_disk != null)
{ {
_trackImageData = _disk.GetDataForTrack(_trackNumber); _trackImageData = _disk.GetDataForTrack(_trackNumber);
_diskBits = _trackImageData[_diskByteOffset] >> (Disk.FLUX_BITS_PER_ENTRY - _diskBitsLeft); _diskBits = _trackImageData[_diskByteOffset] >> (Disk.FluxBitsPerEntry - _diskBitsLeft);
} }
} }

View File

@ -10,11 +10,16 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
{ {
public sealed class SerialPort : IDriveLight public sealed class SerialPort : IDriveLight
{ {
[SaveState.DoNotSave]
public Func<bool> ReadMasterAtn = () => true; public Func<bool> ReadMasterAtn = () => true;
[SaveState.DoNotSave]
public Func<bool> ReadMasterClk = () => true; public Func<bool> ReadMasterClk = () => true;
[SaveState.DoNotSave]
public Func<bool> ReadMasterData = () => true; public Func<bool> ReadMasterData = () => true;
[SaveState.SaveWithName("Device")]
private SerialPortDevice _device; private SerialPortDevice _device;
[SaveState.SaveWithName("Connected")]
private bool _connected; private bool _connected;
public void HardReset() public void HardReset()
@ -75,7 +80,9 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
_device.ReadMasterData = () => ReadMasterData(); _device.ReadMasterData = () => ReadMasterData();
} }
[SaveState.DoNotSave]
public bool DriveLightEnabled { get { return true; } } public bool DriveLightEnabled { get { return true; } }
[SaveState.DoNotSave]
public bool DriveLightOn { get { return ReadDeviceLight(); } } public bool DriveLightOn { get { return ReadDeviceLight(); } }
} }
} }

View File

@ -1,47 +1,50 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using BizHawk.Common; using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial namespace BizHawk.Emulation.Cores.Computers.Commodore64.Serial
{ {
public abstract class SerialPortDevice public abstract class SerialPortDevice
{ {
public Func<bool> ReadMasterAtn; [SaveState.DoNotSave]
public Func<bool> ReadMasterClk; public Func<bool> ReadMasterAtn;
public Func<bool> ReadMasterData; [SaveState.DoNotSave]
public Func<bool> ReadMasterClk;
public virtual void ExecutePhase() [SaveState.DoNotSave]
{ public Func<bool> ReadMasterData;
}
public virtual void ExecutePhase()
public virtual void ExecuteDeferred(int cycles) {
{ }
}
public virtual void ExecuteDeferred(int cycles)
public virtual void HardReset() {
{ }
}
public virtual void HardReset()
public virtual bool ReadDeviceClk() {
{ }
return true;
} public virtual bool ReadDeviceClk()
{
public virtual bool ReadDeviceData() return true;
{ }
return true;
} public virtual bool ReadDeviceData()
{
public virtual bool ReadDeviceLight() return true;
{ }
return false;
} public virtual bool ReadDeviceLight()
{
public virtual void SyncState(Serializer ser) return false;
{ }
SaveState.SyncObject(ser, this);
} public virtual void SyncState(Serializer ser)
} {
} SaveState.SyncObject(ser, this);
}
}
}