diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 22418902bb..ccdf468532 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -119,11 +119,12 @@ + AppleII.cs - AppleII.cs + AppleII.cs AppleII.cs diff --git a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IEmulator.cs b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IEmulator.cs index 2b1726e992..bf871b57ab 100644 --- a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IEmulator.cs @@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII [FeatureNotImplemented] public ISyncSoundProvider SyncSoundProvider { - get { return _soundService; } + get { return this; } } [FeatureNotImplemented] diff --git a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IStatable.cs b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IStatable.cs index 7a42219d89..f6fefbc326 100644 --- a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IStatable.cs +++ b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IStatable.cs @@ -1,5 +1,8 @@ using BizHawk.Emulation.Common; using System.IO; +using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace BizHawk.Emulation.Cores.Computers.AppleII { @@ -7,39 +10,84 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII { public bool BinarySaveStatesPreferred { get { return true; } } + private class OtherData + { + public int Frame; + public int LagCount; + public bool IsLagFrame; + public int CurrentDisk; + public JObject Core; + } + private JsonSerializer ser = new JsonSerializer(); + [FeatureNotImplemented] public void SaveStateText(TextWriter writer) { + var w = new JTokenWriter(); + _machine.Serialize(w); + var o = new OtherData + { + Frame = Frame, + LagCount = LagCount, + IsLagFrame = IsLagFrame, + CurrentDisk = CurrentDisk, + Core = (JObject)w.Token, + }; + + var jw = new JsonTextWriter(writer) { Formatting = Newtonsoft.Json.Formatting.Indented }; + ser.Serialize(jw, o); } - [FeatureNotImplemented] public void LoadStateText(TextReader reader) { + var o = (OtherData)ser.Deserialize(reader, typeof(OtherData)); + Frame = o.Frame; + LagCount = o.LagCount; + IsLagFrame = o.IsLagFrame; + CurrentDisk = o.CurrentDisk; + var r = new JTokenReader(o.Core); + try + { + _machine = Jellyfish.Virtu.Machine.Deserialize(r); + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + throw; + } + // should not be needed. + // InitDisk(); } public void SaveStateBinary(BinaryWriter writer) { + /* writer.Write(Frame); writer.Write(LagCount); writer.Write(IsLagFrame); writer.Write(CurrentDisk); _machine.SaveState(writer); + */ } public void LoadStateBinary(BinaryReader reader) { + /* Frame = reader.ReadInt32(); LagCount = reader.ReadInt32(); IsLagFrame = reader.ReadBoolean(); CurrentDisk = reader.ReadInt32(); InitDisk(); _machine.LoadState(reader); + */ } public byte[] SaveStateBinary() { + return new byte[16]; + if (_stateBuffer == null) { var stream = new MemoryStream(); diff --git a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IVideoProvider.cs b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IVideoProvider.cs index ea2041f74e..3de60f4e10 100644 --- a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IVideoProvider.cs +++ b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IVideoProvider.cs @@ -3,45 +3,23 @@ using Jellyfish.Virtu; namespace BizHawk.Emulation.Cores.Computers.AppleII { - public partial class AppleII + public partial class AppleII : IVideoProvider { - public class BizVideoService : Jellyfish.Virtu.Services.VideoService, IVideoProvider - { - public int[] fb; + private Jellyfish.Virtu.Services.VideoService _V + { get { return _machine.Video.VideoService; } } - int[] IVideoProvider.GetVideoBuffer() { return fb; } + int[] IVideoProvider.GetVideoBuffer() { return _V.fb; } - // put together, these describe a metric on the screen - // they should define the smallest size that the buffer can be placed inside such that: - // 1. no actual pixel data is lost - // 2. aspect ratio is accurate - int IVideoProvider.VirtualWidth { get { return 560; } } - int IVideoProvider.VirtualHeight { get { return 384; } } + // put together, these describe a metric on the screen + // they should define the smallest size that the buffer can be placed inside such that: + // 1. no actual pixel data is lost + // 2. aspect ratio is accurate + int IVideoProvider.VirtualWidth { get { return 560; } } + int IVideoProvider.VirtualHeight { get { return 384; } } - int IVideoProvider.BufferWidth { get { return 560; } } - int IVideoProvider.BufferHeight { get { return 384; } } - int IVideoProvider.BackgroundColor { get { return 0; } } + int IVideoProvider.BufferWidth { get { return 560; } } + int IVideoProvider.BufferHeight { get { return 384; } } + int IVideoProvider.BackgroundColor { get { return 0; } } - public BizVideoService(Machine machine) : - base(machine) - { - fb = new int[560 * 384]; - } - - public override void SetFullScreen(bool isFullScreen) - { - - } - - public override void SetPixel(int x, int y, uint color) - { - int i = 560 * y + x; - fb[i] = fb[i + 560] = (int)color; - } - public override void Update() - { - - } - } } } diff --git a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs index f4805d4713..cd28019296 100644 --- a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs +++ b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs @@ -14,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII isPorted: true, isReleased: false )] - public partial class AppleII : IEmulator, IStatable + public partial class AppleII : IEmulator { public AppleII(CoreComm comm, IEnumerable gameInfoSet, IEnumerable romSet, object settings) : this(comm, gameInfoSet.First(), romSet.First(), settings) @@ -42,27 +42,11 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII _machine = new Machine(_appleIIRom, _diskIIRom); - var vidService = new BizVideoService(_machine); - _soundService = new BizAudioService(_machine); - var gpService = new Jellyfish.Virtu.Services.GamePortService(_machine); - var kbService = new BizKeyboardService(_machine); - - _machine.Services.AddService(typeof(Jellyfish.Virtu.Services.DebugService), new Jellyfish.Virtu.Services.DebugService(_machine)); - _machine.Services.AddService(typeof(Jellyfish.Virtu.Services.AudioService), _soundService); - _machine.Services.AddService(typeof(Jellyfish.Virtu.Services.VideoService), vidService); - _machine.Services.AddService(typeof(Jellyfish.Virtu.Services.GamePortService), gpService); - _machine.Services.AddService(typeof(Jellyfish.Virtu.Services.KeyboardService), kbService); _machine.BizInitialize(); - (ServiceProvider as BasicServiceProvider).Register(vidService); - //make a writeable memory stream cloned from the rom. //for junk.dsk the .dsk is important because it determines the format from that - var ms = new MemoryStream(); - ms.Write(_disk1, 0, _disk1.Length); - ms.Position = 0; - bool writeProtected = false; //!!!!!!!!!!!!!!!!!!! - Jellyfish.Virtu.Services.StorageService.LoadFile(ms, stream => _machine.BootDiskII.Drives[0].InsertDisk("junk.dsk", stream, writeProtected)); + InitDisk(); SetupMemoryDomains(); } @@ -108,56 +92,31 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII //make a writeable memory stream cloned from the rom. //for junk.dsk the .dsk is important because it determines the format from that - var ms = new MemoryStream(); - ms.Write(_disk1, 0, _disk1.Length); - ms.Position = 0; - bool writeProtected = false; //!!!!!!!!!!!!!!!!!!! - Jellyfish.Virtu.Services.StorageService.LoadFile(ms, stream => _machine.BootDiskII.Drives[0].InsertDisk("junk.dsk", stream, writeProtected)); - _machine.BizNewDisk(); + + bool writeProtected = false; //!!!!!!!!!!!!!!!!!! + _machine.BootDiskII.Drives[0].InsertDisk("junk.dsk", (byte[])_disk1.Clone(), false); } - private readonly Machine _machine; + private Machine _machine; private byte[] _disk1; private readonly byte[] _appleIIRom; private readonly byte[] _diskIIRom; - private readonly BizAudioService _soundService; - private static readonly ControllerDefinition AppleIIController = - new ControllerDefinition - { - Name = "Apple II Keyboard", - BoolButtons = - { - "Up", "Down", "Left", "Right", - "Tab", "Enter", "Escape", "Back", "Space", - "Ctrl", "Shift", "Caps", - "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", - "A", "B", "C", "D", "E", "F", "G", "H", "I", - "J", "K", "L", "M", "N", "O", "P", "Q", "R", - "S", "T", "U", "V", "W", "X", "Y", "Z", - "Next Disk", "Previous Disk" - } - }; + private static readonly ControllerDefinition AppleIIController; - private class BizKeyboardService : KeyboardService + private static readonly List RealButtons = new List(Keyboard.GetKeyNames()); + + private static readonly List ExtraButtons = new List { - public BizKeyboardService(Machine _machine) : base(_machine) { } - public override bool IsKeyDown(int key) - { - return key > 0; - } - } + "Previous Disk", + "Next Disk", + }; - private class BizAudioService : AudioService, ISyncSoundProvider + static AppleII() { - public BizAudioService(Machine _machine) : base(_machine) { } - public override void SetVolume(float volume) - { - } - public void DiscardSamples() - { - Reset(); - } + AppleIIController = new ControllerDefinition { Name = "Apple IIe Keyboard" }; + AppleIIController.BoolButtons.AddRange(RealButtons); + AppleIIController.BoolButtons.AddRange(ExtraButtons); } private void FrameAdv(bool render, bool rendersound) @@ -170,9 +129,8 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII { DecrementDisk(); } - - _machine.Buttons = GetButtons(); - _machine.BizFrameAdvance(); + + _machine.BizFrameAdvance(RealButtons.Where(b => Controller[b])); if (IsLagFrame) { LagCount++; @@ -181,59 +139,5 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII Frame++; } - private Buttons GetButtons() - { - Jellyfish.Virtu.Buttons ret = 0; - if (Controller["Up"]) ret |= Jellyfish.Virtu.Buttons.Up; - if (Controller["Down"]) ret |= Jellyfish.Virtu.Buttons.Down; - if (Controller["Left"]) ret |= Jellyfish.Virtu.Buttons.Left; - if (Controller["Right"]) ret |= Jellyfish.Virtu.Buttons.Right; - if (Controller["Tab"]) ret |= Jellyfish.Virtu.Buttons.Tab; - if (Controller["Enter"]) ret |= Jellyfish.Virtu.Buttons.Enter; - if (Controller["Escape"]) ret |= Jellyfish.Virtu.Buttons.Escape; - if (Controller["Back"]) ret |= Jellyfish.Virtu.Buttons.Back; - if (Controller["Space"]) ret |= Jellyfish.Virtu.Buttons.Space; - if (Controller["Ctrl"]) ret |= Jellyfish.Virtu.Buttons.Ctrl; - if (Controller["Shift"]) ret |= Jellyfish.Virtu.Buttons.Shift; - if (Controller["Caps"]) ret |= Jellyfish.Virtu.Buttons.Caps; - if (Controller["1"]) ret |= Jellyfish.Virtu.Buttons.Key1; - if (Controller["2"]) ret |= Jellyfish.Virtu.Buttons.Key2; - if (Controller["3"]) ret |= Jellyfish.Virtu.Buttons.Key3; - if (Controller["4"]) ret |= Jellyfish.Virtu.Buttons.Key4; - if (Controller["5"]) ret |= Jellyfish.Virtu.Buttons.Key5; - if (Controller["6"]) ret |= Jellyfish.Virtu.Buttons.Key6; - if (Controller["7"]) ret |= Jellyfish.Virtu.Buttons.Key7; - if (Controller["8"]) ret |= Jellyfish.Virtu.Buttons.Key8; - if (Controller["9"]) ret |= Jellyfish.Virtu.Buttons.Key9; - if (Controller["0"]) ret |= Jellyfish.Virtu.Buttons.Key0; - if (Controller["A"]) ret |= Jellyfish.Virtu.Buttons.KeyA; - if (Controller["B"]) ret |= Jellyfish.Virtu.Buttons.KeyB; - if (Controller["C"]) ret |= Jellyfish.Virtu.Buttons.KeyC; - if (Controller["D"]) ret |= Jellyfish.Virtu.Buttons.KeyD; - if (Controller["E"]) ret |= Jellyfish.Virtu.Buttons.KeyE; - if (Controller["F"]) ret |= Jellyfish.Virtu.Buttons.KeyF; - if (Controller["G"]) ret |= Jellyfish.Virtu.Buttons.KeyG; - if (Controller["H"]) ret |= Jellyfish.Virtu.Buttons.KeyH; - if (Controller["I"]) ret |= Jellyfish.Virtu.Buttons.KeyI; - if (Controller["J"]) ret |= Jellyfish.Virtu.Buttons.KeyJ; - if (Controller["K"]) ret |= Jellyfish.Virtu.Buttons.KeyK; - if (Controller["L"]) ret |= Jellyfish.Virtu.Buttons.KeyL; - if (Controller["M"]) ret |= Jellyfish.Virtu.Buttons.KeyM; - if (Controller["N"]) ret |= Jellyfish.Virtu.Buttons.KeyN; - if (Controller["O"]) ret |= Jellyfish.Virtu.Buttons.KeyO; - if (Controller["P"]) ret |= Jellyfish.Virtu.Buttons.KeyP; - if (Controller["Q"]) ret |= Jellyfish.Virtu.Buttons.KeyQ; - if (Controller["R"]) ret |= Jellyfish.Virtu.Buttons.KeyR; - if (Controller["S"]) ret |= Jellyfish.Virtu.Buttons.KeyS; - if (Controller["T"]) ret |= Jellyfish.Virtu.Buttons.KeyT; - if (Controller["U"]) ret |= Jellyfish.Virtu.Buttons.KeyU; - if (Controller["V"]) ret |= Jellyfish.Virtu.Buttons.KeyV; - if (Controller["W"]) ret |= Jellyfish.Virtu.Buttons.KeyW; - if (Controller["X"]) ret |= Jellyfish.Virtu.Buttons.KeyX; - if (Controller["Y"]) ret |= Jellyfish.Virtu.Buttons.KeyY; - if (Controller["Z"]) ret |= Jellyfish.Virtu.Buttons.KeyZ; - - return ret; - } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/VRC7.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/VRC7.cs index 2c84cf4106..0012ee430c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/VRC7.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/VRC7.cs @@ -130,7 +130,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } prg_bank_mask_8k = Cart.prg_size / 8 - 1; - chr_bank_mask_1k = Cart.chr_size - 1; + chr_bank_mask_1k = 0xff; // Cart.chr_size - 1; SetMirrorType(EMirrorType.Vertical); diff --git a/ExternalCoreProjects/Virtu/Cassette.cs b/ExternalCoreProjects/Virtu/Cassette.cs index 93abdb9d2f..0cde6083b2 100644 --- a/ExternalCoreProjects/Virtu/Cassette.cs +++ b/ExternalCoreProjects/Virtu/Cassette.cs @@ -4,18 +4,17 @@ namespace Jellyfish.Virtu { public sealed class Cassette : MachineComponent { + public Cassette() { } public Cassette(Machine machine) : base(machine) { } - [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")] public bool ReadInput() { return false; } - [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")] public void ToggleOutput() { } diff --git a/ExternalCoreProjects/Virtu/Cpu.cs b/ExternalCoreProjects/Virtu/Cpu.cs index 816908ae25..c05f799f32 100644 --- a/ExternalCoreProjects/Virtu/Cpu.cs +++ b/ExternalCoreProjects/Virtu/Cpu.cs @@ -7,6 +7,7 @@ namespace Jellyfish.Virtu { public sealed partial class Cpu : MachineComponent { + public Cpu() { } public Cpu(Machine machine) : base(machine) { @@ -169,44 +170,6 @@ namespace Jellyfish.Virtu } } - public override void LoadState(BinaryReader reader, Version version) - { - if (reader == null) - { - throw new ArgumentNullException("reader"); - } - - Is65C02 = reader.ReadBoolean(); - IsThrottled = reader.ReadBoolean(); - Multiplier = reader.ReadInt32(); - - RA = reader.ReadInt32(); - RX = reader.ReadInt32(); - RY = reader.ReadInt32(); - RS = reader.ReadInt32(); - RP = reader.ReadInt32(); - RPC = reader.ReadInt32(); - } - - public override void SaveState(BinaryWriter writer) - { - if (writer == null) - { - throw new ArgumentNullException("writer"); - } - - writer.Write(Is65C02); - writer.Write(IsThrottled); - writer.Write(Multiplier); - - writer.Write(RA); - writer.Write(RX); - writer.Write(RY); - writer.Write(RS); - writer.Write(RP); - writer.Write(RPC); - } - public override string ToString() { return string.Format(CultureInfo.InvariantCulture, "A = 0x{0:X2} X = 0x{1:X2} Y = 0x{2:X2} P = 0x{3:X2} S = 0x01{4:X2} PC = 0x{5:X4} EA = 0x{6:X4} CC = {7}", @@ -214,14 +177,15 @@ namespace Jellyfish.Virtu } public int Execute() - { - CC = 0; + { + CC = 0; OpCode = _memory.Read(RPC); RPC = (RPC + 1) & 0xFFFF; _executeOpCode[OpCode](); Cycles += CC; - return CC; + + return CC; } #region Core Operand Actions @@ -3238,6 +3202,7 @@ namespace Jellyfish.Virtu } #endregion + [Newtonsoft.Json.JsonIgnore] public bool Is65C02 { get { return _is65C02; } set { _is65C02 = value; _executeOpCode = _is65C02 ? ExecuteOpCode65C02 : ExecuteOpCode65N02; } } public bool IsThrottled { get; set; } public int Multiplier { get; set; } diff --git a/ExternalCoreProjects/Virtu/CpuData.cs b/ExternalCoreProjects/Virtu/CpuData.cs index b0baaefc1d..e21859092c 100644 --- a/ExternalCoreProjects/Virtu/CpuData.cs +++ b/ExternalCoreProjects/Virtu/CpuData.cs @@ -6,8 +6,8 @@ namespace Jellyfish.Virtu { private const int OpCodeCount = 256; - private readonly Action[] ExecuteOpCode65N02; - private readonly Action[] ExecuteOpCode65C02; + private Action[] ExecuteOpCode65N02; + private Action[] ExecuteOpCode65C02; private const int PC = 0x01; private const int PZ = 0x02; diff --git a/ExternalCoreProjects/Virtu/Disk525.cs b/ExternalCoreProjects/Virtu/Disk525.cs index 888a536813..0dccaf1c2a 100644 --- a/ExternalCoreProjects/Virtu/Disk525.cs +++ b/ExternalCoreProjects/Virtu/Disk525.cs @@ -8,6 +8,7 @@ namespace Jellyfish.Virtu { public abstract class Disk525 { + public Disk525() { } protected Disk525(string name, byte[] data, bool isWriteProtected) { Name = name; @@ -15,43 +16,13 @@ namespace Jellyfish.Virtu IsWriteProtected = isWriteProtected; } - public static Disk525 CreateDisk(string name, Stream stream, bool isWriteProtected) + public static Disk525 CreateDisk(string name, byte[] data, bool isWriteProtected) { if (name == null) { throw new ArgumentNullException("name"); } - if (name.EndsWith(".do", StringComparison.OrdinalIgnoreCase) || - name.EndsWith(".dsk", StringComparison.OrdinalIgnoreCase)) // assumes dos sector skew - { - return new DiskDsk(name, stream, isWriteProtected, SectorSkew.Dos); - } - else if (name.EndsWith(".nib", StringComparison.OrdinalIgnoreCase)) - { - return new DiskNib(name, stream, isWriteProtected); - } - else if (name.EndsWith(".po", StringComparison.OrdinalIgnoreCase)) - { - return new DiskDsk(name, stream, isWriteProtected, SectorSkew.ProDos); - } - - return null; - } - - [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "version")] - public static Disk525 LoadState(BinaryReader reader, Version version) - { - if (reader == null) - { - throw new ArgumentNullException("reader"); - } - - string name = reader.ReadString(); - var dataSize = reader.ReadInt32(); - var data = reader.ReadBytes(dataSize); - bool isWriteProtected = reader.ReadBoolean(); - if (name.EndsWith(".do", StringComparison.OrdinalIgnoreCase) || name.EndsWith(".dsk", StringComparison.OrdinalIgnoreCase)) // assumes dos sector skew { @@ -69,19 +40,6 @@ namespace Jellyfish.Virtu return null; } - public void SaveState(BinaryWriter writer) - { - if (writer == null) - { - throw new ArgumentNullException("writer"); - } - - writer.Write(Name); - writer.Write(Data.Length); - writer.Write(Data); - writer.Write(IsWriteProtected); - } - public abstract void ReadTrack(int number, int fraction, byte[] buffer); public abstract void WriteTrack(int number, int fraction, byte[] buffer); diff --git a/ExternalCoreProjects/Virtu/DiskDsk.cs b/ExternalCoreProjects/Virtu/DiskDsk.cs index 90cc81add1..11c3a598f6 100644 --- a/ExternalCoreProjects/Virtu/DiskDsk.cs +++ b/ExternalCoreProjects/Virtu/DiskDsk.cs @@ -8,6 +8,7 @@ namespace Jellyfish.Virtu public sealed class DiskDsk : Disk525 { + public DiskDsk() { } public DiskDsk(string name, byte[] data, bool isWriteProtected, SectorSkew sectorSkew) : base(name, data, isWriteProtected) { diff --git a/ExternalCoreProjects/Virtu/DiskIIController.cs b/ExternalCoreProjects/Virtu/DiskIIController.cs index 99d579ed8c..a969f4bfc9 100644 --- a/ExternalCoreProjects/Virtu/DiskIIController.cs +++ b/ExternalCoreProjects/Virtu/DiskIIController.cs @@ -4,11 +4,13 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using Jellyfish.Library; using Jellyfish.Virtu.Services; +using System.Collections.Generic; namespace Jellyfish.Virtu { public sealed class DiskIIController : PeripheralCard { + public DiskIIController() { } public DiskIIController(Machine machine, byte[] diskIIRom) : base(machine) { @@ -16,7 +18,7 @@ namespace Jellyfish.Virtu Drive1 = new DiskIIDrive(machine); Drive2 = new DiskIIDrive(machine); - Drives = new Collection { Drive1, Drive2 }; + Drives = new List { Drive1, Drive2 }; BootDrive = Drive1; } @@ -32,50 +34,6 @@ namespace Jellyfish.Virtu _writeMode = false; } - public override void LoadState(BinaryReader reader, Version version) - { - if (reader == null) - { - throw new ArgumentNullException("reader"); - } - - _latch = reader.ReadInt32(); - _phaseStates = reader.ReadInt32(); - _motorOn = reader.ReadBoolean(); - _driveNumber = reader.ReadInt32(); - _loadMode = reader.ReadBoolean(); - _writeMode = reader.ReadBoolean(); - _driveSpin = reader.ReadBoolean(); - foreach (var drive in Drives) - { - DebugService.WriteMessage("Loading machine '{0}'", drive.GetType().Name); - drive.LoadState(reader, version); - //DebugService.WriteMessage("Loaded machine '{0}'", drive.GetType().Name); - } - } - - public override void SaveState(BinaryWriter writer) - { - if (writer == null) - { - throw new ArgumentNullException("writer"); - } - - writer.Write(_latch); - writer.Write(_phaseStates); - writer.Write(_motorOn); - writer.Write(_driveNumber); - writer.Write(_loadMode); - writer.Write(_writeMode); - writer.Write(_driveSpin); - foreach (var drive in Drives) - { - DebugService.WriteMessage("Saving machine '{0}'", drive.GetType().Name); - drive.SaveState(writer); - //DebugService.WriteMessage("Saved machine '{0}'", drive.GetType().Name); - } - } - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] public override int ReadIoRegionC0C0(int address) { @@ -263,7 +221,7 @@ namespace Jellyfish.Virtu public DiskIIDrive Drive1 { get; private set; } public DiskIIDrive Drive2 { get; private set; } - public Collection Drives { get; private set; } + public List Drives { get; private set; } public DiskIIDrive BootDrive { get; private set; } diff --git a/ExternalCoreProjects/Virtu/DiskIIDrive.cs b/ExternalCoreProjects/Virtu/DiskIIDrive.cs index c59c2cf096..8dbb6e75b2 100644 --- a/ExternalCoreProjects/Virtu/DiskIIDrive.cs +++ b/ExternalCoreProjects/Virtu/DiskIIDrive.cs @@ -7,6 +7,7 @@ namespace Jellyfish.Virtu { public sealed class DiskIIDrive : MachineComponent { + public DiskIIDrive() { } public DiskIIDrive(Machine machine) : base(machine) { @@ -16,60 +17,11 @@ namespace Jellyfish.Virtu DriveArmStepDelta[3] = new int[] { 0, 1, 0, 1, -1, 0, -1, 0, 0, 1, 0, 1, -1, 0, -1, 0 }; // phase 3 } - public override void LoadState(BinaryReader reader, Version version) - { - if (reader == null) - { - throw new ArgumentNullException("reader"); - } - - _trackLoaded = reader.ReadBoolean(); - _trackChanged = reader.ReadBoolean(); - _trackNumber = reader.ReadInt32(); - _trackOffset = reader.ReadInt32(); - if (_trackLoaded) - { - reader.Read(_trackData, 0, _trackData.Length); - } - if (reader.ReadBoolean()) - { - DebugService.WriteMessage("Loading machine '{0}'", typeof(Disk525).Name); - _disk = Disk525.LoadState(reader, version); - } - else - { - _disk = null; - } - } - - public override void SaveState(BinaryWriter writer) - { - if (writer == null) - { - throw new ArgumentNullException("writer"); - } - - writer.Write(_trackLoaded); - writer.Write(_trackChanged); - writer.Write(_trackNumber); - writer.Write(_trackOffset); - if (_trackLoaded) - { - writer.Write(_trackData); - } - writer.Write(_disk != null); - if (_disk != null) - { - DebugService.WriteMessage("Saving machine '{0}'", _disk.GetType().Name); - _disk.SaveState(writer); - } - } - - public void InsertDisk(string name, Stream stream, bool isWriteProtected) + public void InsertDisk(string name, byte[] data, bool isWriteProtected) { DebugService.WriteMessage("Inserting disk '{0}'", name); FlushTrack(); - _disk = Disk525.CreateDisk(name, stream, isWriteProtected); + _disk = Disk525.CreateDisk(name, data, isWriteProtected); _trackLoaded = false; } @@ -116,7 +68,9 @@ namespace Jellyfish.Virtu return data; } - return _random.Next(0x01, 0xFF); + return 0x80; + // TODO: WTF was this + //return _random.Next(0x01, 0xFF); } public void Write(int data) @@ -152,13 +106,14 @@ namespace Jellyfish.Virtu } } + [Newtonsoft.Json.JsonIgnore] public bool IsWriteProtected { get { return _disk.IsWriteProtected; } } private const int TrackNumberMax = 0x44; private const int PhaseCount = 4; - private readonly int[][] DriveArmStepDelta = new int[PhaseCount][]; + private int[][] DriveArmStepDelta = new int[PhaseCount][]; private bool _trackLoaded; private bool _trackChanged; @@ -166,7 +121,5 @@ namespace Jellyfish.Virtu private int _trackOffset; private byte[] _trackData = new byte[Disk525.TrackSize]; private Disk525 _disk; - - private Random _random = new Random(); } } diff --git a/ExternalCoreProjects/Virtu/DiskNib.cs b/ExternalCoreProjects/Virtu/DiskNib.cs index e186e007c2..e3c0db90c1 100644 --- a/ExternalCoreProjects/Virtu/DiskNib.cs +++ b/ExternalCoreProjects/Virtu/DiskNib.cs @@ -6,6 +6,7 @@ namespace Jellyfish.Virtu { public sealed class DiskNib : Disk525 { + public DiskNib() { } public DiskNib(string name, byte[] data, bool isWriteProtected) : base(name, data, isWriteProtected) { diff --git a/ExternalCoreProjects/Virtu/ExtraConverters.cs b/ExternalCoreProjects/Virtu/ExtraConverters.cs new file mode 100644 index 0000000000..2e66bfc438 --- /dev/null +++ b/ExternalCoreProjects/Virtu/ExtraConverters.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json.Linq; +using System.Reflection; + +namespace Jellyfish.Virtu +{ + public class ArrayConverter : JsonConverter + { + // JSON.NET cannot, when reading, use PreserveReferencesHandling on arrays, although it fully supports it on writing. + // stupid decision, but there you have it. we need that to work here. + + // as an added "bonus", this disables base64ing of byte[] arrays. + // TODO: optimize the byte/short/int cases. + + // TODO: on serialization, the type of the object is available, but is the expected type (ie, the one that we'll be fed during deserialization) available? + // need this to at least detect covariance cases... + + public override bool CanConvert(Type objectType) + { + if (!typeof(Array).IsAssignableFrom(objectType)) + return false; + + if (objectType.GetArrayRank() > 1) + throw new NotImplementedException(); + + return true; + } + + public override bool CanRead { get { return true; } } + public override bool CanWrite { get { return true; } } + + int nextRef = 1; + Dictionary refs = new Dictionary(); + Dictionary readrefs = new Dictionary(); + + private static void ReadExpectType(JsonReader reader, JsonToken expected) + { + if (!reader.Read()) + throw new InvalidOperationException(); + if (reader.TokenType != expected) + throw new InvalidOperationException(); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) + return null; + if (reader.TokenType != JsonToken.StartObject) + throw new InvalidOperationException(); + + ReadExpectType(reader, JsonToken.PropertyName); + if (reader.Value.ToString() != "$myRef") + throw new InvalidOperationException(); + ReadExpectType(reader, JsonToken.Integer); + int myRef = Convert.ToInt32(reader.Value); + + if (!reader.Read()) + throw new InvalidOperationException(); + if (reader.TokenType == JsonToken.EndObject) + return readrefs[myRef]; + else if (reader.TokenType != JsonToken.PropertyName || reader.Value.ToString() != "$myCount") + throw new InvalidOperationException(); + ReadExpectType(reader, JsonToken.Integer); + int myCount = Convert.ToInt32(reader.Value); + + ReadExpectType(reader, JsonToken.PropertyName); + if (reader.Value.ToString() != "$myVals") + throw new InvalidOperationException(); + ReadExpectType(reader, JsonToken.StartArray); + var elementType = objectType.GetElementType(); + Array ret = Array.CreateInstance(elementType, myCount); + for (int i = 0; i < myCount; i++) + { + if (!reader.Read()) + throw new InvalidOperationException(); + ret.SetValue(serializer.Deserialize(reader, elementType), i); + } + ReadExpectType(reader, JsonToken.EndArray); + + ReadExpectType(reader, JsonToken.EndObject); + readrefs[myRef] = ret; + return ret; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + int myRef; + if (refs.TryGetValue(value, out myRef)) + { + writer.WriteStartObject(); + writer.WritePropertyName("$myRef"); + writer.WriteValue(myRef); + writer.WriteEndObject(); + } + else + { + myRef = nextRef++; + refs.Add(value, myRef); + writer.WriteStartObject(); + writer.WritePropertyName("$myRef"); + writer.WriteValue(myRef); + writer.WritePropertyName("$myCount"); // not needed, but avoids us having to make some sort of temp structure on deserialization + writer.WriteValue(((Array)value).Length); + writer.WritePropertyName("$myVals"); + writer.WriteStartArray(); + var elementType = value.GetType().GetElementType(); + foreach (object o in (Array)value) + { + serializer.Serialize(writer, o, elementType); + } + writer.WriteEndArray(); + writer.WriteEndObject(); + } + } + } + + public class DelegateConverter : JsonConverter + { + // caveats: if used on anonymous delegates and/or closures, brittle to name changes in the generated classes and methods + // brittle to type name changes in general + // must be serialized in tree with any real classes referred to by closures + + // TODO: much of this could be made somewhat smarter and more resilient + + public override bool CanConvert(Type objectType) + { + return typeof(Delegate).IsAssignableFrom(objectType); + } + + public override bool CanRead { get { return true; } } + public override bool CanWrite { get { return true; } } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var slug = serializer.Deserialize(reader); + if (slug == null) + return null; + return slug.GetDelegate(); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var slug = new Slug((Delegate)value); + serializer.Serialize(writer, slug); + } + + private class Slug + { + public Type DelegateType; + public Type MethodDeclaringType; + public string MethodName; + public List MethodParameters; + public object Target; + + public Delegate GetDelegate() + { + var mi = MethodDeclaringType.GetMethod( + MethodName, + BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static, + null, + MethodParameters.ToArray(), + null); + + return Delegate.CreateDelegate(DelegateType, Target, mi); + } + + public Slug() { } + + public Slug(Delegate d) + { + DelegateType = d.GetType(); + MethodDeclaringType = d.Method.DeclaringType; + MethodName = d.Method.Name; + MethodParameters = d.Method.GetParameters().Select(p => p.ParameterType).ToList(); + Target = d.Target; + } + } + } +} diff --git a/ExternalCoreProjects/Virtu/GamePort.cs b/ExternalCoreProjects/Virtu/GamePort.cs index 1c5320e761..a562f35da7 100644 --- a/ExternalCoreProjects/Virtu/GamePort.cs +++ b/ExternalCoreProjects/Virtu/GamePort.cs @@ -8,15 +8,31 @@ namespace Jellyfish.Virtu { public sealed class GamePort : MachineComponent { + // TODO: ressurect this + public bool ReadButton0() { return false; } + public bool ReadButton1() { return false; } + public bool ReadButton2() { return false; } + + public bool Paddle0Strobe { get { return false; } } + public bool Paddle1Strobe { get { return false; } } + public bool Paddle2Strobe { get { return false; } } + public bool Paddle3Strobe { get { return false; } } + + public void TriggerTimers() { } + + public GamePort() { } public GamePort(Machine machine) : base(machine) { + /* _resetPaddle0StrobeEvent = ResetPaddle0StrobeEvent; // cache delegates; avoids garbage _resetPaddle1StrobeEvent = ResetPaddle1StrobeEvent; _resetPaddle2StrobeEvent = ResetPaddle2StrobeEvent; _resetPaddle3StrobeEvent = ResetPaddle3StrobeEvent; + */ } + /* public override void Initialize() { _keyboardService = Machine.Services.GetService(); @@ -46,137 +62,7 @@ namespace Jellyfish.Virtu Button2TouchHeight = 0.25f; Button2TouchOrder = 1; } - - public override void LoadState(BinaryReader reader, Version version) - { - if (reader == null) - { - throw new ArgumentNullException("reader"); - } - - InvertPaddles = reader.ReadBoolean(); - SwapPaddles = reader.ReadBoolean(); - UseShiftKeyMod = reader.ReadBoolean(); - JoystickDeadZone = reader.ReadSingle(); - - UseKeyboard = reader.ReadBoolean(); - Joystick0UpLeftKey = reader.ReadInt32(); - Joystick0UpKey = reader.ReadInt32(); - Joystick0UpRightKey = reader.ReadInt32(); - Joystick0LeftKey = reader.ReadInt32(); - Joystick0RightKey = reader.ReadInt32(); - Joystick0DownLeftKey = reader.ReadInt32(); - Joystick0DownKey = reader.ReadInt32(); - Joystick0DownRightKey = reader.ReadInt32(); - Joystick1UpLeftKey = reader.ReadInt32(); - Joystick1UpKey = reader.ReadInt32(); - Joystick1UpRightKey = reader.ReadInt32(); - Joystick1LeftKey = reader.ReadInt32(); - Joystick1RightKey = reader.ReadInt32(); - Joystick1DownLeftKey = reader.ReadInt32(); - Joystick1DownKey = reader.ReadInt32(); - Joystick1DownRightKey = reader.ReadInt32(); - Button0Key = reader.ReadInt32(); - Button1Key = reader.ReadInt32(); - Button2Key = reader.ReadInt32(); - - UseTouch = reader.ReadBoolean(); - Joystick0TouchX = reader.ReadSingle(); - Joystick0TouchY = reader.ReadSingle(); - Joystick0TouchWidth = reader.ReadSingle(); - Joystick0TouchHeight = reader.ReadSingle(); - Joystick0TouchOrder = reader.ReadInt32(); - Joystick0TouchRadius = reader.ReadSingle(); - Joystick0TouchKeepLast = reader.ReadBoolean(); - Joystick1TouchX = reader.ReadSingle(); - Joystick1TouchY = reader.ReadSingle(); - Joystick1TouchWidth = reader.ReadSingle(); - Joystick1TouchHeight = reader.ReadSingle(); - Joystick1TouchOrder = reader.ReadInt32(); - Joystick1TouchRadius = reader.ReadSingle(); - Joystick1TouchKeepLast = reader.ReadBoolean(); - Button0TouchX = reader.ReadSingle(); - Button0TouchY = reader.ReadSingle(); - Button0TouchWidth = reader.ReadSingle(); - Button0TouchHeight = reader.ReadSingle(); - Button0TouchOrder = reader.ReadInt32(); - Button1TouchX = reader.ReadSingle(); - Button1TouchY = reader.ReadSingle(); - Button1TouchWidth = reader.ReadSingle(); - Button1TouchHeight = reader.ReadSingle(); - Button1TouchOrder = reader.ReadInt32(); - Button2TouchX = reader.ReadSingle(); - Button2TouchY = reader.ReadSingle(); - Button2TouchWidth = reader.ReadSingle(); - Button2TouchHeight = reader.ReadSingle(); - Button2TouchOrder = reader.ReadInt32(); - } - - public override void SaveState(BinaryWriter writer) - { - if (writer == null) - { - throw new ArgumentNullException("writer"); - } - - writer.Write(InvertPaddles); - writer.Write(SwapPaddles); - writer.Write(UseShiftKeyMod); - writer.Write(JoystickDeadZone); - - writer.Write(UseKeyboard); - writer.Write(Joystick0UpLeftKey); - writer.Write(Joystick0UpKey); - writer.Write(Joystick0UpRightKey); - writer.Write(Joystick0LeftKey); - writer.Write(Joystick0RightKey); - writer.Write(Joystick0DownLeftKey); - writer.Write(Joystick0DownKey); - writer.Write(Joystick0DownRightKey); - writer.Write(Joystick1UpLeftKey); - writer.Write(Joystick1UpKey); - writer.Write(Joystick1UpRightKey); - writer.Write(Joystick1LeftKey); - writer.Write(Joystick1RightKey); - writer.Write(Joystick1DownLeftKey); - writer.Write(Joystick1DownKey); - writer.Write(Joystick1DownRightKey); - writer.Write(Button0Key); - writer.Write(Button1Key); - writer.Write(Button2Key); - - writer.Write(UseTouch); - writer.Write(Joystick0TouchX); - writer.Write(Joystick0TouchY); - writer.Write(Joystick0TouchWidth); - writer.Write(Joystick0TouchHeight); - writer.Write(Joystick0TouchOrder); - writer.Write(Joystick0TouchRadius); - writer.Write(Joystick0TouchKeepLast); - writer.Write(Joystick1TouchX); - writer.Write(Joystick1TouchY); - writer.Write(Joystick1TouchWidth); - writer.Write(Joystick1TouchHeight); - writer.Write(Joystick1TouchOrder); - writer.Write(Joystick1TouchRadius); - writer.Write(Joystick1TouchKeepLast); - writer.Write(Button0TouchX); - writer.Write(Button0TouchY); - writer.Write(Button0TouchWidth); - writer.Write(Button0TouchHeight); - writer.Write(Button0TouchOrder); - writer.Write(Button1TouchX); - writer.Write(Button1TouchY); - writer.Write(Button1TouchWidth); - writer.Write(Button1TouchHeight); - writer.Write(Button1TouchOrder); - writer.Write(Button2TouchX); - writer.Write(Button2TouchY); - writer.Write(Button2TouchWidth); - writer.Write(Button2TouchHeight); - writer.Write(Button2TouchOrder); - } - + public bool ReadButton0() { return (_gamePortService.IsButton0Down || _keyboardService.IsOpenAppleKeyDown || @@ -365,6 +251,6 @@ namespace Jellyfish.Virtu private Action _resetPaddle3StrobeEvent; private KeyboardService _keyboardService; - private GamePortService _gamePortService; + private GamePortService _gamePortService;*/ } } diff --git a/ExternalCoreProjects/Virtu/Keyboard.cs b/ExternalCoreProjects/Virtu/Keyboard.cs index dd54a83b53..dce867045d 100644 --- a/ExternalCoreProjects/Virtu/Keyboard.cs +++ b/ExternalCoreProjects/Virtu/Keyboard.cs @@ -1,122 +1,370 @@ using System; using System.IO; +using System.Collections.Generic; using Jellyfish.Virtu.Services; +using System.ComponentModel; +using System.Linq; namespace Jellyfish.Virtu { + [Flags] + internal enum Keys : ulong + { + // https://archive.org/stream/Apple_IIe_Technical_Reference_Manual + + // 56 basic keys as described in the reference manual + [Description("Delete")] + Delete = 1UL, + [Description("Left")] + Left = 2UL, + [Description("Tab")] + Tab = 4UL, + [Description("Down")] + Down = 8UL, + [Description("Up")] + Up = 16UL, + [Description("Return")] + Return = 32UL, + [Description("Right")] + Right = 64UL, + [Description("Escape")] + Escape = 128UL, + [Description("Space")] + Space = 256UL, + [Description("'")] + Apostrophe = 512UL, + [Description(",")] + Comma = 1024UL, + [Description("-")] + Dash = 2048UL, + [Description(".")] + Period = 4096UL, + [Description("/")] + Slash = 8192UL, + [Description("0")] + Key0 = 16384UL, + [Description("1")] + Key1 = 32768UL, + [Description("2")] + Key2 = 65536UL, + [Description("3")] + Key3 = 131072UL, + [Description("4")] + Key4 = 262144UL, + [Description("5")] + Key5 = 524288UL, + [Description("6")] + Key6 = 1048576UL, + [Description("7")] + Key7 = 2097152UL, + [Description("8")] + Key8 = 4194304UL, + [Description("9")] + Key9 = 8388608UL, + [Description(";")] + Semicolon = 16777216UL, + [Description("=")] + Equals = 33554432UL, + [Description("[")] + LeftBracket = 67108864UL, + [Description("\\")] + Backslash = 134217728UL, + [Description("]")] + RightBracket = 268435456UL, + [Description("`")] + Backtick = 536870912UL, + [Description("A")] + A = 1073741824UL, + [Description("B")] + B = 2147483648UL, + [Description("C")] + C = 4294967296UL, + [Description("D")] + D = 8589934592UL, + [Description("E")] + E = 17179869184UL, + [Description("F")] + F = 34359738368UL, + [Description("G")] + G = 68719476736UL, + [Description("H")] + H = 137438953472UL, + [Description("I")] + I = 274877906944UL, + [Description("J")] + J = 549755813888UL, + [Description("K")] + K = 1099511627776UL, + [Description("L")] + L = 2199023255552UL, + [Description("M")] + M = 4398046511104UL, + [Description("N")] + N = 8796093022208UL, + [Description("O")] + O = 17592186044416UL, + [Description("P")] + P = 35184372088832UL, + [Description("Q")] + Q = 70368744177664UL, + [Description("R")] + R = 140737488355328UL, + [Description("S")] + S = 281474976710656UL, + [Description("T")] + T = 562949953421312UL, + [Description("U")] + U = 1125899906842624UL, + [Description("V")] + V = 2251799813685248UL, + [Description("W")] + W = 4503599627370496UL, + [Description("X")] + X = 9007199254740992UL, + [Description("Y")] + Y = 18014398509481984UL, + [Description("Z")] + Z = 36028797018963968UL, + + // three modifier keys, cannot be read directly + [Description("Control")] + Control = 72057594037927936UL, + [Description("Shift")] + Shift = 144115188075855872UL, + [Description("Caps Lock")] + CapsLock = 288230376151711744UL, + + // three special keys + [Description("White Apple")] + WhiteApple = 576460752303423488UL, // connected to GAME1 + [Description("Black Apple")] + BlackApple = 1152921504606846976UL, // connected to GAME2 + [Description("Reset")] + Reset = 2305843009213693952UL, + } + + public sealed class Keyboard : MachineComponent { - public Keyboard(Machine machine) : + private static readonly uint[] KeyAsciiData = new uint[] + { + // https://archive.org/stream/Apple_IIe_Technical_Reference_Manual#page/n47/mode/2up + // 0xNNCCSSBB normal, control, shift both + // keys in same order as above + 0x7f7f7f7f, + 0x08080808, + 0x09090909, + 0x0a0a0a0a, + 0x0b0b0b0b, + 0x0d0d0d0d, + 0x15151515, + 0x1b1b1b1b, + 0x20202020, + 0x27272222, + 0x2c2c3c3c, + 0x2d1f5f1f, + 0x2e2e3e3e, + 0x2f2f3f3f, + 0x30302929, // 0 + 0x31312121, + 0x32004000, + 0x33332323, + 0x34342424, + 0x35352525, + 0x361e5e1e, + 0x37372626, + 0x38382a2a, + 0x39392828, // 9 + 0x3b3b3a3a, + 0x3d3d2b2b, + 0x5b1b7b1b, + 0x5c1c7c1c, + 0x5d1d7d1d, + 0x60607e7e, + + 0x61014101, // a + 0x62024202, + 0x63034303, + 0x64044404, + 0x65054505, + 0x66064606, + 0x67074707, + 0x68084808, + 0x69094909, + 0x6a0a4a0a, + 0x6b0b4b0b, + 0x6c0c4c0c, + 0x6d0d4d0d, + 0x6e0e4e0e, + 0x6f0f4f0f, + 0x70105010, + 0x71115111, + 0x72125212, + 0x73135313, + 0x74145414, + 0x75155515, + 0x76165616, + 0x77175717, + 0x78185818, + 0x79195919, + 0x7a1a5a1a, // z + }; + + /// + /// + /// + /// 0 - 55 + /// + /// + /// + private static int KeyToAscii(int key, bool control, bool shift) + { + int s = control ? (shift ? 0 : 16) : (shift ? 8 : 24); + return (int)(KeyAsciiData[key] >> s); + } + + private static Dictionary DescriptionsToKeys = new Dictionary(); + + static Keyboard() + { + for (int i = 0; i < 62; i++) + { + // http://stackoverflow.com/questions/2650080/how-to-get-c-sharp-enum-description-from-value + Keys value = (Keys)(1UL << i); + var fi = typeof(Keys).GetField(value.ToString()); + var attr = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); + string name = attr[0].Description; + DescriptionsToKeys[name] = value; + } + + } + + public static IEnumerable GetKeyNames() + { + return DescriptionsToKeys.Keys.ToList(); + } + + private static Keys FromStrings(IEnumerable keynames) + { + Keys ret = 0; + foreach (string s in keynames) + { + ret |= DescriptionsToKeys[s]; + } + return ret; + } + + public Keyboard() { } + public Keyboard(Machine machine) : base(machine) { } public override void Initialize() { - _keyboardService = Machine.Services.GetService(); - - UseGamePort = true; // Raster Blaster - Button2Key = ' '; } - public override void LoadState(BinaryReader reader, Version version) - { - if (reader == null) - { - throw new ArgumentNullException("reader"); - } + /// + /// Call this at 60hz with all of the currently pressed keys + /// + /// + public void SetKeys(IEnumerable keynames) + { + Keys keys = FromStrings(keynames); - DisableResetKey = reader.ReadBoolean(); + if (keys.HasFlag(Keys.WhiteApple)) { } // TODO: set GAME1 + if (keys.HasFlag(Keys.BlackApple)) { } // TODO: set GAME2 - UseGamePort = reader.ReadBoolean(); - Joystick0UpLeftKey = reader.ReadInt32(); - Joystick0UpKey = reader.ReadInt32(); - Joystick0UpRightKey = reader.ReadInt32(); - Joystick0LeftKey = reader.ReadInt32(); - Joystick0RightKey = reader.ReadInt32(); - Joystick0DownLeftKey = reader.ReadInt32(); - Joystick0DownKey = reader.ReadInt32(); - Joystick0DownRightKey = reader.ReadInt32(); - Joystick1UpLeftKey = reader.ReadInt32(); - Joystick1UpKey = reader.ReadInt32(); - Joystick1UpRightKey = reader.ReadInt32(); - Joystick1LeftKey = reader.ReadInt32(); - Joystick1RightKey = reader.ReadInt32(); - Joystick1DownLeftKey = reader.ReadInt32(); - Joystick1DownKey = reader.ReadInt32(); - Joystick1DownRightKey = reader.ReadInt32(); - Button0Key = reader.ReadUInt64(); - Button1Key = reader.ReadInt32(); - Button2Key = reader.ReadInt32(); - } + if (keys.HasFlag(Keys.Reset) && keys.HasFlag(Keys.Control)) { } // TODO: reset console - public override void SaveState(BinaryWriter writer) - { - if (writer == null) - { - throw new ArgumentNullException("writer"); - } + bool control = keys.HasFlag(Keys.Control); + bool shift = keys.HasFlag(Keys.Shift); - writer.Write(DisableResetKey); + bool caps = keys.HasFlag(Keys.CapsLock); + if (caps && !CurrentCapsLockState) // leading edge: toggle capslock + { + CapsActive ^= true; + } + CurrentCapsLockState = caps; + shift ^= CapsActive; + + // work with only the first 56 real keys + long k = (long)keys & 0xffffffffffffffL; + + IsAnyKeyDown = k != 0; + + if (!IsAnyKeyDown) + { + CurrentKeyPressed = -1; + return; + } + + // TODO: on real hardware, multiple keys pressed in physical would cause a conflict + // that would be somehow resolved by the scan pattern. we don't emulate that. + + // instead, just arbitrarily choose the lowest key in our list + + // BSF + int NewKeyPressed = 0; + while ((k & 1) == 0) + { + k >>= 1; + NewKeyPressed++; + } + + if (NewKeyPressed != CurrentKeyPressed) + { + // strobe, start new repeat cycle + Strobe = true; + Latch = KeyToAscii(NewKeyPressed, control, shift); + FramesToRepeat = KeyRepeatStart; + } + else + { + // check for repeat + FramesToRepeat--; + if (FramesToRepeat == 0) + { + Strobe = true; + Latch = KeyToAscii(NewKeyPressed, control, shift); + FramesToRepeat = KeyRepeatRate; + } + } + + CurrentKeyPressed = NewKeyPressed; + } - writer.Write(UseGamePort); - writer.Write(Joystick0UpLeftKey); - writer.Write(Joystick0UpKey); - writer.Write(Joystick0UpRightKey); - writer.Write(Joystick0LeftKey); - writer.Write(Joystick0RightKey); - writer.Write(Joystick0DownLeftKey); - writer.Write(Joystick0DownKey); - writer.Write(Joystick0DownRightKey); - writer.Write(Joystick1UpLeftKey); - writer.Write(Joystick1UpKey); - writer.Write(Joystick1UpRightKey); - writer.Write(Joystick1LeftKey); - writer.Write(Joystick1RightKey); - writer.Write(Joystick1DownLeftKey); - writer.Write(Joystick1DownKey); - writer.Write(Joystick1DownRightKey); - writer.Write(Button0Key); - writer.Write(Button1Key); - writer.Write(Button2Key); - } public void ResetStrobe() { Strobe = false; } - - public bool DisableResetKey { get; set; } - - public bool UseGamePort { get; set; } - public int Joystick0UpLeftKey { get; set; } - public int Joystick0UpKey { get; set; } - public int Joystick0UpRightKey { get; set; } - public int Joystick0LeftKey { get; set; } - public int Joystick0RightKey { get; set; } - public int Joystick0DownLeftKey { get; set; } - public int Joystick0DownKey { get; set; } - public int Joystick0DownRightKey { get; set; } - public int Joystick1UpLeftKey { get; set; } - public int Joystick1UpKey { get; set; } - public int Joystick1UpRightKey { get; set; } - public int Joystick1LeftKey { get; set; } - public int Joystick1RightKey { get; set; } - public int Joystick1DownLeftKey { get; set; } - public int Joystick1DownKey { get; set; } - public int Joystick1DownRightKey { get; set; } - public ulong Button0Key { get; set; } - public int Button1Key { get; set; } - public int Button2Key { get; set; } - - public bool IsAnyKeyDown { get { return _keyboardService.IsAnyKeyDown; } } - public bool IsShiftKeyDown { get { return _keyboardService.IsShiftKeyDown; } } - public bool IsControlKeyDown { get { return _keyboardService.IsControlKeyDown; } } - public int Latch { get { return _latch; } set { _latch = value; Strobe = true; } } + + /// + /// true if any of the 56 basic keys are pressed + /// + public bool IsAnyKeyDown { get; private set; } + /// + /// the currently latched key; 7 bits. + /// + public int Latch { get; private set; } public bool Strobe { get; private set; } - private KeyboardService _keyboardService; + /// + /// true if caps lock is active + /// + public bool CapsActive { get; private set; } - private int _latch; + private bool CurrentCapsLockState; + + /// + /// 0-55, -1 = none + /// + private int CurrentKeyPressed; + + private int FramesToRepeat; + + private const int KeyRepeatRate = 6; // 10hz + private const int KeyRepeatStart = 40; // ~666ms? } } diff --git a/ExternalCoreProjects/Virtu/Machine.cs b/ExternalCoreProjects/Virtu/Machine.cs index 5334d67569..958932c5af 100644 --- a/ExternalCoreProjects/Virtu/Machine.cs +++ b/ExternalCoreProjects/Virtu/Machine.cs @@ -1,391 +1,190 @@ using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Threading; using Jellyfish.Virtu.Services; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; namespace Jellyfish.Virtu { - public enum MachineState { Stopped = 0, Starting, Running, Pausing, Paused, Stopping } - - public enum Buttons : ulong - { - Up = 0x0000000000001, - Down = 0x0000000000002, - Left = 0x0000000000004, - Right = 0x0000000000008, - Tab = 0x0000000000010, - Enter = 0x0000000000020, - Escape = 0x0000000000040, - Back = 0x0000000000080, - Space = 0x0000000000100, - Ctrl = 0x0000000000200, - Shift = 0x0000000000400, - Caps = 0x0000000000800, - Key1 = 0x0000000001000, - Key2 = 0x0000000002000, - Key3 = 0x0000000004000, - Key4 = 0x0000000008000, - Key5 = 0x0000000010000, - Key6 = 0x0000000020000, - Key7 = 0x0000000040000, - Key8 = 0x0000000080000, - Key9 = 0x0000000100000, - Key0 = 0x0000000200000, - KeyA = 0x0000001000000, - KeyB = 0x0000002000000, - KeyC = 0x0000004000000, - KeyD = 0x0000008000000, - KeyE = 0x0000010000000, - KeyF = 0x0000020000000, - KeyG = 0x0000040000000, - KeyH = 0x0000080000000, - KeyI = 0x0000100000000, - KeyJ = 0x0000200000000, - KeyK = 0x0000400000000, - KeyL = 0x0000800000000, - KeyM = 0x0001000000000, - KeyN = 0x0002000000000, - KeyO = 0x0004000000000, - KeyP = 0x0008000000000, - KeyQ = 0x0010000000000, - KeyR = 0x0020000000000, - KeyS = 0x0040000000000, - KeyT = 0x0080000000000, - KeyU = 0x0100000000000, - KeyV = 0x0200000000000, - KeyW = 0x0400000000000, - KeyX = 0x0800000000000, - KeyY = 0x1000000000000, - KeyZ = 0x2000000000000 - } - - public sealed class Machine : IDisposable - { - public Machine(byte[] appleIIe, byte[] diskIIRom) - { + public sealed class Machine : IDisposable + { + public Machine(byte[] appleIIe, byte[] diskIIRom) + { Events = new MachineEvents(); - Services = new MachineServices(); - Cpu = new Cpu(this); - Memory = new Memory(this, appleIIe); - Keyboard = new Keyboard(this); - GamePort = new GamePort(this); - Cassette = new Cassette(this); - Speaker = new Speaker(this); - Video = new Video(this); - NoSlotClock = new NoSlotClock(this); + Cpu = new Cpu(this); + Memory = new Memory(this, appleIIe); + Keyboard = new Keyboard(this); + GamePort = new GamePort(this); + Cassette = new Cassette(this); + Speaker = new Speaker(this); + Video = new Video(this); + NoSlotClock = new NoSlotClock(this); - var emptySlot = new PeripheralCard(this); - Slot1 = emptySlot; - Slot2 = emptySlot; - Slot3 = emptySlot; - Slot4 = emptySlot; - Slot5 = emptySlot; - Slot6 = new DiskIIController(this, diskIIRom); - Slot7 = emptySlot; + var emptySlot = new PeripheralCard(this); + Slot1 = emptySlot; + Slot2 = emptySlot; + Slot3 = emptySlot; + Slot4 = emptySlot; + Slot5 = emptySlot; + Slot6 = new DiskIIController(this, diskIIRom); + Slot7 = emptySlot; - Slots = new Collection { null, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 }; - Components = new Collection { Cpu, Memory, Keyboard, GamePort, Cassette, Speaker, Video, NoSlotClock, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 }; + Slots = new List { null, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 }; + Components = new List { Cpu, Memory, Keyboard, GamePort, Cassette, Speaker, Video, NoSlotClock, Slot1, Slot2, Slot3, Slot4, Slot5, Slot6, Slot7 }; - BootDiskII = Slots.OfType().Last(); + BootDiskII = Slots.OfType().Last(); + } - //Thread = new Thread(Run) { Name = "Machine" }; - } - - public void Dispose() - { - _pauseEvent.Close(); - _unpauseEvent.Close(); - } - - public void Reset() - { - foreach (var component in Components) - { - _debugService.WriteMessage("Resetting machine '{0}'", component.GetType().Name); - component.Reset(); - //_debugService.WriteMessage("Reset machine '{0}'", component.GetType().Name); - } - } - - //[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Jellyfish.Virtu.Services.DebugService.WriteMessage(System.String)")] - //public void Start() - //{ - // _debugService = Services.GetService(); - // _storageService = Services.GetService(); - - // _debugService.WriteMessage("Starting machine"); - // State = MachineState.Starting; - // Thread.Start(); - //} - - //[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Jellyfish.Virtu.Services.DebugService.WriteMessage(System.String)")] - //public void Pause() - //{ - // _debugService.WriteMessage("Pausing machine"); - // State = MachineState.Pausing; - // _pauseEvent.WaitOne(); - // State = MachineState.Paused; - // _debugService.WriteMessage("Paused machine"); - //} - - //[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Jellyfish.Virtu.Services.DebugService.WriteMessage(System.String)")] - //public void Unpause() - //{ - // _debugService.WriteMessage("Running machine"); - // State = MachineState.Running; - // _unpauseEvent.Set(); - //} - - //[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Jellyfish.Virtu.Services.DebugService.WriteMessage(System.String)")] - //public void Stop() - //{ - // _debugService.WriteMessage("Stopping machine"); - // State = MachineState.Stopping; - // _unpauseEvent.Set(); - // if (Thread.IsAlive) - // { - // Thread.Join(); - // } - // State = MachineState.Stopped; - // _debugService.WriteMessage("Stopped machine"); - //} - - private void Initialize() - { - foreach (var component in Components) - { - _debugService.WriteMessage("Initializing machine '{0}'", component.GetType().Name); - component.Initialize(); - //_debugService.WriteMessage("Initialized machine '{0}'", component.GetType().Name); - } - } - - private void LoadState() - { -#if WINDOWS - var args = Environment.GetCommandLineArgs(); - if (args.Length > 1) - { - string name = args[1]; - Func, bool> loader = StorageService.LoadFile; - - if (name.StartsWith("res://", StringComparison.OrdinalIgnoreCase)) - { - name = name.Substring(6); - loader = StorageService.LoadResource; - } - - if (name.EndsWith(".bin", StringComparison.OrdinalIgnoreCase)) - { - loader(name, stream => LoadState(stream)); - } - else if (name.EndsWith(".prg", StringComparison.OrdinalIgnoreCase)) - { - loader(name, stream => Memory.LoadPrg(stream)); - } - else if (name.EndsWith(".xex", StringComparison.OrdinalIgnoreCase)) - { - loader(name, stream => Memory.LoadXex(stream)); - } - else - { - loader(name, stream => BootDiskII.BootDrive.InsertDisk(name, stream, false)); - } - } - else -#endif - if (!_storageService.Load(Machine.StateFileName, stream => LoadState(stream))) - { - StorageService.LoadResource("Disks/Default.dsk", stream => BootDiskII.BootDrive.InsertDisk("Default.dsk", stream, false)); - } - } - - // TODO: don't copy paste - public void LoadState(BinaryReader reader) + public void Dispose() + { + } + + public void Reset() { - string signature = reader.ReadString(); - var version = new Version(reader.ReadString()); - if ((signature != StateSignature) || (version != new Version(Machine.Version))) // avoid state version mismatch (for now) - { - throw new InvalidOperationException(); - } foreach (var component in Components) { - _debugService.WriteMessage("Loading machine '{0}'", component.GetType().Name); - component.LoadState(reader, version); - //_debugService.WriteMessage("Loaded machine '{0}'", component.GetType().Name); + DebugService.WriteMessage("Resetting machine '{0}'", component.GetType().Name); + component.Reset(); + //DebugService.WriteMessage("Reset machine '{0}'", component.GetType().Name); } } - private void LoadState(Stream stream) - { - using (var reader = new BinaryReader(stream)) - { - string signature = reader.ReadString(); - var version = new Version(reader.ReadString()); - if ((signature != StateSignature) || (version != new Version(Machine.Version))) // avoid state version mismatch (for now) - { - throw new InvalidOperationException(); - } - foreach (var component in Components) - { - _debugService.WriteMessage("Loading machine '{0}'", component.GetType().Name); - component.LoadState(reader, version); - //_debugService.WriteMessage("Loaded machine '{0}'", component.GetType().Name); - } - } - } - private void SaveState() - { - _storageService.Save(Machine.StateFileName, stream => SaveState(stream)); - } - public void SaveState(BinaryWriter writer) + private void Initialize() { - writer.Write(StateSignature); - writer.Write(Machine.Version); foreach (var component in Components) { - _debugService.WriteMessage("Saving machine '{0}'", component.GetType().Name); - component.SaveState(writer); - //_debugService.WriteMessage("Saved machine '{0}'", component.GetType().Name); + DebugService.WriteMessage("Initializing machine '{0}'", component.GetType().Name); + component.Initialize(); + //DebugService.WriteMessage("Initialized machine '{0}'", component.GetType().Name); } } - private void SaveState(Stream stream) - { - using (var writer = new BinaryWriter(stream)) - { - writer.Write(StateSignature); - writer.Write(Machine.Version); - foreach (var component in Components) - { - _debugService.WriteMessage("Saving machine '{0}'", component.GetType().Name); - component.SaveState(writer); - //_debugService.WriteMessage("Saved machine '{0}'", component.GetType().Name); - } - } - } + private void Uninitialize() + { + foreach (var component in Components) + { + DebugService.WriteMessage("Uninitializing machine '{0}'", component.GetType().Name); + component.Uninitialize(); + //DebugService.WriteMessage("Uninitialized machine '{0}'", component.GetType().Name); + } + } - private void Uninitialize() - { - foreach (var component in Components) - { - _debugService.WriteMessage("Uninitializing machine '{0}'", component.GetType().Name); - component.Uninitialize(); - //_debugService.WriteMessage("Uninitialized machine '{0}'", component.GetType().Name); - } - } - //[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Jellyfish.Virtu.Services.DebugService.WriteMessage(System.String)")] - //private void Run() // machine thread - //{ - // Initialize(); - // Reset(); - // LoadState(); - // - // _debugService.WriteMessage("Running machine"); - // State = MachineState.Running; - // do - // { - // do - // { - // Events.HandleEvents(Cpu.Execute()); - // } - // while (State == MachineState.Running); - // - // if (State == MachineState.Pausing) - // { - // _pauseEvent.Set(); - // _unpauseEvent.WaitOne(); - // } - // } - // while (State != MachineState.Stopping); - // - // SaveState(); - // Uninitialize(); - //} + public void BizInitialize() + { + Initialize(); + Reset(); + } - public void BizInitialize() - { - _debugService = Services.GetService(); - _storageService = Services.GetService(); + public void BizFrameAdvance(IEnumerable buttons) + { + Lagged = true; - Initialize(); - Reset(); - } + Keyboard.SetKeys(buttons); - public void BizNewDisk() - { - _storageService = Services.GetService(); - } + //frame begins at vsync.. beginning of vblank + while (Video.IsVBlank) + { + /* + var sb = new System.Text.StringBuilder(); + sb.AppendFormat("{0} ", Cpu); + for (int i = 0; i < 256; i++) + sb.AppendFormat("{0:x2} ", Memory.Read(i)); + tw.WriteLine(sb.ToString());*/ + Events.HandleEvents(Cpu.Execute()); + } + //now, while not vblank, we're in a frame + while (!Video.IsVBlank) + { + /* + var sb = new System.Text.StringBuilder(); + sb.AppendFormat("{0} ", Cpu); + for (int i = 0; i < 256; i++) + sb.AppendFormat("{0:x2} ", Memory.Read(i)); + tw.WriteLine(sb.ToString()); */ - public void BizFrameAdvance() - { - Lagged = true; - Services.GetService().Update(); - Services.GetService().Update(); - //frame begins at vsync.. beginning of vblank - while (Video.IsVBlank) - Events.HandleEvents(Cpu.Execute()); - //now, while not vblank, we're in a frame - while (!Video.IsVBlank) - Events.HandleEvents(Cpu.Execute()); - - } + Events.HandleEvents(Cpu.Execute()); + } + } - public void BizShutdown() - { - Uninitialize(); - } + public void BizShutdown() + { + Uninitialize(); + } - public const string Version = "0.9.4.0"; + private static JsonSerializer CreateSerializer() + { + var ser = new JsonSerializer + { + TypeNameHandling = TypeNameHandling.Auto, + PreserveReferencesHandling = PreserveReferencesHandling.All, // leaving out Array is a very important problem, and means that we can't rely on a directly shared array to work. + ReferenceLoopHandling = ReferenceLoopHandling.Serialize, + }; - public MachineEvents Events { get; private set; } - public MachineServices Services { get; private set; } - public MachineState State { get { return _state; } private set { _state = value; } } + ser.Converters.Add(new DelegateConverter()); + ser.Converters.Add(new ArrayConverter()); + var cr = new DefaultContractResolver(); + cr.DefaultMembersSearchFlags |= System.Reflection.BindingFlags.NonPublic; + ser.ContractResolver = cr; - public Cpu Cpu { get; private set; } - public Memory Memory { get; private set; } - public Keyboard Keyboard { get; private set; } - public GamePort GamePort { get; private set; } - public Cassette Cassette { get; private set; } - public Speaker Speaker { get; private set; } - public Video Video { get; private set; } - public NoSlotClock NoSlotClock { get; private set; } + return ser; + } - public PeripheralCard Slot1 { get; private set; } - public PeripheralCard Slot2 { get; private set; } - public PeripheralCard Slot3 { get; private set; } - public PeripheralCard Slot4 { get; private set; } - public PeripheralCard Slot5 { get; private set; } - public PeripheralCard Slot6 { get; private set; } - public PeripheralCard Slot7 { get; private set; } + public void Serialize(JsonWriter w) + { + CreateSerializer().Serialize(w, this); + } - public Collection Slots { get; private set; } - public Collection Components { get; private set; } + public static Machine Deserialize(JsonReader r) + { + var ret = CreateSerializer().Deserialize(r); + + // for some unknown reason, these particular references get nuked by JSON.NET on deserializating + foreach (var c in ret.Components) + { + c.Machine = ret; + } + ret.BootDiskII.Drive1.Machine = ret; + ret.BootDiskII.Drive2.Machine = ret; - public DiskIIController BootDiskII { get; private set; } + return ret; + } - public Thread Thread { get; private set; } + public const string Version = "0.9.4.0"; - public Buttons Buttons; + public MachineEvents Events { get; private set; } - private const string StateFileName = "State.bin"; - private const string StateSignature = "Virtu"; + public Cpu Cpu { get; private set; } + public Memory Memory { get; private set; } + public Keyboard Keyboard { get; private set; } + public GamePort GamePort { get; private set; } + public Cassette Cassette { get; private set; } + public Speaker Speaker { get; private set; } + public Video Video { get; private set; } + public NoSlotClock NoSlotClock { get; private set; } - private DebugService _debugService; - private StorageService _storageService; - private volatile MachineState _state; + public PeripheralCard Slot1 { get; private set; } + public PeripheralCard Slot2 { get; private set; } + public PeripheralCard Slot3 { get; private set; } + public PeripheralCard Slot4 { get; private set; } + public PeripheralCard Slot5 { get; private set; } + public PeripheralCard Slot6 { get; private set; } + public PeripheralCard Slot7 { get; private set; } - private AutoResetEvent _pauseEvent = new AutoResetEvent(false); - private AutoResetEvent _unpauseEvent = new AutoResetEvent(false); + public IList Slots { get; private set; } + public IList Components { get; private set; } + + public DiskIIController BootDiskII { get; private set; } public bool Lagged { get; set; } - } + } } diff --git a/ExternalCoreProjects/Virtu/MachineComponent.cs b/ExternalCoreProjects/Virtu/MachineComponent.cs index 195b8ed3fb..cd6d407e6c 100644 --- a/ExternalCoreProjects/Virtu/MachineComponent.cs +++ b/ExternalCoreProjects/Virtu/MachineComponent.cs @@ -7,11 +7,10 @@ namespace Jellyfish.Virtu { public abstract class MachineComponent { + public MachineComponent() { } protected MachineComponent(Machine machine) { - Machine = machine; - - _debugService = new Lazy(() => Machine.Services.GetService()); + _machine = machine; } public virtual void Initialize() @@ -22,21 +21,17 @@ namespace Jellyfish.Virtu { } - public virtual void LoadState(BinaryReader reader, Version version) - { - } - public virtual void Uninitialize() { } - public virtual void SaveState(BinaryWriter writer) - { - } + [Newtonsoft.Json.JsonIgnore] + private Machine _machine; - protected Machine Machine { get; private set; } - protected DebugService DebugService { get { return _debugService.Value; } } - - private Lazy _debugService; + public Machine Machine + { + get { return _machine; } + set { _machine = value; } + } } } diff --git a/ExternalCoreProjects/Virtu/MachineEvents.cs b/ExternalCoreProjects/Virtu/MachineEvents.cs index f008d049c1..8cd705a691 100644 --- a/ExternalCoreProjects/Virtu/MachineEvents.cs +++ b/ExternalCoreProjects/Virtu/MachineEvents.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; namespace Jellyfish.Virtu { @@ -25,6 +26,8 @@ namespace Jellyfish.Virtu { public void AddEvent(int delta, Action action) { + //Console.WriteLine("+{0} @ {1}", action.Method.Name, delta); + var node = _used.First; for (; node != null; node = node.Next) { @@ -68,23 +71,37 @@ namespace Jellyfish.Virtu for (var node = _used.First; node != null; node = node.Next) { delta += node.Value.Delta; - if (object.ReferenceEquals(node.Value.Action, action)) // assumes delegate cached - { - return delta; - } + + var other = node.Value.Action; + + if (other.Method == action.Method && other.Target == action.Target) + { + //Console.WriteLine("={0} @ {1}", action.Method.Name, delta); + return delta; + } + + // our delegate serializer doesn't preserve reference equality + //if (object.ReferenceEquals(node.Value.Action, action)) // assumes delegate cached + //{ + // return delta; + //} } - return 0; + //Console.WriteLine("=???? @ 0"); + return 0; } public void HandleEvents(int delta) { + //Console.WriteLine("[{0}]", delta); + var node = _used.First; node.Value.Delta -= delta; while (node.Value.Delta <= 0) { - node.Value.Action(); + //Console.WriteLine("!{0} @ {1}", node.Value.Action.Method.Name, node.Value.Delta); + node.Value.Action(); RemoveEvent(node); node = _used.First; } diff --git a/ExternalCoreProjects/Virtu/Memory.cs b/ExternalCoreProjects/Virtu/Memory.cs index 6c90939738..8074474224 100644 --- a/ExternalCoreProjects/Virtu/Memory.cs +++ b/ExternalCoreProjects/Virtu/Memory.cs @@ -13,6 +13,7 @@ namespace Jellyfish.Virtu public sealed partial class Memory : MachineComponent { + public Memory() { } public Memory(Machine machine, byte[] appleIIe) : base(machine) { @@ -89,7 +90,7 @@ namespace Jellyfish.Virtu _writeRomRegionD0FF = WriteRomRegionD0FF; } - private readonly byte[] _appleIIe; + private byte[] _appleIIe; public override void Initialize() { @@ -138,55 +139,6 @@ namespace Jellyfish.Virtu MapRegionD0FF(); } - public override void LoadState(BinaryReader reader, Version version) - { - if (reader == null) - { - throw new ArgumentNullException("reader"); - } - - _state = reader.ReadInt32(); - _slotRegionC8CF = reader.ReadInt32(); - - reader.Read(_ramMainRegion0001, 0, _ramMainRegion0001.Length); - reader.Read(_ramMainRegion02BF, 0, _ramMainRegion02BF.Length); - reader.Read(_ramMainBank1RegionD0DF, 0, _ramMainBank1RegionD0DF.Length); - reader.Read(_ramMainBank2RegionD0DF, 0, _ramMainBank2RegionD0DF.Length); - reader.Read(_ramMainRegionE0FF, 0, _ramMainRegionE0FF.Length); - reader.Read(_ramAuxRegion0001, 0, _ramAuxRegion0001.Length); - reader.Read(_ramAuxRegion02BF, 0, _ramAuxRegion02BF.Length); - reader.Read(_ramAuxBank1RegionD0DF, 0, _ramAuxBank1RegionD0DF.Length); - reader.Read(_ramAuxBank2RegionD0DF, 0, _ramAuxBank2RegionD0DF.Length); - reader.Read(_ramAuxRegionE0FF, 0, _ramAuxRegionE0FF.Length); - - MapRegion0001(); - MapRegion02BF(); - MapRegionC0CF(); - MapRegionD0FF(); - } - - public override void SaveState(BinaryWriter writer) - { - if (writer == null) - { - throw new ArgumentNullException("writer"); - } - - writer.Write(_state); - writer.Write(_slotRegionC8CF); - - writer.Write(_ramMainRegion0001); - writer.Write(_ramMainRegion02BF); - writer.Write(_ramMainBank1RegionD0DF); - writer.Write(_ramMainBank2RegionD0DF); - writer.Write(_ramMainRegionE0FF); - writer.Write(_ramAuxRegion0001); - writer.Write(_ramAuxRegion02BF); - writer.Write(_ramAuxBank1RegionD0DF); - writer.Write(_ramAuxBank2RegionD0DF); - writer.Write(_ramAuxRegionE0FF); - } - public void LoadPrg(Stream stream) { if (stream == null) @@ -282,8 +234,6 @@ namespace Jellyfish.Virtu return _video.ReadFloatingBus(); } - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] - [SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode")] private int ReadIoRegionC0C0(int address) { Machine.Lagged = false; diff --git a/ExternalCoreProjects/Virtu/MemoryData.cs b/ExternalCoreProjects/Virtu/MemoryData.cs index e2e9bfaad3..3de7adf037 100644 --- a/ExternalCoreProjects/Virtu/MemoryData.cs +++ b/ExternalCoreProjects/Virtu/MemoryData.cs @@ -101,6 +101,6 @@ namespace Jellyfish.Virtu Video.ModeC, Video.ModeD, Video.Mode1, Video.Mode2, Video.ModeE, Video.ModeF, Video.Mode1, Video.Mode2 }; - private readonly Action[][][] WriteRamModeBankRegion; + private Action[][][] WriteRamModeBankRegion; } } diff --git a/ExternalCoreProjects/Virtu/NoSlotClock.cs b/ExternalCoreProjects/Virtu/NoSlotClock.cs index 9ff12922f3..8ce39a8d32 100644 --- a/ExternalCoreProjects/Virtu/NoSlotClock.cs +++ b/ExternalCoreProjects/Virtu/NoSlotClock.cs @@ -5,6 +5,7 @@ namespace Jellyfish.Virtu { public sealed class NoSlotClock : MachineComponent { + public NoSlotClock() { } public NoSlotClock(Machine machine) : base(machine) { @@ -18,34 +19,6 @@ namespace Jellyfish.Virtu _comparisonRegister = new RingRegister(ClockInitSequence, 0x1); } - public override void LoadState(BinaryReader reader, Version version) - { - if (reader == null) - { - throw new ArgumentNullException("reader"); - } - - _clockEnabled = reader.ReadBoolean(); - _writeEnabled = reader.ReadBoolean(); - _clockRegister = new RingRegister(reader.ReadUInt64(), reader.ReadUInt64()); - _comparisonRegister = new RingRegister(reader.ReadUInt64(), reader.ReadUInt64()); - } - - public override void SaveState(BinaryWriter writer) - { - if (writer == null) - { - throw new ArgumentNullException("writer"); - } - - writer.Write(_clockEnabled); - writer.Write(_writeEnabled); - writer.Write(_clockRegister.Data); - writer.Write(_clockRegister.Mask); - writer.Write(_comparisonRegister.Data); - writer.Write(_comparisonRegister.Mask); - } - public int Read(int address, int data) { // this may read or write the clock diff --git a/ExternalCoreProjects/Virtu/PeripheralCard.cs b/ExternalCoreProjects/Virtu/PeripheralCard.cs index 662f61ebfa..3785c06775 100644 --- a/ExternalCoreProjects/Virtu/PeripheralCard.cs +++ b/ExternalCoreProjects/Virtu/PeripheralCard.cs @@ -2,6 +2,7 @@ { public class PeripheralCard : MachineComponent { + public PeripheralCard() { } public PeripheralCard(Machine machine) : base(machine) { diff --git a/ExternalCoreProjects/Virtu/Services/AudioService.cs b/ExternalCoreProjects/Virtu/Services/AudioService.cs index eb68746637..d4593fd871 100644 --- a/ExternalCoreProjects/Virtu/Services/AudioService.cs +++ b/ExternalCoreProjects/Virtu/Services/AudioService.cs @@ -5,12 +5,12 @@ using Jellyfish.Library; namespace Jellyfish.Virtu.Services { - public abstract class AudioService : MachineService + /// + /// this isn't really a "service" anymore, just a helper for the speaker class + /// + public class AudioService { - protected AudioService(Machine machine) : - base(machine) - { - } + public AudioService() { } public void Output(int data) // machine thread { @@ -25,21 +25,16 @@ namespace Jellyfish.Virtu.Services private short[] buff = new short[4096]; private int pos = 0; - public void Reset() - { + public void Clear() + { pos = 0; - } - - public abstract void SetVolume(float volume); - + } public void GetSamples(out short[] samples, out int nsamp) { samples = buff; nsamp = pos / 2; pos = 0; - - Console.WriteLine(nsamp); } } } diff --git a/ExternalCoreProjects/Virtu/Services/DebugService.cs b/ExternalCoreProjects/Virtu/Services/DebugService.cs index ecdef36fb2..6b89b2e3ff 100644 --- a/ExternalCoreProjects/Virtu/Services/DebugService.cs +++ b/ExternalCoreProjects/Virtu/Services/DebugService.cs @@ -7,24 +7,22 @@ using Jellyfish.Library; namespace Jellyfish.Virtu.Services { - public class DebugService : MachineService + /// + /// this isn't really a "service" anymore + /// + public static class DebugService { - public DebugService(Machine machine) : - base(machine) - { - } - - public void WriteMessage(string message) + public static void WriteMessage(string message) { OnWriteMessage(FormatMessage(message)); } - public void WriteMessage(string format, params object[] args) + public static void WriteMessage(string format, params object[] args) { OnWriteMessage(FormatMessage(format, args)); } - protected virtual void OnWriteMessage(string message) + private static void OnWriteMessage(string message) { #if SILVERLIGHT Debug.WriteLine(message); @@ -33,7 +31,7 @@ namespace Jellyfish.Virtu.Services #endif } - private string FormatMessage(string format, params object[] args) + private static string FormatMessage(string format, params object[] args) { var message = new StringBuilder(256); message.AppendFormat(CultureInfo.InvariantCulture, "[{0} T{1:X3} Virtu] ", DateTime.Now.ToString("HH:mm:ss.fff", CultureInfo.InvariantCulture), Thread.CurrentThread.ManagedThreadId); @@ -55,9 +53,5 @@ namespace Jellyfish.Virtu.Services return message.ToString(); } - - public static DebugService Default { get { return _default.Value; } } - - private static readonly Lazy _default = new Lazy(() => new DebugService(null)); } } diff --git a/ExternalCoreProjects/Virtu/Services/GamePortService.cs b/ExternalCoreProjects/Virtu/Services/GamePortService.cs deleted file mode 100644 index 0972680ba4..0000000000 --- a/ExternalCoreProjects/Virtu/Services/GamePortService.cs +++ /dev/null @@ -1,333 +0,0 @@ -using System; - -namespace Jellyfish.Virtu.Services -{ - public class GamePortService : MachineService - { - public GamePortService(Machine machine) : - base(machine) - { - Paddle0 = Paddle1 = Paddle2 = Paddle3 = 255; // not connected - } - - public virtual void Update() // main thread - { - var keyboard = Machine.Keyboard; - - if (keyboard.UseGamePort) - { - //UpdateKey(keyboard.Joystick0UpKey, IsJoystick0Up, ref _isJoystick0UpKeyDown, ref _wasJoystick0UpKeyDown); - //UpdateKey(keyboard.Joystick0LeftKey, IsJoystick0Left, ref _isJoystick0LeftKeyDown, ref _wasJoystick0LeftKeyDown); - //UpdateKey(keyboard.Joystick0RightKey, IsJoystick0Right, ref _isJoystick0RightKeyDown, ref _wasJoystick0RightKeyDown); - //UpdateKey(keyboard.Joystick0DownKey, IsJoystick0Down, ref _isJoystick0DownKeyDown, ref _wasJoystick0DownKeyDown); - //UpdateKey(keyboard.Joystick0UpLeftKey, IsJoystick0Up && IsJoystick0Left, ref _isJoystick0UpLeftKeyDown, ref _wasJoystick0UpLeftKeyDown); - //UpdateKey(keyboard.Joystick0UpRightKey, IsJoystick0Up && IsJoystick0Right, ref _isJoystick0UpRightKeyDown, ref _wasJoystick0UpRightKeyDown); - //UpdateKey(keyboard.Joystick0DownLeftKey, IsJoystick0Down && IsJoystick0Left, ref _isJoystick0DownLeftKeyDown, ref _wasJoystick0DownLeftKeyDown); - //UpdateKey(keyboard.Joystick0DownRightKey, IsJoystick0Down && IsJoystick0Right, ref _isJoystick0DownRightKeyDown, ref _wasJoystick0DownRightKeyDown); - //UpdateKey(keyboard.Joystick1UpKey, IsJoystick1Up, ref _isJoystick1UpKeyDown, ref _wasJoystick1UpKeyDown); - //UpdateKey(keyboard.Joystick1LeftKey, IsJoystick1Left, ref _isJoystick1LeftKeyDown, ref _wasJoystick1LeftKeyDown); - //UpdateKey(keyboard.Joystick1RightKey, IsJoystick1Right, ref _isJoystick1RightKeyDown, ref _wasJoystick1RightKeyDown); - //UpdateKey(keyboard.Joystick1DownKey, IsJoystick1Down, ref _isJoystick1DownKeyDown, ref _wasJoystick1DownKeyDown); - //UpdateKey(keyboard.Joystick1UpLeftKey, IsJoystick1Up && IsJoystick1Left, ref _isJoystick1UpLeftKeyDown, ref _wasJoystick1UpLeftKeyDown); - //UpdateKey(keyboard.Joystick1UpRightKey, IsJoystick1Up && IsJoystick1Right, ref _isJoystick1UpRightKeyDown, ref _wasJoystick1UpRightKeyDown); - //UpdateKey(keyboard.Joystick1DownLeftKey, IsJoystick1Down && IsJoystick1Left, ref _isJoystick1DownLeftKeyDown, ref _wasJoystick1DownLeftKeyDown); - //UpdateKey(keyboard.Joystick1DownRightKey, IsJoystick1Down && IsJoystick1Right, ref _isJoystick1DownRightKeyDown, ref _wasJoystick1DownRightKeyDown); - - //all the keys are going through this one thing atm - UpdateKey(keyboard.Button0Key, IsButton0Down, ref _isButton0KeyDown, ref _wasButton0KeyDown); - //UpdateKey(keyboard.Button1Key, IsButton1Down, ref _isButton1KeyDown, ref _wasButton1KeyDown); - //UpdateKey(keyboard.Button2Key, IsButton2Down, ref _isButton2KeyDown, ref _wasButton2KeyDown); - - - /* - if (_lastKey > 0) // repeat last key - { - long time = DateTime.UtcNow.Ticks; - if (time - _lastTime >= _repeatTime) - { - _lastTime = time; - _repeatTime = RepeatSpeed; - keyboard.Latch = GetAsciiKey((Buttons)_lastKey, Machine.Keyboard.IsControlKeyDown, Machine.Keyboard.IsShiftKeyDown, false); - } - } - * */ - } - } - - //static int t = 0; - - private void UpdateKey(ulong key, bool isActive, ref bool isKeyDown, ref bool wasKeyDown) - { - wasKeyDown = isKeyDown; - isKeyDown = (key > 0);// && isActive; - - if (isKeyDown != wasKeyDown) - { - if (isKeyDown) - { - _lastKey = key; - _lastTime = DateTime.UtcNow.Ticks; - _repeatTime = RepeatDelay; - Machine.Keyboard.Latch = GetAsciiKey((Buttons)key, Machine.Keyboard.IsControlKeyDown, Machine.Keyboard.IsShiftKeyDown, false); - } - else if (key == _lastKey) - { - _lastKey = 0; - } - } - - - } - - private static int GetAsciiKey(Buttons bizKey, bool bizCtrl, bool bizShift, bool bizCaps) - { - - bool control = bizCtrl; - bool shift = bizShift; - bool capsLock = bizCaps; - - switch (bizKey) - { - case 0: - return 0x00; - case Buttons.Left: - return 0x08; - - case Buttons.Tab: - return 0x09; - - case Buttons.Down: - return 0x0A; - - case Buttons.Up: - return 0x0B; - - case Buttons.Enter: - return 0x0D; - - case Buttons.Right: - return 0x15; - - case Buttons.Escape: - return 0x1B; - - case Buttons.Back: - return control ? -1 : 0x7F; - - case Buttons.Space: - return ' '; - - case Buttons.Key1: - return shift ? '!' : '1'; - - case Buttons.Key2: - return control ? 0x00 : shift ? '@' : '2'; - - case Buttons.Key3: - return shift ? '#' : '3'; - - case Buttons.Key4: - return shift ? '$' : '4'; - - case Buttons.Key5: - return shift ? '%' : '5'; - - case Buttons.Key6: - return control ? 0x1E : shift ? '^' : '6'; - - case Buttons.Key7: - return shift ? '&' : '7'; - - case Buttons.Key8: - return shift ? '*' : '8'; - - case Buttons.Key9: - return shift ? '(' : '9'; - - case Buttons.Key0: - return shift ? ')' : '0'; - - case Buttons.KeyA: - return control ? 0x01 : capsLock ? 'A' : 'a'; - - case Buttons.KeyB: - return control ? 0x02 : capsLock ? 'B' : 'b'; - - case Buttons.KeyC: - return control ? 0x03 : capsLock ? 'C' : 'c'; - - case Buttons.KeyD: - return control ? 0x04 : capsLock ? 'D' : 'd'; - - case Buttons.KeyE: - return control ? 0x05 : capsLock ? 'E' : 'e'; - - case Buttons.KeyF: - return control ? 0x06 : capsLock ? 'F' : 'f'; - - case Buttons.KeyG: - return control ? 0x07 : capsLock ? 'G' : 'g'; - - case Buttons.KeyH: - return control ? 0x08 : capsLock ? 'H' : 'h'; - - case Buttons.KeyI: - return control ? 0x09 : capsLock ? 'I' : 'i'; - - case Buttons.KeyJ: - return control ? 0x0A : capsLock ? 'J' : 'j'; - - case Buttons.KeyK: - return control ? 0x0B : capsLock ? 'K' : 'k'; - - case Buttons.KeyL: - return control ? 0x0C : capsLock ? 'L' : 'l'; - - case Buttons.KeyM: - return control ? 0x0D : capsLock ? 'M' : 'm'; - - case Buttons.KeyN: - return control ? 0x0E : capsLock ? 'N' : 'n'; - - case Buttons.KeyO: - return control ? 0x0F : capsLock ? 'O' : 'o'; - - case Buttons.KeyP: - return control ? 0x10 : capsLock ? 'P' : 'p'; - - case Buttons.KeyQ: - return control ? 0x11 : capsLock ? 'Q' : 'q'; - - case Buttons.KeyR: - return control ? 0x12 : capsLock ? 'R' : 'r'; - - case Buttons.KeyS: - return control ? 0x13 : capsLock ? 'S' : 's'; - - case Buttons.KeyT: - return control ? 0x14 : capsLock ? 'T' : 't'; - - case Buttons.KeyU: - return control ? 0x15 : capsLock ? 'U' : 'u'; - - case Buttons.KeyV: - return control ? 0x16 : capsLock ? 'V' : 'v'; - - case Buttons.KeyW: - return control ? 0x17 : capsLock ? 'W' : 'w'; - - case Buttons.KeyX: - return control ? 0x18 : capsLock ? 'X' : 'x'; - - case Buttons.KeyY: - return control ? 0x19 : capsLock ? 'Y' : 'y'; - - case Buttons.KeyZ: - return control ? 0x1A : capsLock ? 'Z' : 'z'; - //TODO: Get around to supporting those keys too - /* - case Key.Oem1: - return shift ? ':' : ';'; - - case Key.Oem2: - return shift ? '?' : '/'; - - case Key.Oem3: - return shift ? '~' : '`'; - - case Key.Oem4: - return shift ? '{' : '['; - - case Key.Oem5: - return control ? 0x1C : shift ? '|' : '\\'; - - case Key.Oem6: - return control ? 0x1D : shift ? '}' : ']'; - - case Key.Oem7: - return shift ? '"' : '\''; - - case Key.OemMinus: - return control ? 0x1F : shift ? '_' : '-'; - - case Key.OemPlus: - return shift ? '+' : '='; - - case Key.OemComma: - return shift ? '<' : ','; - - case Key.OemPeriod: - return shift ? '>' : '.'; - * */ - } - - return 0; - } - - public int Paddle0 { get; protected set; } - public int Paddle1 { get; protected set; } - public int Paddle2 { get; protected set; } - public int Paddle3 { get; protected set; } - - public bool IsJoystick0Up { get; protected set; } - public bool IsJoystick0Left { get; protected set; } - public bool IsJoystick0Right { get; protected set; } - public bool IsJoystick0Down { get; protected set; } - - public bool IsJoystick1Up { get; protected set; } - public bool IsJoystick1Left { get; protected set; } - public bool IsJoystick1Right { get; protected set; } - public bool IsJoystick1Down { get; protected set; } - - public bool IsButton0Down { get; protected set; } - public bool IsButton1Down { get; protected set; } - public bool IsButton2Down { get; protected set; } - - private static readonly long RepeatDelay = TimeSpan.FromMilliseconds(500).Ticks; - private static readonly long RepeatSpeed = TimeSpan.FromMilliseconds(32).Ticks; - - //private bool _isJoystick0UpLeftKeyDown; - //private bool _isJoystick0UpKeyDown; - //private bool _isJoystick0UpRightKeyDown; - //private bool _isJoystick0LeftKeyDown; - //private bool _isJoystick0RightKeyDown; - //private bool _isJoystick0DownLeftKeyDown; - //private bool _isJoystick0DownKeyDown; - //private bool _isJoystick0DownRightKeyDown; - //private bool _isJoystick1UpLeftKeyDown; - //private bool _isJoystick1UpKeyDown; - //private bool _isJoystick1UpRightKeyDown; - //private bool _isJoystick1LeftKeyDown; - //private bool _isJoystick1RightKeyDown; - //private bool _isJoystick1DownLeftKeyDown; - //private bool _isJoystick1DownKeyDown; - //private bool _isJoystick1DownRightKeyDown; - private bool _isButton0KeyDown; - //private bool _isButton1KeyDown; - //private bool _isButton2KeyDown; - - //private bool _wasJoystick0UpLeftKeyDown; - //private bool _wasJoystick0UpKeyDown; - //private bool _wasJoystick0UpRightKeyDown; - //private bool _wasJoystick0LeftKeyDown; - //private bool _wasJoystick0RightKeyDown; - //private bool _wasJoystick0DownLeftKeyDown; - //private bool _wasJoystick0DownKeyDown; - //private bool _wasJoystick0DownRightKeyDown; - //private bool _wasJoystick1UpLeftKeyDown; - //private bool _wasJoystick1UpKeyDown; - //private bool _wasJoystick1UpRightKeyDown; - //private bool _wasJoystick1LeftKeyDown; - //private bool _wasJoystick1RightKeyDown; - //private bool _wasJoystick1DownLeftKeyDown; - //private bool _wasJoystick1DownKeyDown; - //private bool _wasJoystick1DownRightKeyDown; - private bool _wasButton0KeyDown; - //private bool _wasButton1KeyDown; - //private bool _wasButton2KeyDown; - - private ulong _lastKey; - private long _lastTime; - private long _repeatTime; - } -} diff --git a/ExternalCoreProjects/Virtu/Services/IsolatedStorageService.cs b/ExternalCoreProjects/Virtu/Services/IsolatedStorageService.cs deleted file mode 100644 index 68159a96ba..0000000000 --- a/ExternalCoreProjects/Virtu/Services/IsolatedStorageService.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.IO.IsolatedStorage; - -namespace Jellyfish.Virtu.Services -{ - public class IsolatedStorageService : StorageService - { - public IsolatedStorageService(Machine machine) : - base(machine) - { - } - - protected override void OnLoad(string fileName, Action reader) - { - if (reader == null) - { - throw new ArgumentNullException("reader"); - } - - using (var store = GetStore()) - { - using (var stream = store.OpenFile(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - reader(stream); - } - } - } - - protected override void OnSave(string fileName, Action writer) - { - if (writer == null) - { - throw new ArgumentNullException("writer"); - } - - using (var store = GetStore()) - { - using (var stream = store.OpenFile(fileName, FileMode.Create, FileAccess.Write, FileShare.None)) - { - writer(stream); - } - } - } - - [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] - protected virtual IsolatedStorageFile GetStore() - { - return IsolatedStorageFile.GetUserStoreForApplication(); - } - } -} diff --git a/ExternalCoreProjects/Virtu/Services/KeyboardService.cs b/ExternalCoreProjects/Virtu/Services/KeyboardService.cs deleted file mode 100644 index db3b7daffa..0000000000 --- a/ExternalCoreProjects/Virtu/Services/KeyboardService.cs +++ /dev/null @@ -1,48 +0,0 @@ -namespace Jellyfish.Virtu.Services -{ - public abstract class KeyboardService : MachineService - { - protected KeyboardService(Machine machine) : - base(machine) - { - } - - public abstract bool IsKeyDown(int key); - - public virtual void Update() // main thread - { - var keyboard = Machine.Keyboard; - var buttons = Machine.Buttons; - - keyboard.Button0Key = (ulong)buttons; - - if (IsResetKeyDown && !keyboard.DisableResetKey) - { - if (!_resetKeyDown) - { - _resetKeyDown = true; // entering reset; pause until key released - //TODO ADELIKAT : HANDLE RESET DIFFERENTLY - //Machine.Pause(); - //Machine.Reset(); - } - } - else if (_resetKeyDown) - { - _resetKeyDown = false; // leaving reset - //TODO ADELIKAT : HANDLE RESET DIFFERENTLY - //Machine.Unpause(); - } - } - - public bool IsAnyKeyDown { get { return Machine.Buttons > 0; }} - public bool IsControlKeyDown { get { return Machine.Buttons.HasFlag(Buttons.Ctrl); }} - public bool IsShiftKeyDown { get { return Machine.Buttons.HasFlag(Buttons.Shift); }} - - public bool IsOpenAppleKeyDown { get; protected set; } - public bool IsCloseAppleKeyDown { get; protected set; } - - protected bool IsResetKeyDown { get; set; } - - private bool _resetKeyDown; - } -} diff --git a/ExternalCoreProjects/Virtu/Services/MachineService.cs b/ExternalCoreProjects/Virtu/Services/MachineService.cs deleted file mode 100644 index 8c2b246410..0000000000 --- a/ExternalCoreProjects/Virtu/Services/MachineService.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Jellyfish.Library; - -namespace Jellyfish.Virtu.Services -{ - public abstract class MachineService : DisposableBase - { - protected MachineService(Machine machine) - { - Machine = machine; - - _debugService = new Lazy(() => Machine.Services.GetService()); - } - - protected Machine Machine { get; private set; } - protected DebugService DebugService { get { return _debugService.Value; } } - - private Lazy _debugService; - } -} diff --git a/ExternalCoreProjects/Virtu/Services/MachineServices.cs b/ExternalCoreProjects/Virtu/Services/MachineServices.cs deleted file mode 100644 index b8669ee362..0000000000 --- a/ExternalCoreProjects/Virtu/Services/MachineServices.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using Jellyfish.Virtu.Properties; - -namespace Jellyfish.Virtu.Services -{ - public sealed class MachineServices : IServiceProvider - { - public void AddService(Type serviceType, MachineService serviceProvider) - { - if (serviceType == null) - { - throw new ArgumentNullException("serviceType"); - } - if (_serviceProviders.ContainsKey(serviceType)) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, Strings.ServiceAlreadyPresent, serviceType.FullName), "serviceType"); - } - if (serviceProvider == null) - { - throw new ArgumentNullException("serviceProvider"); - } - if (!serviceType.IsAssignableFrom(serviceProvider.GetType())) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, Strings.ServiceMustBeAssignable, serviceType.FullName, serviceProvider.GetType().FullName)); - } - - _serviceProviders.Add(serviceType, serviceProvider); - } - - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] - public T GetService() - { - return (T)((IServiceProvider)this).GetService(typeof(T)); - } - - public void RemoveService(Type serviceType) - { - _serviceProviders.Remove(serviceType); - } - - object IServiceProvider.GetService(Type serviceType) - { - return _serviceProviders.ContainsKey(serviceType) ? _serviceProviders[serviceType] : null; - } - - private Dictionary _serviceProviders = new Dictionary(); - } -} diff --git a/ExternalCoreProjects/Virtu/Services/StorageService.cs b/ExternalCoreProjects/Virtu/Services/StorageService.cs deleted file mode 100644 index f70ad21c0d..0000000000 --- a/ExternalCoreProjects/Virtu/Services/StorageService.cs +++ /dev/null @@ -1,214 +0,0 @@ -using System; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.IO; -using System.Security; -using Jellyfish.Virtu.Properties; - -namespace Jellyfish.Virtu.Services -{ - public abstract class StorageService : MachineService - { - protected StorageService(Machine machine) : - base(machine) - { - } - - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] - public bool Load(string fileName, Action reader) - { - try - { - DebugService.WriteMessage("Loading file '{0}'", fileName); - OnLoad(fileName, reader); - } - catch (Exception ex) - { - DebugService.WriteMessage(ex.ToString()); - return false; - } - - return true; - } - -#if !WINDOWS - [SecuritySafeCritical] -#endif - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] - public static bool LoadFile(Stream stream, Action reader) - { - if (reader == null) - { - throw new ArgumentNullException("reader"); - } - - try - { - DebugService.Default.WriteMessage("Loading file '{0}'", "STREAM"); - { - reader(stream); - } - } - catch (Exception ex) - { - DebugService.Default.WriteMessage(ex.ToString()); - return false; - } - - return true; - } - -#if !WINDOWS - [SecuritySafeCritical] -#endif - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] - public static bool LoadFile(FileInfo fileInfo, Action reader) - { - if (fileInfo == null) - { - throw new ArgumentNullException("fileInfo"); - } - if (reader == null) - { - throw new ArgumentNullException("reader"); - } - - try - { - DebugService.Default.WriteMessage("Loading file '{0}'", fileInfo.Name); - using (var stream = fileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.Read)) - { - reader(stream); - } - } - catch (Exception ex) - { - DebugService.Default.WriteMessage(ex.ToString()); - return false; - } - - return true; - } - - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] - public static bool LoadResource(string resourceName, Action reader) - { - if (reader == null) - { - throw new ArgumentNullException("reader"); - } - - try - { - DebugService.Default.WriteMessage("Loading resource '{0}'", resourceName); - using (var stream = File.OpenRead(resourceName)) - reader(stream); - //using (var stream = GetResourceStream(resourceName)) - //{ - // reader(stream); - //} - } - catch (Exception ex) - { - DebugService.Default.WriteMessage(ex.ToString()); - return false; - } - - return true; - } - - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] - public bool Save(string fileName, Action writer) - { - try - { - DebugService.WriteMessage("Saving file '{0}'", fileName); - OnSave(fileName, writer); - } - catch (Exception ex) - { - DebugService.WriteMessage(ex.ToString()); - return false; - } - - return true; - } - -#if !WINDOWS - [SecuritySafeCritical] -#endif - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] - public static bool SaveFile(string fileName, Action writer) - { - if (writer == null) - { - throw new ArgumentNullException("writer"); - } - - try - { - DebugService.Default.WriteMessage("Saving file '{0}'", fileName); - using (var stream = File.Open(fileName, FileMode.Create, FileAccess.Write, FileShare.None)) - { - writer(stream); - } - } - catch (Exception ex) - { - DebugService.Default.WriteMessage(ex.ToString()); - return false; - } - - return true; - } - -#if !WINDOWS - [SecuritySafeCritical] -#endif - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] - public static bool SaveFile(FileInfo fileInfo, Action writer) - { - if (fileInfo == null) - { - throw new ArgumentNullException("fileInfo"); - } - if (writer == null) - { - throw new ArgumentNullException("writer"); - } - - try - { - DebugService.Default.WriteMessage("Saving file '{0}'", fileInfo.Name); - using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write, FileShare.None)) - { - writer(stream); - } - } - catch (Exception ex) - { - DebugService.Default.WriteMessage(ex.ToString()); - return false; - } - - return true; - } - - protected abstract void OnLoad(string fileName, Action reader); - - protected abstract void OnSave(string fileName, Action writer); - - private static Stream GetResourceStream(string resourceName) - { - resourceName = "Jellyfish.Virtu." + resourceName.Replace('/', '.'); - var resourceStream = typeof(StorageService).Assembly.GetManifestResourceStream(resourceName); - if (resourceStream == null) - { - throw new FileNotFoundException(string.Format(CultureInfo.CurrentUICulture, Strings.ResourceNotFound, resourceName)); - } - - return resourceStream; - } - } -} diff --git a/ExternalCoreProjects/Virtu/Services/VideoService.cs b/ExternalCoreProjects/Virtu/Services/VideoService.cs index 43a81ae789..bcbb0015e9 100644 --- a/ExternalCoreProjects/Virtu/Services/VideoService.cs +++ b/ExternalCoreProjects/Virtu/Services/VideoService.cs @@ -1,17 +1,25 @@ namespace Jellyfish.Virtu.Services { - public abstract class VideoService : MachineService + /// + /// this isn't really a "service" anymore, just a helper for the video class + /// + public class VideoService { - protected VideoService(Machine machine) : - base(machine) - { - } + public VideoService() + { + fb = new int[560 * 384]; + } + public VideoService(int[] fb) + { + this.fb = fb; + } - public virtual void SetFullScreen(bool isFullScreen) - { - } + public int[] fb; - public abstract void SetPixel(int x, int y, uint color); - public abstract void Update(); // main thread + public void SetPixel(int x, int y, uint color) + { + int i = 560 * y + x; + fb[i] = fb[i + 560] = (int)color; + } } } diff --git a/ExternalCoreProjects/Virtu/Speaker.cs b/ExternalCoreProjects/Virtu/Speaker.cs index a19e53fe71..2a2a89b468 100644 --- a/ExternalCoreProjects/Virtu/Speaker.cs +++ b/ExternalCoreProjects/Virtu/Speaker.cs @@ -6,6 +6,7 @@ namespace Jellyfish.Virtu { public sealed class Speaker : MachineComponent { + public Speaker() { } public Speaker(Machine machine) : base(machine) { @@ -14,39 +15,17 @@ namespace Jellyfish.Virtu public override void Initialize() { - _audioService = Machine.Services.GetService(); + AudioService = new Services.AudioService(); - Volume = 0.5f; Machine.Events.AddEvent(CyclesPerFlush * Machine.Cpu.Multiplier, _flushOutputEvent); } public override void Reset() { - _audioService.Reset(); _isHigh = false; _highCycles = _totalCycles = 0; } - public override void LoadState(BinaryReader reader, Version version) - { - if (reader == null) - { - throw new ArgumentNullException("reader"); - } - - Volume = reader.ReadSingle(); - } - - public override void SaveState(BinaryWriter writer) - { - if (writer == null) - { - throw new ArgumentNullException("writer"); - } - - writer.Write(Volume); - } - public void ToggleOutput() { UpdateCycles(); @@ -56,7 +35,8 @@ namespace Jellyfish.Virtu private void FlushOutputEvent() { UpdateCycles(); - _audioService.Output(_highCycles * short.MaxValue / _totalCycles); // quick and dirty decimation + // TODO: better than simple decimation here!! + AudioService.Output(_highCycles * short.MaxValue / _totalCycles); _highCycles = _totalCycles = 0; Machine.Events.AddEvent(CyclesPerFlush * Machine.Cpu.Multiplier, _flushOutputEvent); @@ -73,20 +53,15 @@ namespace Jellyfish.Virtu _lastCycles = Machine.Cpu.Cycles; } - public float Volume { get { return _volume; } set { _volume = value; _audioService.SetVolume(_volume); } } - private const int CyclesPerFlush = 23; private Action _flushOutputEvent; - private AudioService _audioService; - private bool _isHigh; private int _highCycles; private int _totalCycles; private long _lastCycles; - private float _volume; - public AudioService AudioService { get { return _audioService; } } + public AudioService AudioService { get; private set; } } } diff --git a/ExternalCoreProjects/Virtu/Video.cs b/ExternalCoreProjects/Virtu/Video.cs index 4f2330aed1..2094d5fdc3 100644 --- a/ExternalCoreProjects/Virtu/Video.cs +++ b/ExternalCoreProjects/Virtu/Video.cs @@ -9,6 +9,7 @@ namespace Jellyfish.Virtu public sealed partial class Video : MachineComponent { + public Video() { } public Video(Machine machine) : base(machine) { @@ -27,7 +28,7 @@ namespace Jellyfish.Virtu public override void Initialize() { _memory = Machine.Memory; - _videoService = Machine.Services.GetService(); + VideoService = new Services.VideoService(); //#if SILVERLIGHT || WPF _colorBlack = 0xFF000000; // BGRA @@ -68,7 +69,6 @@ namespace Jellyfish.Virtu //#endif SetPalette(); - IsFullScreen = false; IsMonochrome = false; ScannerOptions = ScannerOptions.None; @@ -86,71 +86,6 @@ namespace Jellyfish.Virtu FlushScreen(); } - public override void LoadState(BinaryReader reader, Version version) - { - if (reader == null) - { - throw new ArgumentNullException("reader"); - } - - _colorBlack = reader.ReadUInt32(); - _colorDarkBlue = reader.ReadUInt32(); - _colorDarkGreen = reader.ReadUInt32(); - _colorMediumBlue = reader.ReadUInt32(); - _colorBrown = reader.ReadUInt32(); - _colorLightGrey = reader.ReadUInt32(); - _colorGreen = reader.ReadUInt32(); - _colorAquamarine = reader.ReadUInt32(); - _colorDeepRed = reader.ReadUInt32(); - _colorPurple = reader.ReadUInt32(); - _colorDarkGrey = reader.ReadUInt32(); - _colorLightBlue = reader.ReadUInt32(); - _colorOrange = reader.ReadUInt32(); - _colorPink = reader.ReadUInt32(); - _colorYellow = reader.ReadUInt32(); - _colorWhite = reader.ReadUInt32(); - _colorMonochrome = reader.ReadUInt32(); - SetPalette(); - - IsFullScreen = reader.ReadBoolean(); - IsMonochrome = reader.ReadBoolean(); - ScannerOptions = (ScannerOptions)reader.ReadInt32(); - - SetCharSet(); - DirtyScreen(); - FlushScreen(); - } - - public override void SaveState(BinaryWriter writer) - { - if (writer == null) - { - throw new ArgumentNullException("writer"); - } - - writer.Write(_colorBlack); - writer.Write(_colorDarkBlue); - writer.Write(_colorDarkGreen); - writer.Write(_colorMediumBlue); - writer.Write(_colorBrown); - writer.Write(_colorLightGrey); - writer.Write(_colorGreen); - writer.Write(_colorAquamarine); - writer.Write(_colorDeepRed); - writer.Write(_colorPurple); - writer.Write(_colorDarkGrey); - writer.Write(_colorLightBlue); - writer.Write(_colorOrange); - writer.Write(_colorPink); - writer.Write(_colorYellow); - writer.Write(_colorWhite); - writer.Write(_colorMonochrome); - - writer.Write(IsFullScreen); - writer.Write(IsMonochrome); - writer.Write((int)ScannerOptions); - } - public void DirtyCell(int addressOffset) { _isCellDirty[CellIndex[addressOffset]] = true; @@ -1061,7 +996,7 @@ namespace Jellyfish.Virtu private void SetPixel(int x, int y, int color) { - _videoService.SetPixel(x, 2 * y, _colorPalette[color]); + VideoService.SetPixel(x, 2 * y, _colorPalette[color]); } private void SetScanner() @@ -1083,25 +1018,41 @@ namespace Jellyfish.Virtu _cyclesPerFlash = VSyncsPerFlash * _cyclesPerVSync; } - public uint ColorBlack { get { return _colorBlack; } set { _colorBlack = value; SetPalette(); } } - public uint ColorDarkBlue { get { return _colorDarkBlue; } set { _colorDarkBlue = value; SetPalette(); } } - public uint ColorDarkGreen { get { return _colorDarkGreen; } set { _colorDarkGreen = value; SetPalette(); } } - public uint ColorMediumBlue { get { return _colorMediumBlue; } set { _colorMediumBlue = value; SetPalette(); } } - public uint ColorBrown { get { return _colorBrown; } set { _colorBrown = value; SetPalette(); } } - public uint ColorLightGrey { get { return _colorLightGrey; } set { _colorLightGrey = value; SetPalette(); } } - public uint ColorGreen { get { return _colorGreen; } set { _colorGreen = value; SetPalette(); } } - public uint ColorAquamarine { get { return _colorAquamarine; } set { _colorAquamarine = value; SetPalette(); } } - public uint ColorDeepRed { get { return _colorDeepRed; } set { _colorDeepRed = value; SetPalette(); } } - public uint ColorPurple { get { return _colorPurple; } set { _colorPurple = value; SetPalette(); } } - public uint ColorDarkGrey { get { return _colorDarkGrey; } set { _colorDarkGrey = value; SetPalette(); } } - public uint ColorLightBlue { get { return _colorLightBlue; } set { _colorLightBlue = value; SetPalette(); } } - public uint ColorOrange { get { return _colorOrange; } set { _colorOrange = value; SetPalette(); } } - public uint ColorPink { get { return _colorPink; } set { _colorPink = value; SetPalette(); } } - public uint ColorYellow { get { return _colorYellow; } set { _colorYellow = value; SetPalette(); } } - public uint ColorWhite { get { return _colorWhite; } set { _colorWhite = value; SetPalette(); } } - public uint ColorMonochrome { get { return _colorMonochrome; } set { _colorMonochrome = value; SetPalette(); } } - - public bool IsFullScreen { get { return _isFullScreen; } set { _isFullScreen = value; _videoService.SetFullScreen(_isFullScreen); } } + [Newtonsoft.Json.JsonIgnore] + public uint ColorBlack { get { return _colorBlack; } set { _colorBlack = value; SetPalette(); } } + [Newtonsoft.Json.JsonIgnore] + public uint ColorDarkBlue { get { return _colorDarkBlue; } set { _colorDarkBlue = value; SetPalette(); } } + [Newtonsoft.Json.JsonIgnore] + public uint ColorDarkGreen { get { return _colorDarkGreen; } set { _colorDarkGreen = value; SetPalette(); } } + [Newtonsoft.Json.JsonIgnore] + public uint ColorMediumBlue { get { return _colorMediumBlue; } set { _colorMediumBlue = value; SetPalette(); } } + [Newtonsoft.Json.JsonIgnore] + public uint ColorBrown { get { return _colorBrown; } set { _colorBrown = value; SetPalette(); } } + [Newtonsoft.Json.JsonIgnore] + public uint ColorLightGrey { get { return _colorLightGrey; } set { _colorLightGrey = value; SetPalette(); } } + [Newtonsoft.Json.JsonIgnore] + public uint ColorGreen { get { return _colorGreen; } set { _colorGreen = value; SetPalette(); } } + [Newtonsoft.Json.JsonIgnore] + public uint ColorAquamarine { get { return _colorAquamarine; } set { _colorAquamarine = value; SetPalette(); } } + [Newtonsoft.Json.JsonIgnore] + public uint ColorDeepRed { get { return _colorDeepRed; } set { _colorDeepRed = value; SetPalette(); } } + [Newtonsoft.Json.JsonIgnore] + public uint ColorPurple { get { return _colorPurple; } set { _colorPurple = value; SetPalette(); } } + [Newtonsoft.Json.JsonIgnore] + public uint ColorDarkGrey { get { return _colorDarkGrey; } set { _colorDarkGrey = value; SetPalette(); } } + [Newtonsoft.Json.JsonIgnore] + public uint ColorLightBlue { get { return _colorLightBlue; } set { _colorLightBlue = value; SetPalette(); } } + [Newtonsoft.Json.JsonIgnore] + public uint ColorOrange { get { return _colorOrange; } set { _colorOrange = value; SetPalette(); } } + [Newtonsoft.Json.JsonIgnore] + public uint ColorPink { get { return _colorPink; } set { _colorPink = value; SetPalette(); } } + [Newtonsoft.Json.JsonIgnore] + public uint ColorYellow { get { return _colorYellow; } set { _colorYellow = value; SetPalette(); } } + [Newtonsoft.Json.JsonIgnore] + public uint ColorWhite { get { return _colorWhite; } set { _colorWhite = value; SetPalette(); } } + [Newtonsoft.Json.JsonIgnore] + public uint ColorMonochrome { get { return _colorMonochrome; } set { _colorMonochrome = value; SetPalette(); } } + [Newtonsoft.Json.JsonIgnore] public bool IsMonochrome { get { return _isMonochrome; } set { _isMonochrome = value; DirtyScreen(); } } public ScannerOptions ScannerOptions { get { return _scannerOptions; } set { _scannerOptions = value; SetScanner(); } } @@ -1113,7 +1064,7 @@ namespace Jellyfish.Virtu private Action _resetVSyncEvent; private Memory _memory; - private VideoService _videoService; + public VideoService VideoService { get; private set; } private uint _colorBlack; private uint _colorDarkBlue; @@ -1132,7 +1083,6 @@ namespace Jellyfish.Virtu private uint _colorYellow; private uint _colorWhite; private uint _colorMonochrome; - private bool _isFullScreen; private bool _isMonochrome; private bool _isTextInversed; private ScannerOptions _scannerOptions; diff --git a/ExternalCoreProjects/Virtu/VideoData.cs b/ExternalCoreProjects/Virtu/VideoData.cs index b6085fc62c..0579e26d0b 100644 --- a/ExternalCoreProjects/Virtu/VideoData.cs +++ b/ExternalCoreProjects/Virtu/VideoData.cs @@ -1627,7 +1627,7 @@ namespace Jellyfish.Virtu public const int ModeE = 0xE; public const int ModeF = 0xF; - private readonly Action[] FlushRowMode; + private Action[] FlushRowMode; private const int Width = 560; private const int Height = VLineEnterVBlank; diff --git a/ExternalCoreProjects/Virtu/Virtu.csproj b/ExternalCoreProjects/Virtu/Virtu.csproj index 7c845ddfa0..cf661914c6 100644 --- a/ExternalCoreProjects/Virtu/Virtu.csproj +++ b/ExternalCoreProjects/Virtu/Virtu.csproj @@ -1,5 +1,5 @@  - + Debug @@ -31,6 +31,9 @@ 4 + + ..\..\References\Newtonsoft.Json.dll + @@ -43,6 +46,7 @@ + @@ -64,12 +68,6 @@ - - - - - - diff --git a/References/Virtu.dll b/References/Virtu.dll index 13786ad65e..8ab1333616 100644 Binary files a/References/Virtu.dll and b/References/Virtu.dll differ